diff --git a/.github/workflows/build_llvm_libraries.yml b/.github/workflows/build_llvm_libraries.yml index 7ef1dd63f..a24e340fa 100644 --- a/.github/workflows/build_llvm_libraries.yml +++ b/.github/workflows/build_llvm_libraries.yml @@ -11,6 +11,9 @@ on: arch: required: true type: string + container_image: + required: false + type: string outputs: cache_key: description: "A cached key of LLVM libraries" @@ -19,6 +22,10 @@ on: jobs: build_llvm_libraries: runs-on: ${{ inputs.os }} + # Using given container image if it is specified. + # Otherwise, it will be ignored by the runner. + container: + image: ${{ inputs.container_image }} outputs: key: ${{ steps.create_lib_cache_key.outputs.key}} @@ -71,8 +78,9 @@ jobs: 0-ccache-${{ inputs.os }} if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' && inputs.os == 'ubuntu-22.04' + # Don't install dependencies if the cache is hit or running in docker container - run: sudo apt install -y ccache ninja-build - if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' && startsWith(inputs.os, 'ubuntu') + if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' && startsWith(inputs.os, 'ubuntu') && inputs.container_image == '' - uses: actions/cache@v3 with: diff --git a/.github/workflows/compilation_on_android_ubuntu.yml b/.github/workflows/compilation_on_android_ubuntu.yml index 6b653b501..98d346f9e 100644 --- a/.github/workflows/compilation_on_android_ubuntu.yml +++ b/.github/workflows/compilation_on_android_ubuntu.yml @@ -444,6 +444,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: [ diff --git a/.github/workflows/compilation_on_macos.yml b/.github/workflows/compilation_on_macos.yml index aac16898b..12f1d73cb 100644 --- a/.github/workflows/compilation_on_macos.yml +++ b/.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 diff --git a/.github/workflows/compilation_on_nuttx.yml b/.github/workflows/compilation_on_nuttx.yml index 2f4e3aca3..8e1f4aad0 100644 --- a/.github/workflows/compilation_on_nuttx.yml +++ b/.github/workflows/compilation_on_nuttx.yml @@ -50,7 +50,10 @@ env: jobs: build_iwasm_on_nuttx: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest + container: + image: ghcr.io/apache/nuttx/apache-nuttx-ci-linux@sha256:4b4cbf0b70512e61ada9cdcb76b97e90ad478b85e4d0774d05a95fa32caa8c39 + strategy: matrix: nuttx_board_config: [ @@ -60,12 +63,14 @@ jobs: "boards/arm/rp2040/raspberrypi-pico/configs/nsh", # cortex-m7 "boards/arm/stm32h7/nucleo-h743zi/configs/nsh", - # riscv32imac + # riscv32imc + "boards/risc-v/espressif/esp32c3-generic/configs/nsh", + # riscv32gc "boards/risc-v/qemu-rv/rv-virt/configs/nsh", - # riscv64imac - "boards/risc-v/qemu-rv/rv-virt/configs/nsh64", # riscv64gc - "boards/risc-v/k210/maix-bit/configs/nsh", + "boards/risc-v/qemu-rv/rv-virt/configs/nsh64", + # arm64 + "boards/arm64/qemu/qemu-armv8a/configs/nsh", ] wamr_config_option: [ "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_FAST=y\\n", @@ -81,39 +86,18 @@ jobs: ] steps: - - name: Install Utilities - run: | - sudo apt install -y kconfig-frontends-nox genromfs - pip3 install pyelftools - pip3 install cxxfilt - - - name: Install ARM Compilers - if: contains(matrix.nuttx_board_config, 'arm') - run: sudo apt install -y gcc-arm-none-eabi - - - 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 - tar xvf riscv.tar.gz - echo "$PWD/riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-x86_64-linux-ubuntu14/bin" >> $GITHUB_PATH - - - name: Install WASI-SDK - run: | - curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz > wasi-sdk.tar.gz - tar xvf wasi-sdk.tar.gz - sudo mv wasi-sdk-* /opt/wasi-sdk - - name: Checkout NuttX uses: actions/checkout@v3 with: repository: apache/incubator-nuttx + ref: releases/12.3 path: nuttx - name: Checkout NuttX Apps uses: actions/checkout@v3 with: repository: apache/incubator-nuttx-apps + ref: releases/12.3 path: apps - name: Checkout WAMR @@ -124,7 +108,7 @@ jobs: - name: Enable WAMR for NuttX run: | - find nuttx/boards -name defconfig | xargs sed -i '$a\CONFIG_EOL_IS_LF=y\nCONFIG_PSEUDOFS_SOFTLINKS=y\n${{ matrix.wamr_config_option }}' + find nuttx/boards -name defconfig | xargs sed -i '$a\CONFIG_EOL_IS_LF=y\n${{ matrix.wamr_config_option }}' find nuttx/boards/sim -name defconfig | xargs sed -i '$a\CONFIG_LIBM=y\n' - name: Build diff --git a/.github/workflows/compilation_on_windows.yml b/.github/workflows/compilation_on_windows.yml index 0d38e8ae5..97a4aaae2 100644 --- a/.github/workflows/compilation_on_windows.yml +++ b/.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 diff --git a/.github/workflows/nightly_run.yml b/.github/workflows/nightly_run.yml index bef639792..1bd0c4856 100644 --- a/.github/workflows/nightly_run.yml +++ b/.github/workflows/nightly_run.yml @@ -49,10 +49,17 @@ jobs: with: os: "ubuntu-20.04" arch: "X86" + build_llvm_libraries_on_ubuntu_2204: + uses: ./.github/workflows/build_llvm_libraries.yml + with: + os: "ubuntu-22.04" + arch: "X86" build_wamrc: needs: - [build_llvm_libraries_on_ubuntu_2004] + [ + build_llvm_libraries_on_ubuntu_2004, + ] runs-on: ${{ matrix.os }} strategy: matrix: @@ -90,7 +97,9 @@ jobs: build_iwasm: needs: - [build_llvm_libraries_on_ubuntu_2004] + [ + build_llvm_libraries_on_ubuntu_2004, + ] runs-on: ${{ matrix.os }} strategy: matrix: @@ -492,19 +501,26 @@ 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: [ build_iwasm, build_llvm_libraries_on_ubuntu_2004, + build_llvm_libraries_on_ubuntu_2204, build_wamrc, ] runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: - os: [ubuntu-20.04] - sanitizer: ["", "ubsan", "asan"] + os: [ubuntu-20.04, ubuntu-22.04] + sanitizer: ["", "ubsan", "asan", "tsan"] running_mode: [ "classic-interp", @@ -530,11 +546,14 @@ jobs: - os: ubuntu-20.04 llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2004.outputs.cache_key }} ubuntu_version: "20.04" + - os: ubuntu-22.04 + llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2204.outputs.cache_key }} + ubuntu_version: "22.04" exclude: # uncompatiable modes and features - os: ubuntu-20.04 - sanitizer: asan + sanitizer: tsan # asan works only for aot now - running_mode: "classic-interp" sanitizer: asan @@ -546,6 +565,14 @@ jobs: sanitizer: asan - running_mode: "multi-tier-jit" sanitizer: asan + - running_mode: "classic-interp" + sanitizer: tsan + - running_mode: "jit" + sanitizer: tsan + - running_mode: "fast-jit" + sanitizer: tsan + - running_mode: "multi-tier-jit" + sanitizer: tsan # classic-interp and fast-interp don't support simd - running_mode: "classic-interp" test_option: $SIMD_TEST_OPTIONS @@ -595,9 +622,10 @@ jobs: || matrix.test_option == '$WASI_TEST_OPTIONS') && matrix.running_mode != 'fast-jit' && matrix.running_mode != 'jit' && matrix.running_mode != 'multi-tier-jit' run: echo "TEST_ON_X86_32=true" >> $GITHUB_ENV - - - name: set sanitizer - run: echo "WAMR_BUILD_SANITIZER=${{ matrix.sanitizer }}" >> $GITHUB_ENV + + - name: set additional tsan options + run: echo "TSAN_OPTIONS=suppressions=$PWD/tsan_suppressions.txt" >> $GITHUB_ENV + working-directory: tests/wamr-test-suites #only download llvm libraries in jit and aot mode - name: Get LLVM libraries @@ -638,7 +666,7 @@ jobs: - name: run tests timeout-minutes: 40 - run: ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }} + run: ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }} -T "${{ matrix.sanitizer }}" working-directory: ./tests/wamr-test-suites #only install x32 support libraries when to run x86_32 cases diff --git a/.github/workflows/release_process.yml b/.github/workflows/release_process.yml index 4188b4d40..ef722acdb 100644 --- a/.github/workflows/release_process.yml +++ b/.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 diff --git a/.github/workflows/spec_test_on_nuttx.yml b/.github/workflows/spec_test_on_nuttx.yml index 4ffa943a9..957f82f34 100644 --- a/.github/workflows/spec_test_on_nuttx.yml +++ b/.github/workflows/spec_test_on_nuttx.yml @@ -4,6 +4,13 @@ name: spec test on nuttx on: + pull_request: + types: + - opened + - synchronize + paths: + - ".github/workflows/spec_test_on_nuttx.yml" + schedule: - cron: '0 0 * * *' @@ -12,6 +19,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: @@ -19,59 +28,85 @@ jobs: with: os: "ubuntu-22.04" arch: "ARM RISCV AArch64" + container_image: ghcr.io/apache/nuttx/apache-nuttx-ci-linux@sha256:4b4cbf0b70512e61ada9cdcb76b97e90ad478b85e4d0774d05a95fa32caa8c39 spec_test_on_qemu: - runs-on: ${{ matrix.os }} + runs-on: ubuntu-latest needs: [build_llvm_libraries] + container: + image: ghcr.io/apache/nuttx/apache-nuttx-ci-linux@sha256:4b4cbf0b70512e61ada9cdcb76b97e90ad478b85e4d0774d05a95fa32caa8c39 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", + # fpu_type: "fp" + # }, + # { + # config: "boards/arm/imx6/sabre-6quad/configs/nsh", + # target: "thumbv7", + # fpu_type: "none" + # }, + { + config: "boards/arm/imx6/sabre-6quad/configs/nsh", + target: "thumbv7_vfp", + fpu_type: "dp" + }, + { + config: "boards/risc-v/qemu-rv/rv-virt/configs/nsh", + target: "riscv32", + fpu_type: "none" + }, + # { + # config: "boards/risc-v/qemu-rv/rv-virt/configs/nsh", + # target: "riscv32_ilp32d", + # fpu_type: "dp" + # }, + { + config: "boards/risc-v/qemu-rv/rv-virt/configs/nsh64", + target: "riscv64", + fpu_type: "none" + }, ] + 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 }}" ] + + exclude: + # XIP is not fully supported yet on RISCV64, some relocations can not be resolved + - target_config: { config: "boards/risc-v/qemu-rv/rv-virt/configs/nsh64" } + wamr_test_option: { mode: "-t aot -X" } + 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 - - - 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 - tar xvf riscv.tar.gz - echo "$PWD/riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-x86_64-linux-ubuntu14/bin" >> $GITHUB_PATH - - - name: Install WASI-SDK - run: | - curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz > wasi-sdk.tar.gz - tar xvf wasi-sdk.tar.gz - sudo mv wasi-sdk-* /opt/wasi-sdk - - name: Checkout NuttX uses: actions/checkout@v3 with: repository: apache/incubator-nuttx + ref: releases/12.3 path: nuttx - name: Checkout NuttX Apps uses: actions/checkout@v3 with: repository: apache/incubator-nuttx-apps + ref: releases/12.3 path: apps - name: Checkout WAMR @@ -81,6 +116,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 +126,50 @@ 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.fpu_type == 'none' + run: | + find nuttx/boards -name defconfig | xargs sed -i '$a\# CONFIG_ARCH_FPU is not set\n' + + - name: Disable DPFPU for NuttX + if: matrix.target_config.fpu_type == 'fp' + run: | + find nuttx/boards -name defconfig | xargs sed -i '$a\# CONFIG_ARCH_DPFPU 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 - - - name: Test on ARM - if: endsWith(matrix.nuttx_board_config, 'sabre-6quad/configs/nsh') + echo "firmware=$PWD/nuttx" >> $GITHUB_OUTPUT + + - name: Test 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 }} - - - name: Test on RISCV32 - if: endsWith(matrix.nuttx_board_config, 'rv-virt/configs/nsh') - 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') - 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 }} diff --git a/CMakeLists.txt b/CMakeLists.txt index fbea2616e..1c8799494 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,11 +107,6 @@ endif () set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}) -# Set the strip command based on the system (GNU or Clang) -if (CMAKE_STRIP) - set (CMAKE_STRIP_FLAGS "--strip-all") -endif () - include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security -Wshadow -Wno-unused-parameter") @@ -146,15 +141,6 @@ endif () install (TARGETS iwasm_static ARCHIVE DESTINATION lib) -# If it's a Release build, strip the static library -if (CMAKE_STRIP AND CMAKE_BUILD_TYPE STREQUAL "Release") - # Strip static library - message (STATUS "Stripping static library after build!") - add_custom_command (TARGET iwasm_static POST_BUILD - COMMAND ${CMAKE_STRIP} ${CMAKE_STRIP_FLAGS} $ - ) -endif () - # SHARED LIBRARY add_library (iwasm_shared SHARED ${WAMR_RUNTIME_LIB_SOURCE}) set_target_properties (iwasm_shared PROPERTIES OUTPUT_NAME iwasm) @@ -176,12 +162,3 @@ install (FILES ${WAMR_ROOT_DIR}/core/iwasm/include/wasm_export.h ${WAMR_ROOT_DIR}/core/iwasm/include/lib_export.h DESTINATION include) - -# If it's a Release build, strip the shared library -if (CMAKE_STRIP AND CMAKE_BUILD_TYPE STREQUAL "Release") - # Strip shared library - message (STATUS "Stripping shared library after build!") - add_custom_command (TARGET iwasm_shared POST_BUILD - COMMAND ${CMAKE_STRIP} ${CMAKE_STRIP_FLAGS} $ - ) -endif () diff --git a/README.md b/README.md index 486ca0fd0..dfdae2da8 100644 --- a/README.md +++ b/README.md @@ -92,8 +92,10 @@ The current TSC members: - [lum1n0us](https://github.com/lum1n0us) - **Liang He**, - [no1wudi](https://github.com/no1wudi) **Qi Huang**, - [qinxk-inter](https://github.com/qinxk-inter) - **Xiaokang Qin**, +- [ttrenner ](https://github.com/ttrenner) - **Trenner, Thomas**, - [wei-tang](https://github.com/wei-tang) - **Wei Tang**, - [wenyongh](https://github.com/wenyongh) - **Wenyong Huang**, +- [woodsmc](https://github.com/woodsmc) - **Woods, Chris**, - [xujuntwt95329](https://github.com/xujuntwt95329) - **Jun Xu**, - [xwang98](https://github.com/xwang98) - **Xin Wang**, (chair) - [yamt](https://github.com/yamt) - **Takashi Yamamoto**, diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 5c7f598da..fbb97f5d7 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,3 +1,172 @@ +## WAMR-1.3.0 + +### Breaking Changes +- Abstract POSIX filesystem functions (#2585) + - Change API wasm_runtime_set_wasi_args_ex's arguments + `int stdinfd/stdoutfd/stderrfd` to `int64_t stdinfd/stdoutfd/stderrfd` +- core/iwasm: Support mapped file system access on non-libuv WASI (#2628) + - Enable mapping host directories to guest directories by parsing + the `map_dir_list` argument in API `wasm_runtime_init_wasi` for libc-wasi +- Support muti-module for AOT mode (#2482) + - Add argument `package_type_t module_type` for module_reader callback +- Generate jitdump to support linux perf for LLVM JIT (#2788) + - Add a field `bool linux_perf_support` in RuntimeInitArgs +- Remove provision of unnecessary fd rights (#2579) +- libc-wasi: Conditionally support SYNC flags (#2581) + +### New Features +- Support muti-module for AOT mode (#2482) +- Implement libc-wasi for Windows platform (#2740) +- Implement module instance context APIs (#2436) +- Implement async termination of blocking thread (#2516) +- Generate jitdump to support linux perf for LLVM JIT (#2788) +- Add Cosmopolitan Libc Platform (#2598) + +### Bug Fixes +- sgx-ra: Disable the building of samples (#2507) +- Handle a return from wasi _start function correctly (#2529) +- fd_object_release: Preserve errno (#2535) +- Fix build error with ancient GCC (4.8) (#2553) +- Fix compiling error for RT-Thread (#2569) +- Fix potential unaligned store issue when extra return value is v128 (#2583) +- Fix loader push_pop_frame_ref_offset (#2590) +- Fix compilation error on Android platform (#2594) +- Ignore handling SIG_DFL/SIG_IGN for previous sig action (#2589) +- Fix nightly run sanitizer error in Fast JIT (#2601) +- Check ValueKind before extracting a constant int value (#2595) +- Patch implementations of vfbinop(min,max,pmin,pax) (#2584) +- Improve stack trace dump and fix coding guideline CI (#2599) +- aot_resolve_stack_sizes: Disable the size check for now (#2608) +- Remove module instance from hashmap in wasi_nn_destroy (#2613) +- Fix label index out-of-range references in op_br_table_cache (#2615) +- Fix compilation of shift opcodes on x86_64 and i386 architectures (#2619) +- Fix potential issue in aot compiler when translating block opcodes (#2622) +- Use another default pipeline when opt-level is 0 (#2624) +- Fix AOT shift operations for indirect constants (#2627) +- Fix fast-interp "pre-compiled label offset out of range" issue (#2659) +- Revert "Strip static and shared libraries of iwasm to reduce the binary size (#2431)" (#2669) +- Fix windows compilation on C++20 (#2670) +- Fix fast-jit f32/f64 truncate to i32/i64 (#2671) +- Fix use getrandom on cosmopolitan libc (#2674) +- Fix repeatedly initialize shared memory data and protect the memory's fields (#2673) +- Minor fixes for Go bindings (#2676) +- Fix issues reported by Coverity (#2681) +- Add more buffer boundary checks in wasm loader (#2734) +- Grab cluster->lock when modifying exec_env->module_inst (#2685) +- Fix CMSIS import with Zephyr 3.4+ (#2744) +- Fix log messages in Zephyr example (#2761) +- Fix fast-jit callnative translation (#2765) +- aot compiler: Disable musttail for thumb (#2771) +- Fix data/elem drop (#2747) +- Fix formatting in aot_dump_perf_profiling (#2796) +- Fix formatting in wasm_dump_perf_profiling (#2799) +- Fix memory.init opcode issue in fast-interp (#2798) +- aot compiler: Fix handle next reachable if block (#2793) +- Fix configurable bounds checks typo (#2809) +- Attestation: Free JSON from the Wasm module heap (#2803) +- Update Zephyr support to v3.5.0 and make instructions generic to boards (#2805) +- Return error when shutdown() fails (#2801) +- iwasm: Print help when meeting unknown cmd options (#2824) +- Fix fast-jit accessing shared memory's fields issue (#2841) +- Fix wasm loader handle op_br_table and op_drop (#2864) +- Fix block with type issue in fast interp (#2866) +- Fix float argument handling for riscv32 ilp32d (#2871) +- Portably handle fd_advise on directory fd (#2875) +- Fix sample basic intToStr was called with wrong length (#2876) + +### Enhancements +- Implement strict validation of thread IDs according to the specification (#2521) +- Stop abusing shared memory lock to protect exception (#2509) +- Implement os_usleep for posix (#2517) +- set_exception_visitor: Remove the special case for wasi proc exit (#2525) +- Revert "Return error when exception was raised after main thread finishes" (#2524) +- libc-wasi: Remove unused code (#2528) +- Add callback to handle memory.grow failures (#2522) +- Add context to enlarge memory error callback (#2546) +- Add ARM aeabi symbol for clearing memory content in a specific range (#2531) +- Unifdef -U WASMTIME_SSP_STATIC_CURFDS (#2533) +- Fix typo for IP address buffer (#2532) +- Add an API to terminate instance (#2538) +- Add user to enlarge memory error callback (#2546) +- runtest.py: Show accurate case amount in summary (#2549) +- Allow using custom signal handler from non-main thread (#2551) +- Return __WASI_EINVAL from fd_prestat_dir_name (#2580) +- Support AOT compiler with LLVM 17 (#2567) +- Add support for closing/renumbering preopen fds (#2578) +- Enable AOT usage on M1 mac (#2618) +- core/iwasm: Support mapped file system access on non-libuv WASI (#2628) +- Enable MASM automatically in runtime_lib.cmake (#2634) +- Abstract POSIX filesystem functions (#2585) +- Implement wasi clock_time/clock_res get (#2637) +- Fix several typo/warning/unused-code issues (#2655) +- Partial windows filesystem implementation (#2657) +- Apply no_sanitize_address for clang compiler in several places (#2663) +- Refactor clock functions to use WASI types (#2666) +- Refine lock/unlock shared memory (#2682) +- Fix several AOT compiler issues (#2697) +- Fix AOT compiler simd shift opcodes (#2715) +- Fix invalid use of jit_reg_is_const_val in fast-jit (#2718) +- Use user defined malloc/free functions for user defined memory allocator (#2717) +- Move WASI types into separate header (#2724) +- Provide default vprintf on UWP (#2725) +- Fix typo in Zephyr simple example (#2738) +- Fix switch-case fallthrough compilation warning (#2753) +- Add eabihf ABI support and set vendor-sys of bare-metal targets (#2745) +- Return uint32 from WASI functions (#2749) +- Add compilation flag to enable/disable heap corruption check (#2766) +- Extend os_mmap to support map file from fd (#2763) +- Fix printing ref.extern addresses in wasm_application.c (#2774) +- Remove unused JitBitmap (#2775) +- Use next generation crypto API on Windows (#2769) +- More precise help info of enabled targets for wamrc (#2783) +- Refine atomic operation flags in bh_atomic.h (#2780) +- Fix comment in WAMR_MEM_DUAL_BUS_MIRROR (#2791) +- Fix return type in wasm_loader_get_custom_section (#2794) +- Add support for custom sections in nuttx (#2795) +- Change is_shared_memory type from bool to uint8 (#2800) +- Fix typos in zephyr platform struct descriptions (#2818) +- Access linear memory size atomically (#2834) +- Output warning and quit if import/export name contains '\00' (#2806) +- Use wasm_config_t to pass private configuration to wasm_engine_new (#2837) +- core/iwasm/interpreter/wasm_loader.c: remove an extra validation (#2845) +- Don't add "+d" to riscv cpu features if already given (#2855) +- Fix compilation warnings on Windows (#2868) + +### Others +- Add mutex stress test (#2472) +- Add unit tests for the tid allocator (#2519) +- Add support for running tests on apple M1 macs (#2554) +- export_native_api.md: Add a note about thread termination (#2572) +- test_wamr.sh: Print a bit more meaningful message (#2574) +- run_wasi_tests.sh: Provide stdin by ourselves (#2576) +- Fix a few issues in "run_wasi_tests.sh: provide stdin by ourselves" (#2582) +- Fix compile error of tsf benchmark (#2588) +- test_wamr.sh: Bump wasi-testsuite version (#2568) +- samples/inst-context-threads: Add a brief explanation (#2592) +- doc/memory_tune.md: "remove malloc" hack is not relevant to wasi-threads (#2603) +- Refactor stress tests to make them runnable in reactor mode (#2614) +- Run rust tests from wasi-testsuite (#2484) +- spec-test-script: Fix NaN comparision between v128 values (#2605) +- CI: Enable testing AOT multi-module feature (#2621) +- Vote for nomination of Woods, Chris and Trenner, Thomas as TSC members (#2638) +- Add tsan for fast interp and aot (#2679) +- Enable WASI tests on Windows CI (#2699) +- docs: Fix typo in export native APIs doc (#2750) +- Update RISC-V compilers in Nuttx compilation CI and spec test CI (#2756) +- Enable more LLVM backends for the release wamrc binary (#2778) +- Disable FPU in NuttX spec test (#2781) +- Fix broken links in app-mgr README.md (#2786) +- Fix build error of libsodium benchmark (#2792) +- Fix wamr-test-suites script for macos (#2819) +- Run spec test for classic/fast-interp in NuttX CI (#2817) +- test_wamr.sh: Don't bother to build shared library (#2844) +- doc/build_wamr.md: Fix links to RISC-V named ABIs (#2852) +- Fix typos of CIDR in docs and help text (#2851) +- Enable spectest on riscv64 (#2843) +- Update FPU configuration in spec_test_on_nuttx.yml (#2856) + +--- + ## WAMR-1.2.3 ### Breaking Changes diff --git a/build-scripts/build_llvm.py b/build-scripts/build_llvm.py index d70915c3b..e5036e5ca 100755 --- a/build-scripts/build_llvm.py +++ b/build-scripts/build_llvm.py @@ -55,8 +55,6 @@ def build_llvm(llvm_dir, platform, backends, projects, use_clang=False, extra_fl "-DLLVM_APPEND_VC_REV:BOOL=ON", "-DLLVM_BUILD_EXAMPLES:BOOL=OFF", "-DLLVM_BUILD_LLVM_DYLIB:BOOL=OFF", - "-DLLVM_BUILD_TESTS:BOOL=OFF", - "-DLLVM_CCACHE_BUILD:BOOL=ON", "-DLLVM_ENABLE_BINDINGS:BOOL=OFF", "-DLLVM_ENABLE_IDE:BOOL=OFF", "-DLLVM_ENABLE_LIBEDIT=OFF", @@ -67,10 +65,16 @@ 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", ] + # ccache is not available on Windows + if not "windows" == platform: + LLVM_COMPILE_OPTIONS.append("-DLLVM_CCACHE_BUILD:BOOL=ON") + # perf support is available on Linux only + if "linux" == platform: + LLVM_COMPILE_OPTIONS.append("-DLLVM_USE_PERF:BOOL=ON") + # use clang/clang++/lld. but macos doesn't support lld if not sys.platform.startswith("darwin") and use_clang: if shutil.which("clang") and shutil.which("clang++") and shutil.which("lld"): @@ -255,7 +259,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 +285,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( diff --git a/build-scripts/config_common.cmake b/build-scripts/config_common.cmake index 210f2d788..e73ebc85f 100644 --- a/build-scripts/config_common.cmake +++ b/build-scripts/config_common.cmake @@ -122,6 +122,11 @@ if (WAMR_BUILD_JIT EQUAL 1) if (CXX_SUPPORTS_REDUNDANT_MOVE_FLAG) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-redundant-move") endif () + # Enable exporting symbols after llvm-17, or LLVM JIT may run failed + # with `llvm_orc_registerEHFrameSectionWrapper` symbol not found error + if (${LLVM_PACKAGE_VERSION} VERSION_GREATER_EQUAL "17.0.0") + set (CMAKE_ENABLE_EXPORTS 1) + endif () endif () else () unset (LLVM_AVAILABLE_LIBS) diff --git a/build-scripts/runtime_lib.cmake b/build-scripts/runtime_lib.cmake index 8ac519b77..811009df6 100644 --- a/build-scripts/runtime_lib.cmake +++ b/build-scripts/runtime_lib.cmake @@ -165,7 +165,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) diff --git a/core/app-mgr/README.md b/core/app-mgr/README.md index 31c705e1f..7a561897e 100644 --- a/core/app-mgr/README.md +++ b/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. diff --git a/core/app-mgr/app-manager/module_wasm_app.c b/core/app-mgr/app-manager/module_wasm_app.c index 2005ad8e8..6fd929b10 100644 --- a/core/app-mgr/app-manager/module_wasm_app.c +++ b/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, diff --git a/core/app-mgr/app-manager/platform/zephyr/app_mgr_zephyr.c b/core/app-mgr/app-manager/platform/zephyr/app_mgr_zephyr.c index 650e536f1..68147c062 100644 --- a/core/app-mgr/app-manager/platform/zephyr/app_mgr_zephyr.c +++ b/core/app-mgr/app-manager/platform/zephyr/app_mgr_zephyr.c @@ -6,8 +6,14 @@ #include "app_manager.h" #include "bh_platform.h" #include + +#if KERNEL_VERSION_NUMBER < 0x030200 /* version 3.2.0 */ #include #include +#else +#include +#endif + #if 0 #include #endif diff --git a/core/config.h b/core/config.h index 4bbb10234..acf70ff08 100644 --- a/core/config.h +++ b/core/config.h @@ -315,6 +315,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 @@ -472,7 +477,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. */ diff --git a/core/iwasm/aot/aot_loader.c b/core/iwasm/aot/aot_loader.c index 6575c8aca..abffd6438 100644 --- a/core/iwasm/aot/aot_loader.c +++ b/core/iwasm/aot/aot_loader.c @@ -1095,7 +1095,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; data_list[i]->offset.init_expr_type = (uint8)init_expr_type; data_list[i]->offset.u.i64 = (int64)init_expr_value; @@ -1574,8 +1573,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; } @@ -2470,7 +2470,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; } @@ -2593,7 +2594,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; } @@ -3106,8 +3108,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"); diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 0799d625f..076574cb7 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -7,6 +7,7 @@ #include "bh_log.h" #include "mem_alloc.h" #include "../common/wasm_runtime_common.h" +#include "../common/wasm_memory.h" #include "../interpreter/wasm_runtime.h" #if WASM_ENABLE_SHARED_MEMORY != 0 #include "../common/wasm_shared_memory.h" @@ -382,7 +383,7 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent, uint32 inc_page_count, aux_heap_base, global_idx; uint32 bytes_of_last_page, bytes_to_page_end; uint32 heap_offset = num_bytes_per_page * init_page_count; - uint64 total_size; + uint64 memory_data_size, max_memory_data_size; uint8 *p = NULL, *global_addr; #ifdef OS_ENABLE_HW_BOUND_CHECK uint8 *mapped_mem; @@ -488,6 +489,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", @@ -496,67 +503,80 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent, module->aux_stack_size); LOG_VERBOSE(" heap offset: %u, heap size: %d\n", heap_offset, heap_size); - total_size = (uint64)num_bytes_per_page * init_page_count; -#if WASM_ENABLE_SHARED_MEMORY != 0 - if (is_shared_memory) { - /* Allocate max page for shared memory */ - total_size = (uint64)num_bytes_per_page * max_page_count; - } -#endif - bh_assert(total_size <= UINT32_MAX); + memory_data_size = (uint64)num_bytes_per_page * init_page_count; + max_memory_data_size = (uint64)num_bytes_per_page * max_page_count; + bh_assert(memory_data_size <= UINT32_MAX); + bh_assert(max_memory_data_size <= 4 * (uint64)BH_GB); + (void)max_memory_data_size; #ifndef OS_ENABLE_HW_BOUND_CHECK - /* Allocate memory */ - if (total_size > 0 - && !(p = runtime_malloc(total_size, error_buf, error_buf_size))) { - return NULL; +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (is_shared_memory) { + /* Allocate maximum memory size when memory is shared */ + if (max_memory_data_size > 0 + && !(p = runtime_malloc(max_memory_data_size, error_buf, + error_buf_size))) { + return NULL; + } } -#else - total_size = (total_size + page_size - 1) & ~(page_size - 1); + else +#endif + { + /* Allocate initial memory size when memory is not shared */ + if (memory_data_size > 0 + && !(p = runtime_malloc(memory_data_size, error_buf, + error_buf_size))) { + return NULL; + } + } +#else /* else of OS_ENABLE_HW_BOUND_CHECK */ + memory_data_size = (memory_data_size + page_size - 1) & ~(page_size - 1); /* Totally 8G is mapped, the opcode load/store address range is 0 to 8G: * ea = i + memarg.offset * both i and memarg.offset are u32 in range 0 to 4G * so the range of ea is 0 to 8G */ - 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; } #ifdef BH_PLATFORM_WINDOWS - if (!os_mem_commit(p, total_size, MMAP_PROT_READ | MMAP_PROT_WRITE)) { + if (!os_mem_commit(p, 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); return NULL; } #endif - if (os_mprotect(p, total_size, MMAP_PROT_READ | MMAP_PROT_WRITE) != 0) { + if (os_mprotect(p, memory_data_size, MMAP_PROT_READ | MMAP_PROT_WRITE) + != 0) { set_error_buf(error_buf, error_buf_size, "mprotect memory failed"); #ifdef BH_PLATFORM_WINDOWS - os_mem_decommit(p, total_size); + os_mem_decommit(p, memory_data_size); #endif os_munmap(mapped_mem, map_size); return NULL; } + /* Newly allocated pages are filled with zero by the OS, we don't fill it * again here */ -#endif /* end of OS_ENABLE_HW_BOUND_CHECK */ - if (total_size > UINT32_MAX) - total_size = UINT32_MAX; + if (memory_data_size > UINT32_MAX) + memory_data_size = UINT32_MAX; +#endif /* end of OS_ENABLE_HW_BOUND_CHECK */ memory_inst->module_type = Wasm_Module_AoT; memory_inst->num_bytes_per_page = num_bytes_per_page; memory_inst->cur_page_count = init_page_count; memory_inst->max_page_count = max_page_count; - memory_inst->memory_data_size = (uint32)total_size; + memory_inst->memory_data_size = (uint32)memory_data_size; /* Init memory info */ memory_inst->memory_data = p; - memory_inst->memory_data_end = p + (uint32)total_size; + memory_inst->memory_data_end = p + (uint32)memory_data_size; /* Initialize heap info */ memory_inst->heap_data = p + heap_offset; @@ -579,24 +599,13 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent, } } - if (total_size > 0) { -#if UINTPTR_MAX == UINT64_MAX - memory_inst->mem_bound_check_1byte.u64 = total_size - 1; - memory_inst->mem_bound_check_2bytes.u64 = total_size - 2; - memory_inst->mem_bound_check_4bytes.u64 = total_size - 4; - memory_inst->mem_bound_check_8bytes.u64 = total_size - 8; - memory_inst->mem_bound_check_16bytes.u64 = total_size - 16; -#else - memory_inst->mem_bound_check_1byte.u32[0] = (uint32)total_size - 1; - memory_inst->mem_bound_check_2bytes.u32[0] = (uint32)total_size - 2; - memory_inst->mem_bound_check_4bytes.u32[0] = (uint32)total_size - 4; - memory_inst->mem_bound_check_8bytes.u32[0] = (uint32)total_size - 8; - memory_inst->mem_bound_check_16bytes.u32[0] = (uint32)total_size - 16; -#endif + if (memory_data_size > 0) { + wasm_runtime_set_mem_bound_check_bytes(memory_inst, memory_data_size); } #if WASM_ENABLE_SHARED_MEMORY != 0 if (is_shared_memory) { + memory_inst->is_shared_memory = 1; memory_inst->ref_count = 1; } #endif @@ -613,7 +622,7 @@ fail1: #else #ifdef BH_PLATFORM_WINDOWS if (memory_inst->memory_data) - os_mem_decommit(p, total_size); + os_mem_decommit(p, memory_data_size); #endif os_munmap(mapped_mem, map_size); #endif @@ -673,6 +682,10 @@ memories_instantiate(AOTModuleInstance *module_inst, AOTModuleInstance *parent, if (data_seg->is_passive) continue; #endif + if (parent != NULL) + /* Ignore setting memory init data if the memory has been + initialized */ + continue; bh_assert(data_seg->offset.init_expr_type == INIT_EXPR_TYPE_I32_CONST || data_seg->offset.init_expr_type @@ -969,7 +982,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 */ @@ -994,7 +1008,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); } } @@ -1044,12 +1059,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); } @@ -1083,6 +1098,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 = @@ -1149,6 +1167,32 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent, } #endif +#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; @@ -1249,6 +1293,8 @@ fail: 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 @@ -1291,7 +1337,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); @@ -1302,6 +1348,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); } @@ -1700,7 +1753,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); } } @@ -1711,7 +1765,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); @@ -1767,7 +1821,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); } } @@ -1775,7 +1830,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); @@ -1897,6 +1952,13 @@ aot_module_free_internal(AOTModuleInstance *module_inst, WASMExecEnv *exec_env, if (ptr) { uint8 *addr = memory_inst->memory_data + ptr; + uint8 *memory_data_end; + + /* memory->memory_data_end may be changed in memory grow */ + SHARED_MEMORY_LOCK(memory_inst); + memory_data_end = memory_inst->memory_data_end; + SHARED_MEMORY_UNLOCK(memory_inst); + if (memory_inst->heap_handle && memory_inst->heap_data < addr && addr < memory_inst->heap_data_end) { mem_allocator_free(memory_inst->heap_handle, addr); @@ -1904,7 +1966,7 @@ aot_module_free_internal(AOTModuleInstance *module_inst, WASMExecEnv *exec_env, else if (module->malloc_func_index != (uint32)-1 && module->free_func_index != (uint32)-1 && memory_inst->memory_data <= addr - && addr < memory_inst->memory_data_end) { + && addr < memory_data_end) { AOTFunctionInstance *free_func; char *free_func_name; @@ -2278,13 +2340,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)) @@ -2298,16 +2368,18 @@ aot_memory_init(AOTModuleInstance *module_inst, uint32 seg_index, uint32 offset, maddr = wasm_runtime_addr_app_to_native( (WASMModuleInstanceCommon *)module_inst, dst); + SHARED_MEMORY_LOCK(memory_inst); bh_memcpy_s(maddr, memory_inst->memory_data_size - dst, data + offset, len); + SHARED_MEMORY_UNLOCK(memory_inst); return true; } 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; @@ -2520,9 +2592,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 @@ -2550,7 +2622,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; } @@ -2891,13 +2965,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); } diff --git a/core/iwasm/aot/arch/aot_reloc_riscv.c b/core/iwasm/aot/arch/aot_reloc_riscv.c index 7798d55c6..31830f780 100644 --- a/core/iwasm/aot/arch/aot_reloc_riscv.c +++ b/core/iwasm/aot/arch/aot_reloc_riscv.c @@ -11,21 +11,52 @@ #define R_RISCV_CALL_PLT 19 #define R_RISCV_PCREL_HI20 23 #define R_RISCV_PCREL_LO12_I 24 +#define R_RISCV_PCREL_LO12_S 25 #define R_RISCV_HI20 26 #define R_RISCV_LO12_I 27 #define R_RISCV_LO12_S 28 #define RV_OPCODE_SW 0x23 +#undef NEED_SOFT_FP +#undef NEED_SOFT_DP +#undef NEED_SOFT_I32_MUL +#undef NEED_SOFT_I32_DIV +#undef NEED_SOFT_I64_MUL +#undef NEED_SOFT_I64_DIV + +#ifdef __riscv_flen +#if __riscv_flen == 32 +#define NEED_SOFT_DP +#endif +#else +#define NEED_SOFT_FP +#define NEED_SOFT_DP +#endif + +#ifndef __riscv_mul +#define NEED_SOFT_I32_MUL +#define NEED_SOFT_I64_MUL +#elif __riscv_xlen == 32 +#define NEED_SOFT_I64_MUL +#endif + +#ifndef __riscv_div +#define NEED_SOFT_I32_DIV +#define NEED_SOFT_I64_DIV +#elif __riscv_xlen == 32 +#define NEED_SOFT_I64_DIV +#endif + /* clang-format off */ void __adddf3(); void __addsf3(); -void __divdi3(); -void __divsi3(); void __divdf3(); +void __divdi3(); void __divsf3(); -void __eqsf2(); +void __divsi3(); void __eqdf2(); +void __eqsf2(); void __extendsfdf2(); void __fixdfdi(); void __fixdfsi(); @@ -37,12 +68,12 @@ void __fixunssfdi(); void __fixunssfsi(); void __floatdidf(); void __floatdisf(); -void __floatsisf(); void __floatsidf(); +void __floatsisf(); void __floatundidf(); void __floatundisf(); -void __floatunsisf(); void __floatunsidf(); +void __floatunsisf(); void __gedf2(); void __gesf2(); void __gtdf2(); @@ -58,6 +89,8 @@ void __muldi3(); void __mulsf3(); void __mulsi3(); void __nedf2(); +void __negdf2(); +void __negsf2(); void __nesf2(); void __subdf3(); void __subsf3(); @@ -73,60 +106,74 @@ void __unordsf2(); static SymbolMap target_sym_map[] = { /* clang-format off */ REG_COMMON_SYMBOLS -#ifndef __riscv_flen - REG_SYM(__adddf3), +#ifdef NEED_SOFT_FP REG_SYM(__addsf3), - REG_SYM(__divdf3), REG_SYM(__divsf3), - REG_SYM(__eqdf2), REG_SYM(__eqsf2), - REG_SYM(__extendsfdf2), - REG_SYM(__fixunsdfdi), - REG_SYM(__fixunsdfsi), + REG_SYM(__fixsfdi), REG_SYM(__fixunssfdi), REG_SYM(__fixunssfsi), - REG_SYM(__gedf2), + REG_SYM(__floatsidf), REG_SYM(__gesf2), - REG_SYM(__gtdf2), REG_SYM(__gtsf2), - REG_SYM(__ledf2), REG_SYM(__lesf2), - REG_SYM(__ltdf2), - REG_SYM(__ltsf2), + REG_SYM(__mulsf3), + REG_SYM(__negsf2), + REG_SYM(__nesf2), + REG_SYM(__subsf3), + REG_SYM(__unordsf2), +#elif __riscv_xlen == 32 + /* rv32f, support FP instruction but need soft routines + * to convert float and long long + */ + REG_SYM(__floatundisf), +#endif +#ifdef NEED_SOFT_DP + REG_SYM(__adddf3), + REG_SYM(__divdf3), + REG_SYM(__eqdf2), + REG_SYM(__extendsfdf2), + REG_SYM(__fixdfdi), + REG_SYM(__fixunsdfdi), + REG_SYM(__fixunsdfsi), + REG_SYM(__floatdidf), + REG_SYM(__floatsidf), + REG_SYM(__floatundidf), + REG_SYM(__floatunsidf), + REG_SYM(__gedf2), + REG_SYM(__gtdf2), + REG_SYM(__ledf2), REG_SYM(__muldf3), REG_SYM(__nedf2), - REG_SYM(__nesf2), + REG_SYM(__negdf2), REG_SYM(__subdf3), - REG_SYM(__subsf3), REG_SYM(__truncdfsf2), REG_SYM(__unorddf2), - REG_SYM(__unordsf2), -#if __riscv_xlen == 32 +#elif __riscv_xlen == 32 + /* rv32d, support DP instruction but need soft routines + * to convert double and long long + */ REG_SYM(__fixdfdi), - REG_SYM(__fixdfsi), - REG_SYM(__fixsfdi), - REG_SYM(__fixsfsi), - REG_SYM(__floatdidf), - REG_SYM(__floatdisf), - REG_SYM(__floatsidf), - REG_SYM(__floatsisf), REG_SYM(__floatundidf), - REG_SYM(__floatundisf), - REG_SYM(__floatunsidf), - REG_SYM(__floatunsisf), - REG_SYM(__mulsf3), +#endif +#ifdef NEED_SOFT_I32_MUL REG_SYM(__mulsi3), #endif -#endif - REG_SYM(__divdi3), +#ifdef NEED_SOFT_I32_DIV REG_SYM(__divsi3), - REG_SYM(__moddi3), REG_SYM(__modsi3), - REG_SYM(__muldi3), - REG_SYM(__udivdi3), REG_SYM(__udivsi3), - REG_SYM(__umoddi3), REG_SYM(__umodsi3), +#endif +#ifdef NEED_SOFT_I64_MUL + REG_SYM(__muldi3), +#endif +#ifdef NEED_SOFT_I64_DIV + REG_SYM(__divdi3), + REG_SYM(__moddi3), + REG_SYM(__udivdi3), + REG_SYM(__umoddi3), +#endif /* clang-format on */ }; @@ -177,7 +224,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 */ @@ -265,9 +316,10 @@ typedef struct RelocTypeStrMap { } static RelocTypeStrMap reloc_type_str_maps[] = { - RELOC_TYPE_MAP(R_RISCV_32), RELOC_TYPE_MAP(R_RISCV_CALL), - RELOC_TYPE_MAP(R_RISCV_CALL_PLT), RELOC_TYPE_MAP(R_RISCV_PCREL_HI20), - RELOC_TYPE_MAP(R_RISCV_PCREL_LO12_I), RELOC_TYPE_MAP(R_RISCV_HI20), + RELOC_TYPE_MAP(R_RISCV_32), RELOC_TYPE_MAP(R_RISCV_64), + RELOC_TYPE_MAP(R_RISCV_CALL), RELOC_TYPE_MAP(R_RISCV_CALL_PLT), + RELOC_TYPE_MAP(R_RISCV_PCREL_HI20), RELOC_TYPE_MAP(R_RISCV_PCREL_LO12_I), + RELOC_TYPE_MAP(R_RISCV_PCREL_LO12_S), RELOC_TYPE_MAP(R_RISCV_HI20), RELOC_TYPE_MAP(R_RISCV_LO12_I), RELOC_TYPE_MAP(R_RISCV_LO12_S), }; @@ -323,21 +375,37 @@ apply_relocation(AOTModule *module, uint8 *target_section_addr, rv_set_val((uint16 *)addr, val_32); break; } + +#if __riscv_xlen == 64 case R_RISCV_64: { uint64 val_64 = - (uint64)((uintptr_t)symbol_addr + (intptr_t)reloc_addend); + (uint64)((intptr_t)symbol_addr + (intptr_t)reloc_addend); + CHECK_RELOC_OFFSET(sizeof(uint64)); + if (val_64 + != (uint64)((intptr_t)symbol_addr + (intptr_t)reloc_addend)) { + goto fail_addr_out_of_range; + } + bh_memcpy_s(addr, 8, &val_64, 8); +#ifdef __riscv_zifencei + __asm__ volatile("fence.i"); +#else + __asm__ volatile("fence"); +#endif break; } +#endif + case R_RISCV_CALL: case R_RISCV_CALL_PLT: + case R_RISCV_PCREL_HI20: /* S + A - P */ { - val = (int32)(intptr_t)((uint8 *)symbol_addr - addr); + val = (int32)(intptr_t)((uint8 *)symbol_addr + reloc_addend - addr); CHECK_RELOC_OFFSET(sizeof(uint32)); - if (val != (intptr_t)((uint8 *)symbol_addr - addr)) { + if (val != (intptr_t)((uint8 *)symbol_addr + reloc_addend - addr)) { if (symbol_index >= 0) { /* Call runtime function by plt code */ symbol_addr = (uint8 *)module->code + module->code_size @@ -347,7 +415,7 @@ apply_relocation(AOTModule *module, uint8 *target_section_addr, } } - if (val != (intptr_t)((uint8 *)symbol_addr - addr)) { + if (val != (intptr_t)((uint8 *)symbol_addr + reloc_addend - addr)) { goto fail_addr_out_of_range; } @@ -368,32 +436,15 @@ apply_relocation(AOTModule *module, uint8 *target_section_addr, break; } - case R_RISCV_HI20: /* S + A */ - case R_RISCV_PCREL_HI20: /* S + A - P */ + case R_RISCV_HI20: /* S + A */ { - if (reloc_type == R_RISCV_PCREL_HI20) { - val = (int32)((intptr_t)symbol_addr + (intptr_t)reloc_addend - - (intptr_t)addr); - } - else { - val = (int32)((intptr_t)symbol_addr + (intptr_t)reloc_addend); - } + val = (int32)((intptr_t)symbol_addr + (intptr_t)reloc_addend); CHECK_RELOC_OFFSET(sizeof(uint32)); - if (reloc_type == R_RISCV_PCREL_HI20) { - if (val - != ((intptr_t)symbol_addr + (intptr_t)reloc_addend - - (intptr_t)addr)) { - goto fail_addr_out_of_range; - } - } - else { - if (val != ((intptr_t)symbol_addr + (intptr_t)reloc_addend)) { - goto fail_addr_out_of_range; - } + if (val != ((intptr_t)symbol_addr + (intptr_t)reloc_addend)) { + goto fail_addr_out_of_range; } - addr = target_section_addr + reloc_offset; insn = rv_get_val((uint16 *)addr); rv_calc_imm(val, &imm_hi, &imm_lo); insn = (insn & 0x00000fff) | (imm_hi << 12); @@ -401,27 +452,44 @@ apply_relocation(AOTModule *module, uint8 *target_section_addr, break; } - case R_RISCV_LO12_I: /* S + A */ case R_RISCV_PCREL_LO12_I: /* S - P */ + case R_RISCV_PCREL_LO12_S: /* S - P */ { - if (reloc_type == R_RISCV_PCREL_LO12_I) { - /* A = 0 */ - val = (int32)((intptr_t)symbol_addr - (intptr_t)addr); - } - else { - val = (int32)((intptr_t)symbol_addr + (intptr_t)reloc_addend); + /* Already handled in R_RISCV_PCREL_HI20, it should be skipped for + * most cases. But it is still needed for some special cases, e.g. + * ``` + * label: + * auipc t0, %pcrel_hi(symbol) # R_RISCV_PCREL_HI20 (symbol) + * lui t1, 1 + * lw t2, t0, %pcrel_lo(label) # R_RISCV_PCREL_LO12_I (label) + * add t2, t2, t1 + * sw t2, t0, %pcrel_lo(label) # R_RISCV_PCREL_LO12_S (label) + * ``` + * In this case, the R_RISCV_PCREL_LO12_I/S relocation should be + * handled after R_RISCV_PCREL_HI20 relocation. + * + * So, if the R_RISCV_PCREL_LO12_I/S relocation is not followed by + * R_RISCV_PCREL_HI20 relocation, it should be handled here but + * not implemented yet. + */ + + if ((uintptr_t)addr - (uintptr_t)symbol_addr + - (uintptr_t)reloc_addend + != 4) { + goto fail_addr_out_of_range; } + break; + } + + case R_RISCV_LO12_I: /* S + A */ + { + + val = (int32)((intptr_t)symbol_addr + (intptr_t)reloc_addend); CHECK_RELOC_OFFSET(sizeof(uint32)); - if (reloc_type == R_RISCV_PCREL_LO12_I) { - if (val != (intptr_t)symbol_addr - (intptr_t)addr) { - goto fail_addr_out_of_range; - } - } - else { - if (val != (intptr_t)symbol_addr + (intptr_t)reloc_addend) { - goto fail_addr_out_of_range; - } + + if (val != (intptr_t)symbol_addr + (intptr_t)reloc_addend) { + goto fail_addr_out_of_range; } addr = target_section_addr + reloc_offset; diff --git a/core/iwasm/common/wasm_application.c b/core/iwasm/common/wasm_application.c index 02999584f..93c9342da 100644 --- a/core/iwasm/common/wasm_application.c +++ b/core/iwasm/common/wasm_application.c @@ -312,7 +312,6 @@ execute_func(WASMModuleInstanceCommon *module_inst, const char *name, #endif int32 i, p, module_type; uint64 total_size; - const char *exception; char buf[128]; bh_assert(argc >= 0); @@ -389,6 +388,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; @@ -423,6 +434,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; @@ -586,7 +600,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++; @@ -599,7 +613,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 @@ -632,9 +646,7 @@ fail: if (argv1) wasm_runtime_free(argv1); - exception = wasm_runtime_get_exception(module_inst); - bh_assert(exception); - os_printf("%s\n", exception); + bh_assert(wasm_runtime_get_exception(module_inst)); return false; } diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index 2da733874..57c3ebd0d 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -292,13 +292,46 @@ WASM_DEFINE_VEC_OWN(valtype, wasm_valtype_delete) own wasm_config_t * wasm_config_new(void) { - return NULL; + /* since wasm_runtime_malloc is not ready */ + wasm_config_t *config = os_malloc(sizeof(wasm_config_t)); + if (!config) + return NULL; + + memset(config, 0, sizeof(wasm_config_t)); + config->mem_alloc_type = Alloc_With_System_Allocator; + return config; } void wasm_config_delete(own wasm_config_t *config) { - (void)config; + if (config) + os_free(config); +} + +wasm_config_t * +wasm_config_set_mem_alloc_opt(wasm_config_t *config, + mem_alloc_type_t mem_alloc_type, + MemAllocOption *mem_alloc_option) +{ + if (!config) + return NULL; + + config->mem_alloc_type = mem_alloc_type; + if (mem_alloc_option) + memcpy(&config->mem_alloc_option, mem_alloc_option, + sizeof(MemAllocOption)); + return config; +} + +wasm_config_t * +wasm_config_set_linux_perf_opt(wasm_config_t *config, bool enable) +{ + if (!config) + return NULL; + + config->linux_perf_support = enable; + return config; } static void @@ -329,12 +362,11 @@ wasm_engine_delete_internal(wasm_engine_t *engine) } static wasm_engine_t * -wasm_engine_new_internal(mem_alloc_type_t type, const MemAllocOption *opts) +wasm_engine_new_internal(wasm_config_t *config) { wasm_engine_t *engine = NULL; /* init runtime */ RuntimeInitArgs init_args = { 0 }; - init_args.mem_alloc_type = type; #ifndef NDEBUG bh_log_set_verbose_level(BH_LOG_LEVEL_VERBOSE); @@ -344,34 +376,11 @@ wasm_engine_new_internal(mem_alloc_type_t type, const MemAllocOption *opts) WASM_C_DUMP_PROC_MEM(); - if (type == Alloc_With_Pool) { - if (!opts) { - return NULL; - } - - init_args.mem_alloc_option.pool.heap_buf = opts->pool.heap_buf; - init_args.mem_alloc_option.pool.heap_size = opts->pool.heap_size; - } - else if (type == Alloc_With_Allocator) { - if (!opts) { - return NULL; - } - - init_args.mem_alloc_option.allocator.malloc_func = - opts->allocator.malloc_func; - init_args.mem_alloc_option.allocator.free_func = - opts->allocator.free_func; - init_args.mem_alloc_option.allocator.realloc_func = - opts->allocator.realloc_func; -#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 - init_args.mem_alloc_option.allocator.user_data = - opts->allocator.user_data; -#endif - } - else { - init_args.mem_alloc_option.pool.heap_buf = NULL; - init_args.mem_alloc_option.pool.heap_size = 0; - } + /* wasm_config_t->MemAllocOption -> RuntimeInitArgs->MemAllocOption */ + init_args.mem_alloc_type = config->mem_alloc_type; + memcpy(&init_args.mem_alloc_option, &config->mem_alloc_option, + sizeof(MemAllocOption)); + init_args.linux_perf_support = config->linux_perf_support; if (!wasm_runtime_full_init(&init_args)) { LOG_DEBUG("wasm_runtime_full_init failed"); @@ -418,14 +427,23 @@ static korp_mutex engine_lock = OS_THREAD_MUTEX_INITIALIZER; #endif own wasm_engine_t * -wasm_engine_new_with_args(mem_alloc_type_t type, const MemAllocOption *opts) +wasm_engine_new() +{ + wasm_config_t config = { 0 }; + wasm_config_set_mem_alloc_opt(&config, Alloc_With_System_Allocator, NULL); + wasm_engine_t *engine = wasm_engine_new_with_config(&config); + return engine; +} + +own wasm_engine_t * +wasm_engine_new_with_config(wasm_config_t *config) { #if defined(OS_THREAD_MUTEX_INITIALIZER) os_mutex_lock(&engine_lock); #endif if (!singleton_engine) - singleton_engine = wasm_engine_new_internal(type, opts); + singleton_engine = wasm_engine_new_internal(config); else singleton_engine->ref_count++; @@ -437,16 +455,12 @@ wasm_engine_new_with_args(mem_alloc_type_t type, const MemAllocOption *opts) } own wasm_engine_t * -wasm_engine_new() +wasm_engine_new_with_args(mem_alloc_type_t type, const MemAllocOption *opts) { - return wasm_engine_new_with_args(Alloc_With_System_Allocator, NULL); -} - -own wasm_engine_t * -wasm_engine_new_with_config(own wasm_config_t *config) -{ - (void)config; - return wasm_engine_new_with_args(Alloc_With_System_Allocator, NULL); + wasm_config_t config = { 0 }; + config.mem_alloc_type = type; + memcpy(&config.mem_alloc_option, opts, sizeof(MemAllocOption)); + return wasm_engine_new_with_config(&config); } void diff --git a/core/iwasm/common/wasm_exec_env.c b/core/iwasm/common/wasm_exec_env.c index 5f317944d..a92e09b21 100644 --- a/core/iwasm/common/wasm_exec_env.c +++ b/core/iwasm/common/wasm_exec_env.c @@ -53,7 +53,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 fail4; #endif @@ -187,7 +188,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 diff --git a/core/iwasm/common/wasm_exec_env.h b/core/iwasm/common/wasm_exec_env.h index ac090f5f6..c3f4dfd71 100644 --- a/core/iwasm/common/wasm_exec_env.h +++ b/core/iwasm/common/wasm_exec_env.h @@ -309,6 +309,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); diff --git a/core/iwasm/common/wasm_memory.c b/core/iwasm/common/wasm_memory.c index b104299ca..360eee96c 100644 --- a/core/iwasm/common/wasm_memory.c +++ b/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; @@ -298,10 +298,15 @@ wasm_runtime_validate_app_addr(WASMModuleInstanceCommon *module_inst_comm, goto fail; } + SHARED_MEMORY_LOCK(memory_inst); + if (app_offset + size <= memory_inst->memory_data_size) { + SHARED_MEMORY_UNLOCK(memory_inst); return true; } + SHARED_MEMORY_UNLOCK(memory_inst); + fail: wasm_set_exception(module_inst, "out of bounds memory access"); return false; @@ -364,11 +369,16 @@ wasm_runtime_validate_native_addr(WASMModuleInstanceCommon *module_inst_comm, goto fail; } + SHARED_MEMORY_LOCK(memory_inst); + if (memory_inst->memory_data <= addr && addr + size <= memory_inst->memory_data_end) { + SHARED_MEMORY_UNLOCK(memory_inst); return true; } + SHARED_MEMORY_UNLOCK(memory_inst); + fail: wasm_set_exception(module_inst, "out of bounds memory access"); return false; @@ -393,20 +403,24 @@ wasm_runtime_addr_app_to_native(WASMModuleInstanceCommon *module_inst_comm, return NULL; } + SHARED_MEMORY_LOCK(memory_inst); + addr = memory_inst->memory_data + app_offset; if (bounds_checks) { if (memory_inst->memory_data <= addr && addr < memory_inst->memory_data_end) { - + SHARED_MEMORY_UNLOCK(memory_inst); return addr; } } /* If bounds checks is disabled, return the address directly */ else if (app_offset != 0) { + SHARED_MEMORY_UNLOCK(memory_inst); return addr; } + SHARED_MEMORY_UNLOCK(memory_inst); return NULL; } @@ -418,6 +432,7 @@ wasm_runtime_addr_native_to_app(WASMModuleInstanceCommon *module_inst_comm, WASMMemoryInstance *memory_inst; uint8 *addr = (uint8 *)native_ptr; bool bounds_checks; + uint32 ret; bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode || module_inst_comm->module_type == Wasm_Module_AoT); @@ -429,16 +444,24 @@ wasm_runtime_addr_native_to_app(WASMModuleInstanceCommon *module_inst_comm, return 0; } + SHARED_MEMORY_LOCK(memory_inst); + if (bounds_checks) { if (memory_inst->memory_data <= addr - && addr < memory_inst->memory_data_end) - return (uint32)(addr - memory_inst->memory_data); + && addr < memory_inst->memory_data_end) { + ret = (uint32)(addr - memory_inst->memory_data); + SHARED_MEMORY_UNLOCK(memory_inst); + return ret; + } } /* If bounds checks is disabled, return the offset directly */ else if (addr != NULL) { - return (uint32)(addr - memory_inst->memory_data); + ret = (uint32)(addr - memory_inst->memory_data); + SHARED_MEMORY_UNLOCK(memory_inst); + return ret; } + SHARED_MEMORY_UNLOCK(memory_inst); return 0; } @@ -459,6 +482,8 @@ wasm_runtime_get_app_addr_range(WASMModuleInstanceCommon *module_inst_comm, return false; } + SHARED_MEMORY_LOCK(memory_inst); + memory_data_size = memory_inst->memory_data_size; if (app_offset < memory_data_size) { @@ -466,9 +491,11 @@ wasm_runtime_get_app_addr_range(WASMModuleInstanceCommon *module_inst_comm, *p_app_start_offset = 0; if (p_app_end_offset) *p_app_end_offset = memory_data_size; + SHARED_MEMORY_UNLOCK(memory_inst); return true; } + SHARED_MEMORY_UNLOCK(memory_inst); return false; } @@ -490,15 +517,19 @@ wasm_runtime_get_native_addr_range(WASMModuleInstanceCommon *module_inst_comm, return false; } + SHARED_MEMORY_LOCK(memory_inst); + if (memory_inst->memory_data <= addr && addr < memory_inst->memory_data_end) { if (p_native_start_addr) *p_native_start_addr = memory_inst->memory_data; if (p_native_end_addr) *p_native_end_addr = memory_inst->memory_data_end; + SHARED_MEMORY_UNLOCK(memory_inst); return true; } + SHARED_MEMORY_UNLOCK(memory_inst); return false; } @@ -512,7 +543,8 @@ wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str, bool bounds_checks; if (!memory_inst) { - goto fail; + wasm_set_exception(module_inst, "out of bounds memory access"); + return false; } native_addr = memory_inst->memory_data + app_buf_addr; @@ -529,6 +561,8 @@ wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str, /* No need to check the app_offset and buf_size if memory access boundary check with hardware trap is enabled */ #ifndef OS_ENABLE_HW_BOUND_CHECK + SHARED_MEMORY_LOCK(memory_inst); + if (app_buf_addr >= memory_inst->memory_data_size) { goto fail; } @@ -549,14 +583,20 @@ wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str, if (str == str_end) goto fail; } + + SHARED_MEMORY_UNLOCK(memory_inst); #endif success: *p_native_addr = (void *)native_addr; return true; + +#ifndef OS_ENABLE_HW_BOUND_CHECK fail: + SHARED_MEMORY_UNLOCK(memory_inst); wasm_set_exception(module_inst, "out of bounds memory access"); return false; +#endif } WASMMemoryInstance * @@ -568,6 +608,27 @@ wasm_get_default_memory(WASMModuleInstance *module_inst) return NULL; } +void +wasm_runtime_set_mem_bound_check_bytes(WASMMemoryInstance *memory, + uint64 memory_data_size) +{ +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 || WASM_ENABLE_AOT != 0 +#if UINTPTR_MAX == UINT64_MAX + memory->mem_bound_check_1byte.u64 = memory_data_size - 1; + memory->mem_bound_check_2bytes.u64 = memory_data_size - 2; + memory->mem_bound_check_4bytes.u64 = memory_data_size - 4; + memory->mem_bound_check_8bytes.u64 = memory_data_size - 8; + memory->mem_bound_check_16bytes.u64 = memory_data_size - 16; +#else + memory->mem_bound_check_1byte.u32[0] = (uint32)memory_data_size - 1; + memory->mem_bound_check_2bytes.u32[0] = (uint32)memory_data_size - 2; + memory->mem_bound_check_4bytes.u32[0] = (uint32)memory_data_size - 4; + memory->mem_bound_check_8bytes.u32[0] = (uint32)memory_data_size - 8; + memory->mem_bound_check_16bytes.u32[0] = (uint32)memory_data_size - 16; +#endif +#endif +} + #ifndef OS_ENABLE_HW_BOUND_CHECK bool wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count) @@ -625,9 +686,10 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count) memory->num_bytes_per_page = num_bytes_per_page; memory->cur_page_count = total_page_count; memory->max_page_count = max_page_count; - /* No need to update memory->memory_data_size as it is - initialized with the maximum memory data size for - shared memory */ + SET_LINEAR_MEMORY_SIZE(memory, (uint32)total_size_new); + memory->memory_data_end = memory->memory_data + (uint32)total_size_new; + + wasm_runtime_set_mem_bound_check_bytes(memory, total_size_new); return true; } #endif @@ -679,21 +741,7 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count) memory->memory_data = memory_data_new; memory->memory_data_end = memory_data_new + (uint32)total_size_new; -#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 || WASM_ENABLE_AOT != 0 -#if UINTPTR_MAX == UINT64_MAX - memory->mem_bound_check_1byte.u64 = total_size_new - 1; - memory->mem_bound_check_2bytes.u64 = total_size_new - 2; - memory->mem_bound_check_4bytes.u64 = total_size_new - 4; - memory->mem_bound_check_8bytes.u64 = total_size_new - 8; - memory->mem_bound_check_16bytes.u64 = total_size_new - 16; -#else - memory->mem_bound_check_1byte.u32[0] = (uint32)total_size_new - 1; - memory->mem_bound_check_2bytes.u32[0] = (uint32)total_size_new - 2; - memory->mem_bound_check_4bytes.u32[0] = (uint32)total_size_new - 4; - memory->mem_bound_check_8bytes.u32[0] = (uint32)total_size_new - 8; - memory->mem_bound_check_16bytes.u32[0] = (uint32)total_size_new - 16; -#endif -#endif + wasm_runtime_set_mem_bound_check_bytes(memory, total_size_new); #if defined(os_writegsbase) /* write base addr of linear memory to GS segment register */ @@ -786,16 +834,10 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count) memory->num_bytes_per_page = num_bytes_per_page; memory->cur_page_count = total_page_count; memory->max_page_count = max_page_count; - memory->memory_data_size = (uint32)total_size_new; + SET_LINEAR_MEMORY_SIZE(memory, (uint32)total_size_new); memory->memory_data_end = memory->memory_data + (uint32)total_size_new; -#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 || WASM_ENABLE_AOT != 0 - memory->mem_bound_check_1byte.u64 = total_size_new - 1; - memory->mem_bound_check_2bytes.u64 = total_size_new - 2; - memory->mem_bound_check_4bytes.u64 = total_size_new - 4; - memory->mem_bound_check_8bytes.u64 = total_size_new - 8; - memory->mem_bound_check_16bytes.u64 = total_size_new - 16; -#endif + wasm_runtime_set_mem_bound_check_bytes(memory, total_size_new); return_func: if (!ret && enlarge_memory_error_cb) { diff --git a/core/iwasm/common/wasm_memory.h b/core/iwasm/common/wasm_memory.h index daca2b71e..9b74db526 100644 --- a/core/iwasm/common/wasm_memory.h +++ b/core/iwasm/common/wasm_memory.h @@ -14,6 +14,16 @@ extern "C" { #endif +#if WASM_ENABLE_SHARED_MEMORY != 0 +#define GET_LINEAR_MEMORY_SIZE(memory) \ + BH_ATOMIC_32_LOAD(memory->memory_data_size) +#define SET_LINEAR_MEMORY_SIZE(memory, size) \ + BH_ATOMIC_32_STORE(memory->memory_data_size, size) +#else +#define GET_LINEAR_MEMORY_SIZE(memory) memory->memory_data_size +#define SET_LINEAR_MEMORY_SIZE(memory, size) memory->memory_data_size = size +#endif + bool wasm_runtime_memory_init(mem_alloc_type_t mem_alloc_type, const MemAllocOption *alloc_option); @@ -24,6 +34,10 @@ wasm_runtime_memory_destroy(); unsigned wasm_runtime_memory_pool_size(); +void +wasm_runtime_set_mem_bound_check_bytes(WASMMemoryInstance *memory, + uint64 memory_data_size); + void wasm_runtime_set_enlarge_mem_error_callback( const enlarge_memory_error_callback_t callback, void *user_data); diff --git a/core/iwasm/common/wasm_native.c b/core/iwasm/common/wasm_native.c index 0a5851349..c42bf7b31 100644 --- a/core/iwasm/common/wasm_native.c +++ b/core/iwasm/common/wasm_native.c @@ -542,8 +542,7 @@ void wasm_runtime_set_wasi_ctx(WASMModuleInstanceCommon *module_inst_comm, WASIContext *wasi_ctx) { - return wasm_native_set_context(module_inst_comm, g_wasi_context_key, - wasi_ctx); + wasm_native_set_context(module_inst_comm, g_wasi_context_key, wasi_ctx); } static void diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 019f99769..b9c913fb5 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -158,7 +158,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 static RunningMode runtime_running_mode = Mode_Default; @@ -662,9 +662,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()) { @@ -2616,7 +2621,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) @@ -2813,7 +2818,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); @@ -2827,9 +2832,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 @@ -2924,8 +2929,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; @@ -2943,7 +2949,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; @@ -3013,15 +3019,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; @@ -3029,7 +3039,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, @@ -3038,17 +3048,101 @@ 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; } - 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 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; + } + } + + for (i = 0; i < map_dir_count; i++, wasm_fd++) { + char mapping_copy_buf[256]; + char *mapping_copy = mapping_copy_buf; + char *map_mapped = NULL, *map_host = NULL; + const unsigned long max_len = strlen(map_dir_list[i]) * 2 + 3; + + /* Allocation limit for runtime environments with reduced stack size */ + if (max_len > 256) { + if (!(mapping_copy = wasm_runtime_malloc(max_len))) { + snprintf(error_buf, error_buf_size, + "error while allocating for directory mapping\n"); + goto fail; + } + } + + bh_memcpy_s(mapping_copy, max_len, map_dir_list[i], + (uint32)(strlen(map_dir_list[i]) + 1)); + map_mapped = strtok(mapping_copy, "::"); + map_host = strtok(NULL, "::"); + + if (!map_mapped || !map_host) { + if (error_buf) + snprintf(error_buf, error_buf_size, + "error while pre-opening mapped directory: " + "invalid map\n"); + if (mapping_copy != mapping_copy_buf) + wasm_runtime_free(mapping_copy); + goto fail; + } + + path = os_realpath(map_host, resolved_path); + if (!path) { + if (error_buf) + snprintf(error_buf, error_buf_size, + "error while pre-opening mapped directory %s: %d\n", + map_host, errno); + if (mapping_copy != mapping_copy_buf) + wasm_runtime_free(mapping_copy); + goto fail; + } + + __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", + map_host, errno); + if (mapping_copy != mapping_copy_buf) + wasm_runtime_free(mapping_copy); + goto fail; + } + + 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, + "error while pre-opening mapped directory %s: " + "insertion failed\n", + dir_list[i]); + if (mapping_copy != mapping_copy_buf) + wasm_runtime_free(mapping_copy); + goto fail; + } + + if (mapping_copy != mapping_copy_buf) + wasm_runtime_free(mapping_copy); } /* addr_pool(textual) -> apool */ @@ -3176,8 +3270,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; @@ -3963,16 +4058,14 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, if (n_stacks & 1) n_stacks++; if (func_type->types[i] == VALUE_TYPE_F32) { - *(float32 *)&stacks[n_stacks] = *(float32 *)argv_src++; - /* NaN boxing, the upper bits of a valid NaN-boxed - value must be all 1s. */ - stacks[n_stacks + 1] = 0xFFFFFFFF; + *(float32 *)&stacks[n_stacks++] = + *(float32 *)argv_src++; } else { *(float64 *)&stacks[n_stacks] = *(float64 *)argv_src; argv_src += 2; + n_stacks += 2; } - n_stacks += 2; } break; } @@ -4374,10 +4467,12 @@ static V128FuncPtr invokeNative_V128 = (V128FuncPtr)(uintptr_t)invokeNative; || defined(BUILD_TARGET_RISCV64_LP64) */ #endif /* end of defined(_WIN32) || defined(_WIN32_) */ -/* ASAN is not designed to work with custom stack unwind or other low-level \ - things. > Ignore a function that does some low-level magic. (e.g. walking \ - through the thread's stack bypassing the frame boundaries) */ -#if defined(__GNUC__) +/* + * ASAN is not designed to work with custom stack unwind or other low-level + * things. Ignore a function that does some low-level magic. (e.g. walking + * through the thread's stack bypassing the frame boundaries) + */ +#if defined(__GNUC__) || defined(__clang__) __attribute__((no_sanitize_address)) #endif bool @@ -5811,7 +5906,7 @@ wasm_runtime_register_sub_module(const WASMModuleCommon *parent_module, { /* register sub_module into its parent sub module list */ WASMRegisteredModule *node = NULL; - bh_list_status ret; + bh_list_status ret = BH_LIST_ERROR; if (wasm_runtime_search_sub_module(parent_module, sub_module_name)) { LOG_DEBUG("%s has been registered in its parent", sub_module_name); diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index a9518564a..c7b487aa8 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -12,9 +12,9 @@ #include "wasm_native.h" #include "../include/wasm_export.h" #include "../interpreter/wasm.h" + #if WASM_ENABLE_LIBC_WASI != 0 #if WASM_ENABLE_UVWASI == 0 -#include "wasmtime_ssp.h" #include "posix.h" #else #include "uvwasi.h" @@ -44,14 +44,21 @@ extern "C" { /* For STORE opcodes */ #define STORE_I64 PUT_I64_TO_ADDR -#define STORE_U32(addr, value) \ - do { \ - *(uint32 *)(addr) = (uint32)(value); \ - } while (0) -#define STORE_U16(addr, value) \ - do { \ - *(uint16 *)(addr) = (uint16)(value); \ - } while (0) +static inline void +STORE_U32(void *addr, uint32_t value) +{ + *(uint32_t *)(addr) = (uint32_t)(value); +} +static inline void +STORE_U16(void *addr, uint16_t value) +{ + *(uint16_t *)(addr) = (uint16_t)(value); +} +static inline void +STORE_U8(void *addr, uint8_t value) +{ + *(uint8 *)addr = value; +} /* For LOAD opcodes */ #define LOAD_I64(addr) (*(int64 *)(addr)) @@ -147,42 +154,49 @@ GET_F64_FROM_ADDR(uint32 *addr) } \ } while (0) -#define STORE_U32(addr, value) \ - do { \ - uintptr_t addr_ = (uintptr_t)(addr); \ - union { \ - uint32 val; \ - uint16 u16[2]; \ - uint8 u8[4]; \ - } u; \ - if ((addr_ & (uintptr_t)3) == 0) \ - *(uint32 *)(addr) = (uint32)(value); \ - else { \ - u.val = (uint32)(value); \ - if ((addr_ & (uintptr_t)1) == 0) { \ - ((uint16 *)(addr))[0] = u.u16[0]; \ - ((uint16 *)(addr))[1] = u.u16[1]; \ - } \ - else { \ - ((uint8 *)(addr))[0] = u.u8[0]; \ - ((uint8 *)(addr))[1] = u.u8[1]; \ - ((uint8 *)(addr))[2] = u.u8[2]; \ - ((uint8 *)(addr))[3] = u.u8[3]; \ - } \ - } \ - } while (0) +static inline void +STORE_U32(void *addr, uint32_t value) +{ + uintptr_t addr_ = (uintptr_t)(addr); + union { + uint32_t val; + uint16_t u16[2]; + uint8_t u8[4]; + } u; + if ((addr_ & (uintptr_t)3) == 0) + *(uint32_t *)(addr) = (uint32_t)(value); + else { + u.val = (uint32_t)(value); + if ((addr_ & (uintptr_t)1) == 0) { + ((uint16_t *)(addr))[0] = u.u16[0]; + ((uint16_t *)(addr))[1] = u.u16[1]; + } + else { + ((uint8_t *)(addr))[0] = u.u8[0]; + ((uint8_t *)(addr))[1] = u.u8[1]; + ((uint8_t *)(addr))[2] = u.u8[2]; + ((uint8_t *)(addr))[3] = u.u8[3]; + } + } +} -#define STORE_U16(addr, value) \ - do { \ - union { \ - uint16 val; \ - uint8 u8[2]; \ - } u; \ - u.val = (uint16)(value); \ - ((uint8 *)(addr))[0] = u.u8[0]; \ - ((uint8 *)(addr))[1] = u.u8[1]; \ - } while (0) +static inline void +STORE_U8(void *addr, uint8_t value) +{ + *(uint8 *)addr = value; +} +static inline void +STORE_U16(void *addr, uint16_t value) +{ + union { + uint16_t val; + uint8_t u8[2]; + } u; + u.val = (uint16_t)(value); + ((uint8_t *)(addr))[0] = u.u8[0]; + ((uint8_t *)(addr))[1] = u.u8[1]; +} /* For LOAD opcodes */ static inline int64 LOAD_I64(void *addr) @@ -298,6 +312,14 @@ LOAD_I16(void *addr) #endif /* WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 */ +#if WASM_ENABLE_SHARED_MEMORY != 0 +#define SHARED_MEMORY_LOCK(memory) shared_memory_lock(memory) +#define SHARED_MEMORY_UNLOCK(memory) shared_memory_unlock(memory) +#else +#define SHARED_MEMORY_LOCK(memory) (void)0 +#define SHARED_MEMORY_UNLOCK(memory) (void)0 +#endif + typedef struct WASMModuleCommon { /* Module type, for module loaded from WASM bytecode binary, this field is Wasm_Module_Bytecode, and this structure should @@ -421,6 +443,7 @@ typedef struct LLVMJITOptions { uint32 opt_level; uint32 size_level; uint32 segue_flags; + bool linux_perf_support; } LLVMJITOptions; #endif @@ -598,7 +621,7 @@ wasm_runtime_get_user_data(WASMExecEnv *exec_env); WASMExecEnv * wasm_runtime_get_cur_exec_env(const WASMModuleInstanceCommon *module_inst); -#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, @@ -863,7 +886,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 @@ -891,8 +914,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); diff --git a/core/iwasm/common/wasm_shared_memory.c b/core/iwasm/common/wasm_shared_memory.c index 5c06a3465..614acb062 100644 --- a/core/iwasm/common/wasm_shared_memory.c +++ b/core/iwasm/common/wasm_shared_memory.c @@ -18,7 +18,7 @@ * - If you care performance, it's better to make the interpreters * use atomic ops. */ -static korp_mutex _shared_memory_lock; +korp_mutex g_shared_memory_lock; /* clang-format off */ enum { @@ -55,13 +55,13 @@ destroy_wait_info(void *wait_info); bool wasm_shared_memory_init() { - if (os_mutex_init(&_shared_memory_lock) != 0) + if (os_mutex_init(&g_shared_memory_lock) != 0) return false; /* wait map not exists, create new map */ if (!(wait_map = bh_hash_map_create(32, true, (HashFunc)wait_address_hash, (KeyEqualFunc)wait_address_equal, NULL, destroy_wait_info))) { - os_mutex_destroy(&_shared_memory_lock); + os_mutex_destroy(&g_shared_memory_lock); return false; } return true; @@ -71,79 +71,47 @@ void wasm_shared_memory_destroy() { bh_hash_map_destroy(wait_map); - os_mutex_destroy(&_shared_memory_lock); + os_mutex_destroy(&g_shared_memory_lock); } -uint32 +uint16 shared_memory_inc_reference(WASMMemoryInstance *memory) { bh_assert(shared_memory_is_shared(memory)); - uint32 old; -#if BH_ATOMIC_32_IS_ATOMIC == 0 - os_mutex_lock(&_shared_memory_lock); + uint16 old; +#if BH_ATOMIC_16_IS_ATOMIC == 0 + os_mutex_lock(&g_shared_memory_lock); #endif - old = BH_ATOMIC_32_FETCH_ADD(memory->ref_count, 1); -#if BH_ATOMIC_32_IS_ATOMIC == 0 - os_mutex_unlock(&_shared_memory_lock); + old = BH_ATOMIC_16_FETCH_ADD(memory->ref_count, 1); +#if BH_ATOMIC_16_IS_ATOMIC == 0 + os_mutex_unlock(&g_shared_memory_lock); #endif bh_assert(old >= 1); - bh_assert(old < UINT32_MAX); + bh_assert(old < UINT16_MAX); return old + 1; } -uint32 +uint16 shared_memory_dec_reference(WASMMemoryInstance *memory) { bh_assert(shared_memory_is_shared(memory)); - uint32 old; -#if BH_ATOMIC_32_IS_ATOMIC == 0 - os_mutex_lock(&_shared_memory_lock); + uint16 old; +#if BH_ATOMIC_16_IS_ATOMIC == 0 + os_mutex_lock(&g_shared_memory_lock); #endif - old = BH_ATOMIC_32_FETCH_SUB(memory->ref_count, 1); -#if BH_ATOMIC_32_IS_ATOMIC == 0 - os_mutex_unlock(&_shared_memory_lock); + old = BH_ATOMIC_16_FETCH_SUB(memory->ref_count, 1); +#if BH_ATOMIC_16_IS_ATOMIC == 0 + os_mutex_unlock(&g_shared_memory_lock); #endif bh_assert(old > 0); return old - 1; } -bool -shared_memory_is_shared(WASMMemoryInstance *memory) -{ - uint32 old; -#if BH_ATOMIC_32_IS_ATOMIC == 0 - os_mutex_lock(&_shared_memory_lock); -#endif - old = BH_ATOMIC_32_LOAD(memory->ref_count); -#if BH_ATOMIC_32_IS_ATOMIC == 0 - os_mutex_unlock(&_shared_memory_lock); -#endif - return old > 0; -} - static korp_mutex * shared_memory_get_lock_pointer(WASMMemoryInstance *memory) { bh_assert(memory != NULL); - return &_shared_memory_lock; -} - -void -shared_memory_lock(WASMMemoryInstance *memory) -{ - /* - * Note: exception logic is currently abusing this lock. - * cf. https://github.com/bytecodealliance/wasm-micro-runtime/issues/2407 - */ - bh_assert(memory != NULL); - os_mutex_lock(&_shared_memory_lock); -} - -void -shared_memory_unlock(WASMMemoryInstance *memory) -{ - bh_assert(memory != NULL); - os_mutex_unlock(&_shared_memory_lock); + return &g_shared_memory_lock; } /* Atomics wait && notify APIs */ @@ -301,12 +269,15 @@ wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address, return -1; } + shared_memory_lock(module_inst->memories[0]); if ((uint8 *)address < module_inst->memories[0]->memory_data || (uint8 *)address + (wait64 ? 8 : 4) > module_inst->memories[0]->memory_data_end) { + shared_memory_unlock(module_inst->memories[0]); wasm_runtime_set_exception(module, "out of bounds memory access"); return -1; } + shared_memory_unlock(module_inst->memories[0]); #if WASM_ENABLE_THREAD_MGR != 0 exec_env = @@ -423,9 +394,11 @@ wasm_runtime_atomic_notify(WASMModuleInstanceCommon *module, void *address, bh_assert(module->module_type == Wasm_Module_Bytecode || module->module_type == Wasm_Module_AoT); + shared_memory_lock(module_inst->memories[0]); out_of_bounds = ((uint8 *)address < module_inst->memories[0]->memory_data || (uint8 *)address + 4 > module_inst->memories[0]->memory_data_end); + shared_memory_unlock(module_inst->memories[0]); if (out_of_bounds) { wasm_runtime_set_exception(module, "out of bounds memory access"); diff --git a/core/iwasm/common/wasm_shared_memory.h b/core/iwasm/common/wasm_shared_memory.h index 6a6538d21..8bbc4a800 100644 --- a/core/iwasm/common/wasm_shared_memory.h +++ b/core/iwasm/common/wasm_shared_memory.h @@ -14,26 +14,39 @@ extern "C" { #endif +extern korp_mutex g_shared_memory_lock; + bool wasm_shared_memory_init(); void wasm_shared_memory_destroy(); -uint32 +uint16 shared_memory_inc_reference(WASMMemoryInstance *memory); -uint32 +uint16 shared_memory_dec_reference(WASMMemoryInstance *memory); -bool -shared_memory_is_shared(WASMMemoryInstance *memory); +#define shared_memory_is_shared(memory) memory->is_shared_memory -void -shared_memory_lock(WASMMemoryInstance *memory); +#define shared_memory_lock(memory) \ + do { \ + /* \ + * Note: exception logic is currently abusing this lock. \ + * cf. \ + * https://github.com/bytecodealliance/wasm-micro-runtime/issues/2407 \ + */ \ + bh_assert(memory != NULL); \ + if (memory->is_shared_memory) \ + os_mutex_lock(&g_shared_memory_lock); \ + } while (0) -void -shared_memory_unlock(WASMMemoryInstance *memory); +#define shared_memory_unlock(memory) \ + do { \ + if (memory->is_shared_memory) \ + os_mutex_unlock(&g_shared_memory_lock); \ + } while (0) uint32 wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address, diff --git a/core/iwasm/compilation/aot.c b/core/iwasm/compilation/aot.c index e836df28f..8162d006e 100644 --- a/core/iwasm/compilation/aot.c +++ b/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, diff --git a/core/iwasm/compilation/aot.h b/core/iwasm/compilation/aot.h index 088460636..4bee70f9c 100644 --- a/core/iwasm/compilation/aot.h +++ b/core/iwasm/compilation/aot.h @@ -143,7 +143,6 @@ typedef struct AOTTableInitData { uint32 mode; /* funcref or externref, elemkind will be considered as funcref */ uint32 elem_type; - bool is_dropped; /* optional, only for active */ uint32 table_index; /* Start address of init data */ diff --git a/core/iwasm/compilation/aot_emit_aot_file.c b/core/iwasm/compilation/aot_emit_aot_file.c index 103b2750e..80bcdc7db 100644 --- a/core/iwasm/compilation/aot_emit_aot_file.c +++ b/core/iwasm/compilation/aot_emit_aot_file.c @@ -269,7 +269,7 @@ static uint32 get_table_init_data_size(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) diff --git a/core/iwasm/compilation/aot_emit_control.c b/core/iwasm/compilation/aot_emit_control.c index 5216955bc..31fe1baef 100644 --- a/core/iwasm/compilation/aot_emit_control.c +++ b/core/iwasm/compilation/aot_emit_control.c @@ -202,6 +202,9 @@ handle_next_reachable_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, *p_frame_ip = block->wasm_code_else + 1; /* Push back the block */ aot_block_stack_push(&func_ctx->block_stack, block); + /* Recover parameters of else branch */ + for (i = 0; i < block->param_count; i++) + PUSH(block->else_param_phis[i], block->param_types[i]); return true; } else if (block->llvm_end_block) { @@ -221,6 +224,19 @@ handle_next_reachable_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return true; } + if (block->label_type == LABEL_TYPE_IF && block->llvm_else_block + && !block->skip_wasm_code_else + && *p_frame_ip <= block->wasm_code_else) { + /* Clear value stack and start to translate else branch */ + aot_value_stack_destroy(&block->value_stack); + /* Recover parameters of else branch */ + for (i = 0; i < block->param_count; i++) + PUSH(block->else_param_phis[i], block->param_types[i]); + SET_BUILDER_POS(block->llvm_else_block); + *p_frame_ip = block->wasm_code_else + 1; + return true; + } + *p_frame_ip = block->wasm_code_end + 1; SET_BUILDER_POS(block->llvm_end_block); @@ -344,7 +360,9 @@ push_aot_block_to_stack_and_pass_params(AOTCompContext *comp_ctx, for (i = 0; i < block->param_count; i++) { param_index = block->param_count - 1 - i; POP(value, block->param_types[param_index]); - ADD_TO_PARAM_PHIS(block, value, param_index); + if (block->llvm_entry_block) + /* Only add incoming phis if the entry block was created */ + ADD_TO_PARAM_PHIS(block, value, param_index); if (block->label_type == LABEL_TYPE_IF && !block->skip_wasm_code_else) { if (block->llvm_else_block) { @@ -366,7 +384,17 @@ push_aot_block_to_stack_and_pass_params(AOTCompContext *comp_ctx, /* Push param phis to the new block */ for (i = 0; i < block->param_count; i++) { - PUSH(block->param_phis[i], block->param_types[i]); + if (block->llvm_entry_block) + /* Push param phis if the entry basic block was created */ + PUSH(block->param_phis[i], block->param_types[i]); + else { + bh_assert(block->label_type == LABEL_TYPE_IF + && block->llvm_else_block && block->else_param_phis + && !block->skip_wasm_code_else); + /* Push else param phis if we start to translate the + else branch */ + PUSH(block->else_param_phis[i], block->param_types[i]); + } } return true; diff --git a/core/iwasm/compilation/aot_emit_function.c b/core/iwasm/compilation/aot_emit_function.c index def3f7d04..bc8cb0a55 100644 --- a/core/iwasm/compilation/aot_emit_function.c +++ b/core/iwasm/compilation/aot_emit_function.c @@ -22,11 +22,14 @@ static bool is_win_platform(AOTCompContext *comp_ctx) { char *triple = LLVMGetTargetMachineTriple(comp_ctx->target_machine); + bool ret; bh_assert(triple); - if (strstr(triple, "win32") || strstr(triple, "win")) - return true; - return false; + ret = (strstr(triple, "win32") || strstr(triple, "win")) ? true : false; + + LLVMDisposeMessage(triple); + + return ret; } static bool diff --git a/core/iwasm/compilation/aot_emit_memory.c b/core/iwasm/compilation/aot_emit_memory.c index 7484d4b5b..8c35c3fe6 100644 --- a/core/iwasm/compilation/aot_emit_memory.c +++ b/core/iwasm/compilation/aot_emit_memory.c @@ -157,7 +157,10 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, if (mem_offset + bytes <= mem_data_size) { /* inside memory space */ - offset1 = I32_CONST((uint32)mem_offset); + if (comp_ctx->pointer_size == sizeof(uint64)) + offset1 = I64_CONST((uint32)mem_offset); + else + offset1 = I32_CONST((uint32)mem_offset); CHECK_LLVM_CONST(offset1); if (!enable_segue) { if (!(maddr = LLVMBuildInBoundsGEP2(comp_ctx->builder, diff --git a/core/iwasm/compilation/aot_emit_numberic.c b/core/iwasm/compilation/aot_emit_numberic.c index bda64f831..8b6ec02d6 100644 --- a/core/iwasm/compilation/aot_emit_numberic.c +++ b/core/iwasm/compilation/aot_emit_numberic.c @@ -171,15 +171,6 @@ right = shift_count_mask; \ } while (0) -static bool -is_shift_count_mask_needed(AOTCompContext *comp_ctx, LLVMValueRef left, - LLVMValueRef right) -{ - return (strcmp(comp_ctx->target_arch, "x86_64") != 0 - && strcmp(comp_ctx->target_arch, "i386") != 0) - || (LLVMIsEfficientConstInt(left) && LLVMIsEfficientConstInt(right)); -} - /* Call llvm constrained floating-point intrinsic */ static LLVMValueRef call_llvm_float_experimental_constrained_intrinsic(AOTCompContext *comp_ctx, @@ -737,8 +728,7 @@ compile_int_shl(AOTCompContext *comp_ctx, LLVMValueRef left, LLVMValueRef right, { LLVMValueRef res; - if (is_shift_count_mask_needed(comp_ctx, left, right)) - SHIFT_COUNT_MASK; + SHIFT_COUNT_MASK; /* Build shl */ LLVM_BUILD_OP(Shl, left, right, res, "shl", NULL); @@ -752,8 +742,7 @@ compile_int_shr_s(AOTCompContext *comp_ctx, LLVMValueRef left, { LLVMValueRef res; - if (is_shift_count_mask_needed(comp_ctx, left, right)) - SHIFT_COUNT_MASK; + SHIFT_COUNT_MASK; /* Build shl */ LLVM_BUILD_OP(AShr, left, right, res, "shr_s", NULL); @@ -767,8 +756,7 @@ compile_int_shr_u(AOTCompContext *comp_ctx, LLVMValueRef left, { LLVMValueRef res; - if (is_shift_count_mask_needed(comp_ctx, left, right)) - SHIFT_COUNT_MASK; + SHIFT_COUNT_MASK; /* Build shl */ LLVM_BUILD_OP(LShr, left, right, res, "shr_u", NULL); @@ -789,17 +777,25 @@ compile_int_rot(AOTCompContext *comp_ctx, LLVMValueRef left, LLVMValueRef right, if (IS_CONST_ZERO(right)) return left; - /* Calculate (bits - shif_count) */ + /* Calculate (bits - shift_count) */ LLVM_BUILD_OP(Sub, is_i32 ? I32_32 : I64_64, right, bits_minus_shift_count, "bits_minus_shift_count", NULL); + /* Calculate (bits - shift_count) & mask */ + bits_minus_shift_count = + LLVMBuildAnd(comp_ctx->builder, bits_minus_shift_count, + is_i32 ? I32_31 : I64_63, "bits_minus_shift_count_and"); + if (!bits_minus_shift_count) { + aot_set_last_error("llvm build and failed."); + return NULL; + } if (is_rotl) { - /* left<>(BITS-count) */ + /* (left << count) | (left >> ((BITS - count) & mask)) */ LLVM_BUILD_OP(Shl, left, right, tmp_l, "tmp_l", NULL); LLVM_BUILD_OP(LShr, left, bits_minus_shift_count, tmp_r, "tmp_r", NULL); } else { - /* left>>count | left<<(BITS-count) */ + /* (left >> count) | (left << ((BITS - count) & mask)) */ LLVM_BUILD_OP(LShr, left, right, tmp_l, "tmp_l", NULL); LLVM_BUILD_OP(Shl, left, bits_minus_shift_count, tmp_r, "tmp_r", NULL); } diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index 6dc3a0f7d..bbf16f55c 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -153,6 +153,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 * @@ -646,6 +653,20 @@ 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, (unsigned)strlen(key), val, + (unsigned)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); @@ -1915,6 +1936,7 @@ static ArchItem valid_archs[] = { static const char *valid_abis[] = { "gnu", "eabi", + "eabihf", "gnueabihf", "msvc", "ilp32", @@ -1930,13 +1952,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 @@ -1992,6 +2034,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) { @@ -2120,7 +2174,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; @@ -2160,6 +2214,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; @@ -2214,7 +2276,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; @@ -2258,6 +2320,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; } @@ -2361,7 +2434,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 { @@ -2510,6 +2583,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-"; @@ -2517,7 +2591,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) @@ -2553,6 +2630,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) @@ -2627,13 +2709,14 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option) meta_target_abi); if (!strcmp(abi, "lp64d") || !strcmp(abi, "ilp32d")) { - if (features) { + if (features && !strstr(features, "+d")) { snprintf(features_buf, sizeof(features_buf), "%s%s", features, ",+d"); features = features_buf; } - else + else if (!features) { features = "+d"; + } } } diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index b46ac3bd0..32d7bbeba 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/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" @@ -422,6 +423,8 @@ typedef struct AOTCompContext { char stack_usage_temp_file[64]; const char *llvm_passes; const char *builtin_intrinsics; + + bool emit_frame_pointer; } AOTCompContext; enum { @@ -431,6 +434,7 @@ enum { AOT_LLVMIR_OPT_FILE, }; +/* always sync it with AOTCompOption in aot_export.h */ typedef struct AOTCompOption { bool is_jit_mode; bool is_indirect_mode; @@ -457,6 +461,7 @@ typedef struct AOTCompOption { uint32 bounds_checks; uint32 stack_bounds_checks; uint32 segue_flags; + bool linux_perf_support; char **custom_sections; uint32 custom_sections_count; const char *stack_usage_file; diff --git a/core/iwasm/compilation/aot_llvm_extra.cpp b/core/iwasm/compilation/aot_llvm_extra.cpp index ab6c621a0..ed0205c3c 100644 --- a/core/iwasm/compilation/aot_llvm_extra.cpp +++ b/core/iwasm/compilation/aot_llvm_extra.cpp @@ -36,6 +36,7 @@ #include #if LLVM_VERSION_MAJOR >= 17 #include +#include #endif #include #include @@ -203,19 +204,27 @@ aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx, LLVMModuleRef module) Optional PGO = llvm::None; #endif -// TODO -#if LLVM_VERSION_MAJOR < 17 if (comp_ctx->enable_llvm_pgo) { /* Disable static counter allocation for value profiler, it will be allocated by runtime */ const char *argv[] = { "", "-vp-static-alloc=false" }; cl::ParseCommandLineOptions(2, argv); +#if LLVM_VERSION_MAJOR < 17 PGO = PGOOptions("", "", "", PGOOptions::IRInstr); +#else + auto FS = vfs::getRealFileSystem(); + PGO = PGOOptions("", "", "", "", FS, PGOOptions::IRInstr); +#endif } else if (comp_ctx->use_prof_file) { +#if LLVM_VERSION_MAJOR < 17 PGO = PGOOptions(comp_ctx->use_prof_file, "", "", PGOOptions::IRUse); - } +#else + auto FS = vfs::getRealFileSystem(); + PGO = PGOOptions(comp_ctx->use_prof_file, "", "", "", FS, + PGOOptions::IRUse); #endif + } #ifdef DEBUG_PASS PassInstrumentationCallbacks PIC; @@ -343,18 +352,29 @@ aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx, LLVMModuleRef module) ExitOnErr(PB.parsePassPipeline(MPM, comp_ctx->llvm_passes)); } - if (!disable_llvm_lto) { - /* Apply LTO for AOT mode */ - if (comp_ctx->comp_data->func_count >= 10 - || comp_ctx->enable_llvm_pgo || comp_ctx->use_prof_file) - /* Add the pre-link optimizations if the func count - is large enough or PGO is enabled */ - MPM.addPass(PB.buildLTOPreLinkDefaultPipeline(OL)); - else - MPM.addPass(PB.buildLTODefaultPipeline(OL, NULL)); + if ( +#if LLVM_VERSION_MAJOR <= 13 + PassBuilder::OptimizationLevel::O0 == OL +#else + OptimizationLevel::O0 == OL +#endif + ) { + MPM.addPass(PB.buildO0DefaultPipeline(OL)); } else { - MPM.addPass(PB.buildPerModuleDefaultPipeline(OL)); + if (!disable_llvm_lto) { + /* Apply LTO for AOT mode */ + if (comp_ctx->comp_data->func_count >= 10 + || comp_ctx->enable_llvm_pgo || comp_ctx->use_prof_file) + /* Add the pre-link optimizations if the func count + is large enough or PGO is enabled */ + MPM.addPass(PB.buildLTOPreLinkDefaultPipeline(OL)); + else + MPM.addPass(PB.buildLTODefaultPipeline(OL, NULL)); + } + else { + MPM.addPass(PB.buildPerModuleDefaultPipeline(OL)); + } } /* Run specific passes for AOT indirect mode in last since general diff --git a/core/iwasm/compilation/aot_orc_extra.cpp b/core/iwasm/compilation/aot_orc_extra.cpp index 51d61bf3c..ad8c41c3f 100644 --- a/core/iwasm/compilation/aot_orc_extra.cpp +++ b/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()); +} diff --git a/core/iwasm/compilation/aot_orc_extra.h b/core/iwasm/compilation/aot_orc_extra.h index 44c2cd7a7..32ece4de4 100644 --- a/core/iwasm/compilation/aot_orc_extra.h +++ b/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 diff --git a/core/iwasm/compilation/simd/simd_bit_shifts.c b/core/iwasm/compilation/simd/simd_bit_shifts.c index 675ffbcfe..1d645ed71 100644 --- a/core/iwasm/compilation/simd/simd_bit_shifts.c +++ b/core/iwasm/compilation/simd/simd_bit_shifts.c @@ -30,11 +30,11 @@ simd_shift(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVM_CONST(i16x8_vec_zero), LLVM_CONST(i32x4_vec_zero), LLVM_CONST(i64x2_vec_zero) }; - LLVMValueRef lane_bits[] = { - LLVM_CONST(i32_eight), - LLVMConstInt(I32_TYPE, 16, true), - LLVMConstInt(I32_TYPE, 32, true), - LLVMConstInt(I32_TYPE, 64, true), + LLVMValueRef lane_shift_masks[] = { + LLVMConstInt(I32_TYPE, 7, true), + LLVMConstInt(I32_TYPE, 15, true), + LLVMConstInt(I32_TYPE, 31, true), + LLVMConstInt(I32_TYPE, 63, true), }; POP_I32(offset); @@ -44,11 +44,11 @@ simd_shift(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return false; } - /* offset mod LaneBits */ - if (!lane_bits[itype] - || !(offset = LLVMBuildSRem(comp_ctx->builder, offset, lane_bits[itype], - "offset_fix"))) { - HANDLE_FAILURE("LLVMBuildSRem"); + /* offset = offset & shift_mask */ + if (!lane_shift_masks[itype] + || !(offset = LLVMBuildAnd(comp_ctx->builder, offset, + lane_shift_masks[itype], "offset_fix"))) { + HANDLE_FAILURE("LLVMBuildAnd"); return false; } diff --git a/core/iwasm/fast-jit/fe/jit_emit_compare.c b/core/iwasm/fast-jit/fe/jit_emit_compare.c index d41249346..8fe48f142 100644 --- a/core/iwasm/fast-jit/fe/jit_emit_compare.c +++ b/core/iwasm/fast-jit/fe/jit_emit_compare.c @@ -227,7 +227,7 @@ jit_compile_op_f32_compare(JitCompContext *cc, FloatCond cond) POP_F32(rhs); POP_F32(lhs); - if (jit_reg_is_const_val(lhs) && jit_reg_is_const_val(rhs)) { + if (jit_reg_is_const(lhs) && jit_reg_is_const(rhs)) { float32 lvalue = jit_cc_get_const_F32(cc, lhs); float32 rvalue = jit_cc_get_const_F32(cc, rhs); @@ -290,7 +290,7 @@ jit_compile_op_f64_compare(JitCompContext *cc, FloatCond cond) POP_F64(rhs); POP_F64(lhs); - if (jit_reg_is_const_val(lhs) && jit_reg_is_const_val(rhs)) { + if (jit_reg_is_const(lhs) && jit_reg_is_const(rhs)) { float64 lvalue = jit_cc_get_const_F64(cc, lhs); float64 rvalue = jit_cc_get_const_F64(cc, rhs); diff --git a/core/iwasm/fast-jit/fe/jit_emit_control.c b/core/iwasm/fast-jit/fe/jit_emit_control.c index eda6554b7..07c6e7632 100644 --- a/core/iwasm/fast-jit/fe/jit_emit_control.c +++ b/core/iwasm/fast-jit/fe/jit_emit_control.c @@ -808,7 +808,7 @@ jit_compile_op_block(JitCompContext *cc, uint8 **p_frame_ip, else if (label_type == LABEL_TYPE_IF) { POP_I32(value); - if (!jit_reg_is_const_val(value)) { + if (!jit_reg_is_const(value)) { /* Compare value is not constant, create condition br IR */ /* Create entry block */ diff --git a/core/iwasm/fast-jit/fe/jit_emit_conversion.c b/core/iwasm/fast-jit/fe/jit_emit_conversion.c index 8308a3ca9..89d84f142 100644 --- a/core/iwasm/fast-jit/fe/jit_emit_conversion.c +++ b/core/iwasm/fast-jit/fe/jit_emit_conversion.c @@ -192,6 +192,55 @@ jit_compile_check_value_range(JitCompContext *cc, JitReg value, JitReg min_fp, bh_assert(JIT_REG_KIND_F32 == kind || JIT_REG_KIND_F64 == kind); + if (JIT_REG_KIND_F32 == kind && jit_reg_is_const(value)) { + /* value is an f32 const */ + float value_f32_const = jit_cc_get_const_F32(cc, value); + float min_fp_f32_const = jit_cc_get_const_F32(cc, min_fp); + float max_fp_f32_const = jit_cc_get_const_F32(cc, max_fp); + + if (isnan(value_f32_const)) { + /* throw exception if value is nan */ + if (!jit_emit_exception(cc, EXCE_INVALID_CONVERSION_TO_INTEGER, + JIT_OP_JMP, 0, NULL)) + goto fail; + } + + if (value_f32_const <= min_fp_f32_const + || value_f32_const >= max_fp_f32_const) { + /* throw exception if value is out of range */ + if (!jit_emit_exception(cc, EXCE_INTEGER_OVERFLOW, JIT_OP_JMP, 0, + NULL)) + goto fail; + } + + /* value is in range, do nothing */ + return true; + } + else if (JIT_REG_KIND_F64 == kind && jit_reg_is_const(value)) { + /* value is an f64 const */ + double value_f64_const = jit_cc_get_const_F64(cc, value); + double min_fp_f64_const = jit_cc_get_const_F64(cc, min_fp); + double max_fp_f64_const = jit_cc_get_const_F64(cc, max_fp); + + if (isnan(value_f64_const)) { + /* throw exception if value is nan */ + if (!jit_emit_exception(cc, EXCE_INVALID_CONVERSION_TO_INTEGER, + JIT_OP_JMP, 0, NULL)) + goto fail; + } + + if (value_f64_const <= min_fp_f64_const + || value_f64_const >= max_fp_f64_const) { + /* throw exception if value is out of range */ + if (!jit_emit_exception(cc, EXCE_INTEGER_OVERFLOW, JIT_OP_JMP, 0, + NULL)) + goto fail; + } + + /* value is in range, do nothing */ + return true; + } + /* If value is NaN, throw exception */ if (JIT_REG_KIND_F32 == kind) emit_ret = jit_emit_callnative(cc, local_isnanf, nan_ret, &value, 1); diff --git a/core/iwasm/fast-jit/fe/jit_emit_function.c b/core/iwasm/fast-jit/fe/jit_emit_function.c index 3ac9e3ed6..43a71e26a 100644 --- a/core/iwasm/fast-jit/fe/jit_emit_function.c +++ b/core/iwasm/fast-jit/fe/jit_emit_function.c @@ -827,23 +827,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])) { @@ -865,6 +887,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: diff --git a/core/iwasm/fast-jit/fe/jit_emit_memory.c b/core/iwasm/fast-jit/fe/jit_emit_memory.c index 9635d4e57..420b4dd8e 100644 --- a/core/iwasm/fast-jit/fe/jit_emit_memory.c +++ b/core/iwasm/fast-jit/fe/jit_emit_memory.c @@ -137,6 +137,7 @@ check_and_seek(JitCompContext *cc, JitReg addr, uint32 offset, uint32 bytes) { JitReg memory_boundary = 0, offset1; #ifndef OS_ENABLE_HW_BOUND_CHECK + JitReg cur_page_count; /* the default memory */ uint32 mem_idx = 0; #endif @@ -146,16 +147,10 @@ check_and_seek(JitCompContext *cc, JitReg addr, uint32 offset, uint32 bytes) /* 1. shortcut if the memory size is 0 */ if (cc->cur_wasm_module->memories != NULL && 0 == cc->cur_wasm_module->memories[mem_idx].init_page_count) { - JitReg module_inst, cur_page_count; - uint32 cur_page_count_offset = - (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) - + (uint32)offsetof(WASMMemoryInstance, cur_page_count); + + cur_page_count = get_cur_page_count_reg(cc->jit_frame, mem_idx); /* if (cur_mem_page_count == 0) goto EXCEPTION */ - module_inst = get_module_inst_reg(cc->jit_frame); - cur_page_count = jit_cc_new_reg_I32(cc); - GEN_INSN(LDI32, cur_page_count, module_inst, - NEW_CONST(I32, cur_page_count_offset)); GEN_INSN(CMP, cc->cmp_reg, cur_page_count, NEW_CONST(I32, 0)); if (!jit_emit_exception(cc, EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, JIT_OP_BEQ, cc->cmp_reg, NULL)) { @@ -580,15 +575,9 @@ fail: bool jit_compile_op_memory_size(JitCompContext *cc, uint32 mem_idx) { - JitReg module_inst, cur_page_count; - uint32 cur_page_count_offset = - (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) - + (uint32)offsetof(WASMMemoryInstance, cur_page_count); + JitReg cur_page_count; - module_inst = get_module_inst_reg(cc->jit_frame); - cur_page_count = jit_cc_new_reg_I32(cc); - GEN_INSN(LDI32, cur_page_count, module_inst, - NEW_CONST(I32, cur_page_count_offset)); + cur_page_count = get_cur_page_count_reg(cc->jit_frame, mem_idx); PUSH_I32(cur_page_count); @@ -600,18 +589,11 @@ fail: bool jit_compile_op_memory_grow(JitCompContext *cc, uint32 mem_idx) { - JitReg module_inst, grow_res, res; + JitReg grow_res, res; JitReg prev_page_count, inc_page_count, args[2]; - /* Get current page count */ - uint32 cur_page_count_offset = - (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) - + (uint32)offsetof(WASMMemoryInstance, cur_page_count); - - module_inst = get_module_inst_reg(cc->jit_frame); - prev_page_count = jit_cc_new_reg_I32(cc); - GEN_INSN(LDI32, prev_page_count, module_inst, - NEW_CONST(I32, cur_page_count_offset)); + /* Get current page count as prev_page_count */ + prev_page_count = get_cur_page_count_reg(cc->jit_frame, mem_idx); /* Call wasm_enlarge_memory */ POP_I32(inc_page_count); @@ -650,6 +632,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 +642,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 +695,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 diff --git a/core/iwasm/fast-jit/fe/jit_emit_table.c b/core/iwasm/fast-jit/fe/jit_emit_table.c index ea1b33883..b8ed6a1d5 100644 --- a/core/iwasm/fast-jit/fe/jit_emit_table.c +++ b/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); + args[0] = get_module_inst_reg(cc->jit_frame); + args[1] = NEW_CONST(I32, tbl_seg_idx); - tbl_segs = jit_cc_new_reg_ptr(cc); - GEN_INSN(LDPTR, tbl_segs, module, - NEW_CONST(I32, offsetof(WASMModule, table_segments))); - - 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 @@ -105,6 +106,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(uint32), (uint32)((tbl_sz - dst_offset) * sizeof(uint32)), diff --git a/core/iwasm/fast-jit/jit_codecache.c b/core/iwasm/fast-jit/jit_codecache.c index 73a034f34..ef2074747 100644 --- a/core/iwasm/fast-jit/jit_codecache.c +++ b/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; } diff --git a/core/iwasm/fast-jit/jit_compiler.h b/core/iwasm/fast-jit/jit_compiler.h index 9a49cffdd..dee2631d1 100644 --- a/core/iwasm/fast-jit/jit_compiler.h +++ b/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 diff --git a/core/iwasm/fast-jit/jit_frontend.c b/core/iwasm/fast-jit/jit_frontend.c index ec68ad91d..c9c22e0ad 100644 --- a/core/iwasm/fast-jit/jit_frontend.c +++ b/core/iwasm/fast-jit/jit_frontend.c @@ -218,42 +218,149 @@ get_aux_stack_bottom_reg(JitFrame *frame) return frame->aux_stack_bottom_reg; } +#if WASM_ENABLE_SHARED_MEMORY != 0 +static bool +is_shared_memory(WASMModule *module, uint32 mem_idx) +{ + WASMMemory *memory; + WASMMemoryImport *memory_import; + bool is_shared; + + if (mem_idx < module->import_memory_count) { + memory_import = &(module->import_memories[mem_idx].u.memory); + is_shared = memory_import->flags & 0x02 ? true : false; + } + else { + memory = &module->memories[mem_idx - module->import_memory_count]; + is_shared = memory->flags & 0x02 ? true : false; + } + return is_shared; +} +#endif + +JitReg +get_memory_inst_reg(JitFrame *frame, uint32 mem_idx) +{ + JitCompContext *cc = frame->cc; + JitReg module_inst_reg = get_module_inst_reg(frame); + uint32 memory_inst_offset; +#if WASM_ENABLE_SHARED_MEMORY != 0 + JitReg memories_addr; + uint32 memories_offset; + bool is_shared; +#endif + + if (frame->memory_regs[mem_idx].memory_inst) + return frame->memory_regs[mem_idx].memory_inst; + + frame->memory_regs[mem_idx].memory_inst = + cc->memory_regs[mem_idx].memory_inst; + + bh_assert(mem_idx == 0); +#if WASM_ENABLE_SHARED_MEMORY != 0 + is_shared = is_shared_memory(cc->cur_wasm_module, mem_idx); + if (is_shared) { + memories_addr = jit_cc_new_reg_ptr(cc); + memories_offset = (uint32)offsetof(WASMModuleInstance, memories); + /* module_inst->memories */ + GEN_INSN(LDPTR, memories_addr, module_inst_reg, + NEW_CONST(I32, memories_offset)); + /* module_inst->memories[mem_idx], mem_idx can only be 0 now */ + GEN_INSN(LDPTR, frame->memory_regs[mem_idx].memory_inst, memories_addr, + NEW_CONST(I32, mem_idx)); + } + else +#endif + { + memory_inst_offset = + (uint32)offsetof(WASMModuleInstance, global_table_data.bytes); + GEN_INSN(LDPTR, frame->memory_regs[mem_idx].memory_inst, + module_inst_reg, NEW_CONST(I32, memory_inst_offset)); + } + + return frame->memory_regs[mem_idx].memory_inst; +} + +JitReg +get_cur_page_count_reg(JitFrame *frame, uint32 mem_idx) +{ + JitCompContext *cc = frame->cc; + JitReg module_inst_reg; + uint32 cur_page_count_offset; +#if WASM_ENABLE_SHARED_MEMORY != 0 + JitReg memory_inst_reg; + bool is_shared; +#endif + + if (frame->memory_regs[mem_idx].cur_page_count) + return frame->memory_regs[mem_idx].cur_page_count; + + frame->memory_regs[mem_idx].cur_page_count = + cc->memory_regs[mem_idx].cur_page_count; + + /* Get current page count */ + bh_assert(mem_idx == 0); +#if WASM_ENABLE_SHARED_MEMORY != 0 + is_shared = is_shared_memory(cc->cur_wasm_module, mem_idx); + if (is_shared) { + memory_inst_reg = get_memory_inst_reg(frame, mem_idx); + cur_page_count_offset = + (uint32)offsetof(WASMMemoryInstance, cur_page_count); + /* memories[mem_idx]->cur_page_count_offset */ + GEN_INSN(LDI32, frame->memory_regs[mem_idx].cur_page_count, + memory_inst_reg, NEW_CONST(I32, cur_page_count_offset)); + } + else +#endif + { + module_inst_reg = get_module_inst_reg(frame); + cur_page_count_offset = + (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) + + (uint32)offsetof(WASMMemoryInstance, cur_page_count); + GEN_INSN(LDI32, frame->memory_regs[mem_idx].cur_page_count, + module_inst_reg, NEW_CONST(I32, cur_page_count_offset)); + } + + return frame->memory_regs[mem_idx].cur_page_count; +} + JitReg get_memory_data_reg(JitFrame *frame, uint32 mem_idx) { JitCompContext *cc = frame->cc; - JitReg module_inst_reg = get_module_inst_reg(frame); + JitReg module_inst_reg; uint32 memory_data_offset; +#if WASM_ENABLE_SHARED_MEMORY != 0 + JitReg memory_inst_reg; + bool is_shared; +#endif + + if (frame->memory_regs[mem_idx].memory_data) + return frame->memory_regs[mem_idx].memory_data; + + frame->memory_regs[mem_idx].memory_data = + cc->memory_regs[mem_idx].memory_data; bh_assert(mem_idx == 0); #if WASM_ENABLE_SHARED_MEMORY != 0 - uint32 memories_offset = (uint32)offsetof(WASMModuleInstance, memories); - JitReg memories_addr = jit_cc_new_reg_ptr(cc); - JitReg memories_0_addr = jit_cc_new_reg_ptr(cc); - memory_data_offset = (uint32)offsetof(WASMMemoryInstance, memory_data); - if (!frame->memory_regs[mem_idx].memory_data) { - frame->memory_regs[mem_idx].memory_data = - cc->memory_regs[mem_idx].memory_data; - /* module_inst->memories */ - GEN_INSN(LDPTR, memories_addr, module_inst_reg, - NEW_CONST(I32, memories_offset)); - /* module_inst->memories[0] */ - GEN_INSN(LDPTR, memories_0_addr, memories_addr, NEW_CONST(I32, 0)); - /* memories[0]->memory_data */ + is_shared = is_shared_memory(cc->cur_wasm_module, mem_idx); + if (is_shared) { + memory_inst_reg = get_memory_inst_reg(frame, mem_idx); + memory_data_offset = (uint32)offsetof(WASMMemoryInstance, memory_data); + /* memories[mem_idx]->memory_data */ GEN_INSN(LDPTR, frame->memory_regs[mem_idx].memory_data, - memories_0_addr, NEW_CONST(I32, memory_data_offset)); + memory_inst_reg, NEW_CONST(I32, memory_data_offset)); } -#else - memory_data_offset = - (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) - + (uint32)offsetof(WASMMemoryInstance, memory_data); - if (!frame->memory_regs[mem_idx].memory_data) { - frame->memory_regs[mem_idx].memory_data = - cc->memory_regs[mem_idx].memory_data; + else +#endif + { + module_inst_reg = get_module_inst_reg(frame); + memory_data_offset = + (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) + + (uint32)offsetof(WASMMemoryInstance, memory_data); GEN_INSN(LDPTR, frame->memory_regs[mem_idx].memory_data, module_inst_reg, NEW_CONST(I32, memory_data_offset)); } -#endif return frame->memory_regs[mem_idx].memory_data; } @@ -261,16 +368,37 @@ JitReg get_memory_data_end_reg(JitFrame *frame, uint32 mem_idx) { JitCompContext *cc = frame->cc; - JitReg module_inst_reg = get_module_inst_reg(frame); - uint32 memory_data_end_offset = - (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) - + (uint32)offsetof(WASMMemoryInstance, memory_data_end); + JitReg module_inst_reg; + uint32 memory_data_end_offset; +#if WASM_ENABLE_SHARED_MEMORY != 0 + JitReg memory_inst_reg; + bool is_shared; +#endif + + if (frame->memory_regs[mem_idx].memory_data_end) + return frame->memory_regs[mem_idx].memory_data_end; + + frame->memory_regs[mem_idx].memory_data_end = + cc->memory_regs[mem_idx].memory_data_end; bh_assert(mem_idx == 0); - - if (!frame->memory_regs[mem_idx].memory_data_end) { - frame->memory_regs[mem_idx].memory_data_end = - cc->memory_regs[mem_idx].memory_data_end; +#if WASM_ENABLE_SHARED_MEMORY != 0 + is_shared = is_shared_memory(cc->cur_wasm_module, mem_idx); + if (is_shared) { + memory_inst_reg = get_memory_inst_reg(frame, mem_idx); + memory_data_end_offset = + (uint32)offsetof(WASMMemoryInstance, memory_data_end); + /* memories[mem_idx]->memory_data_end */ + GEN_INSN(LDPTR, frame->memory_regs[mem_idx].memory_data_end, + memory_inst_reg, NEW_CONST(I32, memory_data_end_offset)); + } + else +#endif + { + module_inst_reg = get_module_inst_reg(frame); + memory_data_end_offset = + (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) + + (uint32)offsetof(WASMMemoryInstance, memory_data_end); GEN_INSN(LDPTR, frame->memory_regs[mem_idx].memory_data_end, module_inst_reg, NEW_CONST(I32, memory_data_end_offset)); } @@ -281,16 +409,43 @@ JitReg get_mem_bound_check_1byte_reg(JitFrame *frame, uint32 mem_idx) { JitCompContext *cc = frame->cc; - JitReg module_inst_reg = get_module_inst_reg(frame); - uint32 mem_bound_check_1byte_offset = - (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) - + (uint32)offsetof(WASMMemoryInstance, mem_bound_check_1byte); + JitReg module_inst_reg; + uint32 mem_bound_check_1byte_offset; +#if WASM_ENABLE_SHARED_MEMORY != 0 + JitReg memory_inst_reg; + bool is_shared; +#endif + + if (frame->memory_regs[mem_idx].mem_bound_check_1byte) + return frame->memory_regs[mem_idx].mem_bound_check_1byte; + + frame->memory_regs[mem_idx].mem_bound_check_1byte = + cc->memory_regs[mem_idx].mem_bound_check_1byte; bh_assert(mem_idx == 0); - if (!frame->memory_regs[mem_idx].mem_bound_check_1byte) { - frame->memory_regs[mem_idx].mem_bound_check_1byte = - cc->memory_regs[mem_idx].mem_bound_check_1byte; +#if WASM_ENABLE_SHARED_MEMORY != 0 + is_shared = is_shared_memory(cc->cur_wasm_module, mem_idx); + if (is_shared) { + memory_inst_reg = get_memory_inst_reg(frame, mem_idx); + mem_bound_check_1byte_offset = + (uint32)offsetof(WASMMemoryInstance, mem_bound_check_1byte); + /* memories[mem_idx]->mem_bound_check_1byte */ +#if UINTPTR_MAX == UINT64_MAX + GEN_INSN(LDI64, frame->memory_regs[mem_idx].mem_bound_check_1byte, + memory_inst_reg, NEW_CONST(I32, mem_bound_check_1byte_offset)); +#else + GEN_INSN(LDI32, frame->memory_regs[mem_idx].mem_bound_check_1byte, + memory_inst_reg, NEW_CONST(I32, mem_bound_check_1byte_offset)); +#endif + } + else +#endif + { + module_inst_reg = get_module_inst_reg(frame); + mem_bound_check_1byte_offset = + (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) + + (uint32)offsetof(WASMMemoryInstance, mem_bound_check_1byte); #if UINTPTR_MAX == UINT64_MAX GEN_INSN(LDI64, frame->memory_regs[mem_idx].mem_bound_check_1byte, module_inst_reg, NEW_CONST(I32, mem_bound_check_1byte_offset)); @@ -306,16 +461,45 @@ JitReg get_mem_bound_check_2bytes_reg(JitFrame *frame, uint32 mem_idx) { JitCompContext *cc = frame->cc; - JitReg module_inst_reg = get_module_inst_reg(frame); - uint32 mem_bound_check_2bytes_offset = - (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) - + (uint32)offsetof(WASMMemoryInstance, mem_bound_check_2bytes); + JitReg module_inst_reg; + uint32 mem_bound_check_2bytes_offset; +#if WASM_ENABLE_SHARED_MEMORY != 0 + JitReg memory_inst_reg; + bool is_shared; +#endif + + if (frame->memory_regs[mem_idx].mem_bound_check_2bytes) + return frame->memory_regs[mem_idx].mem_bound_check_2bytes; + + frame->memory_regs[mem_idx].mem_bound_check_2bytes = + cc->memory_regs[mem_idx].mem_bound_check_2bytes; bh_assert(mem_idx == 0); - if (!frame->memory_regs[mem_idx].mem_bound_check_2bytes) { - frame->memory_regs[mem_idx].mem_bound_check_2bytes = - cc->memory_regs[mem_idx].mem_bound_check_2bytes; +#if WASM_ENABLE_SHARED_MEMORY != 0 + is_shared = is_shared_memory(cc->cur_wasm_module, mem_idx); + if (is_shared) { + memory_inst_reg = get_memory_inst_reg(frame, mem_idx); + mem_bound_check_2bytes_offset = + (uint32)offsetof(WASMMemoryInstance, mem_bound_check_2bytes); + /* memories[mem_idx]->mem_bound_check_2bytes */ +#if UINTPTR_MAX == UINT64_MAX + GEN_INSN(LDI64, frame->memory_regs[mem_idx].mem_bound_check_2bytes, + memory_inst_reg, + NEW_CONST(I32, mem_bound_check_2bytes_offset)); +#else + GEN_INSN(LDI32, frame->memory_regs[mem_idx].mem_bound_check_2bytes, + memory_inst_reg, + NEW_CONST(I32, mem_bound_check_2bytes_offset)); +#endif + } + else +#endif + { + module_inst_reg = get_module_inst_reg(frame); + mem_bound_check_2bytes_offset = + (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) + + (uint32)offsetof(WASMMemoryInstance, mem_bound_check_2bytes); #if UINTPTR_MAX == UINT64_MAX GEN_INSN(LDI64, frame->memory_regs[mem_idx].mem_bound_check_2bytes, module_inst_reg, @@ -333,16 +517,45 @@ JitReg get_mem_bound_check_4bytes_reg(JitFrame *frame, uint32 mem_idx) { JitCompContext *cc = frame->cc; - JitReg module_inst_reg = get_module_inst_reg(frame); - uint32 mem_bound_check_4bytes_offset = - (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) - + (uint32)offsetof(WASMMemoryInstance, mem_bound_check_4bytes); + JitReg module_inst_reg; + uint32 mem_bound_check_4bytes_offset; +#if WASM_ENABLE_SHARED_MEMORY != 0 + JitReg memory_inst_reg; + bool is_shared; +#endif + + if (frame->memory_regs[mem_idx].mem_bound_check_4bytes) + return frame->memory_regs[mem_idx].mem_bound_check_4bytes; + + frame->memory_regs[mem_idx].mem_bound_check_4bytes = + cc->memory_regs[mem_idx].mem_bound_check_4bytes; bh_assert(mem_idx == 0); - if (!frame->memory_regs[mem_idx].mem_bound_check_4bytes) { - frame->memory_regs[mem_idx].mem_bound_check_4bytes = - cc->memory_regs[mem_idx].mem_bound_check_4bytes; +#if WASM_ENABLE_SHARED_MEMORY != 0 + is_shared = is_shared_memory(cc->cur_wasm_module, mem_idx); + if (is_shared) { + memory_inst_reg = get_memory_inst_reg(frame, mem_idx); + mem_bound_check_4bytes_offset = + (uint32)offsetof(WASMMemoryInstance, mem_bound_check_4bytes); + /* memories[mem_idx]->mem_bound_check_4bytes */ +#if UINTPTR_MAX == UINT64_MAX + GEN_INSN(LDI64, frame->memory_regs[mem_idx].mem_bound_check_4bytes, + memory_inst_reg, + NEW_CONST(I32, mem_bound_check_4bytes_offset)); +#else + GEN_INSN(LDI32, frame->memory_regs[mem_idx].mem_bound_check_4bytes, + memory_inst_reg, + NEW_CONST(I32, mem_bound_check_4bytes_offset)); +#endif + } + else +#endif + { + module_inst_reg = get_module_inst_reg(frame); + mem_bound_check_4bytes_offset = + (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) + + (uint32)offsetof(WASMMemoryInstance, mem_bound_check_4bytes); #if UINTPTR_MAX == UINT64_MAX GEN_INSN(LDI64, frame->memory_regs[mem_idx].mem_bound_check_4bytes, module_inst_reg, @@ -360,16 +573,45 @@ JitReg get_mem_bound_check_8bytes_reg(JitFrame *frame, uint32 mem_idx) { JitCompContext *cc = frame->cc; - JitReg module_inst_reg = get_module_inst_reg(frame); - uint32 mem_bound_check_8bytes_offset = - (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) - + (uint32)offsetof(WASMMemoryInstance, mem_bound_check_8bytes); + JitReg module_inst_reg; + uint32 mem_bound_check_8bytes_offset; +#if WASM_ENABLE_SHARED_MEMORY != 0 + JitReg memory_inst_reg; + bool is_shared; +#endif + + if (frame->memory_regs[mem_idx].mem_bound_check_8bytes) + return frame->memory_regs[mem_idx].mem_bound_check_8bytes; + + frame->memory_regs[mem_idx].mem_bound_check_8bytes = + cc->memory_regs[mem_idx].mem_bound_check_8bytes; bh_assert(mem_idx == 0); - if (!frame->memory_regs[mem_idx].mem_bound_check_8bytes) { - frame->memory_regs[mem_idx].mem_bound_check_8bytes = - cc->memory_regs[mem_idx].mem_bound_check_8bytes; +#if WASM_ENABLE_SHARED_MEMORY != 0 + is_shared = is_shared_memory(cc->cur_wasm_module, mem_idx); + if (is_shared) { + memory_inst_reg = get_memory_inst_reg(frame, mem_idx); + mem_bound_check_8bytes_offset = + (uint32)offsetof(WASMMemoryInstance, mem_bound_check_8bytes); + /* memories[mem_idx]->mem_bound_check_8bytes */ +#if UINTPTR_MAX == UINT64_MAX + GEN_INSN(LDI64, frame->memory_regs[mem_idx].mem_bound_check_8bytes, + memory_inst_reg, + NEW_CONST(I32, mem_bound_check_8bytes_offset)); +#else + GEN_INSN(LDI32, frame->memory_regs[mem_idx].mem_bound_check_8bytes, + memory_inst_reg, + NEW_CONST(I32, mem_bound_check_8bytes_offset)); +#endif + } + else +#endif + { + module_inst_reg = get_module_inst_reg(frame); + mem_bound_check_8bytes_offset = + (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) + + (uint32)offsetof(WASMMemoryInstance, mem_bound_check_8bytes); #if UINTPTR_MAX == UINT64_MAX GEN_INSN(LDI64, frame->memory_regs[mem_idx].mem_bound_check_8bytes, module_inst_reg, @@ -387,16 +629,45 @@ JitReg get_mem_bound_check_16bytes_reg(JitFrame *frame, uint32 mem_idx) { JitCompContext *cc = frame->cc; - JitReg module_inst_reg = get_module_inst_reg(frame); - uint32 mem_bound_check_16bytes_offset = - (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) - + (uint32)offsetof(WASMMemoryInstance, mem_bound_check_16bytes); + JitReg module_inst_reg; + uint32 mem_bound_check_16bytes_offset; +#if WASM_ENABLE_SHARED_MEMORY != 0 + JitReg memory_inst_reg; + bool is_shared; +#endif + + if (frame->memory_regs[mem_idx].mem_bound_check_16bytes) + return frame->memory_regs[mem_idx].mem_bound_check_16bytes; + + frame->memory_regs[mem_idx].mem_bound_check_16bytes = + cc->memory_regs[mem_idx].mem_bound_check_16bytes; bh_assert(mem_idx == 0); - if (!frame->memory_regs[mem_idx].mem_bound_check_16bytes) { - frame->memory_regs[mem_idx].mem_bound_check_16bytes = - cc->memory_regs[mem_idx].mem_bound_check_16bytes; +#if WASM_ENABLE_SHARED_MEMORY != 0 + is_shared = is_shared_memory(cc->cur_wasm_module, mem_idx); + if (is_shared) { + memory_inst_reg = get_memory_inst_reg(frame, mem_idx); + mem_bound_check_16bytes_offset = + (uint32)offsetof(WASMMemoryInstance, mem_bound_check_16bytes); + /* memories[mem_idx]->mem_bound_check_16bytes */ +#if UINTPTR_MAX == UINT64_MAX + GEN_INSN(LDI64, frame->memory_regs[mem_idx].mem_bound_check_16bytes, + memory_inst_reg, + NEW_CONST(I32, mem_bound_check_16bytes_offset)); +#else + GEN_INSN(LDI32, frame->memory_regs[mem_idx].mem_bound_check_16bytes, + memory_inst_reg, + NEW_CONST(I32, mem_bound_check_16bytes_offset)); +#endif + } + else +#endif + { + module_inst_reg = get_module_inst_reg(frame); + mem_bound_check_16bytes_offset = + (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) + + (uint32)offsetof(WASMMemoryInstance, mem_bound_check_16bytes); #if UINTPTR_MAX == UINT64_MAX GEN_INSN(LDI64, frame->memory_regs[mem_idx].mem_bound_check_16bytes, module_inst_reg, @@ -462,6 +733,8 @@ clear_fixed_virtual_regs(JitFrame *frame) count = module->import_memory_count + module->memory_count; for (i = 0; i < count; i++) { + frame->memory_regs[i].memory_inst = 0; + frame->memory_regs[i].cur_page_count = 0; frame->memory_regs[i].memory_data = 0; frame->memory_regs[i].memory_data_end = 0; frame->memory_regs[i].mem_bound_check_1byte = 0; @@ -486,6 +759,7 @@ clear_memory_regs(JitFrame *frame) count = module->import_memory_count + module->memory_count; for (i = 0; i < count; i++) { + frame->memory_regs[i].cur_page_count = 0; frame->memory_regs[i].memory_data = 0; frame->memory_regs[i].memory_data_end = 0; frame->memory_regs[i].mem_bound_check_1byte = 0; @@ -654,6 +928,8 @@ create_fixed_virtual_regs(JitCompContext *cc) } for (i = 0; i < count; i++) { + cc->memory_regs[i].memory_inst = jit_cc_new_reg_ptr(cc); + cc->memory_regs[i].cur_page_count = jit_cc_new_reg_I32(cc); cc->memory_regs[i].memory_data = jit_cc_new_reg_ptr(cc); cc->memory_regs[i].memory_data_end = jit_cc_new_reg_ptr(cc); cc->memory_regs[i].mem_bound_check_1byte = jit_cc_new_reg_ptr(cc); @@ -2311,77 +2587,3 @@ jit_frontend_get_jitted_return_addr_offset() { return (uint32)offsetof(WASMInterpFrame, jitted_return_addr); } - -#if 0 -#if WASM_ENABLE_THREAD_MGR != 0 -bool -check_suspend_flags(JitCompContext *cc, JITFuncContext *func_ctx) -{ - LLVMValueRef terminate_addr, terminate_flags, flag, offset, res; - JitBasicBlock *terminate_check_block, non_terminate_block; - JITFuncType *jit_func_type = func_ctx->jit_func->func_type; - JitBasicBlock *terminate_block; - - /* Offset of suspend_flags */ - offset = I32_FIVE; - - if (!(terminate_addr = LLVMBuildInBoundsGEP( - cc->builder, func_ctx->exec_env, &offset, 1, "terminate_addr"))) { - jit_set_last_error("llvm build in bounds gep failed"); - return false; - } - if (!(terminate_addr = - LLVMBuildBitCast(cc->builder, terminate_addr, INT32_PTR_TYPE, - "terminate_addr_ptr"))) { - jit_set_last_error("llvm build bit cast failed"); - return false; - } - - if (!(terminate_flags = - LLVMBuildLoad(cc->builder, terminate_addr, "terminate_flags"))) { - jit_set_last_error("llvm build bit cast failed"); - return false; - } - /* Set terminate_flags memory accecc to volatile, so that the value - will always be loaded from memory rather than register */ - LLVMSetVolatile(terminate_flags, true); - - CREATE_BASIC_BLOCK(terminate_check_block, "terminate_check"); - MOVE_BASIC_BLOCK_AFTER_CURR(terminate_check_block); - - CREATE_BASIC_BLOCK(non_terminate_block, "non_terminate"); - MOVE_BASIC_BLOCK_AFTER_CURR(non_terminate_block); - - BUILD_ICMP(LLVMIntSGT, terminate_flags, I32_ZERO, res, "need_terminate"); - BUILD_COND_BR(res, terminate_check_block, non_terminate_block); - - /* Move builder to terminate check block */ - SET_BUILDER_POS(terminate_check_block); - - CREATE_BASIC_BLOCK(terminate_block, "terminate"); - MOVE_BASIC_BLOCK_AFTER_CURR(terminate_block); - - if (!(flag = LLVMBuildAnd(cc->builder, terminate_flags, I32_ONE, - "termination_flag"))) { - jit_set_last_error("llvm build AND failed"); - return false; - } - - BUILD_ICMP(LLVMIntSGT, flag, I32_ZERO, res, "need_terminate"); - BUILD_COND_BR(res, terminate_block, non_terminate_block); - - /* Move builder to terminate block */ - SET_BUILDER_POS(terminate_block); - if (!jit_build_zero_function_ret(cc, func_ctx, jit_func_type)) { - goto fail; - } - - /* Move builder to terminate block */ - SET_BUILDER_POS(non_terminate_block); - return true; - -fail: - return false; -} -#endif /* End of WASM_ENABLE_THREAD_MGR */ -#endif diff --git a/core/iwasm/fast-jit/jit_frontend.h b/core/iwasm/fast-jit/jit_frontend.h index 7aa460fd9..9065d23ec 100644 --- a/core/iwasm/fast-jit/jit_frontend.h +++ b/core/iwasm/fast-jit/jit_frontend.h @@ -192,6 +192,12 @@ get_aux_stack_bound_reg(JitFrame *frame); JitReg get_aux_stack_bottom_reg(JitFrame *frame); +JitReg +get_memory_inst_reg(JitFrame *frame, uint32 mem_idx); + +JitReg +get_cur_page_count_reg(JitFrame *frame, uint32 mem_idx); + JitReg get_memory_data_reg(JitFrame *frame, uint32 mem_idx); diff --git a/core/iwasm/fast-jit/jit_ir.h b/core/iwasm/fast-jit/jit_ir.h index e13a41d1d..bef3fcc0c 100644 --- a/core/iwasm/fast-jit/jit_ir.h +++ b/core/iwasm/fast-jit/jit_ir.h @@ -866,6 +866,8 @@ typedef struct JitValueSlot { typedef struct JitMemRegs { /* The following registers should be re-loaded after memory.grow, callbc and callnative */ + JitReg memory_inst; + JitReg cur_page_count; JitReg memory_data; JitReg memory_data_end; JitReg mem_bound_check_1byte; diff --git a/core/iwasm/fast-jit/jit_utils.c b/core/iwasm/fast-jit/jit_utils.c deleted file mode 100644 index 57a3e8f67..000000000 --- a/core/iwasm/fast-jit/jit_utils.c +++ /dev/null @@ -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; -} diff --git a/core/iwasm/fast-jit/jit_utils.h b/core/iwasm/fast-jit/jit_utils.h index c165b7a3c..a533c70bc 100644 --- a/core/iwasm/fast-jit/jit_utils.h +++ b/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 diff --git a/core/iwasm/include/aot_export.h b/core/iwasm/include/aot_export.h index ce8ae81fe..f2184033a 100644 --- a/core/iwasm/include/aot_export.h +++ b/core/iwasm/include/aot_export.h @@ -38,6 +38,7 @@ enum { AOT_LLVMIR_OPT_FILE, }; +/* always sync it with AOTCompOption in compilation/aot_llvm.h */ typedef struct AOTCompOption { bool is_jit_mode; bool is_indirect_mode; @@ -64,6 +65,7 @@ typedef struct AOTCompOption { uint32_t bounds_checks; uint32_t stack_bounds_checks; uint32_t segue_flags; + bool linux_perf_support; char **custom_sections; uint32_t custom_sections_count; const char *stack_usage_file; diff --git a/core/iwasm/include/wasm_c_api.h b/core/iwasm/include/wasm_c_api.h index 324a43bd5..eaad941e4 100644 --- a/core/iwasm/include/wasm_c_api.h +++ b/core/iwasm/include/wasm_c_api.h @@ -21,6 +21,15 @@ #endif #endif +#if defined(__GNUC__) || defined(__clang__) +#define DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) +#define DEPRECATED __declspec(deprecated) +#else +#pragma message("WARNING: You need to implement DEPRECATED for this compiler") +#define DEPRECATED +#endif + #ifdef __cplusplus extern "C" { #endif @@ -136,31 +145,6 @@ static inline void wasm_name_new_from_string_nt( WASM_DECLARE_OWN(config) -WASM_API_EXTERN own wasm_config_t* wasm_config_new(void); - -// Embedders may provide custom functions for manipulating configs. - - -// Engine - -WASM_DECLARE_OWN(engine) - -/** - * Create a new engine - * - * Note: for the engine new/delete operations, including this, - * wasm_engine_new_with_config, wasm_engine_new_with_args, and - * wasm_engine_delete, if the platform has mutex initializer, - * then they are thread-safe: we use a global lock to lock the - * operations of the engine. Otherwise they are not thread-safe: - * when there are engine new/delete operations happening - * simultaneously in multiple threads, developer must create - * the lock by himself, and add the lock when calling these - * functions. - */ -WASM_API_EXTERN own wasm_engine_t* wasm_engine_new(void); -WASM_API_EXTERN own wasm_engine_t* wasm_engine_new_with_config(own wasm_config_t*); - #ifndef MEM_ALLOC_OPTION_DEFINED #define MEM_ALLOC_OPTION_DEFINED /* same definition from wasm_export.h */ @@ -191,9 +175,51 @@ typedef union MemAllocOption { void *user_data; } allocator; } MemAllocOption; -#endif +#endif /* MEM_ALLOC_OPTION_DEFINED */ -WASM_API_EXTERN own wasm_engine_t * +/* Runtime configration */ +struct wasm_config_t { + mem_alloc_type_t mem_alloc_type; + MemAllocOption mem_alloc_option; + bool linux_perf_support; + /*TODO: wasi args*/ +}; + +/* + * by default: + * - mem_alloc_type is Alloc_With_System_Allocator + * - mem_alloc_option is all 0 + * - linux_perf_support is false + */ +WASM_API_EXTERN own wasm_config_t* wasm_config_new(void); + +// Embedders may provide custom functions for manipulating configs. +WASM_API_EXTERN own wasm_config_t* +wasm_config_set_mem_alloc_opt(wasm_config_t *, mem_alloc_type_t, MemAllocOption *); + +WASM_API_EXTERN own wasm_config_t* +wasm_config_set_linux_perf_opt(wasm_config_t *, bool); + +// Engine + +WASM_DECLARE_OWN(engine) + +/** + * Create a new engine + * + * Note: for the engine new/delete operations, including this, + * wasm_engine_new_with_config, wasm_engine_new_with_args, and + * wasm_engine_delete, if the platform has mutex initializer, + * then they are thread-safe: we use a global lock to lock the + * operations of the engine. Otherwise they are not thread-safe: + * when there are engine new/delete operations happening + * simultaneously in multiple threads, developer must create + * the lock by himself, and add the lock when calling these + * functions. + */ +WASM_API_EXTERN own wasm_engine_t* wasm_engine_new(void); +WASM_API_EXTERN own wasm_engine_t* wasm_engine_new_with_config(wasm_config_t*); +DEPRECATED WASM_API_EXTERN own wasm_engine_t * wasm_engine_new_with_args(mem_alloc_type_t type, const MemAllocOption *opts); // Store diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 2a30ddc93..d8e761e83 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -118,7 +118,7 @@ typedef union MemAllocOption { void *realloc_func; void *free_func; /* allocator user data, only used when - WASM_MEM_ALLOC_WITH_USER_DATA is defined */ + WASM_MEM_ALLOC_WITH_USER_DATA is defined */ void *user_data; } allocator; } MemAllocOption; @@ -149,7 +149,7 @@ typedef struct RuntimeInitArgs { uint32_t n_native_symbols; /* maximum thread number, only used when - WASM_ENABLE_THREAD_MGR is defined */ + WASM_ENABLE_THREAD_MGR is defined */ uint32_t max_thread_num; /* Debug settings, only used when @@ -169,6 +169,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 @@ -311,7 +320,8 @@ wasm_runtime_is_xip_file(const uint8_t *buf, uint32_t size); /** * Callback to load a module file into a buffer in multi-module feature */ -typedef bool (*module_reader)(package_type_t module_type,const char *module_name, +typedef bool (*module_reader)(package_type_t module_type, + const char *module_name, uint8_t **p_buffer, uint32_t *p_size); /** @@ -423,6 +433,7 @@ wasm_runtime_get_module_hash(wasm_module_t module); * @param dir_list The list of directories to preopen. (real path) * @param dir_count The number of elements in dir_list. * @param map_dir_list The list of directories to preopen. (mapped path) + * Format for each map entry: :: * @param map_dir_count The number of elements in map_dir_list. * If map_dir_count is smaller than dir_count, * mapped path is assumed to be same as the @@ -431,26 +442,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, @@ -865,6 +881,7 @@ wasm_application_execute_main(wasm_module_inst_t module_inst, WASM_RUNTIME_API_EXTERN bool wasm_application_execute_func(wasm_module_inst_t module_inst, const char *name, int32_t argc, char *argv[]); + /** * Get exception info of the WASM module instance. * @@ -927,6 +944,7 @@ wasm_runtime_terminate(wasm_module_inst_t module_inst); WASM_RUNTIME_API_EXTERN void wasm_runtime_set_custom_data(wasm_module_inst_t module_inst, void *custom_data); + /** * Get the custom data within a WASM module instance. * @@ -939,23 +957,24 @@ 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 */ WASM_RUNTIME_API_EXTERN void 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 wasm_runtime_is_bounds_checks_enabled( wasm_module_inst_t module_inst); + /** * Allocate memory from the heap of WASM module instance * @@ -1330,7 +1349,8 @@ wasm_externref_objdel(wasm_module_inst_t module_inst, void *extern_obj); * * @param module_inst the WASM module instance that the extern object * belongs to - * @param extern_obj the external object to which to set the `extern_obj_cleanup` cleanup callback. + * @param extern_obj the external object to which to set the + * `extern_obj_cleanup` cleanup callback. * @param extern_obj_cleanup a callback to release `extern_obj` * * @return true if success, false otherwise @@ -1538,11 +1558,11 @@ WASM_RUNTIME_API_EXTERN void wasm_runtime_destroy_context_key(void *key); WASM_RUNTIME_API_EXTERN void -wasm_runtime_set_context(wasm_module_inst_t inst, void *key, - void *ctx); +wasm_runtime_set_context(wasm_module_inst_t inst, void *key, void *ctx); + WASM_RUNTIME_API_EXTERN void -wasm_runtime_set_context_spread(wasm_module_inst_t inst, void *key, - void *ctx); +wasm_runtime_set_context_spread(wasm_module_inst_t inst, void *key, void *ctx); + WASM_RUNTIME_API_EXTERN void * wasm_runtime_get_context(wasm_module_inst_t inst, void *key); diff --git a/core/iwasm/interpreter/wasm.h b/core/iwasm/interpreter/wasm.h index c7d9f1de9..ee537aa63 100644 --- a/core/iwasm/interpreter/wasm.h +++ b/core/iwasm/interpreter/wasm.h @@ -311,7 +311,6 @@ typedef struct WASMTableSeg { uint32 mode; /* funcref or externref, elemkind will be considered as funcref */ uint32 elem_type; - bool is_dropped; /* optional, only for active */ uint32 table_index; InitializerExpression base_offset; @@ -350,7 +349,7 @@ typedef struct WASIArguments { uint32 ns_lookup_count; char **argv; uint32 argc; - int stdio[3]; + os_raw_file_handle stdio[3]; } WASIArguments; #endif diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 72e422077..86fad7a42 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -38,7 +38,7 @@ typedef float64 CellType_F64; * multi-threading mode since it may be changed by other * threads in memory.grow */ -#define get_linear_mem_size() memory->memory_data_size +#define get_linear_mem_size() GET_LINEAR_MEMORY_SIZE(memory) #endif #if !defined(OS_ENABLE_HW_BOUND_CHECK) \ @@ -1015,7 +1015,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 = @@ -1037,15 +1038,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 @@ -1158,7 +1152,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #if !defined(OS_ENABLE_HW_BOUND_CHECK) \ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \ || WASM_ENABLE_BULK_MEMORY != 0 - uint32 linear_mem_size = memory ? memory->memory_data_size : 0; + uint32 linear_mem_size = 0; + if (memory) +#if WASM_ENABLE_THREAD_MGR == 0 + linear_mem_size = memory->memory_data_size; +#else + linear_mem_size = GET_LINEAR_MEMORY_SIZE(memory); +#endif #endif WASMType **wasm_types = module->module->types; WASMGlobalInstance *globals = module->e->globals, *global; @@ -1184,7 +1184,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 @@ -2146,7 +2146,11 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #if !defined(OS_ENABLE_HW_BOUND_CHECK) \ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \ || WASM_ENABLE_BULK_MEMORY != 0 +#if WASM_ENABLE_THREAD_MGR == 0 linear_mem_size = memory->memory_data_size; +#else + linear_mem_size = GET_LINEAR_MEMORY_SIZE(memory); +#endif #endif } @@ -3151,7 +3155,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, addr = (uint32)POP_I32(); #if WASM_ENABLE_THREAD_MGR != 0 - linear_mem_size = memory->memory_data_size; + linear_mem_size = get_linear_mem_size(); #endif #ifndef OS_ENABLE_HW_BOUND_CHECK @@ -3163,9 +3167,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; @@ -3178,7 +3190,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: @@ -3193,7 +3206,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, dst = POP_I32(); #if WASM_ENABLE_THREAD_MGR != 0 - linear_mem_size = memory->memory_data_size; + linear_mem_size = get_linear_mem_size(); #endif #ifndef OS_ENABLE_HW_BOUND_CHECK @@ -3224,7 +3237,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, dst = POP_I32(); #if WASM_ENABLE_THREAD_MGR != 0 - linear_mem_size = memory->memory_data_size; + linear_mem_size = get_linear_mem_size(); #endif #ifndef OS_ENABLE_HW_BOUND_CHECK @@ -3273,8 +3286,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; @@ -3306,8 +3319,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: @@ -3901,7 +3914,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \ || WASM_ENABLE_BULK_MEMORY != 0 if (memory) - linear_mem_size = memory->memory_data_size; + linear_mem_size = get_linear_mem_size(); #endif if (wasm_copy_exception(module, NULL)) goto got_exception; @@ -4006,10 +4019,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, } #if WASM_ENABLE_FAST_JIT != 0 -/* ASAN is not designed to work with custom stack unwind or other low-level \ - things. > Ignore a function that does some low-level magic. (e.g. walking \ - through the thread's stack bypassing the frame boundaries) */ -#if defined(__GNUC__) +/* + * ASAN is not designed to work with custom stack unwind or other low-level + * things. Ignore a function that does some low-level magic. (e.g. walking + * through the thread's stack bypassing the frame boundaries) + */ +#if defined(__GNUC__) || defined(__clang__) __attribute__((no_sanitize_address)) #endif static void diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index 415d8950b..7cb28ca82 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -30,7 +30,7 @@ typedef float64 CellType_F64; * multi-threading mode since it may be changed by other * threads in memory.grow */ -#define get_linear_mem_size() memory->memory_data_size +#define get_linear_mem_size() GET_LINEAR_MEMORY_SIZE(memory) #endif #if !defined(OS_ENABLE_HW_BOUND_CHECK) \ @@ -1034,7 +1034,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 = @@ -1056,15 +1057,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 @@ -1142,12 +1136,27 @@ wasm_interp_dump_op_count() goto *p_label_addr; \ } while (0) #else -#define FETCH_OPCODE_AND_DISPATCH() \ - do { \ - const void *p_label_addr = label_base + *(int16 *)frame_ip; \ - frame_ip += sizeof(int16); \ - goto *p_label_addr; \ +#if UINTPTR_MAX == UINT64_MAX +#define FETCH_OPCODE_AND_DISPATCH() \ + do { \ + const void *p_label_addr; \ + bh_assert(((uintptr_t)frame_ip & 1) == 0); \ + /* int32 relative offset was emitted in 64-bit target */ \ + p_label_addr = label_base + (int32)LOAD_U32_WITH_2U16S(frame_ip); \ + frame_ip += sizeof(int32); \ + goto *p_label_addr; \ } while (0) +#else +#define FETCH_OPCODE_AND_DISPATCH() \ + do { \ + const void *p_label_addr; \ + bh_assert(((uintptr_t)frame_ip & 1) == 0); \ + /* uint32 label address was emitted in 32-bit target */ \ + p_label_addr = (void *)(uintptr_t)LOAD_U32_WITH_2U16S(frame_ip); \ + frame_ip += sizeof(int32); \ + goto *p_label_addr; \ + } while (0) +#endif #endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */ #define HANDLE_OP_END() FETCH_OPCODE_AND_DISPATCH() @@ -1185,7 +1194,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #if !defined(OS_ENABLE_HW_BOUND_CHECK) \ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \ || WASM_ENABLE_BULK_MEMORY != 0 - uint32 linear_mem_size = memory ? memory->memory_data_size : 0; + uint32 linear_mem_size = 0; + if (memory) +#if WASM_ENABLE_THREAD_MGR == 0 + linear_mem_size = memory->memory_data_size; +#else + linear_mem_size = GET_LINEAR_MEMORY_SIZE(memory); +#endif #endif WASMGlobalInstance *globals = module->e ? module->e->globals : NULL; WASMGlobalInstance *global; @@ -1197,7 +1212,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, register uint8 *frame_ip = &opcode_IMPDEP; /* cache of frame->ip */ register uint32 *frame_lp = NULL; /* cache of frame->lp */ #if WASM_ENABLE_LABELS_AS_VALUES != 0 -#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 +#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 && UINTPTR_MAX == UINT64_MAX /* cache of label base addr */ register uint8 *label_base = &&HANDLE_WASM_OP_UNREACHABLE; #endif @@ -1212,7 +1227,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint8 opcode, 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 @@ -1691,7 +1706,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, frame_ip += 2; addr_ret = GET_OFFSET(); CHECK_MEMORY_OVERFLOW(1); - frame_lp[addr_ret] = (uint32)(*(uint8 *)maddr); + frame_lp[addr_ret] = (uint32)(*(uint8 *)(maddr)); HANDLE_OP_END(); } @@ -1816,7 +1831,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, addr = GET_OPERAND(uint32, I32, 2); frame_ip += 4; CHECK_MEMORY_OVERFLOW(1); - *(uint8 *)maddr = (uint8)sval; + STORE_U8(maddr, (uint8_t)sval); HANDLE_OP_END(); } @@ -1916,7 +1931,11 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #if !defined(OS_ENABLE_HW_BOUND_CHECK) \ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \ || WASM_ENABLE_BULK_MEMORY != 0 +#if WASM_ENABLE_THREAD_MGR == 0 linear_mem_size = memory->memory_data_size; +#else + linear_mem_size = GET_LINEAR_MEMORY_SIZE(memory); +#endif #endif } @@ -2994,12 +3013,12 @@ 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 - linear_mem_size = memory->memory_data_size; + linear_mem_size = get_linear_mem_size(); #endif #ifndef OS_ENABLE_HW_BOUND_CHECK @@ -3010,10 +3029,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; @@ -3026,8 +3053,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: @@ -3040,7 +3067,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, dst = POP_I32(); #if WASM_ENABLE_THREAD_MGR - linear_mem_size = memory->memory_data_size; + linear_mem_size = get_linear_mem_size(); #endif #ifndef OS_ENABLE_HW_BOUND_CHECK @@ -3070,7 +3097,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, dst = POP_I32(); #if WASM_ENABLE_THREAD_MGR - linear_mem_size = memory->memory_data_size; + linear_mem_size = get_linear_mem_size(); #endif #ifndef OS_ENABLE_HW_BOUND_CHECK @@ -3119,8 +3146,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; @@ -3149,9 +3176,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: @@ -3846,7 +3872,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \ || WASM_ENABLE_BULK_MEMORY != 0 if (memory) - linear_mem_size = memory->memory_data_size; + linear_mem_size = get_linear_mem_size(); #endif if (wasm_copy_exception(module, NULL)) goto got_exception; diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index cf8b7719c..e5460af7f 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -173,7 +173,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 { \ @@ -302,7 +301,13 @@ check_utf8_str(const uint8 *str, uint32 len) while (p < p_end) { chr = *p; - if (chr < 0x80) { + + if (chr == 0) { + LOG_WARNING( + "LIMITATION: a string which contains '\\00' is unsupported"); + return false; + } + else if (chr < 0x80) { p++; } else if (chr >= 0xC2 && chr <= 0xDF && p + 1 < p_end) { @@ -490,6 +495,7 @@ load_init_expr(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; @@ -1163,23 +1169,31 @@ load_memory_import(const uint8 **p_buf, const uint8 *buf_end, (WASMModuleCommon *)parent_module, sub_module_name, error_buf, error_buf_size); if (!sub_module) { +#if WASM_ENABLE_LIB_WASI_THREADS != 0 + /* Avoid memory import failure when wasi-threads is enabled + and the memory is shared */ + if (!(declare_max_page_count_flag & 2)) + return false; +#else return false; +#endif /* WASM_ENABLE_LIB_WASI_THREADS */ } + else { + linked_memory = wasm_loader_resolve_memory( + sub_module_name, memory_name, declare_init_page_count, + declare_max_page_count, error_buf, error_buf_size); + if (!linked_memory) { + return false; + } - linked_memory = wasm_loader_resolve_memory( - sub_module_name, memory_name, declare_init_page_count, - declare_max_page_count, error_buf, error_buf_size); - if (!linked_memory) { - return false; + /** + * reset with linked memory limit + */ + memory->import_module = sub_module; + memory->import_memory_linked = linked_memory; + declare_init_page_count = linked_memory->init_page_count; + declare_max_page_count = linked_memory->max_page_count; } - - /** - * reset with linked memory limit - */ - memory->import_module = sub_module; - memory->import_memory_linked = linked_memory; - declare_init_page_count = linked_memory->init_page_count; - declare_max_page_count = linked_memory->max_page_count; } #endif @@ -1375,7 +1389,15 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory, return false; } if (memory->flags > 1) { - set_error_buf(error_buf, error_buf_size, "integer too large"); + if (memory->flags & 2) { + set_error_buf(error_buf, error_buf_size, + "shared memory flag was found, " + "please enable shared memory, lib-pthread " + "or lib-wasi-threads"); + } + else { + set_error_buf(error_buf, error_buf_size, "invalid memory flags"); + } return false; } #else @@ -2694,7 +2716,7 @@ load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, read_leb_uint32(p, p_end, name_len); - if (name_len == 0 || p + name_len > p_end) { + if (p + name_len > p_end) { set_error_buf(error_buf, error_buf_size, "unexpected end"); return false; } @@ -2870,6 +2892,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; @@ -3979,19 +4002,23 @@ check_wasi_abi_compatibility(const WASMModule *module, return false; } } - - /* (func (export "_initialize") (...) */ - initialize = wasm_loader_find_export( - module, "", "_initialize", EXPORT_KIND_FUNC, error_buf, error_buf_size); - if (initialize) { - WASMType *func_type = - module->functions[initialize->index - module->import_function_count] - ->func_type; - if (func_type->param_count || func_type->result_count) { - set_error_buf( - error_buf, error_buf_size, - "the signature of builtin _initialize function is wrong"); - return false; + else { + /* (func (export "_initialize") (...) */ + initialize = + wasm_loader_find_export(module, "", "_initialize", EXPORT_KIND_FUNC, + error_buf, error_buf_size); + if (initialize) { + WASMType *func_type = + module + ->functions[initialize->index + - module->import_function_count] + ->func_type; + if (func_type->param_count || func_type->result_count) { + set_error_buf( + error_buf, error_buf_size, + "the signature of builtin _initialize function is wrong"); + return false; + } } } @@ -5389,21 +5416,27 @@ fail: LOG_OP("\ndelete last op\n"); \ } while (0) #else /* else of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */ +#if UINTPTR_MAX == UINT64_MAX #define emit_label(opcode) \ do { \ int32 offset = \ (int32)((uint8 *)handle_table[opcode] - (uint8 *)handle_table[0]); \ - if (!(offset >= INT16_MIN && offset < INT16_MAX)) { \ - set_error_buf(error_buf, error_buf_size, \ - "pre-compiled label offset out of range"); \ - goto fail; \ - } \ - wasm_loader_emit_int16(loader_ctx, offset); \ + /* emit int32 relative offset in 64-bit target */ \ + wasm_loader_emit_uint32(loader_ctx, offset); \ LOG_OP("\nemit_op [%02x]\t", opcode); \ } while (0) +#else +#define emit_label(opcode) \ + do { \ + uint32 label_addr = (uint32)(uintptr_t)handle_table[opcode]; \ + /* emit uint32 label address in 32-bit target */ \ + wasm_loader_emit_uint32(loader_ctx, label_addr); \ + LOG_OP("\nemit_op [%02x]\t", opcode); \ + } while (0) +#endif #define skip_label() \ do { \ - wasm_loader_emit_backspace(loader_ctx, sizeof(int16)); \ + wasm_loader_emit_backspace(loader_ctx, sizeof(int32)); \ LOG_OP("\ndelete last op\n"); \ } while (0) #endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */ @@ -5733,12 +5766,6 @@ preserve_referenced_local(WASMLoaderContext *loader_ctx, uint8 opcode, (void)error_buf; (void)error_buf_size; return true; -#if WASM_ENABLE_LABELS_AS_VALUES != 0 -#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 -fail: - return false; -#endif -#endif } static bool @@ -7018,7 +7045,7 @@ wasm_loader_get_custom_section(WASMModule *module, const char *name, section = section->next; } - return false; + return NULL; } #endif @@ -7130,6 +7157,7 @@ re_scan: BlockType block_type; p_org = p - 1; + CHECK_BUF(p, p_end, 1); value_type = read_uint8(p); if (is_byte_a_type(value_type)) { /* If the first byte is one of these special values: @@ -7183,10 +7211,7 @@ re_scan: } #if WASM_ENABLE_FAST_INTERP != 0 - if (opcode == WASM_OP_BLOCK) { - skip_label(); - } - else if (opcode == WASM_OP_LOOP) { + if (opcode == WASM_OP_BLOCK || opcode == WASM_OP_LOOP) { skip_label(); if (BLOCK_HAS_PARAM(block_type)) { /* Make sure params are in dynamic space */ @@ -7194,8 +7219,10 @@ re_scan: loader_ctx, false, error_buf, error_buf_size)) goto fail; } - (loader_ctx->frame_csp - 1)->code_compiled = - loader_ctx->p_code_compiled; + if (opcode == WASM_OP_LOOP) { + (loader_ctx->frame_csp - 1)->code_compiled = + loader_ctx->p_code_compiled; + } } else if (opcode == WASM_OP_IF) { /* If block has parameters, we should make sure they are in @@ -7435,6 +7462,9 @@ re_scan: if (frame_csp_tmp->label_type != LABEL_TYPE_LOOP) ret_count = block_type_get_result_types( &frame_csp_tmp->block_type, &ret_types); + else + ret_count = block_type_get_param_types( + &frame_csp_tmp->block_type, &ret_types); } else { uint8 *tmp_ret_types = NULL; @@ -7445,6 +7475,9 @@ re_scan: if (frame_csp_tmp->label_type != LABEL_TYPE_LOOP) tmp_ret_count = block_type_get_result_types( &frame_csp_tmp->block_type, &tmp_ret_types); + else + tmp_ret_count = block_type_get_param_types( + &frame_csp_tmp->block_type, &tmp_ret_types); if (ret_count != tmp_ret_count || (ret_count @@ -7737,7 +7770,8 @@ re_scan: } if (available_stack_cell > 0) { - if (is_32bit_type(*(loader_ctx->frame_ref - 1))) { + if (is_32bit_type(*(loader_ctx->frame_ref - 1)) + || *(loader_ctx->frame_ref - 1) == VALUE_TYPE_ANY) { loader_ctx->frame_ref--; loader_ctx->stack_cell_num--; #if WASM_ENABLE_FAST_INTERP != 0 @@ -7793,6 +7827,9 @@ re_scan: uint8 ref_type; BranchBlock *cur_block = loader_ctx->frame_csp - 1; int32 available_stack_cell; +#if WASM_ENABLE_FAST_INTERP != 0 + uint8 *p_code_compiled_tmp = loader_ctx->p_code_compiled; +#endif POP_I32(); @@ -7821,26 +7858,26 @@ re_scan: #if WASM_ENABLE_FAST_INTERP != 0 if (loader_ctx->p_code_compiled) { uint8 opcode_tmp = WASM_OP_SELECT_64; - uint8 *p_code_compiled_tmp = - loader_ctx->p_code_compiled - 2; #if WASM_ENABLE_LABELS_AS_VALUES != 0 #if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 *(void **)(p_code_compiled_tmp - sizeof(void *)) = handle_table[opcode_tmp]; #else +#if UINTPTR_MAX == UINT64_MAX + /* emit int32 relative offset in 64-bit target + */ int32 offset = (int32)((uint8 *)handle_table[opcode_tmp] - (uint8 *)handle_table[0]); - if (!(offset >= INT16_MIN - && offset < INT16_MAX)) { - set_error_buf(error_buf, error_buf_size, - "pre-compiled label offset " - "out of range"); - goto fail; - } - *(int16 *)(p_code_compiled_tmp - - sizeof(int16)) = (int16)offset; + *(int32 *)(p_code_compiled_tmp + - sizeof(int32)) = offset; +#else + /* emit uint32 label address in 32-bit target */ + *(uint32 *)(p_code_compiled_tmp + - sizeof(uint32)) = + (uint32)(uintptr_t)handle_table[opcode_tmp]; +#endif #endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */ #else /* else of WASM_ENABLE_LABELS_AS_VALUES */ #if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 @@ -7934,16 +7971,17 @@ re_scan: *(void **)(p_code_compiled_tmp - sizeof(void *)) = handle_table[opcode_tmp]; #else +#if UINTPTR_MAX == UINT64_MAX + /* emit int32 relative offset in 64-bit target */ int32 offset = (int32)((uint8 *)handle_table[opcode_tmp] - (uint8 *)handle_table[0]); - if (!(offset >= INT16_MIN && offset < INT16_MAX)) { - set_error_buf( - error_buf, error_buf_size, - "pre-compiled label offset out of range"); - goto fail; - } - *(int16 *)(p_code_compiled_tmp - sizeof(int16)) = - (int16)offset; + *(int32 *)(p_code_compiled_tmp - sizeof(int32)) = + offset; +#else + /* emit uint32 label address in 32-bit target */ + *(uint32 *)(p_code_compiled_tmp - sizeof(uint32)) = + (uint32)(uintptr_t)handle_table[opcode_tmp]; +#endif #endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */ #else /* else of WASM_ENABLE_LABELS_AS_VALUES */ #if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 @@ -9087,6 +9125,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 */ @@ -9748,6 +9787,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); diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index d16bc1a24..47ec549ee 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -1877,6 +1877,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; @@ -4009,21 +4010,27 @@ wasm_loader_pop_frame_csp(WASMLoaderContext *ctx, char *error_buf, LOG_OP("\ndelete last op\n"); \ } while (0) #else /* else of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */ +#if UINTPTR_MAX == UINT64_MAX #define emit_label(opcode) \ do { \ int32 offset = \ (int32)((uint8 *)handle_table[opcode] - (uint8 *)handle_table[0]); \ - if (!(offset >= INT16_MIN && offset < INT16_MAX)) { \ - set_error_buf(error_buf, error_buf_size, \ - "pre-compiled label offset out of range"); \ - goto fail; \ - } \ - wasm_loader_emit_int16(loader_ctx, offset); \ + /* emit int32 relative offset in 64-bit target */ \ + wasm_loader_emit_uint32(loader_ctx, offset); \ LOG_OP("\nemit_op [%02x]\t", opcode); \ } while (0) +#else +#define emit_label(opcode) \ + do { \ + uint32 label_addr = (uint32)(uintptr_t)handle_table[opcode]; \ + /* emit uint32 label address in 32-bit target */ \ + wasm_loader_emit_uint32(loader_ctx, label_addr); \ + LOG_OP("\nemit_op [%02x]\t", opcode); \ + } while (0) +#endif #define skip_label() \ do { \ - wasm_loader_emit_backspace(loader_ctx, sizeof(int16)); \ + wasm_loader_emit_backspace(loader_ctx, sizeof(int32)); \ LOG_OP("\ndelete last op\n"); \ } while (0) #endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */ @@ -4351,13 +4358,6 @@ preserve_referenced_local(WASMLoaderContext *loader_ctx, uint8 opcode, } return true; - -#if WASM_ENABLE_LABELS_AS_VALUES != 0 -#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 -fail: - return false; -#endif -#endif } static bool @@ -5627,10 +5627,7 @@ re_scan: } #if WASM_ENABLE_FAST_INTERP != 0 - if (opcode == WASM_OP_BLOCK) { - skip_label(); - } - else if (opcode == WASM_OP_LOOP) { + if (opcode == WASM_OP_BLOCK || opcode == WASM_OP_LOOP) { skip_label(); if (BLOCK_HAS_PARAM(block_type)) { /* Make sure params are in dynamic space */ @@ -5638,8 +5635,10 @@ re_scan: loader_ctx, false, error_buf, error_buf_size)) goto fail; } - (loader_ctx->frame_csp - 1)->code_compiled = - loader_ctx->p_code_compiled; + if (opcode == WASM_OP_LOOP) { + (loader_ctx->frame_csp - 1)->code_compiled = + loader_ctx->p_code_compiled; + } } else if (opcode == WASM_OP_IF) { /* If block has parameters, we should make sure they are in @@ -6100,7 +6099,8 @@ re_scan: && !cur_block->is_stack_polymorphic)); if (available_stack_cell > 0) { - if (is_32bit_type(*(loader_ctx->frame_ref - 1))) { + if (is_32bit_type(*(loader_ctx->frame_ref - 1)) + || *(loader_ctx->frame_ref - 1) == VALUE_TYPE_ANY) { loader_ctx->frame_ref--; loader_ctx->stack_cell_num--; #if WASM_ENABLE_FAST_INTERP != 0 @@ -6146,6 +6146,9 @@ re_scan: uint8 ref_type; BranchBlock *cur_block = loader_ctx->frame_csp - 1; int32 available_stack_cell; +#if WASM_ENABLE_FAST_INTERP != 0 + uint8 *p_code_compiled_tmp = loader_ctx->p_code_compiled; +#endif POP_I32(); @@ -6168,26 +6171,26 @@ re_scan: #if WASM_ENABLE_FAST_INTERP != 0 if (loader_ctx->p_code_compiled) { uint8 opcode_tmp = WASM_OP_SELECT_64; - uint8 *p_code_compiled_tmp = - loader_ctx->p_code_compiled - 2; #if WASM_ENABLE_LABELS_AS_VALUES != 0 #if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 *(void **)(p_code_compiled_tmp - sizeof(void *)) = handle_table[opcode_tmp]; #else +#if UINTPTR_MAX == UINT64_MAX + /* emit int32 relative offset in 64-bit target + */ int32 offset = (int32)((uint8 *)handle_table[opcode_tmp] - (uint8 *)handle_table[0]); - if (!(offset >= INT16_MIN - && offset < INT16_MAX)) { - set_error_buf(error_buf, error_buf_size, - "pre-compiled label offset " - "out of range"); - goto fail; - } - *(int16 *)(p_code_compiled_tmp - - sizeof(int16)) = (int16)offset; + *(int32 *)(p_code_compiled_tmp + - sizeof(int32)) = offset; +#else + /* emit uint32 label address in 32-bit target */ + *(uint32 *)(p_code_compiled_tmp + - sizeof(uint32)) = + (uint32)(uintptr_t)handle_table[opcode_tmp]; +#endif #endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */ #else /* else of WASM_ENABLE_LABELS_AS_VALUES */ #if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 @@ -6263,15 +6266,16 @@ re_scan: *(void **)(p_code_compiled_tmp - sizeof(void *)) = handle_table[opcode_tmp]; #else +#if UINTPTR_MAX == UINT64_MAX + /* emit int32 relative offset in 64-bit target */ int32 offset = (int32)((uint8 *)handle_table[opcode_tmp] - (uint8 *)handle_table[0]); - if (!(offset >= INT16_MIN && offset < INT16_MAX)) { - set_error_buf(error_buf, error_buf_size, - "pre-compiled label offset out of range"); - goto fail; - } - *(int16 *)(p_code_compiled_tmp - sizeof(int16)) = - (int16)offset; + *(int32 *)(p_code_compiled_tmp - sizeof(int32)) = offset; +#else + /* emit uint32 label address in 32-bit target */ + *(uint32 *)(p_code_compiled_tmp - sizeof(uint32)) = + (uint32)(uintptr_t)handle_table[opcode_tmp]; +#endif #endif /* end of WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS */ #else /* else of WASM_ENABLE_LABELS_AS_VALUES */ #if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 8fb19d52e..205c6d4b6 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -10,6 +10,7 @@ #include "bh_log.h" #include "mem_alloc.h" #include "../common/wasm_runtime_common.h" +#include "../common/wasm_memory.h" #if WASM_ENABLE_SHARED_MEMORY != 0 #include "../common/wasm_shared_memory.h" #endif @@ -167,7 +168,7 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent, char *error_buf, uint32 error_buf_size) { WASMModule *module = module_inst->module; - uint64 memory_data_size; + uint64 memory_data_size, max_memory_data_size; uint32 heap_offset = num_bytes_per_page * init_page_count; uint32 inc_page_count, aux_heap_base, global_idx; uint32 bytes_of_last_page, bytes_to_page_end; @@ -275,6 +276,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", @@ -282,22 +289,33 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent, LOG_VERBOSE(" heap offset: %u, heap size: %d\n", heap_offset, heap_size); memory_data_size = (uint64)num_bytes_per_page * init_page_count; -#if WASM_ENABLE_SHARED_MEMORY != 0 - if (is_shared_memory) { - /* Allocate max page for shared memory */ - memory_data_size = (uint64)num_bytes_per_page * max_page_count; - } -#endif - bh_assert(memory_data_size <= 4 * (uint64)BH_GB); + max_memory_data_size = (uint64)num_bytes_per_page * max_page_count; + bh_assert(memory_data_size <= UINT32_MAX); + bh_assert(max_memory_data_size <= 4 * (uint64)BH_GB); + (void)max_memory_data_size; bh_assert(memory != NULL); #ifndef OS_ENABLE_HW_BOUND_CHECK - if (memory_data_size > 0 - && !(memory->memory_data = - runtime_malloc(memory_data_size, error_buf, error_buf_size))) { - goto fail1; +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (is_shared_memory) { + /* Allocate maximum memory size when memory is shared */ + if (max_memory_data_size > 0 + && !(memory->memory_data = runtime_malloc( + max_memory_data_size, error_buf, error_buf_size))) { + goto fail1; + } } -#else + else +#endif + { + /* Allocate initial memory size when memory is not shared */ + if (memory_data_size > 0 + && !(memory->memory_data = runtime_malloc( + memory_data_size, error_buf, error_buf_size))) { + goto fail1; + } + } +#else /* else of OS_ENABLE_HW_BOUND_CHECK */ memory_data_size = (memory_data_size + page_size - 1) & ~(page_size - 1); /* Totally 8G is mapped, the opcode load/store address range is 0 to 8G: @@ -306,14 +324,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; @@ -326,12 +346,13 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent, set_error_buf(error_buf, error_buf_size, "mprotect memory failed"); goto fail2; } + /* Newly allocated pages are filled with zero by the OS, we don't fill it * again here */ -#endif /* end of OS_ENABLE_HW_BOUND_CHECK */ if (memory_data_size > UINT32_MAX) - memory_data_size = (uint32)memory_data_size; + memory_data_size = UINT32_MAX; +#endif /* end of OS_ENABLE_HW_BOUND_CHECK */ memory->module_type = Wasm_Module_Bytecode; memory->num_bytes_per_page = num_bytes_per_page; @@ -359,26 +380,13 @@ memory_instantiate(WASMModuleInstance *module_inst, WASMModuleInstance *parent, } } -#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 if (memory_data_size > 0) { -#if UINTPTR_MAX == UINT64_MAX - memory->mem_bound_check_1byte.u64 = memory_data_size - 1; - memory->mem_bound_check_2bytes.u64 = memory_data_size - 2; - memory->mem_bound_check_4bytes.u64 = memory_data_size - 4; - memory->mem_bound_check_8bytes.u64 = memory_data_size - 8; - memory->mem_bound_check_16bytes.u64 = memory_data_size - 16; -#else - memory->mem_bound_check_1byte.u32[0] = (uint32)memory_data_size - 1; - memory->mem_bound_check_2bytes.u32[0] = (uint32)memory_data_size - 2; - memory->mem_bound_check_4bytes.u32[0] = (uint32)memory_data_size - 4; - memory->mem_bound_check_8bytes.u32[0] = (uint32)memory_data_size - 8; - memory->mem_bound_check_16bytes.u32[0] = (uint32)memory_data_size - 16; -#endif + wasm_runtime_set_mem_bound_check_bytes(memory, memory_data_size); } -#endif #if WASM_ENABLE_SHARED_MEMORY != 0 if (is_shared_memory) { + memory->is_shared_memory = 1; memory->ref_count = 1; } #endif @@ -1054,7 +1062,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 */ @@ -1079,7 +1088,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); } } @@ -1112,12 +1122,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); } @@ -1186,7 +1196,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); } } @@ -1197,7 +1208,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); @@ -1253,7 +1264,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); } } @@ -1261,7 +1273,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); @@ -1654,6 +1666,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_DUMP_CALL_STACK != 0 if (!(module_inst->frames = runtime_malloc((uint64)sizeof(Vector), error_buf, error_buf_size))) { @@ -1779,6 +1816,10 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent, if (data_seg->is_passive) continue; #endif + if (is_sub_inst) + /* Ignore setting memory init data if the memory has been + initialized */ + continue; /* has check it in loader */ memory = module_inst->memories[data_seg->memory_index]; @@ -2173,6 +2214,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); } @@ -2371,14 +2419,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); } @@ -2472,15 +2522,20 @@ void wasm_module_free_internal(WASMModuleInstance *module_inst, WASMExecEnv *exec_env, uint32 ptr) { + WASMMemoryInstance *memory = wasm_get_default_memory(module_inst); + + if (!memory) { + return; + } + if (ptr) { - WASMMemoryInstance *memory = wasm_get_default_memory(module_inst); - uint8 *addr; + uint8 *addr = memory->memory_data + ptr; + uint8 *memory_data_end; - if (!memory) { - return; - } - - addr = memory->memory_data + ptr; + /* memory->memory_data_end may be changed in memory grow */ + SHARED_MEMORY_LOCK(memory); + memory_data_end = memory->memory_data_end; + SHARED_MEMORY_UNLOCK(memory); if (memory->heap_handle && memory->heap_data <= addr && addr < memory->heap_data_end) { @@ -2488,7 +2543,7 @@ wasm_module_free_internal(WASMModuleInstance *module_inst, } else if (module_inst->e->malloc_function && module_inst->e->free_function && memory->memory_data <= addr - && addr < memory->memory_data_end) { + && addr < memory_data_end) { execute_free_function(module_inst, exec_env, module_inst->e->free_function, ptr); } @@ -3127,16 +3182,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)) @@ -3150,7 +3212,9 @@ llvm_jit_memory_init(WASMModuleInstance *module_inst, uint32 seg_index, maddr = wasm_runtime_addr_app_to_native( (WASMModuleInstanceCommon *)module_inst, dst); + SHARED_MEMORY_LOCK(memory_inst); bh_memcpy_s(maddr, memory_inst->memory_data_size - dst, data + offset, len); + SHARED_MEMORY_UNLOCK(memory_inst); return true; } @@ -3159,7 +3223,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; @@ -3170,12 +3234,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 @@ -3204,7 +3264,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; } diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index d6661fa0f..bb5fdc80b 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/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" @@ -79,8 +80,16 @@ typedef union { struct WASMMemoryInstance { /* Module type */ uint32 module_type; - /* Shared memory flag */ - bh_atomic_32_t ref_count; /* 0: non-shared, > 0: reference count */ + + /* Whether the memory is shared */ + uint8 is_shared_memory; + + /* 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; @@ -216,10 +225,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 } WASMModuleInstanceExtraCommon; /* Extra info of WASM module instance for interpreter/jit mode */ diff --git a/core/iwasm/libraries/lib-rats/lib_rats_wrapper.c b/core/iwasm/libraries/lib-rats/lib_rats_wrapper.c index 59d61f4c8..bdacc259c 100644 --- a/core/iwasm/libraries/lib-rats/lib_rats_wrapper.c +++ b/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 diff --git a/core/iwasm/libraries/lib-rats/lib_rats_wrapper.h b/core/iwasm/libraries/lib-rats/lib_rats_wrapper.h index e334983e9..928645108 100644 --- a/core/iwasm/libraries/lib-rats/lib_rats_wrapper.h +++ b/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 diff --git a/core/iwasm/libraries/lib-socket/test/manifest.json b/core/iwasm/libraries/lib-socket/test/manifest.json new file mode 100644 index 000000000..b0afd1d6b --- /dev/null +++ b/core/iwasm/libraries/lib-socket/test/manifest.json @@ -0,0 +1,3 @@ +{ + "name": "WAMR lib-socket tests" +} \ No newline at end of file diff --git a/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c b/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c index 504ff7f93..6ead65406 100644 --- a/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c +++ b/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 diff --git a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c index 292bd8379..9f35b81a7 100644 --- a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c +++ b/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 diff --git a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.h b/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.h index be509576b..d958fa39c 100644 --- a/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.h +++ b/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; diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h index efe7c8e3a..ed8463866 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h @@ -3,10 +3,6 @@ * LLVM Exceptions. See * https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE * for license information. - * - * This file declares an interface similar to WASI, but augmented to expose - * some implementation details such as the curfds arguments that we pass - * around to avoid storing them in TLS. */ /** @@ -22,1338 +18,584 @@ #include #include +#include "bh_platform.h" #include "wasm_export.h" -/* clang-format off */ - #ifdef __cplusplus -#ifndef _Static_assert -#define _Static_assert static_assert -#endif /* _Static_assert */ - -#ifndef _Alignof -#define _Alignof alignof -#endif /* _Alignof */ - -#ifndef _Noreturn -#define _Noreturn [[ noreturn ]] -#endif /* _Noreturn */ extern "C" { #endif -_Static_assert(_Alignof(int8_t) == 1, "non-wasi data layout"); -_Static_assert(_Alignof(uint8_t) == 1, "non-wasi data layout"); -_Static_assert(_Alignof(int16_t) == 2, "non-wasi data layout"); -_Static_assert(_Alignof(uint16_t) == 2, "non-wasi data layout"); -_Static_assert(_Alignof(int32_t) == 4, "non-wasi data layout"); -_Static_assert(_Alignof(uint32_t) == 4, "non-wasi data layout"); -#if 0 -_Static_assert(_Alignof(int64_t) == 8, "non-wasi data layout"); -_Static_assert(_Alignof(uint64_t) == 8, "non-wasi data layout"); -#endif - -typedef uint32_t __wasi_size_t; -_Static_assert(_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) - -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; - -typedef uint64_t __wasi_linkcount_t __attribute__((aligned(8))); - -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 __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 __attribute__((aligned(8))); -_Static_assert(offsetof(__wasi_dirent_t, d_next) == 0, "non-wasi data layout"); -_Static_assert(offsetof(__wasi_dirent_t, d_ino) == 8, "non-wasi data layout"); -_Static_assert(offsetof(__wasi_dirent_t, d_namlen) == 16, "non-wasi data layout"); -_Static_assert(offsetof(__wasi_dirent_t, d_type) == 20, "non-wasi data layout"); -_Static_assert(sizeof(__wasi_dirent_t) == 24, "non-wasi data layout"); -_Static_assert(_Alignof(__wasi_dirent_t) == 8, "non-wasi data layout"); - -typedef struct __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 __attribute__((aligned(8))); -_Static_assert(offsetof(__wasi_event_t, userdata) == 0, "non-wasi data layout"); -_Static_assert(offsetof(__wasi_event_t, error) == 8, "non-wasi data layout"); -_Static_assert(offsetof(__wasi_event_t, type) == 10, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_event_t, u.fd_readwrite.nbytes) == 16, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_event_t, u.fd_readwrite.flags) == 24, "non-wasi data layout"); -_Static_assert(sizeof(__wasi_event_t) == 32, "non-wasi data layout"); -_Static_assert(_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; -_Static_assert(offsetof(__wasi_prestat_t, pr_type) == 0, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 4 || - offsetof(__wasi_prestat_t, u.dir.pr_name_len) == 4, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 8 || - offsetof(__wasi_prestat_t, u.dir.pr_name_len) == 8, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 4 || - sizeof(__wasi_prestat_t) == 8, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 8 || - sizeof(__wasi_prestat_t) == 16, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 4 || - _Alignof(__wasi_prestat_t) == 4, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 8 || - _Alignof(__wasi_prestat_t) == 8, "non-wasi data layout"); - -typedef struct __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 __attribute__((aligned(8))); -_Static_assert( - offsetof(__wasi_fdstat_t, fs_filetype) == 0, "non-wasi data layout"); -_Static_assert(offsetof(__wasi_fdstat_t, fs_flags) == 2, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_fdstat_t, fs_rights_base) == 8, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_fdstat_t, fs_rights_inheriting) == 16, - "non-wasi data layout"); -_Static_assert(sizeof(__wasi_fdstat_t) == 24, "non-wasi data layout"); -_Static_assert(_Alignof(__wasi_fdstat_t) == 8, "non-wasi data layout"); - -typedef struct __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 __attribute__((aligned(8))); -_Static_assert(offsetof(__wasi_filestat_t, st_dev) == 0, "non-wasi data layout"); -_Static_assert(offsetof(__wasi_filestat_t, st_ino) == 8, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_filestat_t, st_filetype) == 16, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_filestat_t, st_nlink) == 24, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_filestat_t, st_size) == 32, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_filestat_t, st_atim) == 40, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_filestat_t, st_mtim) == 48, "non-wasi data layout"); -_Static_assert( - offsetof(__wasi_filestat_t, st_ctim) == 56, "non-wasi data layout"); -_Static_assert(sizeof(__wasi_filestat_t) == 64, "non-wasi data layout"); -_Static_assert(_Alignof(__wasi_filestat_t) == 8, "non-wasi data layout"); - -typedef struct __wasi_ciovec_t { - const void *buf; - size_t buf_len; -} __wasi_ciovec_t; -_Static_assert(offsetof(__wasi_ciovec_t, buf) == 0, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 4 || - offsetof(__wasi_ciovec_t, buf_len) == 4, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 8 || - offsetof(__wasi_ciovec_t, buf_len) == 8, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 4 || - sizeof(__wasi_ciovec_t) == 8, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 8 || - sizeof(__wasi_ciovec_t) == 16, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 4 || - _Alignof(__wasi_ciovec_t) == 4, "non-wasi data layout"); -_Static_assert(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; -_Static_assert(offsetof(__wasi_iovec_t, buf) == 0, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 4 || - offsetof(__wasi_iovec_t, buf_len) == 4, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 8 || - offsetof(__wasi_iovec_t, buf_len) == 8, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 4 || - sizeof(__wasi_iovec_t) == 8, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 8 || - sizeof(__wasi_iovec_t) == 16, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 4 || - _Alignof(__wasi_iovec_t) == 4, "non-wasi data layout"); -_Static_assert(sizeof(void *) != 8 || - _Alignof(__wasi_iovec_t) == 8, "non-wasi data layout"); - -/** - * The contents of a `subscription` when type is `eventtype::clock`. - */ -typedef struct __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 __attribute__((aligned(8))); - -_Static_assert(sizeof(__wasi_subscription_clock_t) == 32, "witx calculated size"); -_Static_assert(_Alignof(__wasi_subscription_clock_t) == 8, "witx calculated align"); -_Static_assert(offsetof(__wasi_subscription_clock_t, clock_id) == 0, "witx calculated offset"); -_Static_assert(offsetof(__wasi_subscription_clock_t, timeout) == 8, "witx calculated offset"); -_Static_assert(offsetof(__wasi_subscription_clock_t, precision) == 16, "witx calculated offset"); -_Static_assert(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; - -_Static_assert(sizeof(__wasi_subscription_fd_readwrite_t) == 4, "witx calculated size"); -_Static_assert(_Alignof(__wasi_subscription_fd_readwrite_t) == 4, "witx calculated align"); -_Static_assert(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 __wasi_subscription_u_t { - __wasi_eventtype_t type; - __wasi_subscription_u_u_t u; -} __wasi_subscription_u_t __attribute__((aligned(8))); - -_Static_assert(sizeof(__wasi_subscription_u_t) == 40, "witx calculated size"); -_Static_assert(_Alignof(__wasi_subscription_u_t) == 8, "witx calculated align"); -_Static_assert(offsetof(__wasi_subscription_u_t, u) == 8, "witx calculated union offset"); -_Static_assert(sizeof(__wasi_subscription_u_u_t) == 32, "witx calculated union size"); -_Static_assert(_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; - -_Static_assert(sizeof(__wasi_subscription_t) == 48, "witx calculated size"); -_Static_assert(_Alignof(__wasi_subscription_t) == 8, "witx calculated align"); -_Static_assert(offsetof(__wasi_subscription_t, userdata) == 0, "witx calculated offset"); -_Static_assert(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; - #if defined(WASMTIME_SSP_WASI_API) -#define WASMTIME_SSP_SYSCALL_NAME(name) \ - asm("__wasi_" #name) +#define WASMTIME_SSP_SYSCALL_NAME(name) asm("__wasi_" #name) #else #define WASMTIME_SSP_SYSCALL_NAME(name) #endif -__wasi_errno_t wasmtime_ssp_args_get( - struct argv_environ_values *arg_environ, - char **argv, - char *argv_buf -) WASMTIME_SSP_SYSCALL_NAME(args_get) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_args_sizes_get( - struct argv_environ_values *arg_environ, - size_t *argc, - size_t *argv_buf_size -) WASMTIME_SSP_SYSCALL_NAME(args_sizes_get) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_clock_res_get( - __wasi_clockid_t clock_id, - __wasi_timestamp_t *resolution -) WASMTIME_SSP_SYSCALL_NAME(clock_res_get) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_clock_time_get( - __wasi_clockid_t clock_id, - __wasi_timestamp_t precision, - __wasi_timestamp_t *time -) WASMTIME_SSP_SYSCALL_NAME(clock_time_get) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_environ_get( - struct argv_environ_values *arg_environ, - char **environ, - char *environ_buf -) WASMTIME_SSP_SYSCALL_NAME(environ_get) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_environ_sizes_get( - struct argv_environ_values *arg_environ, - size_t *environ_count, - size_t *environ_buf_size -) WASMTIME_SSP_SYSCALL_NAME(environ_sizes_get) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_prestat_get( - struct fd_prestats *prestats, - __wasi_fd_t fd, - __wasi_prestat_t *buf -) WASMTIME_SSP_SYSCALL_NAME(fd_prestat_get) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_prestat_dir_name( - struct fd_prestats *prestats, - __wasi_fd_t fd, - char *path, - size_t path_len -) WASMTIME_SSP_SYSCALL_NAME(fd_prestat_dir_name) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_close( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - struct fd_prestats *prestats, - __wasi_fd_t fd -) WASMTIME_SSP_SYSCALL_NAME(fd_close) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_datasync( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd -) WASMTIME_SSP_SYSCALL_NAME(fd_datasync) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_pread( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - const __wasi_iovec_t *iovs, - size_t iovs_len, - __wasi_filesize_t offset, - size_t *nread -) WASMTIME_SSP_SYSCALL_NAME(fd_pread) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_pwrite( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - const __wasi_ciovec_t *iovs, - size_t iovs_len, - __wasi_filesize_t offset, - size_t *nwritten -) WASMTIME_SSP_SYSCALL_NAME(fd_pwrite) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_read( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - const __wasi_iovec_t *iovs, - size_t iovs_len, - size_t *nread -) WASMTIME_SSP_SYSCALL_NAME(fd_read) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_renumber( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - struct fd_prestats *prestats, - __wasi_fd_t from, - __wasi_fd_t to -) WASMTIME_SSP_SYSCALL_NAME(fd_renumber) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_seek( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - __wasi_filedelta_t offset, - __wasi_whence_t whence, - __wasi_filesize_t *newoffset -) WASMTIME_SSP_SYSCALL_NAME(fd_seek) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_tell( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - __wasi_filesize_t *newoffset -) WASMTIME_SSP_SYSCALL_NAME(fd_tell) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_fdstat_get( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - __wasi_fdstat_t *buf -) WASMTIME_SSP_SYSCALL_NAME(fd_fdstat_get) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_fdstat_set_flags( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - __wasi_fdflags_t flags -) WASMTIME_SSP_SYSCALL_NAME(fd_fdstat_set_flags) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_fdstat_set_rights( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - __wasi_rights_t fs_rights_base, - __wasi_rights_t fs_rights_inheriting -) WASMTIME_SSP_SYSCALL_NAME(fd_fdstat_set_rights) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_sync( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd -) WASMTIME_SSP_SYSCALL_NAME(fd_sync) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_write( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - const __wasi_ciovec_t *iovs, - size_t iovs_len, - size_t *nwritten -) WASMTIME_SSP_SYSCALL_NAME(fd_write) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_advise( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - __wasi_filesize_t offset, - __wasi_filesize_t len, - __wasi_advice_t advice -) WASMTIME_SSP_SYSCALL_NAME(fd_advise) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_allocate( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - __wasi_filesize_t offset, - __wasi_filesize_t len -) WASMTIME_SSP_SYSCALL_NAME(fd_allocate) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_path_create_directory( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - const char *path, - size_t path_len -) WASMTIME_SSP_SYSCALL_NAME(path_create_directory) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_path_link( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - struct fd_prestats *prestats, - __wasi_fd_t old_fd, - __wasi_lookupflags_t old_flags, - const char *old_path, - size_t old_path_len, - __wasi_fd_t new_fd, - const char *new_path, - size_t new_path_len -) WASMTIME_SSP_SYSCALL_NAME(path_link) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_path_open( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t dirfd, - __wasi_lookupflags_t dirflags, - const char *path, - size_t path_len, - __wasi_oflags_t oflags, - __wasi_rights_t fs_rights_base, - __wasi_rights_t fs_rights_inheriting, - __wasi_fdflags_t fs_flags, - __wasi_fd_t *fd -) WASMTIME_SSP_SYSCALL_NAME(path_open) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_readdir( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - void *buf, - size_t buf_len, - __wasi_dircookie_t cookie, - size_t *bufused -) WASMTIME_SSP_SYSCALL_NAME(fd_readdir) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_path_readlink( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - const char *path, - size_t path_len, - char *buf, - size_t buf_len, - size_t *bufused -) WASMTIME_SSP_SYSCALL_NAME(path_readlink) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_path_rename( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t old_fd, - const char *old_path, - size_t old_path_len, - __wasi_fd_t new_fd, - const char *new_path, - size_t new_path_len -) WASMTIME_SSP_SYSCALL_NAME(path_rename) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_filestat_get( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - __wasi_filestat_t *buf -) WASMTIME_SSP_SYSCALL_NAME(fd_filestat_get) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_filestat_set_times( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - __wasi_timestamp_t st_atim, - __wasi_timestamp_t st_mtim, - __wasi_fstflags_t fstflags -) WASMTIME_SSP_SYSCALL_NAME(fd_filestat_set_times) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_fd_filestat_set_size( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - __wasi_filesize_t st_size -) WASMTIME_SSP_SYSCALL_NAME(fd_filestat_set_size) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_path_filestat_get( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - __wasi_lookupflags_t flags, - const char *path, - size_t path_len, - __wasi_filestat_t *buf -) WASMTIME_SSP_SYSCALL_NAME(path_filestat_get) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_path_filestat_set_times( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - __wasi_lookupflags_t flags, - const char *path, - size_t path_len, - __wasi_timestamp_t st_atim, - __wasi_timestamp_t st_mtim, - __wasi_fstflags_t fstflags -) WASMTIME_SSP_SYSCALL_NAME(path_filestat_set_times) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_path_symlink( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - struct fd_prestats *prestats, - const char *old_path, - size_t old_path_len, - __wasi_fd_t fd, - const char *new_path, - size_t new_path_len -) WASMTIME_SSP_SYSCALL_NAME(path_symlink) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_path_unlink_file( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - const char *path, - size_t path_len -) WASMTIME_SSP_SYSCALL_NAME(path_unlink_file) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_path_remove_directory( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, - const char *path, - size_t path_len -) WASMTIME_SSP_SYSCALL_NAME(path_remove_directory) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_poll_oneoff( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - const __wasi_subscription_t *in, - __wasi_event_t *out, - size_t nsubscriptions, - size_t *nevents -) WASMTIME_SSP_SYSCALL_NAME(poll_oneoff) __attribute__((__warn_unused_result__)); - -__wasi_errno_t wasmtime_ssp_random_get( - void *buf, - size_t buf_len -) WASMTIME_SSP_SYSCALL_NAME(random_get) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_args_get(struct argv_environ_values *arg_environ, char **argv, + char *argv_buf) + WASMTIME_SSP_SYSCALL_NAME(args_get) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_accept( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, __wasi_fdflags_t flags, __wasi_fd_t *fd_new -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_args_sizes_get(struct argv_environ_values *arg_environ, + size_t *argc, size_t *argv_buf_size) + WASMTIME_SSP_SYSCALL_NAME(args_sizes_get) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_addr_local( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, __wasi_addr_t *addr -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_environ_get(struct argv_environ_values *arg_environ, + char **environs, char *environ_buf) + WASMTIME_SSP_SYSCALL_NAME(environ_get) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_addr_remote( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, __wasi_addr_t *addr -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_environ_sizes_get(struct argv_environ_values *arg_environ, + size_t *environ_count, size_t *environ_buf_size) + WASMTIME_SSP_SYSCALL_NAME(environ_sizes_get) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_open( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t poolfd, __wasi_address_family_t af, __wasi_sock_type_t socktype, - __wasi_fd_t *sockfd -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_fd_prestat_get(struct fd_prestats *prestats, __wasi_fd_t fd, + __wasi_prestat_t *buf) + WASMTIME_SSP_SYSCALL_NAME(fd_prestat_get) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_bind( - wasm_exec_env_t exec_env, - struct fd_table *curfds, struct addr_pool *addr_pool, - __wasi_fd_t fd, __wasi_addr_t *addr -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_fd_prestat_dir_name(struct fd_prestats *prestats, __wasi_fd_t fd, + char *path, size_t path_len) + WASMTIME_SSP_SYSCALL_NAME(fd_prestat_dir_name) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_addr_resolve( - wasm_exec_env_t exec_env, - struct fd_table *curfds, char **ns_lookup_list, - const char *host, const char* service, - __wasi_addr_info_hints_t *hints, __wasi_addr_info_t *addr_info, - __wasi_size_t addr_info_size, __wasi_size_t *max_info_size -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_fd_close(wasm_exec_env_t exec_env, struct fd_table *curfds, + struct fd_prestats *prestats, __wasi_fd_t fd) + WASMTIME_SSP_SYSCALL_NAME(fd_close) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_connect( - wasm_exec_env_t exec_env, - struct fd_table *curfds, struct addr_pool *addr_pool, - __wasi_fd_t fd, __wasi_addr_t *addr -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_fd_datasync(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd) + WASMTIME_SSP_SYSCALL_NAME(fd_datasync) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_get_recv_buf_size( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, __wasi_size_t *size -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_fd_pread(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, const __wasi_iovec_t *iovs, + size_t iovs_len, __wasi_filesize_t offset, size_t *nread) + WASMTIME_SSP_SYSCALL_NAME(fd_pread) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_get_reuse_addr( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, uint8_t *reuse -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_fd_pwrite(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, const __wasi_ciovec_t *iovs, + size_t iovs_len, __wasi_filesize_t offset, + size_t *nwritten) + WASMTIME_SSP_SYSCALL_NAME(fd_pwrite) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_get_reuse_port( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, uint8_t *reuse -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_fd_read(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, const __wasi_iovec_t *iovs, + size_t iovs_len, size_t *nread) + WASMTIME_SSP_SYSCALL_NAME(fd_read) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_get_send_buf_size( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, __wasi_size_t *size -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_fd_renumber(wasm_exec_env_t exec_env, struct fd_table *curfds, + struct fd_prestats *prestats, __wasi_fd_t from, + __wasi_fd_t to) + WASMTIME_SSP_SYSCALL_NAME(fd_renumber) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_set_recv_buf_size( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, __wasi_size_t size -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_fd_seek(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, __wasi_filedelta_t offset, + __wasi_whence_t whence, __wasi_filesize_t *newoffset) + WASMTIME_SSP_SYSCALL_NAME(fd_seek) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_set_reuse_addr( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, uint8_t reuse -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_fd_tell(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, __wasi_filesize_t *newoffset) + WASMTIME_SSP_SYSCALL_NAME(fd_tell) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_set_reuse_port( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, uint8_t reuse -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_fd_fdstat_get(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, __wasi_fdstat_t *buf) + WASMTIME_SSP_SYSCALL_NAME(fd_fdstat_get) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_set_send_buf_size( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, __wasi_size_t size -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_fd_fdstat_set_flags(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t fd, + __wasi_fdflags_t flags) + WASMTIME_SSP_SYSCALL_NAME(fd_fdstat_set_flags) WARN_UNUSED; __wasi_errno_t -wasi_ssp_sock_listen( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t fd, __wasi_size_t backlog -) __attribute__((__warn_unused_result__)); +wasmtime_ssp_fd_fdstat_set_rights(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t fd, + __wasi_rights_t fs_rights_base, + __wasi_rights_t fs_rights_inheriting) + WASMTIME_SSP_SYSCALL_NAME(fd_fdstat_set_rights) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_recv( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - void *buf, - size_t buf_len, - size_t *recv_len -) WASMTIME_SSP_SYSCALL_NAME(sock_recv) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_fd_sync(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd) + WASMTIME_SSP_SYSCALL_NAME(fd_sync) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_recv_from( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - void *buf, - size_t buf_len, - __wasi_riflags_t ri_flags, - __wasi_addr_t *src_addr, - size_t *recv_len -) WASMTIME_SSP_SYSCALL_NAME(sock_recv_from) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_fd_write(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, const __wasi_ciovec_t *iovs, + size_t iovs_len, size_t *nwritten) + WASMTIME_SSP_SYSCALL_NAME(fd_write) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_send( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - const void *buf, - size_t buf_len, - size_t *sent_len -) WASMTIME_SSP_SYSCALL_NAME(sock_send) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_fd_advise(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, __wasi_filesize_t offset, + __wasi_filesize_t len, __wasi_advice_t advice) + WASMTIME_SSP_SYSCALL_NAME(fd_advise) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_send_to( - wasm_exec_env_t exec_env, - struct fd_table *curfds, struct addr_pool *addr_pool, - __wasi_fd_t sock, - const void *buf, - size_t buf_len, - __wasi_siflags_t si_flags, - const __wasi_addr_t *dest_addr, - size_t *sent_len -) WASMTIME_SSP_SYSCALL_NAME(sock_send_to) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_fd_allocate(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, __wasi_filesize_t offset, + __wasi_filesize_t len) + WASMTIME_SSP_SYSCALL_NAME(fd_allocate) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_shutdown( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock -) WASMTIME_SSP_SYSCALL_NAME(sock_shutdown) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_path_create_directory(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t fd, + const char *path, size_t path_len) + WASMTIME_SSP_SYSCALL_NAME(path_create_directory) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_recv_timeout( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - uint64_t timeout_us -) WASMTIME_SSP_SYSCALL_NAME(sock_set_recv_timeout) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_path_link(wasm_exec_env_t exec_env, struct fd_table *curfds, + struct fd_prestats *prestats, __wasi_fd_t old_fd, + __wasi_lookupflags_t old_flags, const char *old_path, + size_t old_path_len, __wasi_fd_t new_fd, + const char *new_path, size_t new_path_len) + WASMTIME_SSP_SYSCALL_NAME(path_link) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_recv_timeout( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - uint64_t *timeout_us -) WASMTIME_SSP_SYSCALL_NAME(sock_get_recv_timeout) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_path_open(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t dirfd, __wasi_lookupflags_t dirflags, + const char *path, size_t path_len, + __wasi_oflags_t oflags, __wasi_rights_t fs_rights_base, + __wasi_rights_t fs_rights_inheriting, + __wasi_fdflags_t fs_flags, __wasi_fd_t *fd) + WASMTIME_SSP_SYSCALL_NAME(path_open) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_send_timeout( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - uint64_t timeout_us -) WASMTIME_SSP_SYSCALL_NAME(sock_set_send_timeout) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_fd_readdir(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, void *buf, size_t buf_len, + __wasi_dircookie_t cookie, size_t *bufused) + WASMTIME_SSP_SYSCALL_NAME(fd_readdir) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_send_timeout( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - uint64_t *timeout_us -) WASMTIME_SSP_SYSCALL_NAME(sock_get_send_timeout) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_path_readlink(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, const char *path, size_t path_len, + char *buf, size_t buf_len, size_t *bufused) + WASMTIME_SSP_SYSCALL_NAME(path_readlink) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_send_buf_size( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - size_t bufsiz -) WASMTIME_SSP_SYSCALL_NAME(sock_set_send_buf_size) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_path_rename(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t old_fd, const char *old_path, + size_t old_path_len, __wasi_fd_t new_fd, + const char *new_path, size_t new_path_len) + WASMTIME_SSP_SYSCALL_NAME(path_rename) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_send_buf_size( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - size_t *bufsiz -) WASMTIME_SSP_SYSCALL_NAME(sock_get_send_buf_size) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_fd_filestat_get(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, __wasi_filestat_t *buf) + WASMTIME_SSP_SYSCALL_NAME(fd_filestat_get) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_recv_buf_size( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - size_t bufsiz -) WASMTIME_SSP_SYSCALL_NAME(sock_set_recv_buf_size) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_fd_filestat_set_times(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t fd, + __wasi_timestamp_t st_atim, + __wasi_timestamp_t st_mtim, + __wasi_fstflags_t fstflags) + WASMTIME_SSP_SYSCALL_NAME(fd_filestat_set_times) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_recv_buf_size( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - size_t *bufsiz -) WASMTIME_SSP_SYSCALL_NAME(sock_get_recv_buf_size) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_fd_filestat_set_size(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t fd, + __wasi_filesize_t st_size) + WASMTIME_SSP_SYSCALL_NAME(fd_filestat_set_size) WARN_UNUSED; +__wasi_errno_t +wasmtime_ssp_path_filestat_get(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t fd, + __wasi_lookupflags_t flags, const char *path, + size_t path_len, __wasi_filestat_t *buf) + WASMTIME_SSP_SYSCALL_NAME(path_filestat_get) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_keep_alive( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_set_keep_alive) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_path_filestat_set_times(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t fd, + __wasi_lookupflags_t flags, + const char *path, size_t path_len, + __wasi_timestamp_t st_atim, + __wasi_timestamp_t st_mtim, + __wasi_fstflags_t fstflags) + WASMTIME_SSP_SYSCALL_NAME(path_filestat_set_times) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_keep_alive( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool *is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_get_keep_alive) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_path_symlink(wasm_exec_env_t exec_env, struct fd_table *curfds, + struct fd_prestats *prestats, const char *old_path, + size_t old_path_len, __wasi_fd_t fd, + const char *new_path, size_t new_path_len) + WASMTIME_SSP_SYSCALL_NAME(path_symlink) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_reuse_addr( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_set_reuse_addr) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_path_unlink_file(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, const char *path, size_t path_len) + WASMTIME_SSP_SYSCALL_NAME(path_unlink_file) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_reuse_addr( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool *is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_get_reuse_addr) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_path_remove_directory(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t fd, + const char *path, size_t path_len) + WASMTIME_SSP_SYSCALL_NAME(path_remove_directory) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_reuse_port( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_set_reuse_port) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds, + const __wasi_subscription_t *in, __wasi_event_t *out, + size_t nsubscriptions, size_t *nevents) + WASMTIME_SSP_SYSCALL_NAME(poll_oneoff) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_reuse_port( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool *is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_get_reuse_port) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_random_get(void *buf, size_t buf_len) + WASMTIME_SSP_SYSCALL_NAME(random_get) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_linger( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool is_enabled, - int linger_s -) WASMTIME_SSP_SYSCALL_NAME(sock_set_linger) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_accept(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, __wasi_fdflags_t flags, + __wasi_fd_t *fd_new) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_linger( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, bool *is_enabled, int *linger_s -) WASMTIME_SSP_SYSCALL_NAME(sock_get_linger) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_addr_local(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, __wasi_addr_t *addr) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_broadcast( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_set_broadcast) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_addr_remote(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, __wasi_addr_t *addr) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_broadcast( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool *is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_get_broadcast) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_open(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t poolfd, __wasi_address_family_t af, + __wasi_sock_type_t socktype, + __wasi_fd_t *sockfd) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_tcp_no_delay( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_no_delay) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_bind(wasm_exec_env_t exec_env, struct fd_table *curfds, + struct addr_pool *addr_pool, __wasi_fd_t fd, + __wasi_addr_t *addr) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_tcp_no_delay( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool *is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_no_delay) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_addr_resolve(wasm_exec_env_t exec_env, struct fd_table *curfds, + char **ns_lookup_list, const char *host, + const char *service, __wasi_addr_info_hints_t *hints, + __wasi_addr_info_t *addr_info, + __wasi_size_t addr_info_size, + __wasi_size_t *max_info_size) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_tcp_quick_ack( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_quick_ack) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_connect(wasm_exec_env_t exec_env, struct fd_table *curfds, + struct addr_pool *addr_pool, __wasi_fd_t fd, + __wasi_addr_t *addr) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_tcp_quick_ack( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool *is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_quick_ack) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_get_recv_buf_size(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t fd, + __wasi_size_t *size) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_tcp_keep_idle( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - uint32_t time_s -) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_keep_idle) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_get_reuse_addr(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, uint8_t *reuse) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_tcp_keep_idle( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - uint32_t *time_s -) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_keep_idle) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_get_reuse_port(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, uint8_t *reuse) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_tcp_keep_intvl( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - uint32_t time_s -) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_keep_intvl) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_get_send_buf_size(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t fd, + __wasi_size_t *size) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_tcp_keep_intvl( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - uint32_t *time_s -) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_keep_intvl) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_set_recv_buf_size(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t fd, + __wasi_size_t size) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_tcp_fastopen_connect( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_fastopen_connect) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_set_reuse_addr(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, uint8_t reuse) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_tcp_fastopen_connect( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool *is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_fastopen_connect) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_set_reuse_port(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, uint8_t reuse) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_ip_multicast_loop( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool ipv6, - bool is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_multicast_loop) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_set_send_buf_size(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t fd, + __wasi_size_t size) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_ip_multicast_loop( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool ipv6, - bool *is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_get_ip_multicast_loop) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_listen(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t fd, __wasi_size_t backlog) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_ip_add_membership( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - __wasi_addr_ip_t *imr_multiaddr, - uint32_t imr_interface -) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_add_membership) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_sock_recv(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t sock, void *buf, size_t buf_len, + size_t *recv_len) + WASMTIME_SSP_SYSCALL_NAME(sock_recv) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_ip_drop_membership( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - __wasi_addr_ip_t *imr_multiaddr, - uint32_t imr_interface -) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_drop_membership) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_sock_recv_from(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t sock, void *buf, size_t buf_len, + __wasi_riflags_t ri_flags, __wasi_addr_t *src_addr, + size_t *recv_len) + WASMTIME_SSP_SYSCALL_NAME(sock_recv_from) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_ip_ttl( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - uint8_t ttl_s -) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_ttl) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_sock_send(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t sock, const void *buf, size_t buf_len, + size_t *sent_len) + WASMTIME_SSP_SYSCALL_NAME(sock_send) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_ip_ttl( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - uint8_t *ttl_s -) WASMTIME_SSP_SYSCALL_NAME(sock_get_ip_ttl) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_sock_send_to(wasm_exec_env_t exec_env, struct fd_table *curfds, + struct addr_pool *addr_pool, __wasi_fd_t sock, + const void *buf, size_t buf_len, + __wasi_siflags_t si_flags, + const __wasi_addr_t *dest_addr, size_t *sent_len) + WASMTIME_SSP_SYSCALL_NAME(sock_send_to) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_ip_multicast_ttl( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - uint8_t ttl_s -) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_multicast_ttl) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_sock_shutdown(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t sock) + WASMTIME_SSP_SYSCALL_NAME(sock_shutdown) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_ip_multicast_ttl( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - uint8_t *ttl_s -) WASMTIME_SSP_SYSCALL_NAME(sock_get_ip_multicast_ttl) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_sock_set_recv_timeout(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + uint64_t timeout_us) + WASMTIME_SSP_SYSCALL_NAME(sock_set_recv_timeout) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_set_ipv6_only( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_set_ipv6_only) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_sock_get_recv_timeout(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + uint64_t *timeout_us) + WASMTIME_SSP_SYSCALL_NAME(sock_get_recv_timeout) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sock_get_ipv6_only( - wasm_exec_env_t exec_env, - struct fd_table *curfds, - __wasi_fd_t sock, - bool *is_enabled -) WASMTIME_SSP_SYSCALL_NAME(sock_get_ipv6_only) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_sock_set_send_timeout(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + uint64_t timeout_us) + WASMTIME_SSP_SYSCALL_NAME(sock_set_send_timeout) WARN_UNUSED; -__wasi_errno_t wasmtime_ssp_sched_yield(void) - WASMTIME_SSP_SYSCALL_NAME(sched_yield) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasmtime_ssp_sock_get_send_timeout(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + uint64_t *timeout_us) + WASMTIME_SSP_SYSCALL_NAME(sock_get_send_timeout) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_send_buf_size(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + size_t bufsiz) + WASMTIME_SSP_SYSCALL_NAME(sock_set_send_buf_size) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_send_buf_size(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + size_t *bufsiz) + WASMTIME_SSP_SYSCALL_NAME(sock_get_send_buf_size) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_recv_buf_size(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + size_t bufsiz) + WASMTIME_SSP_SYSCALL_NAME(sock_set_recv_buf_size) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_recv_buf_size(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + size_t *bufsiz) + WASMTIME_SSP_SYSCALL_NAME(sock_get_recv_buf_size) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_keep_alive(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_set_keep_alive) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_keep_alive(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool *is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_get_keep_alive) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_reuse_addr(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_set_reuse_addr) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_reuse_addr(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool *is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_get_reuse_addr) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_reuse_port(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_set_reuse_port) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_reuse_port(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool *is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_get_reuse_port) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_linger(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t sock, bool is_enabled, int linger_s) + WASMTIME_SSP_SYSCALL_NAME(sock_set_linger) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_linger(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t sock, bool *is_enabled, int *linger_s) + WASMTIME_SSP_SYSCALL_NAME(sock_get_linger) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_broadcast(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_set_broadcast) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_broadcast(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool *is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_get_broadcast) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_tcp_no_delay(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_no_delay) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_tcp_no_delay(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool *is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_no_delay) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_tcp_quick_ack(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_quick_ack) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_tcp_quick_ack(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool *is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_quick_ack) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_tcp_keep_idle(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + uint32_t time_s) + WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_keep_idle) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_tcp_keep_idle(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + uint32_t *time_s) + WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_keep_idle) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_tcp_keep_intvl(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + uint32_t time_s) + WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_keep_intvl) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_tcp_keep_intvl(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + uint32_t *time_s) + WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_keep_intvl) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_tcp_fastopen_connect(wasm_exec_env_t exec_env, + struct fd_table *curfds, + __wasi_fd_t sock, bool is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_fastopen_connect) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_tcp_fastopen_connect(wasm_exec_env_t exec_env, + struct fd_table *curfds, + __wasi_fd_t sock, bool *is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_fastopen_connect) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_ip_multicast_loop(wasm_exec_env_t exec_env, + struct fd_table *curfds, + __wasi_fd_t sock, bool ipv6, + bool is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_multicast_loop) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_ip_multicast_loop(wasm_exec_env_t exec_env, + struct fd_table *curfds, + __wasi_fd_t sock, bool ipv6, + bool *is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_get_ip_multicast_loop) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_ip_add_membership(wasm_exec_env_t exec_env, + struct fd_table *curfds, + __wasi_fd_t sock, + __wasi_addr_ip_t *imr_multiaddr, + uint32_t imr_interface) + WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_add_membership) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_ip_drop_membership(wasm_exec_env_t exec_env, + struct fd_table *curfds, + __wasi_fd_t sock, + __wasi_addr_ip_t *imr_multiaddr, + uint32_t imr_interface) + WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_drop_membership) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_ip_ttl(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t sock, uint8_t ttl_s) + WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_ttl) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_ip_ttl(wasm_exec_env_t exec_env, struct fd_table *curfds, + __wasi_fd_t sock, uint8_t *ttl_s) + WASMTIME_SSP_SYSCALL_NAME(sock_get_ip_ttl) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_ip_multicast_ttl(wasm_exec_env_t exec_env, + struct fd_table *curfds, + __wasi_fd_t sock, uint8_t ttl_s) + WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_multicast_ttl) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_ip_multicast_ttl(wasm_exec_env_t exec_env, + struct fd_table *curfds, + __wasi_fd_t sock, uint8_t *ttl_s) + WASMTIME_SSP_SYSCALL_NAME(sock_get_ip_multicast_ttl) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_set_ipv6_only(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_set_ipv6_only) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sock_get_ipv6_only(wasm_exec_env_t exec_env, + struct fd_table *curfds, __wasi_fd_t sock, + bool *is_enabled) + WASMTIME_SSP_SYSCALL_NAME(sock_get_ipv6_only) WARN_UNUSED; + +__wasi_errno_t +wasmtime_ssp_sched_yield(void) + WASMTIME_SSP_SYSCALL_NAME(sched_yield) WARN_UNUSED; #ifdef __cplusplus } @@ -1361,6 +603,4 @@ __wasi_errno_t wasmtime_ssp_sched_yield(void) #undef WASMTIME_SSP_SYSCALL_NAME -/* clang-format on */ - #endif /* end of WASMTIME_SSP_H */ diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.c index 9d01f2bfe..ec1481c2e 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.c +++ b/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 error; +} + +__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)) { + return __WASI_EINTR; + } + __wasi_errno_t error = os_readv(handle, iov, iovcnt, nread); + wasm_runtime_end_blocking_op(exec_env); + return error; +} + +__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)) { + return __WASI_EINTR; + } + __wasi_errno_t ret = os_preadv(handle, iov, iovcnt, offset, nread); wasm_runtime_end_blocking_op(exec_env); return ret; } -ssize_t -blocking_op_readv(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 = readv(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_PREADV -ssize_t -blocking_op_preadv(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 = preadv(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_PREADV */ -ssize_t -blocking_op_pread(wasm_exec_env_t exec_env, int fd, void *p, size_t nb, - off_t offset) -{ - if (!wasm_runtime_begin_blocking_op(exec_env)) { - errno = EINTR; - return -1; - } - ssize_t ret = pread(fd, p, nb, offset); - 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) -{ - if (!wasm_runtime_begin_blocking_op(exec_env)) { - errno = EINTR; - return -1; - } - ssize_t ret = writev(fd, iov, iovcnt); - wasm_runtime_end_blocking_op(exec_env); - return ret; -} - -#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) -{ - if (!wasm_runtime_begin_blocking_op(exec_env)) { - errno = EINTR; - return -1; - } - ssize_t ret = pwritev(fd, iov, iovcnt, offset); - wasm_runtime_end_blocking_op(exec_env); - return ret; -} -#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; } diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.h index 44a16d338..afaa4a4f0 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.h +++ b/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); \ No newline at end of file diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/locking.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/locking.h index 40b064b81..5e0778c3f 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/locking.h +++ b/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 diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c index 0ba91a7e9..9819c92fd 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c @@ -15,6 +15,7 @@ #include "bh_platform.h" #include "blocking_op.h" #include "wasmtime_ssp.h" +#include "libc_errno.h" #include "locking.h" #include "posix.h" #include "random.h" @@ -22,6 +23,18 @@ #include "rights.h" #include "str.h" +/* Some platforms (e.g. Windows) already define `min()` macro. + We're undefing it here to make sure the `min` call does exactly + what we want it to do. */ +#ifdef min +#undef min +#endif +static inline size_t +min(size_t a, size_t b) +{ + return a > b ? b : a; +} + #if 0 /* TODO: -std=gnu99 causes compile error, comment them first */ // struct iovec must have the same layout as __wasi_iovec_t. static_assert(offsetof(struct iovec, iov_base) == @@ -56,105 +69,6 @@ static_assert(sizeof(struct iovec) == sizeof(__wasi_ciovec_t), "Size mismatch"); #endif -// Converts a POSIX error code to a CloudABI error code. -static __wasi_errno_t -convert_errno(int error) -{ - __wasi_errno_t code = __WASI_ENOSYS; -#define X(v) \ - case v: \ - code = __WASI_##v; \ - break; - switch (error) { - X(E2BIG) - X(EACCES) - X(EADDRINUSE) - X(EADDRNOTAVAIL) - X(EAFNOSUPPORT) - X(EAGAIN) - X(EALREADY) - X(EBADF) - X(EBADMSG) - X(EBUSY) - X(ECANCELED) - X(ECHILD) - X(ECONNABORTED) - X(ECONNREFUSED) - X(ECONNRESET) - X(EDEADLK) - X(EDESTADDRREQ) - X(EDOM) - X(EDQUOT) - X(EEXIST) - X(EFAULT) - X(EFBIG) - X(EHOSTUNREACH) - X(EIDRM) - X(EILSEQ) - X(EINPROGRESS) - X(EINTR) - X(EINVAL) - X(EIO) - X(EISCONN) - X(EISDIR) - X(ELOOP) - X(EMFILE) - X(EMLINK) - X(EMSGSIZE) - X(EMULTIHOP) - X(ENAMETOOLONG) - X(ENETDOWN) - X(ENETRESET) - X(ENETUNREACH) - X(ENFILE) - X(ENOBUFS) - X(ENODEV) - X(ENOENT) - X(ENOEXEC) - X(ENOLCK) - X(ENOLINK) - X(ENOMEM) - X(ENOMSG) - X(ENOPROTOOPT) - X(ENOSPC) - X(ENOSYS) -#ifdef ENOTCAPABLE - X(ENOTCAPABLE) -#endif - X(ENOTCONN) - X(ENOTDIR) - X(ENOTEMPTY) - X(ENOTRECOVERABLE) - X(ENOTSOCK) - X(ENOTSUP) - X(ENOTTY) - X(ENXIO) - X(EOVERFLOW) - X(EOWNERDEAD) - X(EPERM) - X(EPIPE) - X(EPROTO) - X(EPROTONOSUPPORT) - X(EPROTOTYPE) - X(ERANGE) - X(EROFS) - X(ESPIPE) - X(ESRCH) - X(ESTALE) - X(ETIMEDOUT) - X(ETXTBSY) - X(EXDEV) - default: - if (error == EOPNOTSUPP) - code = __WASI_ENOTSUP; - else if (code == EWOULDBLOCK) - code = __WASI_EAGAIN; - break; - } -#undef X - return code; -} - static bool ns_lookup_list_search(char **list, const char *host) { @@ -180,21 +94,9 @@ ns_lookup_list_search(char **list, const char *host) return false; } -// Converts a POSIX timespec to a CloudABI 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 CloudABI clock identifier to a POSIX clock identifier. +#if !defined(BH_PLATFORM_WINDOWS) && CONFIG_HAS_CLOCK_NANOSLEEP static bool -convert_clockid(__wasi_clockid_t in, clockid_t *out) +wasi_clockid_to_clockid(__wasi_clockid_t in, clockid_t *out) { switch (in) { case __WASI_CLOCK_MONOTONIC: @@ -217,6 +119,7 @@ convert_clockid(__wasi_clockid_t in, clockid_t *out) return false; } } +#endif static void wasi_addr_to_bh_sockaddr(const __wasi_addr_t *wasi_addr, @@ -294,35 +197,6 @@ wasi_addr_ip_to_bh_ip_addr_buffer(__wasi_addr_ip_t *addr, } } -__wasi_errno_t -wasmtime_ssp_clock_res_get(__wasi_clockid_t clock_id, - __wasi_timestamp_t *resolution) -{ - clockid_t nclock_id; - if (!convert_clockid(clock_id, &nclock_id)) - return __WASI_EINVAL; - struct timespec ts; - if (clock_getres(nclock_id, &ts) < 0) - return convert_errno(errno); - *resolution = convert_timespec(&ts); - return 0; -} - -__wasi_errno_t -wasmtime_ssp_clock_time_get(__wasi_clockid_t clock_id, - __wasi_timestamp_t precision, - __wasi_timestamp_t *time) -{ - clockid_t nclock_id; - if (!convert_clockid(clock_id, &nclock_id)) - return __WASI_EINVAL; - struct timespec ts; - if (clock_gettime(nclock_id, &ts) < 0) - return convert_errno(errno); - *time = convert_timespec(&ts); - return 0; -} - struct fd_prestat { const char *dir; }; @@ -442,13 +316,16 @@ fd_prestats_remove_entry(struct fd_prestats *pt, __wasi_fd_t fd) struct fd_object { struct refcount refcount; __wasi_filetype_t type; - int number; + os_file_handle file_handle; + // Keep track of whether this fd object refers to a stdio stream so we know + // whether to close the underlying file handle when releasing the object. + bool is_stdio; union { // Data associated with directory file descriptors. struct { struct mutex lock; // Lock to protect members below. - DIR *handle; // Directory handle. + os_dir_stream handle; // Directory handle. __wasi_dircookie_t offset; // Offset of the directory. } directory; }; @@ -530,7 +407,7 @@ fd_table_grow(struct fd_table *ft, size_t min, size_t incr) // Allocates a new file descriptor object. static __wasi_errno_t -fd_object_new(__wasi_filetype_t type, struct fd_object **fo) +fd_object_new(__wasi_filetype_t type, bool is_stdio, struct fd_object **fo) TRYLOCKS_SHARED(0, (*fo)->refcount) { *fo = wasm_runtime_malloc(sizeof(**fo)); @@ -538,7 +415,8 @@ fd_object_new(__wasi_filetype_t type, struct fd_object **fo) return __WASI_ENOMEM; refcount_init(&(*fo)->refcount, 1); (*fo)->type = type; - (*fo)->number = -1; + (*fo)->file_handle = os_get_invalid_handle(); + (*fo)->is_stdio = is_stdio; return 0; } @@ -576,139 +454,119 @@ fd_table_detach(struct fd_table *ft, __wasi_fd_t fd, struct fd_object **fo) // Determines the type of a file descriptor and its maximum set of // rights that should be attached to it. static __wasi_errno_t -fd_determine_type_rights(int fd, __wasi_filetype_t *type, +fd_determine_type_rights(os_file_handle fd, __wasi_filetype_t *type, __wasi_rights_t *rights_base, __wasi_rights_t *rights_inheriting) { - struct stat sb; - if (fstat(fd, &sb) < 0) - return convert_errno(errno); - if (S_ISBLK(sb.st_mode)) { - *type = __WASI_FILETYPE_BLOCK_DEVICE; - *rights_base = RIGHTS_BLOCK_DEVICE_BASE; - *rights_inheriting = RIGHTS_BLOCK_DEVICE_INHERITING; - } - else if (S_ISCHR(sb.st_mode)) { - *type = __WASI_FILETYPE_CHARACTER_DEVICE; -#if CONFIG_HAS_ISATTY - if (isatty(fd)) { - *rights_base = RIGHTS_TTY_BASE; - *rights_inheriting = RIGHTS_TTY_INHERITING; - } - else -#endif - { - *rights_base = RIGHTS_CHARACTER_DEVICE_BASE; - *rights_inheriting = RIGHTS_CHARACTER_DEVICE_INHERITING; - } - } - else if (S_ISDIR(sb.st_mode)) { - *type = __WASI_FILETYPE_DIRECTORY; - *rights_base = RIGHTS_DIRECTORY_BASE; - *rights_inheriting = RIGHTS_DIRECTORY_INHERITING; - } - else if (S_ISREG(sb.st_mode)) { - *type = __WASI_FILETYPE_REGULAR_FILE; - *rights_base = RIGHTS_REGULAR_FILE_BASE; - *rights_inheriting = RIGHTS_REGULAR_FILE_INHERITING; - } - else if (S_ISSOCK(sb.st_mode)) { - int socktype; - socklen_t socktypelen = sizeof(socktype); - if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &socktype, &socktypelen) < 0) - return convert_errno(errno); - switch (socktype) { - case SOCK_DGRAM: - *type = __WASI_FILETYPE_SOCKET_DGRAM; - break; - case SOCK_STREAM: - *type = __WASI_FILETYPE_SOCKET_STREAM; - break; - default: - return __WASI_EINVAL; - } - *rights_base = RIGHTS_SOCKET_BASE; - *rights_inheriting = RIGHTS_SOCKET_INHERITING; - } - else if (S_ISFIFO(sb.st_mode)) { - *type = __WASI_FILETYPE_SOCKET_STREAM; - *rights_base = RIGHTS_SOCKET_BASE; - *rights_inheriting = RIGHTS_SOCKET_INHERITING; - } - else { - return __WASI_EINVAL; + struct __wasi_filestat_t buf; + __wasi_errno_t error = os_fstat(fd, &buf); + + if (error != __WASI_ESUCCESS) + return error; + + *type = buf.st_filetype; + + switch (buf.st_filetype) { + case __WASI_FILETYPE_BLOCK_DEVICE: + *rights_base = RIGHTS_BLOCK_DEVICE_BASE; + *rights_inheriting = RIGHTS_BLOCK_DEVICE_INHERITING; + break; + case __WASI_FILETYPE_CHARACTER_DEVICE: + error = os_isatty(fd); + + if (error == __WASI_ESUCCESS) { + *rights_base = RIGHTS_TTY_BASE; + *rights_inheriting = RIGHTS_TTY_INHERITING; + } + else { + *rights_base = RIGHTS_CHARACTER_DEVICE_BASE; + *rights_inheriting = RIGHTS_CHARACTER_DEVICE_INHERITING; + } + break; + case __WASI_FILETYPE_DIRECTORY: + *rights_base = RIGHTS_DIRECTORY_BASE; + *rights_inheriting = RIGHTS_DIRECTORY_INHERITING; + break; + case __WASI_FILETYPE_REGULAR_FILE: + *rights_base = RIGHTS_REGULAR_FILE_BASE; + *rights_inheriting = RIGHTS_REGULAR_FILE_INHERITING; + break; + case __WASI_FILETYPE_SOCKET_DGRAM: + case __WASI_FILETYPE_SOCKET_STREAM: + *rights_base = RIGHTS_SOCKET_BASE; + *rights_inheriting = RIGHTS_SOCKET_INHERITING; + break; + case __WASI_FILETYPE_SYMBOLIC_LINK: + case __WASI_FILETYPE_UNKNOWN: + // If we don't know the type, allow for the maximum set of + // rights + *rights_base = RIGHTS_ALL; + *rights_inheriting = RIGHTS_ALL; + break; + default: + return __WASI_EINVAL; } + wasi_libc_file_access_mode access_mode; + error = os_file_get_access_mode(fd, &access_mode); + + if (error != __WASI_ESUCCESS) + return error; + // Strip off read/write bits based on the access mode. - switch (fcntl(fd, F_GETFL) & O_ACCMODE) { - case O_RDONLY: + switch (access_mode) { + case WASI_LIBC_ACCESS_MODE_READ_ONLY: *rights_base &= ~(__wasi_rights_t)__WASI_RIGHT_FD_WRITE; break; - case O_WRONLY: + case WASI_LIBC_ACCESS_MODE_WRITE_ONLY: *rights_base &= ~(__wasi_rights_t)__WASI_RIGHT_FD_READ; break; } - return 0; -} -// Returns the underlying file descriptor number of a file descriptor -// object. This function can only be applied to objects that have an -// underlying file descriptor number. -static int -fd_number(const struct fd_object *fo) -{ - int number = fo->number; - assert(number >= 0 && "fd_number() called on virtual file descriptor"); - return number; + return error; } -// The env == NULL case is for -// fd_table_destroy, path_get, path_put, fd_table_insert_existing -#define CLOSE_NON_STD_FD(env, fd) \ - do { \ - if (fd > 2) { \ - if (env == NULL) { \ - close(fd); \ - } \ - else { \ - blocking_op_close(env, fd); \ - } \ - } \ - } while (0) - // Lowers the reference count on a file descriptor object. When the // reference count reaches zero, its resources are cleaned up. -static void +static __wasi_errno_t fd_object_release(wasm_exec_env_t env, struct fd_object *fo) UNLOCKS(fo->refcount) { + __wasi_errno_t error = __WASI_ESUCCESS; + if (refcount_release(&fo->refcount)) { int saved_errno = errno; switch (fo->type) { case __WASI_FILETYPE_DIRECTORY: - // For directories we may keep track of a DIR object. Calling - // closedir() on it also closes the underlying file descriptor. + // For directories we may keep track of a DIR object. + // Calling os_closedir() on it also closes the underlying file + // descriptor. mutex_destroy(&fo->directory.lock); - if (fo->directory.handle == NULL) { - CLOSE_NON_STD_FD(env, fd_number(fo)); + if (os_is_dir_stream_valid(&fo->directory.handle)) { + error = os_closedir(fo->directory.handle); + break; } - else { - closedir(fo->directory.handle); - } - break; + // Fallthrough. default: - CLOSE_NON_STD_FD(env, fd_number(fo)); + // The env == NULL case is for + // fd_table_destroy, path_get, path_put, + // fd_table_insert_existing + error = (env == NULL) ? os_close(fo->file_handle, fo->is_stdio) + : blocking_op_close(env, fo->file_handle, + fo->is_stdio); break; } wasm_runtime_free(fo); errno = saved_errno; } + return error; } // Inserts an already existing file descriptor into the file descriptor // table. bool -fd_table_insert_existing(struct fd_table *ft, __wasi_fd_t in, int out) +fd_table_insert_existing(struct fd_table *ft, __wasi_fd_t in, + os_file_handle out, bool is_stdio) { __wasi_filetype_t type = __WASI_FILETYPE_UNKNOWN; __wasi_rights_t rights_base = 0, rights_inheriting = 0; @@ -720,8 +578,8 @@ fd_table_insert_existing(struct fd_table *ft, __wasi_fd_t in, int out) if (error != 0) { #ifdef BH_PLATFORM_EGO /** - * since it is an already opened file and we can assume the opened file - * has all necessary rights no matter how to get + * since it is an already opened file and we can assume the opened + * file has all necessary rights no matter how to get */ if (error != __WASI_ENOTSUP) return false; @@ -730,16 +588,16 @@ fd_table_insert_existing(struct fd_table *ft, __wasi_fd_t in, int out) #endif } - error = fd_object_new(type, &fo); + error = fd_object_new(type, is_stdio, &fo); if (error != 0) return false; - fo->number = out; + fo->file_handle = out; if (type == __WASI_FILETYPE_DIRECTORY) { if (!mutex_init(&fo->directory.lock)) { fd_object_release(NULL, fo); return false; } - fo->directory.handle = NULL; + fo->directory.handle = os_get_invalid_dir_stream(); } // Grow the file descriptor table if needed. @@ -756,14 +614,21 @@ fd_table_insert_existing(struct fd_table *ft, __wasi_fd_t in, int out) } // Picks an unused slot from the file descriptor table. -static __wasi_fd_t -fd_table_unused(struct fd_table *ft) REQUIRES_SHARED(ft->lock) +static __wasi_errno_t +fd_table_unused(struct fd_table *ft, __wasi_fd_t *out) REQUIRES_SHARED(ft->lock) { assert(ft->size > ft->used && "File descriptor table has no free slots"); for (;;) { - __wasi_fd_t fd = (__wasi_fd_t)random_uniform(ft->size); - if (ft->entries[fd].object == NULL) - return fd; + uintmax_t random_fd = 0; + __wasi_errno_t error = random_uniform(ft->size, &random_fd); + + if (error != __WASI_ESUCCESS) + return error; + + if (ft->entries[(__wasi_fd_t)random_fd].object == NULL) { + *out = (__wasi_fd_t)random_fd; + return error; + } } } @@ -783,34 +648,39 @@ fd_table_insert(wasm_exec_env_t exec_env, struct fd_table *ft, return convert_errno(errno); } - *out = fd_table_unused(ft); + __wasi_errno_t error = fd_table_unused(ft, out); + + if (error != __WASI_ESUCCESS) + return error; + fd_table_attach(ft, *out, fo, rights_base, rights_inheriting); rwlock_unlock(&ft->lock); - return 0; + return error; } // Inserts a numerical file descriptor into the file descriptor table. static __wasi_errno_t -fd_table_insert_fd(wasm_exec_env_t exec_env, struct fd_table *ft, int in, - __wasi_filetype_t type, __wasi_rights_t rights_base, +fd_table_insert_fd(wasm_exec_env_t exec_env, struct fd_table *ft, + os_file_handle in, __wasi_filetype_t type, + __wasi_rights_t rights_base, __wasi_rights_t rights_inheriting, __wasi_fd_t *out) REQUIRES_UNLOCKED(ft->lock) { struct fd_object *fo; - __wasi_errno_t error = fd_object_new(type, &fo); + __wasi_errno_t error = fd_object_new(type, false, &fo); if (error != 0) { - close(in); + os_close(in, false); return error; } - fo->number = in; + fo->file_handle = in; if (type == __WASI_FILETYPE_DIRECTORY) { if (!mutex_init(&fo->directory.lock)) { fd_object_release(exec_env, fo); return (__wasi_errno_t)-1; } - fo->directory.handle = NULL; + fo->directory.handle = os_get_invalid_dir_stream(); } return fd_table_insert(exec_env, ft, fo, rights_base, rights_inheriting, out); @@ -948,15 +818,11 @@ wasmtime_ssp_fd_datasync(wasm_exec_env_t exec_env, struct fd_table *curfds, if (error != 0) return error; -#if CONFIG_HAS_FDATASYNC - int ret = fdatasync(fd_number(fo)); -#else - int ret = fsync(fd_number(fo)); -#endif + error = os_fdatasync(fo->file_handle); + fd_object_release(exec_env, fo); - if (ret < 0) - return convert_errno(errno); - return 0; + + return error; } __wasi_errno_t @@ -970,67 +836,16 @@ wasmtime_ssp_fd_pread(wasm_exec_env_t exec_env, struct fd_table *curfds, struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_READ, 0); + if (error != 0) return error; -#if CONFIG_HAS_PREADV - ssize_t len = - blocking_op_preadv(exec_env, fd_number(fo), (const struct iovec *)iov, - (int)iovcnt, (off_t)offset); + error = blocking_op_preadv(exec_env, fo->file_handle, iov, (int)iovcnt, + offset, nread); + fd_object_release(exec_env, fo); - if (len < 0) - return convert_errno(errno); - *nread = (size_t)len; - return 0; -#else - if (iovcnt == 1) { - ssize_t len = blocking_op_pread(exec_env, fd_number(fo), iov->buf, - iov->buf_len, offset); - fd_object_release(exec_env, fo); - if (len < 0) - return convert_errno(errno); - *nread = len; - return 0; - } - 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 = wasm_runtime_malloc(totalsize); - if (buf == NULL) { - fd_object_release(exec_env, fo); - return __WASI_ENOMEM; - } - // Perform a single read operation. - ssize_t len = - blocking_op_pread(exec_env, fd_number(fo), buf, totalsize, offset); - fd_object_release(exec_env, fo); - if (len < 0) { - wasm_runtime_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) { - bh_memcpy_s(iov[i].buf, iov[i].buf_len, buf + bufoff, - iov[i].buf_len); - bufoff += iov[i].buf_len; - } - else { - bh_memcpy_s(iov[i].buf, iov[i].buf_len, buf + bufoff, - len - bufoff); - break; - } - } - wasm_runtime_free(buf); - *nread = len; - return 0; - } -#endif + return error; } __wasi_errno_t @@ -1039,53 +854,18 @@ wasmtime_ssp_fd_pwrite(wasm_exec_env_t exec_env, struct fd_table *curfds, size_t iovcnt, __wasi_filesize_t offset, size_t *nwritten) { - if (iovcnt == 0) - return __WASI_EINVAL; - struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_WRITE, 0); + if (error != 0) return error; - ssize_t len; -#if CONFIG_HAS_PWRITEV - len = - blocking_op_pwritev(exec_env, fd_number(fo), (const struct iovec *)iov, - (int)iovcnt, (off_t)offset); -#else - if (iovcnt == 1) { - len = blocking_op_pwrite(exec_env, fd_number(fo), 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 = wasm_runtime_malloc(totalsize); - if (buf == NULL) { - fd_object_release(exec_env, fo); - return __WASI_ENOMEM; - } - size_t bufoff = 0; - for (size_t i = 0; i < iovcnt; ++i) { - bh_memcpy_s(buf + bufoff, totalsize - bufoff, iov[i].buf, - iov[i].buf_len); - bufoff += iov[i].buf_len; - } - - // Perform a single write operation. - len = - blocking_op_pwrite(exec_env, fd_number(fo), buf, totalsize, offset); - wasm_runtime_free(buf); - } -#endif + error = blocking_op_pwritev(exec_env, fo->file_handle, iov, (int)iovcnt, + offset, nwritten); fd_object_release(exec_env, fo); - if (len < 0) - return convert_errno(errno); - *nwritten = (size_t)len; - return 0; + + return error; } __wasi_errno_t @@ -1096,16 +876,16 @@ wasmtime_ssp_fd_read(wasm_exec_env_t exec_env, struct fd_table *curfds, struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_READ, 0); + if (error != 0) return error; - ssize_t len = blocking_op_readv(exec_env, fd_number(fo), - (const struct iovec *)iov, (int)iovcnt); + error = + blocking_op_readv(exec_env, fo->file_handle, iov, (int)iovcnt, nread); + fd_object_release(exec_env, fo); - if (len < 0) - return convert_errno(errno); - *nread = (size_t)len; - return 0; + + return error; } __wasi_errno_t @@ -1167,9 +947,9 @@ wasmtime_ssp_fd_renumber(wasm_exec_env_t exec_env, struct fd_table *curfds, (void)fd_prestats_remove_entry(prestats, to); } } - // Renumbering from a non-preopened fd to a preopened fd. In this case, we - // can't a keep the destination fd entry in the preopened table so remove - // it entirely. + // Renumbering from a non-preopened fd to a preopened fd. In this case, + // we can't a keep the destination fd entry in the preopened table so + // remove it entirely. else if (prestat_from_error != __WASI_ESUCCESS && prestat_to_error == __WASI_ESUCCESS) { (void)fd_prestats_remove_entry(prestats, to); @@ -1198,21 +978,6 @@ wasmtime_ssp_fd_seek(wasm_exec_env_t exec_env, struct fd_table *curfds, __wasi_fd_t fd, __wasi_filedelta_t offset, __wasi_whence_t whence, __wasi_filesize_t *newoffset) { - 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; - } - struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, @@ -1223,12 +988,11 @@ wasmtime_ssp_fd_seek(wasm_exec_env_t exec_env, struct fd_table *curfds, if (error != 0) return error; - off_t ret = lseek(fd_number(fo), offset, nwhence); + error = os_lseek(fo->file_handle, offset, whence, newoffset); + fd_object_release(exec_env, fo); - if (ret < 0) - return convert_errno(errno); - *newoffset = (__wasi_filesize_t)ret; - return 0; + + return error; } __wasi_errno_t @@ -1241,12 +1005,11 @@ wasmtime_ssp_fd_tell(wasm_exec_env_t exec_env, struct fd_table *curfds, if (error != 0) return error; - off_t ret = lseek(fd_number(fo), 0, SEEK_CUR); + error = os_lseek(fo->file_handle, 0, __WASI_WHENCE_CUR, newoffset); + fd_object_release(exec_env, fo); - if (ret < 0) - return convert_errno(errno); - *newoffset = (__wasi_filesize_t)ret; - return 0; + + return error; } __wasi_errno_t @@ -1257,47 +1020,29 @@ wasmtime_ssp_fd_fdstat_get(wasm_exec_env_t exec_env, struct fd_table *curfds, rwlock_rdlock(&ft->lock); struct fd_entry *fe; __wasi_errno_t error = fd_table_get_entry(ft, fd, 0, 0, &fe); - if (error != 0) { + if (error != __WASI_ESUCCESS) { rwlock_unlock(&ft->lock); return error; } // Extract file descriptor type and rights. struct fd_object *fo = fe->object; - *buf = (__wasi_fdstat_t){ - .fs_filetype = fo->type, - .fs_rights_base = fe->rights_base, - .fs_rights_inheriting = fe->rights_inheriting, - }; - // Fetch file descriptor flags. - int ret; - switch (fo->type) { - default: - ret = fcntl(fd_number(fo), F_GETFL); - break; + __wasi_fdflags_t flags; + error = os_file_get_fdflags(fo->file_handle, &flags); + + if (error != __WASI_ESUCCESS) { + rwlock_unlock(&ft->lock); + return error; } - rwlock_unlock(&ft->lock); - if (ret < 0) - return convert_errno(errno); - if ((ret & O_APPEND) != 0) - buf->fs_flags |= __WASI_FDFLAG_APPEND; -#ifdef CONFIG_HAS_O_DSYNC - if ((ret & O_DSYNC) != 0) - buf->fs_flags |= __WASI_FDFLAG_DSYNC; -#endif - if ((ret & O_NONBLOCK) != 0) - buf->fs_flags |= __WASI_FDFLAG_NONBLOCK; -#ifdef CONFIG_HAS_O_RSYNC - if ((ret & O_RSYNC) != 0) - buf->fs_flags |= __WASI_FDFLAG_RSYNC; -#endif -#ifdef CONFIG_HAS_O_SYNC - if ((ret & O_SYNC) != 0) - buf->fs_flags |= __WASI_FDFLAG_SYNC; -#endif - return 0; + *buf = (__wasi_fdstat_t){ .fs_filetype = fo->type, + .fs_rights_base = fe->rights_base, + .fs_rights_inheriting = fe->rights_inheriting, + .fs_flags = flags }; + + rwlock_unlock(&ft->lock); + return error; } __wasi_errno_t @@ -1305,41 +1050,18 @@ wasmtime_ssp_fd_fdstat_set_flags(wasm_exec_env_t exec_env, struct fd_table *curfds, __wasi_fd_t fd, __wasi_fdflags_t fs_flags) { - int noflags = 0; - if ((fs_flags & __WASI_FDFLAG_APPEND) != 0) - noflags |= O_APPEND; - if ((fs_flags & __WASI_FDFLAG_DSYNC) != 0) -#ifdef CONFIG_HAS_O_DSYNC - noflags |= O_DSYNC; -#else - return __WASI_ENOTSUP; -#endif - if ((fs_flags & __WASI_FDFLAG_NONBLOCK) != 0) - noflags |= O_NONBLOCK; - if ((fs_flags & __WASI_FDFLAG_RSYNC) != 0) -#ifdef CONFIG_HAS_O_RSYNC - noflags |= O_RSYNC; -#else - return __WASI_ENOTSUP; -#endif - if ((fs_flags & __WASI_FDFLAG_SYNC) != 0) -#ifdef CONFIG_HAS_O_SYNC - noflags |= O_SYNC; -#else - return __WASI_ENOTSUP; -#endif - struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_FDSTAT_SET_FLAGS, 0); + if (error != 0) return error; - int ret = fcntl(fd_number(fo), F_SETFL, noflags); + error = os_file_set_fdflags(fo->file_handle, fs_flags); + fd_object_release(exec_env, fo); - if (ret < 0) - return convert_errno(errno); - return 0; + + return error; } __wasi_errno_t @@ -1372,14 +1094,15 @@ wasmtime_ssp_fd_sync(wasm_exec_env_t exec_env, struct fd_table *curfds, struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_SYNC, 0); + if (error != 0) return error; - int ret = fsync(fd_number(fo)); + error = os_fsync(fo->file_handle); + fd_object_release(exec_env, fo); - if (ret < 0) - return convert_errno(errno); - return 0; + + return error; } __wasi_errno_t @@ -1394,33 +1117,31 @@ wasmtime_ssp_fd_write(wasm_exec_env_t exec_env, struct fd_table *curfds, return error; #ifndef BH_VPRINTF - ssize_t len = writev(fd_number(fo), (const struct iovec *)iov, (int)iovcnt); + error = blocking_op_writev(exec_env, fo->file_handle, iov, (int)iovcnt, + nwritten); #else - ssize_t len = 0; /* redirect stdout/stderr output to BH_VPRINTF function */ - if (fd_number(fo) == 1 || fd_number(fo) == 2) { + if (fo->is_stdio) { int i; - const struct iovec *iov1 = (const struct iovec *)iov; - - for (i = 0; i < (int)iovcnt; i++, iov1++) { - if (iov1->iov_len > 0 && iov1->iov_base) { + *nwritten = 0; + for (i = 0; i < (int)iovcnt; i++) { + if (iov[i].buf_len > 0 && iov[i].buf != NULL) { char format[16]; /* make up format string "%.ns" */ - snprintf(format, sizeof(format), "%%.%ds", (int)iov1->iov_len); - len += (ssize_t)os_printf(format, iov1->iov_base); + snprintf(format, sizeof(format), "%%.%ds", (int)iov[i].buf_len); + *nwritten += (size_t)os_printf(format, iov[i].buf); } } } else { - len = writev(fd_number(fo), (const struct iovec *)iov, (int)iovcnt); + error = blocking_op_writev(exec_env, fo->file_handle, iov, (int)iovcnt, + nwritten); } #endif /* end of BH_VPRINTF */ fd_object_release(exec_env, fo); - if (len < 0) - return convert_errno(errno); - *nwritten = (size_t)len; - return 0; + + return error; } __wasi_errno_t @@ -1428,65 +1149,22 @@ wasmtime_ssp_fd_advise(wasm_exec_env_t exec_env, struct fd_table *curfds, __wasi_fd_t fd, __wasi_filesize_t offset, __wasi_filesize_t len, __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; - } - struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_ADVISE, 0); if (error != 0) return error; - int ret = posix_fadvise(fd_number(fo), (off_t)offset, (off_t)len, nadvice); - fd_object_release(exec_env, fo); - if (ret != 0) - return convert_errno(ret); - return 0; -#else - // Advisory information can safely be ignored if unsupported. - 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: - break; - default: - return __WASI_EINVAL; + if (fo->type == __WASI_FILETYPE_DIRECTORY) { + fd_object_release(exec_env, fo); + return __WASI_EBADF; } - // At least check for file descriptor existence. - struct fd_table *ft = curfds; - rwlock_rdlock(&ft->lock); - struct fd_entry *fe; - __wasi_errno_t error = - fd_table_get_entry(ft, fd, __WASI_RIGHT_FD_ADVISE, 0, &fe); - rwlock_unlock(&ft->lock); + error = os_fadvise(fo->file_handle, offset, len, advice); + + fd_object_release(exec_env, fo); + return error; -#endif } __wasi_errno_t @@ -1497,34 +1175,23 @@ wasmtime_ssp_fd_allocate(wasm_exec_env_t exec_env, struct fd_table *curfds, struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_ALLOCATE, 0); - if (error != 0) + if (error != __WASI_ESUCCESS) return error; -#if CONFIG_HAS_POSIX_FALLOCATE - int ret = posix_fallocate(fd_number(fo), (off_t)offset, (off_t)len); -#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(fd_number(fo), &sb); - off_t newsize = (off_t)(offset + len); - if (ret == 0 && sb.st_size < newsize) - ret = ftruncate(fd_number(fo), newsize); -#endif + error = os_fallocate(fo->file_handle, offset, len); fd_object_release(exec_env, fo); - if (ret != 0) - return convert_errno(ret); - return 0; + + return error; } // Reads the entire contents of a symbolic link, returning the contents // in an allocated buffer. The allocated buffer is large enough to fit // at least one extra byte, so the caller may append a trailing slash to // it. This is needed by path_get(). -static char * -readlinkat_dup(int fd, const char *path, size_t *p_len) +__wasi_errno_t +readlinkat_dup(os_file_handle handle, const char *path, size_t *p_len, + char **out_buf) { char *buf = NULL; size_t len = 32; @@ -1536,7 +1203,8 @@ readlinkat_dup(int fd, const char *path, size_t *p_len) if (newbuf == NULL) { if (buf) wasm_runtime_free(buf); - return NULL; + *out_buf = NULL; + return __WASI_ENOMEM; } if (buf != NULL) { @@ -1545,15 +1213,20 @@ readlinkat_dup(int fd, const char *path, size_t *p_len) } buf = newbuf; - ssize_t ret = readlinkat(fd, path, buf, len); - if (ret < 0) { + size_t bytes_read = 0; + __wasi_errno_t error = + os_readlinkat(handle, path, buf, len, &bytes_read); + if (error != __WASI_ESUCCESS) { wasm_runtime_free(buf); - return NULL; + *out_buf = NULL; + return error; } - if ((size_t)ret + 1 < len) { - buf[ret] = '\0'; + if ((size_t)bytes_read + 1 < len) { + buf[bytes_read] = '\0'; *p_len = len; - return buf; + *out_buf = buf; + + return __WASI_ESUCCESS; } len_org = len; len *= 2; @@ -1567,7 +1240,7 @@ readlinkat_dup(int fd, const char *path, size_t *p_len) // descriptor representing the directory where the lookup needs to start // and the actual pathname string. struct path_access { - int fd; // Directory file descriptor. + os_file_handle fd; // Directory file descriptor. const char *path; // Pathname. bool follow; // Whether symbolic links should be followed. char *path_start; // Internal: pathname to free. @@ -1579,10 +1252,10 @@ struct path_access { // pathname to ensure the target path is placed underneath the // directory. static __wasi_errno_t -path_get(struct fd_table *curfds, struct path_access *pa, __wasi_fd_t fd, - __wasi_lookupflags_t flags, const char *upath, size_t upathlen, - __wasi_rights_t rights_base, __wasi_rights_t rights_inheriting, - bool needs_final_component) +path_get(wasm_exec_env_t exec_env, struct fd_table *curfds, + struct path_access *pa, __wasi_fd_t fd, __wasi_lookupflags_t flags, + const char *upath, size_t upathlen, __wasi_rights_t rights_base, + __wasi_rights_t rights_inheriting, bool needs_final_component) TRYLOCKS_EXCLUSIVE(0, pa->fd_object->refcount) { char *path = str_nullterminate(upath, upathlen); @@ -1601,7 +1274,7 @@ path_get(struct fd_table *curfds, struct path_access *pa, __wasi_fd_t fd, #if CONFIG_HAS_CAP_ENTER // Rely on the kernel to constrain access to automatically constrain // access to files stored underneath this directory. - pa->fd = fd_number(fo); + pa->fd = fo->file_handle; pa->path = pa->path_start = path; pa->follow = (flags & __WASI_LOOKUP_SYMLINK_FOLLOW) != 0; pa->fd_object = fo; @@ -1616,8 +1289,8 @@ path_get(struct fd_table *curfds, struct path_access *pa, __wasi_fd_t fd, // causes a file descriptor to be pushed, while handling ".." entries // causes an entry to be popped. Index 0 cannot be popped, as this // would imply escaping the base directory. - int fds[128]; - fds[0] = fd_number(fo); + os_file_handle fds[128]; + fds[0] = fo->file_handle; size_t curfd = 0; // Stack of pathname strings used for symlink expansion. By using a @@ -1628,8 +1301,13 @@ path_get(struct fd_table *curfds, struct path_access *pa, __wasi_fd_t fd, paths[0] = paths_start[0] = path; size_t curpath = 0; size_t expansions = 0; - char *symlink; + char *symlink = NULL; size_t symlink_len; +#ifdef BH_PLATFORM_WINDOWS +#define PATH_SEPARATORS "/\\" +#else +#define PATH_SEPARATORS "/" +#endif for (;;) { // Extract the next pathname component from 'paths[curpath]', null @@ -1637,9 +1315,10 @@ path_get(struct fd_table *curfds, struct path_access *pa, __wasi_fd_t fd, // whether the pathname component is followed by one or more // trailing slashes, as this requires it to be a directory. char *file = paths[curpath]; - char *file_end = file + strcspn(file, "/"); - paths[curpath] = file_end + strspn(file_end, "/"); - bool ends_with_slashes = *file_end == '/'; + char *file_end = file + strcspn(file, PATH_SEPARATORS); + paths[curpath] = file_end + strspn(file_end, PATH_SEPARATORS); + bool ends_with_slashes = + (*file_end != '\0' && strchr(PATH_SEPARATORS, *file_end)); *file_end = '\0'; // Test for empty pathname strings and absolute paths. @@ -1659,7 +1338,10 @@ path_get(struct fd_table *curfds, struct path_access *pa, __wasi_fd_t fd, error = __WASI_ENOTCAPABLE; goto fail; } - close(fds[curfd--]); + error = os_close(fds[curfd--], false); + + if (error != __WASI_ESUCCESS) + goto fail; } else if (curpath > 0 || *paths[curpath] != '\0' || (ends_with_slashes && !needs_final_component)) { @@ -1668,19 +1350,14 @@ path_get(struct fd_table *curfds, struct path_access *pa, __wasi_fd_t fd, // components. In other words, a pathname component that must be a // directory. First attempt to obtain a directory file descriptor // for it. - // - // Note: we don't bother to use blocking_op_openat here - // because openat with O_DIRECTORY should not block. - int newdir = -#ifdef O_SEARCH - openat(fds[curfd], file, O_SEARCH | O_DIRECTORY | O_NOFOLLOW); -#else - openat(fds[curfd], file, O_RDONLY | O_DIRECTORY | O_NOFOLLOW); -#endif - if (newdir != -1) { + os_file_handle newdir; + error = blocking_op_openat( + exec_env, fds[curfd], file, __WASI_O_DIRECTORY, 0, 0, + WASI_LIBC_ACCESS_MODE_READ_ONLY, &newdir); + if (error == __WASI_ESUCCESS) { // Success. Push it onto the directory stack. if (curfd + 1 == sizeof(fds) / sizeof(fds[0])) { - close(newdir); + os_close(newdir, false); error = __WASI_ENAMETOOLONG; goto fail; } @@ -1688,20 +1365,23 @@ path_get(struct fd_table *curfds, struct path_access *pa, __wasi_fd_t fd, } else { // Failed to open it. Attempt symlink expansion. - if (errno != ELOOP && errno != EMLINK && errno != ENOTDIR) { - error = convert_errno(errno); + if (error != __WASI_ELOOP && error != __WASI_EMLINK + && error != __WASI_ENOTDIR) { goto fail; } - symlink = readlinkat_dup(fds[curfd], file, &symlink_len); - if (symlink != NULL) + error = + readlinkat_dup(fds[curfd], file, &symlink_len, &symlink); + + if (error == __WASI_ESUCCESS) { + bh_assert(symlink != NULL); goto push_symlink; + } // readlink returns EINVAL if the path isn't a symlink. In that // case, it's more informative to return ENOTDIR. - if (errno == EINVAL) - errno = ENOTDIR; + if (error == __WASI_EINVAL) + error = __WASI_ENOTDIR; - error = convert_errno(errno); goto fail; } } @@ -1711,11 +1391,13 @@ path_get(struct fd_table *curfds, struct path_access *pa, __wasi_fd_t fd, // expansion. if (ends_with_slashes || (flags & __WASI_LOOKUP_SYMLINK_FOLLOW) != 0) { - symlink = readlinkat_dup(fds[curfd], file, &symlink_len); - if (symlink != NULL) + error = + readlinkat_dup(fds[curfd], file, &symlink_len, &symlink); + if (error == __WASI_ESUCCESS) { + bh_assert(symlink != NULL); goto push_symlink; - if (errno != EINVAL && errno != ENOENT) { - error = convert_errno(errno); + } + if (error != __WASI_EINVAL && error != __WASI_ENOENT) { goto fail; } } @@ -1792,7 +1474,7 @@ success: // Return the lease. Close all directories, except the one the caller // needs to use. for (size_t i = 1; i < curfd; ++i) - close(fds[i]); + os_close(fds[i], false); pa->fd = fds[curfd]; pa->follow = false; pa->fd_object = fo; @@ -1801,7 +1483,7 @@ success: fail: // Failure. Free all resources. for (size_t i = 1; i <= curfd; ++i) - close(fds[i]); + os_close(fds[i], false); for (size_t i = 0; i <= curpath; ++i) wasm_runtime_free(paths_start[i]); fd_object_release(NULL, fo); @@ -1810,14 +1492,14 @@ fail: } static __wasi_errno_t -path_get_nofollow(struct fd_table *curfds, struct path_access *pa, - __wasi_fd_t fd, const char *path, size_t pathlen, - __wasi_rights_t rights_base, +path_get_nofollow(wasm_exec_env_t exec_env, struct fd_table *curfds, + struct path_access *pa, __wasi_fd_t fd, const char *path, + size_t pathlen, __wasi_rights_t rights_base, __wasi_rights_t rights_inheriting, bool needs_final_component) TRYLOCKS_EXCLUSIVE(0, pa->fd_object->refcount) { __wasi_lookupflags_t flags = 0; - return path_get(curfds, pa, fd, flags, path, pathlen, rights_base, + return path_get(exec_env, curfds, pa, fd, flags, path, pathlen, rights_base, rights_inheriting, needs_final_component); } @@ -1826,8 +1508,8 @@ path_put(struct path_access *pa) UNLOCKS(pa->fd_object->refcount) { if (pa->path_start) wasm_runtime_free(pa->path_start); - if (fd_number(pa->fd_object) != pa->fd) - close(pa->fd); + if (pa->fd_object->file_handle != pa->fd) + os_close(pa->fd, false); fd_object_release(NULL, pa->fd_object); } @@ -1838,16 +1520,15 @@ wasmtime_ssp_path_create_directory(wasm_exec_env_t exec_env, { struct path_access pa; __wasi_errno_t error = - path_get_nofollow(curfds, &pa, fd, path, pathlen, + path_get_nofollow(exec_env, curfds, &pa, fd, path, pathlen, __WASI_RIGHT_PATH_CREATE_DIRECTORY, 0, true); if (error != 0) return error; - int ret = mkdirat(pa.fd, pa.path, 0777); + error = os_mkdirat(pa.fd, pa.path); path_put(&pa); - if (ret < 0) - return convert_errno(errno); - return 0; + + return error; } static bool @@ -1857,7 +1538,7 @@ validate_path(const char *path, struct fd_prestats *pt) char path_resolved[PATH_MAX], prestat_dir_resolved[PATH_MAX]; char *path_real, *prestat_dir_real; - if (!(path_real = realpath(path, path_resolved))) + if (!(path_real = os_realpath(path, path_resolved))) /* path doesn't exist, creating a link to this file is allowed: if this file is to be created in the future, WASI will strictly check whether it @@ -1867,7 +1548,7 @@ validate_path(const char *path, struct fd_prestats *pt) for (i = 0; i < pt->size; i++) { if (pt->prestats[i].dir) { if (!(prestat_dir_real = - realpath(pt->prestats[i].dir, prestat_dir_resolved))) + os_realpath(pt->prestats[i].dir, prestat_dir_resolved))) return false; if (!strncmp(path_real, prestat_dir_real, strlen(prestat_dir_real))) return true; @@ -1886,14 +1567,15 @@ wasmtime_ssp_path_link(wasm_exec_env_t exec_env, struct fd_table *curfds, { struct path_access old_pa; __wasi_errno_t error = - path_get(curfds, &old_pa, old_fd, old_flags, old_path, old_path_len, - __WASI_RIGHT_PATH_LINK_SOURCE, 0, false); + path_get(exec_env, curfds, &old_pa, old_fd, old_flags, old_path, + old_path_len, __WASI_RIGHT_PATH_LINK_SOURCE, 0, false); if (error != 0) return error; struct path_access new_pa; - error = path_get_nofollow(curfds, &new_pa, new_fd, new_path, new_path_len, - __WASI_RIGHT_PATH_LINK_TARGET, 0, true); + error = + path_get_nofollow(exec_env, curfds, &new_pa, new_fd, new_path, + new_path_len, __WASI_RIGHT_PATH_LINK_TARGET, 0, true); if (error != 0) { path_put(&old_pa); return error; @@ -1907,14 +1589,18 @@ wasmtime_ssp_path_link(wasm_exec_env_t exec_env, struct fd_table *curfds, } rwlock_unlock(&prestats->lock); - int ret = linkat(old_pa.fd, old_pa.path, new_pa.fd, new_pa.path, - old_pa.follow ? AT_SYMLINK_FOLLOW : 0); - if (ret < 0 && errno == ENOTSUP && !old_pa.follow) { + error = os_linkat(old_pa.fd, old_pa.path, new_pa.fd, new_pa.path, + old_pa.follow ? __WASI_LOOKUP_SYMLINK_FOLLOW : 0); + +#if defined(__APPLE__) + if (error == __WASI_ENOTSUP && !old_pa.follow) { // OS X doesn't allow creating hardlinks to symbolic links. // Duplicate the symbolic link instead. size_t target_len; - char *target = readlinkat_dup(old_pa.fd, old_pa.path, &target_len); - if (target != NULL) { + char *target = NULL; + error = readlinkat_dup(old_pa.fd, old_pa.path, &target_len, &target); + if (error == __WASI_ESUCCESS) { + bh_assert(target != NULL); bh_assert(target[target_len] == '\0'); rwlock_rdlock(&prestats->lock); if (!validate_path(target, prestats)) { @@ -1923,15 +1609,16 @@ wasmtime_ssp_path_link(wasm_exec_env_t exec_env, struct fd_table *curfds, return __WASI_EBADF; } rwlock_unlock(&prestats->lock); - ret = symlinkat(target, new_pa.fd, new_pa.path); + error = os_symlinkat(target, new_pa.fd, new_pa.path); wasm_runtime_free(target); } } +#endif + path_put(&old_pa); path_put(&new_pa); - if (ret < 0) - return convert_errno(errno); - return 0; + + return error; } __wasi_errno_t @@ -1954,7 +1641,11 @@ wasmtime_ssp_path_open(wasm_exec_env_t exec_env, struct fd_table *curfds, & (__WASI_RIGHT_FD_DATASYNC | __WASI_RIGHT_FD_WRITE | __WASI_RIGHT_FD_ALLOCATE | __WASI_RIGHT_FD_FILESTAT_SET_SIZE)) != 0; - int noflags = write ? read ? O_RDWR : O_WRONLY : O_RDONLY; + + wasi_libc_file_access_mode access_mode = + write ? read ? WASI_LIBC_ACCESS_MODE_READ_WRITE + : WASI_LIBC_ACCESS_MODE_WRITE_ONLY + : WASI_LIBC_ACCESS_MODE_READ_ONLY; // Which rights are needed on the directory file descriptor. __wasi_rights_t needed_base = __WASI_RIGHT_PATH_OPEN; @@ -1962,103 +1653,57 @@ wasmtime_ssp_path_open(wasm_exec_env_t exec_env, struct fd_table *curfds, // Convert open flags. if ((oflags & __WASI_O_CREAT) != 0) { - noflags |= O_CREAT; needed_base |= __WASI_RIGHT_PATH_CREATE_FILE; } - if ((oflags & __WASI_O_DIRECTORY) != 0) - noflags |= O_DIRECTORY; - if ((oflags & __WASI_O_EXCL) != 0) - noflags |= O_EXCL; if ((oflags & __WASI_O_TRUNC) != 0) { - noflags |= O_TRUNC; needed_base |= __WASI_RIGHT_PATH_FILESTAT_SET_SIZE; } // Convert file descriptor flags. - if ((fs_flags & __WASI_FDFLAG_APPEND) != 0) - noflags |= O_APPEND; - if ((fs_flags & __WASI_FDFLAG_DSYNC) != 0) { -#ifdef CONFIG_HAS_O_DSYNC - noflags |= O_DSYNC; - needed_inheriting |= __WASI_RIGHT_FD_DATASYNC; -#else - return __WASI_ENOTSUP; -#endif - } - if ((fs_flags & __WASI_FDFLAG_NONBLOCK) != 0) - noflags |= O_NONBLOCK; - if ((fs_flags & __WASI_FDFLAG_RSYNC) != 0) { -#ifdef CONFIG_HAS_O_RSYNC - noflags |= O_RSYNC; - needed_inheriting |= __WASI_RIGHT_FD_SYNC; -#else - return __WASI_ENOTSUP; -#endif - } if ((fs_flags & __WASI_FDFLAG_SYNC) != 0) { -#ifdef CONFIG_HAS_O_SYNC - noflags |= O_SYNC; needed_inheriting |= __WASI_RIGHT_FD_SYNC; -#else - return __WASI_ENOTSUP; -#endif } - if (write && (noflags & (O_APPEND | O_TRUNC)) == 0) + if ((fs_flags & __WASI_FDFLAG_RSYNC) != 0) { + needed_inheriting |= __WASI_RIGHT_FD_SYNC; + } + if ((fs_flags & __WASI_FDFLAG_DSYNC) != 0) { + needed_inheriting |= __WASI_RIGHT_FD_DATASYNC; + } + + if (write + && !((fs_flags & __WASI_FDFLAG_APPEND) || (__WASI_O_TRUNC & oflags))) needed_inheriting |= __WASI_RIGHT_FD_SEEK; struct path_access pa; - __wasi_errno_t error = - path_get(curfds, &pa, dirfd, dirflags, path, pathlen, needed_base, - needed_inheriting, (oflags & __WASI_O_CREAT) != 0); + __wasi_errno_t error = path_get( + exec_env, curfds, &pa, dirfd, dirflags, path, pathlen, needed_base, + needed_inheriting, (oflags & __WASI_O_CREAT) != 0); + if (error != 0) return error; - if (!pa.follow) - noflags |= O_NOFOLLOW; - int nfd = blocking_op_openat(exec_env, pa.fd, pa.path, noflags, 0666); - if (nfd < 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(pa.fd, pa.path, &sb, - pa.follow ? 0 : AT_SYMLINK_NOFOLLOW); - path_put(&pa); - 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 - && (noflags & (O_NOFOLLOW | O_DIRECTORY)) != 0) { - struct stat sb; - int ret = fstatat(pa.fd, pa.path, &sb, AT_SYMLINK_NOFOLLOW); - if (S_ISLNK(sb.st_mode)) { - path_put(&pa); - return __WASI_ELOOP; - } - (void)ret; - } - path_put(&pa); - // FreeBSD returns EMLINK instead of ELOOP when using O_NOFOLLOW on - // a symlink. - if (!pa.follow && openat_errno == EMLINK) - return __WASI_ELOOP; - return convert_errno(openat_errno); - } + os_file_handle handle; + error = blocking_op_openat(exec_env, pa.fd, pa.path, oflags, fs_flags, + dirflags, access_mode, &handle); + path_put(&pa); + if (error != __WASI_ESUCCESS) + return error; + // Determine the type of the new file descriptor and which rights // contradict with this type. __wasi_filetype_t type; __wasi_rights_t max_base, max_inheriting; - error = fd_determine_type_rights(nfd, &type, &max_base, &max_inheriting); - if (error != 0) { - close(nfd); + + error = fd_determine_type_rights(handle, &type, &max_base, &max_inheriting); + + if (error != __WASI_ESUCCESS) { + os_close(handle, false); return error; } - return fd_table_insert_fd(exec_env, curfds, nfd, type, + return fd_table_insert_fd(exec_env, curfds, handle, type, rights_base & max_base, rights_inheriting & max_inheriting, fd); } @@ -2091,15 +1736,13 @@ wasmtime_ssp_fd_readdir(wasm_exec_env_t exec_env, struct fd_table *curfds, // Create a directory handle if none has been opened yet. mutex_lock(&fo->directory.lock); - DIR *dp = fo->directory.handle; - if (dp == NULL) { - dp = fdopendir(fd_number(fo)); - if (dp == NULL) { + if (!os_is_dir_stream_valid(&fo->directory.handle)) { + error = os_fdopendir(fo->file_handle, &fo->directory.handle); + if (error != __WASI_ESUCCESS) { mutex_unlock(&fo->directory.lock); fd_object_release(exec_env, fo); - return convert_errno(errno); + return error; } - fo->directory.handle = dp; fo->directory.offset = __WASI_DIRCOOKIE_START; } @@ -2107,70 +1750,34 @@ wasmtime_ssp_fd_readdir(wasm_exec_env_t exec_env, struct fd_table *curfds, // the current offset. if (fo->directory.offset != cookie) { if (cookie == __WASI_DIRCOOKIE_START) - rewinddir(dp); + os_rewinddir(fo->directory.handle); else - seekdir(dp, (long)cookie); + os_seekdir(fo->directory.handle, cookie); fo->directory.offset = cookie; } *bufused = 0; while (*bufused < nbyte) { // Read the next directory entry. - errno = 0; - struct dirent *de = readdir(dp); - if (de == NULL) { + __wasi_dirent_t cde; + const char *d_name = NULL; + + error = os_readdir(fo->directory.handle, &cde, &d_name); + if (d_name == NULL) { mutex_unlock(&fo->directory.lock); fd_object_release(exec_env, fo); - return errno == 0 || *bufused > 0 ? 0 : convert_errno(errno); - } - fo->directory.offset = (__wasi_dircookie_t)telldir(dp); - // Craft a directory entry and copy that back. - size_t namlen = strlen(de->d_name); - __wasi_dirent_t cde = { - .d_next = fo->directory.offset, -#if CONFIG_HAS_D_INO - .d_ino = de->d_ino, -#else - .d_ino = 0, -#endif - .d_namlen = (uint32)namlen, - }; - switch (de->d_type) { - case DT_BLK: - cde.d_type = __WASI_FILETYPE_BLOCK_DEVICE; - break; - case DT_CHR: - cde.d_type = __WASI_FILETYPE_CHARACTER_DEVICE; - break; - case DT_DIR: - cde.d_type = __WASI_FILETYPE_DIRECTORY; - break; - case DT_FIFO: - cde.d_type = __WASI_FILETYPE_SOCKET_STREAM; - break; - case DT_LNK: - cde.d_type = __WASI_FILETYPE_SYMBOLIC_LINK; - break; - case DT_REG: - cde.d_type = __WASI_FILETYPE_REGULAR_FILE; - break; -#ifdef DT_SOCK - case DT_SOCK: - // Technically not correct, but good enough. - cde.d_type = __WASI_FILETYPE_SOCKET_STREAM; - break; -#endif - default: - cde.d_type = __WASI_FILETYPE_UNKNOWN; - break; + return *bufused > 0 ? __WASI_ESUCCESS : error; } + + fo->directory.offset = cde.d_next; + fd_readdir_put(buf, nbyte, bufused, &cde, sizeof(cde)); - fd_readdir_put(buf, nbyte, bufused, de->d_name, namlen); + fd_readdir_put(buf, nbyte, bufused, d_name, cde.d_namlen); } mutex_unlock(&fo->directory.lock); fd_object_release(exec_env, fo); - return 0; + return __WASI_ESUCCESS; } __wasi_errno_t @@ -2179,21 +1786,18 @@ wasmtime_ssp_path_readlink(wasm_exec_env_t exec_env, struct fd_table *curfds, char *buf, size_t bufsize, size_t *bufused) { struct path_access pa; - __wasi_errno_t error = path_get_nofollow( - curfds, &pa, fd, path, pathlen, __WASI_RIGHT_PATH_READLINK, 0, false); + __wasi_errno_t error = + path_get_nofollow(exec_env, curfds, &pa, fd, path, pathlen, + __WASI_RIGHT_PATH_READLINK, 0, false); + if (error != 0) return error; - // 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(pa.fd, pa.path, bufsize == 0 ? fakebuf : buf, - bufsize == 0 ? sizeof(fakebuf) : bufsize); + error = os_readlinkat(pa.fd, pa.path, buf, bufsize, bufused); + path_put(&pa); - if (len < 0) - return convert_errno(errno); - *bufused = (size_t)len < bufsize ? (size_t)len : bufsize; - return 0; + + return error; } __wasi_errno_t @@ -2203,42 +1807,27 @@ wasmtime_ssp_path_rename(wasm_exec_env_t exec_env, struct fd_table *curfds, const char *new_path, size_t new_path_len) { struct path_access old_pa; - __wasi_errno_t error = - path_get_nofollow(curfds, &old_pa, old_fd, old_path, old_path_len, - __WASI_RIGHT_PATH_RENAME_SOURCE, 0, true); + __wasi_errno_t error = path_get_nofollow( + exec_env, curfds, &old_pa, old_fd, old_path, old_path_len, + __WASI_RIGHT_PATH_RENAME_SOURCE, 0, true); if (error != 0) return error; struct path_access new_pa; - error = path_get_nofollow(curfds, &new_pa, new_fd, new_path, new_path_len, - __WASI_RIGHT_PATH_RENAME_TARGET, 0, true); + error = path_get_nofollow(exec_env, curfds, &new_pa, new_fd, new_path, + new_path_len, __WASI_RIGHT_PATH_RENAME_TARGET, 0, + true); if (error != 0) { path_put(&old_pa); return error; } - int ret = renameat(old_pa.fd, old_pa.path, new_pa.fd, new_pa.path); + error = os_renameat(old_pa.fd, old_pa.path, new_pa.fd, new_pa.path); + path_put(&old_pa); path_put(&new_pa); - if (ret < 0) { - return convert_errno(errno); - } - return 0; -} -// Converts a POSIX stat structure to a CloudABI filestat structure. -static void -convert_stat(const struct stat *in, __wasi_filestat_t *out) -{ - *out = (__wasi_filestat_t){ - .st_dev = in->st_dev, - .st_ino = in->st_ino, - .st_nlink = (__wasi_linkcount_t)in->st_nlink, - .st_size = (__wasi_filesize_t)in->st_size, - .st_atim = convert_timespec(&in->st_atim), - .st_mtim = convert_timespec(&in->st_mtim), - .st_ctim = convert_timespec(&in->st_ctim), - }; + return error; } __wasi_errno_t @@ -2248,24 +1837,15 @@ wasmtime_ssp_fd_filestat_get(wasm_exec_env_t exec_env, struct fd_table *curfds, struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_FILESTAT_GET, 0); + if (error != 0) return error; - int ret; - switch (fo->type) { - default: - { - struct stat sb; - ret = fstat(fd_number(fo), &sb); - convert_stat(&sb, buf); - break; - } - } - buf->st_filetype = fo->type; + error = os_fstat(fo->file_handle, buf); + fd_object_release(exec_env, fo); - if (ret < 0) - return convert_errno(errno); - return 0; + + return error; } static void @@ -2283,34 +1863,6 @@ convert_timestamp(__wasi_timestamp_t in, struct timespec *out) 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 wasmtime_ssp_fd_filestat_set_size(wasm_exec_env_t exec_env, struct fd_table *curfds, __wasi_fd_t fd, @@ -2319,14 +1871,14 @@ wasmtime_ssp_fd_filestat_set_size(wasm_exec_env_t exec_env, struct fd_object *fo; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_FILESTAT_SET_SIZE, 0); + if (error != 0) return error; - int ret = ftruncate(fd_number(fo), (off_t)st_size); + error = os_ftruncate(fo->file_handle, st_size); fd_object_release(exec_env, fo); - if (ret < 0) - return convert_errno(errno); - return 0; + + return error; } __wasi_errno_t @@ -2339,7 +1891,13 @@ wasmtime_ssp_fd_filestat_set_times(wasm_exec_env_t exec_env, if ((fstflags & ~(__WASI_FILESTAT_SET_ATIM | __WASI_FILESTAT_SET_ATIM_NOW | __WASI_FILESTAT_SET_MTIM | __WASI_FILESTAT_SET_MTIM_NOW)) - != 0) + != 0 + || (fstflags + & (__WASI_FILESTAT_SET_ATIM | __WASI_FILESTAT_SET_ATIM_NOW)) + == (__WASI_FILESTAT_SET_ATIM | __WASI_FILESTAT_SET_ATIM_NOW) + || (fstflags + & (__WASI_FILESTAT_SET_MTIM | __WASI_FILESTAT_SET_MTIM_NOW)) + == (__WASI_FILESTAT_SET_MTIM | __WASI_FILESTAT_SET_MTIM_NOW)) return __WASI_EINVAL; struct fd_object *fo; @@ -2348,14 +1906,11 @@ wasmtime_ssp_fd_filestat_set_times(wasm_exec_env_t exec_env, if (error != 0) return error; - struct timespec ts[2]; - convert_utimens_arguments(st_atim, st_mtim, fstflags, ts); - int ret = futimens(fd_number(fo), ts); + error = os_futimens(fo->file_handle, st_atim, st_mtim, fstflags); fd_object_release(exec_env, fo); - if (ret < 0) - return convert_errno(errno); - return 0; + + return error; } __wasi_errno_t @@ -2365,35 +1920,18 @@ wasmtime_ssp_path_filestat_get(wasm_exec_env_t exec_env, size_t pathlen, __wasi_filestat_t *buf) { struct path_access pa; - __wasi_errno_t error = path_get(curfds, &pa, fd, flags, path, pathlen, - __WASI_RIGHT_PATH_FILESTAT_GET, 0, false); + __wasi_errno_t error = + path_get(exec_env, curfds, &pa, fd, flags, path, pathlen, + __WASI_RIGHT_PATH_FILESTAT_GET, 0, false); if (error != 0) return error; - struct stat sb; - int ret = fstatat(pa.fd, pa.path, &sb, pa.follow ? 0 : AT_SYMLINK_NOFOLLOW); - path_put(&pa); - if (ret < 0) - return convert_errno(errno); - convert_stat(&sb, buf); + error = os_fstatat(pa.fd, pa.path, buf, + pa.follow ? __WASI_LOOKUP_SYMLINK_FOLLOW : 0); - // Convert the file type. In the case of sockets there is no way we - // can easily determine the exact socket type. - if (S_ISBLK(sb.st_mode)) - buf->st_filetype = __WASI_FILETYPE_BLOCK_DEVICE; - else if (S_ISCHR(sb.st_mode)) - buf->st_filetype = __WASI_FILETYPE_CHARACTER_DEVICE; - else if (S_ISDIR(sb.st_mode)) - buf->st_filetype = __WASI_FILETYPE_DIRECTORY; - else if (S_ISFIFO(sb.st_mode)) - buf->st_filetype = __WASI_FILETYPE_SOCKET_STREAM; - else if (S_ISLNK(sb.st_mode)) - buf->st_filetype = __WASI_FILETYPE_SYMBOLIC_LINK; - else if (S_ISREG(sb.st_mode)) - buf->st_filetype = __WASI_FILETYPE_REGULAR_FILE; - else if (S_ISSOCK(sb.st_mode)) - buf->st_filetype = __WASI_FILETYPE_SOCKET_STREAM; - return 0; + path_put(&pa); + + return error; } __wasi_errno_t @@ -2419,20 +1957,16 @@ wasmtime_ssp_path_filestat_set_times(wasm_exec_env_t exec_env, struct path_access pa; __wasi_errno_t error = - path_get(curfds, &pa, fd, flags, path, pathlen, + path_get(exec_env, curfds, &pa, fd, flags, path, pathlen, __WASI_RIGHT_PATH_FILESTAT_SET_TIMES, 0, false); if (error != 0) return error; - struct timespec ts[2]; - convert_utimens_arguments(st_atim, st_mtim, fstflags, ts); - int ret = - utimensat(pa.fd, pa.path, ts, pa.follow ? 0 : AT_SYMLINK_NOFOLLOW); + error = os_utimensat(pa.fd, pa.path, st_atim, st_mtim, fstflags, + pa.follow ? __WASI_LOOKUP_SYMLINK_FOLLOW : 0); path_put(&pa); - if (ret < 0) - return convert_errno(errno); - return 0; + return error; } __wasi_errno_t @@ -2447,7 +1981,7 @@ wasmtime_ssp_path_symlink(wasm_exec_env_t exec_env, struct fd_table *curfds, struct path_access pa; __wasi_errno_t error = - path_get_nofollow(curfds, &pa, fd, new_path, new_path_len, + path_get_nofollow(exec_env, curfds, &pa, fd, new_path, new_path_len, __WASI_RIGHT_PATH_SYMLINK, 0, true); if (error != 0) { wasm_runtime_free(target); @@ -2462,12 +1996,12 @@ wasmtime_ssp_path_symlink(wasm_exec_env_t exec_env, struct fd_table *curfds, } rwlock_unlock(&prestats->lock); - int ret = symlinkat(target, pa.fd, pa.path); + error = os_symlinkat(target, pa.fd, pa.path); + path_put(&pa); wasm_runtime_free(target); - if (ret < 0) - return convert_errno(errno); - return 0; + + return error; } __wasi_errno_t @@ -2475,33 +2009,17 @@ wasmtime_ssp_path_unlink_file(wasm_exec_env_t exec_env, struct fd_table *curfds, __wasi_fd_t fd, const char *path, size_t pathlen) { struct path_access pa; - __wasi_errno_t error = path_get_nofollow( - curfds, &pa, fd, path, pathlen, __WASI_RIGHT_PATH_UNLINK_FILE, 0, true); - if (error != 0) + __wasi_errno_t error = + path_get_nofollow(exec_env, curfds, &pa, fd, path, pathlen, + __WASI_RIGHT_PATH_UNLINK_FILE, 0, true); + if (error != __WASI_ESUCCESS) return error; - int ret = unlinkat(pa.fd, pa.path, 0); -#ifndef __linux__ - // 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 (ret < 0 && errno == EPERM) { - struct stat statbuf; - if (fstatat(pa.fd, pa.path, &statbuf, AT_SYMLINK_NOFOLLOW) == 0 - && S_ISDIR(statbuf.st_mode)) { - errno = EISDIR; - } - } -#endif + error = os_unlinkat(pa.fd, pa.path, false); + path_put(&pa); - if (ret < 0) { - return convert_errno(errno); - } - return 0; + + return error; } __wasi_errno_t @@ -2511,24 +2029,16 @@ wasmtime_ssp_path_remove_directory(wasm_exec_env_t exec_env, { struct path_access pa; __wasi_errno_t error = - path_get_nofollow(curfds, &pa, fd, path, pathlen, + path_get_nofollow(exec_env, curfds, &pa, fd, path, pathlen, __WASI_RIGHT_PATH_REMOVE_DIRECTORY, 0, true); if (error != 0) return error; - int ret = unlinkat(pa.fd, pa.path, AT_REMOVEDIR); -#ifndef __linux__ - // POSIX permits either EEXIST or ENOTEMPTY when the directory is not empty. - // Map it to ENOTEMPTY. - if (ret < 0 && errno == EEXIST) { - errno = ENOTEMPTY; - } -#endif + error = os_unlinkat(pa.fd, pa.path, true); + path_put(&pa); - if (ret < 0) { - return convert_errno(errno); - } - return 0; + + return error; } __wasi_errno_t @@ -2537,6 +2047,9 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds, size_t nsubscriptions, size_t *nevents) NO_LOCK_ANALYSIS { +#ifdef BH_PLATFORM_WINDOWS + return __WASI_ENOSYS; +#else // Sleeping. if (nsubscriptions == 1 && in[0].u.type == __WASI_EVENTTYPE_CLOCK) { out[0] = (__wasi_event_t){ @@ -2545,7 +2058,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds, }; #if CONFIG_HAS_CLOCK_NANOSLEEP clockid_t clock_id; - if (convert_clockid(in[0].u.u.clock.clock_id, &clock_id)) { + if (wasi_clockid_to_clockid(in[0].u.u.clock.clock_id, &clock_id)) { struct timespec ts; convert_timestamp(in[0].u.u.clock.timeout, &ts); int ret = clock_nanosleep( @@ -2652,7 +2165,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds, if (error == 0) { // Proper file descriptor on which we can poll(). pfds[i] = (struct pollfd){ - .fd = fd_number(fos[i]), + .fd = fos[i]->file_handle, .events = s->u.type == __WASI_EVENTTYPE_FD_READ ? POLLIN : POLLOUT, @@ -2708,6 +2221,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds, else { timeout = -1; } + int ret = poll(pfds, nsubscriptions, timeout); __wasi_errno_t error = 0; @@ -2728,7 +2242,7 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds, __wasi_filesize_t nbytes = 0; if (in[i].u.type == __WASI_EVENTTYPE_FD_READ) { int l; - if (ioctl(fd_number(fos[i]), FIONREAD, &l) == 0) + if (ioctl(fos[i]->file_handle, FIONREAD, &l) == 0) nbytes = (__wasi_filesize_t)l; } if ((pfds[i].revents & POLLNVAL) != 0) { @@ -2784,13 +2298,13 @@ wasmtime_ssp_poll_oneoff(wasm_exec_env_t exec_env, struct fd_table *curfds, wasm_runtime_free(fos); wasm_runtime_free(pfds); return error; +#endif } __wasi_errno_t wasmtime_ssp_random_get(void *buf, size_t nbyte) { - random_buf(buf, nbyte); - return 0; + return random_buf(buf, nbyte); } __wasi_errno_t @@ -2801,7 +2315,7 @@ wasi_ssp_sock_accept(wasm_exec_env_t exec_env, struct fd_table *curfds, __wasi_filetype_t wasi_type; __wasi_rights_t max_base, max_inheriting; struct fd_object *fo; - bh_socket_t new_sock = -1; + bh_socket_t new_sock = os_get_invalid_handle(); int ret; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_ACCEPT, 0); @@ -2809,7 +2323,7 @@ wasi_ssp_sock_accept(wasm_exec_env_t exec_env, struct fd_table *curfds, goto fail; } - ret = blocking_op_socket_accept(exec_env, fd_number(fo), &new_sock, NULL, + ret = blocking_op_socket_accept(exec_env, fo->file_handle, &new_sock, NULL, NULL); fd_object_release(exec_env, fo); if (BHT_OK != ret) { @@ -2827,14 +2341,14 @@ wasi_ssp_sock_accept(wasm_exec_env_t exec_env, struct fd_table *curfds, max_inheriting, fd_new); if (error != __WASI_ESUCCESS) { /* released in fd_table_insert_fd() */ - new_sock = -1; + new_sock = os_get_invalid_handle(); goto fail; } return __WASI_ESUCCESS; fail: - if (-1 != new_sock) { + if (os_is_handle_valid(&new_sock)) { os_socket_close(new_sock); } return error; @@ -2853,7 +2367,7 @@ wasi_ssp_sock_addr_local(wasm_exec_env_t exec_env, struct fd_table *curfds, if (error != __WASI_ESUCCESS) return error; - ret = os_socket_addr_local(fd_number(fo), &bh_addr); + ret = os_socket_addr_local(fo->file_handle, &bh_addr); fd_object_release(exec_env, fo); if (ret != BHT_OK) { return convert_errno(errno); @@ -2877,7 +2391,7 @@ wasi_ssp_sock_addr_remote(wasm_exec_env_t exec_env, struct fd_table *curfds, if (error != __WASI_ESUCCESS) return error; - ret = os_socket_addr_remote(fd_number(fo), &bh_addr); + ret = os_socket_addr_remote(fo->file_handle, &bh_addr); fd_object_release(exec_env, fo); if (ret != BHT_OK) { return convert_errno(errno); @@ -2940,7 +2454,7 @@ wasi_ssp_sock_bind(wasm_exec_env_t exec_env, struct fd_table *curfds, if (error != __WASI_ESUCCESS) return error; - ret = os_socket_bind(fd_number(fo), buf, &port); + ret = os_socket_bind(fo->file_handle, buf, &port); fd_object_release(exec_env, fo); if (BHT_OK != ret) { return convert_errno(errno); @@ -3023,7 +2537,7 @@ wasi_ssp_sock_connect(wasm_exec_env_t exec_env, struct fd_table *curfds, if (error != __WASI_ESUCCESS) return error; - ret = blocking_op_socket_connect(exec_env, fd_number(fo), buf, + ret = blocking_op_socket_connect(exec_env, fo->file_handle, buf, addr->kind == IPv4 ? addr->addr.ip4.port : addr->addr.ip6.port); fd_object_release(exec_env, fo); @@ -3040,21 +2554,18 @@ wasi_ssp_sock_get_recv_buf_size(wasm_exec_env_t exec_env, __wasi_size_t *size) { struct fd_object *fo; - int ret; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); if (error != __WASI_ESUCCESS) return error; - int optval; - socklen_t optlen = sizeof(optval); - - ret = getsockopt(fd_number(fo), SOL_SOCKET, SO_RCVBUF, &optval, &optlen); + size_t bufsize = 0; + int ret = os_socket_get_recv_buf_size(fo->file_handle, &bufsize); fd_object_release(exec_env, fo); if (BHT_OK != ret) { return convert_errno(errno); } - *size = optval; + *size = (__wasi_size_t)bufsize; return __WASI_ESUCCESS; } @@ -3063,23 +2574,20 @@ __wasi_errno_t wasi_ssp_sock_get_reuse_addr(wasm_exec_env_t exec_env, struct fd_table *curfds, __wasi_fd_t fd, uint8_t *reuse) { - struct fd_object *fo; - int ret; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); if (error != __WASI_ESUCCESS) return error; - int optval; - socklen_t optlen = sizeof(optval); + bool enabled = false; - ret = getsockopt(fd_number(fo), SOL_SOCKET, SO_REUSEADDR, &optval, &optlen); + int ret = os_socket_get_reuse_addr(fo->file_handle, &enabled); fd_object_release(exec_env, fo); if (BHT_OK != ret) { return convert_errno(errno); } - *reuse = optval; + *reuse = (uint8_t)enabled; return __WASI_ESUCCESS; } @@ -3089,28 +2597,19 @@ wasi_ssp_sock_get_reuse_port(wasm_exec_env_t exec_env, struct fd_table *curfds, __wasi_fd_t fd, uint8_t *reuse) { struct fd_object *fo; - int ret; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); if (error != __WASI_ESUCCESS) return error; - int optval; - socklen_t optlen = sizeof(optval); - -#if defined(SO_REUSEPORT) /* NuttX doesn't have SO_REUSEPORT */ - ret = getsockopt(fd_number(fo), SOL_SOCKET, SO_REUSEPORT, &optval, &optlen); -#else - errno = ENOTSUP; - ret = BHT_ERROR; - optval = 0; -#endif /* defined(SO_REUSEPORT) */ + bool enabled = false; + int ret = os_socket_get_reuse_port(fo->file_handle, &enabled); fd_object_release(exec_env, fo); if (BHT_OK != ret) { return convert_errno(errno); } - *reuse = optval; + *reuse = (uint8_t)enabled; return __WASI_ESUCCESS; } @@ -3121,21 +2620,19 @@ wasi_ssp_sock_get_send_buf_size(wasm_exec_env_t exec_env, __wasi_size_t *size) { struct fd_object *fo; - int ret; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); if (error != __WASI_ESUCCESS) return error; - int optval; - socklen_t optlen = sizeof(optval); + size_t bufsize = 0; + int ret = os_socket_get_send_buf_size(fo->file_handle, &bufsize); - ret = getsockopt(fd_number(fo), SOL_SOCKET, SO_SNDBUF, &optval, &optlen); fd_object_release(exec_env, fo); if (BHT_OK != ret) { return convert_errno(errno); } - *size = optval; + *size = (__wasi_size_t)bufsize; return __WASI_ESUCCESS; } @@ -3151,7 +2648,7 @@ wasi_ssp_sock_listen(wasm_exec_env_t exec_env, struct fd_table *curfds, if (error != __WASI_ESUCCESS) return error; - ret = os_socket_listen(fd_number(fo), backlog); + ret = os_socket_listen(fo->file_handle, backlog); fd_object_release(exec_env, fo); if (BHT_OK != ret) { return convert_errno(errno); @@ -3169,8 +2666,8 @@ wasi_ssp_sock_open(wasm_exec_env_t exec_env, struct fd_table *curfds, bool is_tcp = SOCKET_DGRAM == socktype ? false : true; bool is_ipv4 = INET6 == af ? false : true; int ret; - __wasi_filetype_t wasi_type; - __wasi_rights_t max_base, max_inheriting; + __wasi_filetype_t wasi_type = __WASI_FILETYPE_UNKNOWN; + __wasi_rights_t max_base = 0, max_inheriting = 0; __wasi_errno_t error; (void)poolfd; @@ -3210,15 +2707,12 @@ wasi_ssp_sock_set_recv_buf_size(wasm_exec_env_t exec_env, __wasi_size_t size) { struct fd_object *fo; - int ret; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); if (error != __WASI_ESUCCESS) return error; - int optval = size; + int ret = os_socket_set_recv_buf_size(fo->file_handle, size); - ret = setsockopt(fd_number(fo), SOL_SOCKET, SO_RCVBUF, &optval, - sizeof(optval)); fd_object_release(exec_env, fo); if (BHT_OK != ret) { return convert_errno(errno); @@ -3232,15 +2726,12 @@ wasi_ssp_sock_set_reuse_addr(wasm_exec_env_t exec_env, struct fd_table *curfds, __wasi_fd_t fd, uint8_t reuse) { struct fd_object *fo; - int ret; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); if (error != __WASI_ESUCCESS) return error; - int optval = reuse; + int ret = os_socket_set_reuse_addr(fo->file_handle, (bool)reuse); - ret = setsockopt(fd_number(fo), SOL_SOCKET, SO_REUSEADDR, &optval, - sizeof(optval)); fd_object_release(exec_env, fo); if (BHT_OK != ret) { return convert_errno(errno); @@ -3254,20 +2745,11 @@ wasi_ssp_sock_set_reuse_port(wasm_exec_env_t exec_env, struct fd_table *curfds, __wasi_fd_t fd, uint8_t reuse) { struct fd_object *fo; - int ret; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); if (error != __WASI_ESUCCESS) return error; - int optval = reuse; - -#if defined(SO_REUSEPORT) /* NuttX doesn't have SO_REUSEPORT */ - ret = setsockopt(fd_number(fo), SOL_SOCKET, SO_REUSEPORT, &optval, - sizeof(optval)); -#else - errno = ENOTSUP; - ret = BHT_ERROR; -#endif /* defined(SO_REUSEPORT) */ + int ret = os_socket_set_reuse_port(fo->file_handle, (bool)reuse); fd_object_release(exec_env, fo); if (BHT_OK != ret) { @@ -3283,15 +2765,11 @@ wasi_ssp_sock_set_send_buf_size(wasm_exec_env_t exec_env, __wasi_size_t size) { struct fd_object *fo; - int ret; __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); if (error != __WASI_ESUCCESS) return error; - int optval = size; - - ret = setsockopt(fd_number(fo), SOL_SOCKET, SO_SNDBUF, &optval, - sizeof(optval)); + int ret = os_socket_set_send_buf_size(fo->file_handle, size); fd_object_release(exec_env, fo); if (BHT_OK != ret) { @@ -3328,8 +2806,8 @@ wasmtime_ssp_sock_recv_from(wasm_exec_env_t exec_env, struct fd_table *curfds, return error; } - ret = blocking_op_socket_recv_from(exec_env, fd_number(fo), buf, buf_len, 0, - &sockaddr); + ret = blocking_op_socket_recv_from(exec_env, fo->file_handle, buf, buf_len, + 0, &sockaddr); fd_object_release(exec_env, fo); if (-1 == ret) { return convert_errno(errno); @@ -3355,7 +2833,7 @@ wasmtime_ssp_sock_send(wasm_exec_env_t exec_env, struct fd_table *curfds, return error; } - ret = os_socket_send(fd_number(fo), buf, buf_len); + ret = os_socket_send(fo->file_handle, buf, buf_len); fd_object_release(exec_env, fo); if (-1 == ret) { return convert_errno(errno); @@ -3393,7 +2871,7 @@ wasmtime_ssp_sock_send_to(wasm_exec_env_t exec_env, struct fd_table *curfds, wasi_addr_to_bh_sockaddr(dest_addr, &sockaddr); - ret = blocking_op_socket_send_to(exec_env, fd_number(fo), buf, buf_len, 0, + ret = blocking_op_socket_send_to(exec_env, fo->file_handle, buf, buf_len, 0, &sockaddr); fd_object_release(exec_env, fo); if (-1 == ret) { @@ -3410,25 +2888,26 @@ wasmtime_ssp_sock_shutdown(wasm_exec_env_t exec_env, struct fd_table *curfds, { struct fd_object *fo; __wasi_errno_t error; - int ret; error = fd_object_get(curfds, &fo, sock, 0, 0); if (error != 0) return error; - ret = os_socket_shutdown(fd_number(fo)); + error = os_socket_shutdown(fo->file_handle); fd_object_release(exec_env, fo); - if (BHT_OK != ret) - return convert_errno(errno); - return __WASI_ESUCCESS; + return error; } __wasi_errno_t wasmtime_ssp_sched_yield(void) { +#ifdef BH_PLATFORM_WINDOWS + SwitchToThread(); +#else if (sched_yield() < 0) return convert_errno(errno); +#endif return 0; } @@ -3457,14 +2936,14 @@ wasmtime_ssp_args_sizes_get(struct argv_environ_values *argv_environ, __wasi_errno_t wasmtime_ssp_environ_get(struct argv_environ_values *argv_environ, - char **environ, char *environ_buf) + char **environs, char *environ_buf) { for (size_t i = 0; i < argv_environ->environ_count; ++i) { - environ[i] = + environs[i] = environ_buf + (argv_environ->environ_list[i] - argv_environ->environ_buf); } - environ[argv_environ->environ_count] = NULL; + environs[argv_environ->environ_count] = NULL; bh_memcpy_s(environ_buf, (uint32)argv_environ->environ_buf_size, argv_environ->environ_buf, (uint32)argv_environ->environ_buf_size); @@ -3580,12 +3059,6 @@ addr_pool_insert(struct addr_pool *addr_pool, const char *addr, uint8 mask) return true; } -static inline size_t -min(size_t a, size_t b) -{ - return a > b ? b : a; -} - static void init_address_mask(uint8_t *buf, size_t buflen, size_t mask) { @@ -3714,7 +3187,7 @@ addr_pool_destroy(struct addr_pool *addr_pool) error = fd_object_get(curfds, &fo, sock, 0, 0); \ if (error != 0) \ return error; \ - ret = os_socket_##FUNC_NAME(fd_number(fo), option); \ + ret = os_socket_##FUNC_NAME(fo->file_handle, option); \ fd_object_release(exec_env, fo); \ if (BHT_OK != ret) \ return convert_errno(errno); \ @@ -3768,7 +3241,7 @@ wasmtime_ssp_sock_set_linger(wasm_exec_env_t exec_env, struct fd_table *curfds, if (error != 0) return error; - ret = os_socket_set_linger(fd_number(fo), is_enabled, linger_s); + ret = os_socket_set_linger(fo->file_handle, is_enabled, linger_s); fd_object_release(exec_env, fo); if (BHT_OK != ret) return convert_errno(errno); @@ -3786,7 +3259,7 @@ wasmtime_ssp_sock_get_linger(wasm_exec_env_t exec_env, struct fd_table *curfds, if (error != 0) return error; - ret = os_socket_get_linger(fd_number(fo), is_enabled, linger_s); + ret = os_socket_get_linger(fo->file_handle, is_enabled, linger_s); fd_object_release(exec_env, fo); if (BHT_OK != ret) return convert_errno(errno); @@ -3812,7 +3285,7 @@ wasmtime_ssp_sock_set_ip_add_membership(wasm_exec_env_t exec_env, wasi_addr_ip_to_bh_ip_addr_buffer(imr_multiaddr, &addr_info); is_ipv6 = imr_multiaddr->kind == IPv6; - ret = os_socket_set_ip_add_membership(fd_number(fo), &addr_info, + ret = os_socket_set_ip_add_membership(fo->file_handle, &addr_info, imr_interface, is_ipv6); fd_object_release(exec_env, fo); if (BHT_OK != ret) @@ -3838,7 +3311,7 @@ wasmtime_ssp_sock_set_ip_drop_membership(wasm_exec_env_t exec_env, wasi_addr_ip_to_bh_ip_addr_buffer(imr_multiaddr, &addr_info); is_ipv6 = imr_multiaddr->kind == IPv6; - ret = os_socket_set_ip_drop_membership(fd_number(fo), &addr_info, + ret = os_socket_set_ip_drop_membership(fo->file_handle, &addr_info, imr_interface, is_ipv6); fd_object_release(exec_env, fo); if (BHT_OK != ret) @@ -3859,7 +3332,7 @@ wasmtime_ssp_sock_set_ip_multicast_loop(wasm_exec_env_t exec_env, if (error != 0) return error; - ret = os_socket_set_ip_multicast_loop(fd_number(fo), ipv6, is_enabled); + ret = os_socket_set_ip_multicast_loop(fo->file_handle, ipv6, is_enabled); fd_object_release(exec_env, fo); if (BHT_OK != ret) return convert_errno(errno); @@ -3879,7 +3352,7 @@ wasmtime_ssp_sock_get_ip_multicast_loop(wasm_exec_env_t exec_env, if (error != 0) return error; - ret = os_socket_get_ip_multicast_loop(fd_number(fo), ipv6, is_enabled); + ret = os_socket_get_ip_multicast_loop(fo->file_handle, ipv6, is_enabled); fd_object_release(exec_env, fo); if (BHT_OK != ret) return convert_errno(errno); diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h index 7a593390a..75ed59784 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h +++ b/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 diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c index 01a1dab3a..29c50dd87 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c +++ b/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 #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 +#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 ((size_t)read(urandom, buf, len) != len) { - os_printf("Short read on /dev/urandom\n"); - abort(); + if (pthread_ret != 0) + return convert_errno(pthread_ret); + + 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; + } } } diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.h index 23c2da4db..7cd94d74d 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.h +++ b/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 diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h index a69d6ca38..bcc750c26 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h @@ -26,8 +26,8 @@ // On Linux, prefer to use getrandom, though it isn't available in // GLIBC before 2.25. -#if (defined(__linux__) || defined(ESP_PLATFORM)) \ - && (!defined(__GLIBC__) || __GLIBC__ > 2 \ +#if (defined(__linux__) || defined(ESP_PLATFORM) || defined(__COSMOPOLITAN__)) \ + && (!defined(__GLIBC__) || __GLIBC__ > 2 \ || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25)) #define CONFIG_HAS_GETRANDOM 1 #else @@ -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 diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.c b/core/iwasm/libraries/thread-mgr/thread_manager.c index ac00b5124..9f605ae48 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.c +++ b/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -798,10 +798,25 @@ wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env) return NULL; } + if (!(new_module_inst = wasm_runtime_instantiate_internal( + module, module_inst, exec_env, stack_size, 0, NULL, 0))) { + return NULL; + } + + /* Set custom_data to new module instance */ + wasm_runtime_set_custom_data_internal( + new_module_inst, wasm_runtime_get_custom_data(module_inst)); + + wasm_native_inherit_contexts(new_module_inst, module_inst); + + if (!(wasm_cluster_dup_c_api_imports(new_module_inst, module_inst))) { + goto fail1; + } + cluster_lock_thread_list(cluster, exec_env); if (cluster->has_exception || cluster->processing) { - goto fail1; + goto fail2; } #if WASM_ENABLE_INTERP != 0 @@ -818,21 +833,11 @@ wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env) } #endif - if (!(new_module_inst = wasm_runtime_instantiate_internal( - module, module_inst, exec_env, stack_size, 0, NULL, 0))) { - goto fail1; - } - - /* Set custom_data to new module instance */ - wasm_runtime_set_custom_data_internal( - new_module_inst, wasm_runtime_get_custom_data(module_inst)); - - wasm_native_inherit_contexts(new_module_inst, module_inst); - new_exec_env = wasm_exec_env_create_internal(new_module_inst, exec_env->wasm_stack_size); - if (!new_exec_env) + if (!new_exec_env) { goto fail2; + } if (!allocate_aux_stack(exec_env, &aux_stack_start, &aux_stack_size)) { LOG_ERROR("thread manager error: " @@ -850,8 +855,9 @@ wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env) thread_state_lock as the thread list has been locked */ new_exec_env->suspend_flags.flags = exec_env->suspend_flags.flags; - if (!wasm_cluster_add_exec_env(cluster, new_exec_env)) + if (!wasm_cluster_add_exec_env(cluster, new_exec_env)) { goto fail4; + } cluster_unlock_thread_list(cluster); @@ -863,9 +869,9 @@ fail4: fail3: wasm_exec_env_destroy_internal(new_exec_env); fail2: - wasm_runtime_deinstantiate_internal(new_module_inst, true); -fail1: cluster_unlock_thread_list(cluster); +fail1: + wasm_runtime_deinstantiate_internal(new_module_inst, true); return NULL; } @@ -1801,3 +1807,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); + cluster_lock_thread_list(cluster, exec_env); +} + +void +wasm_cluster_traverse_unlock(WASMExecEnv *exec_env) +{ + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + bh_assert(cluster); + cluster_unlock_thread_list(cluster); +} diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.h b/core/iwasm/libraries/thread-mgr/thread_manager.h index 68d8915b9..9257fe881 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.h +++ b/core/iwasm/libraries/thread-mgr/thread_manager.h @@ -240,6 +240,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 diff --git a/core/shared/mem-alloc/ems/ems_alloc.c b/core/shared/mem-alloc/ems/ems_alloc.c index a29539dd5..0e2c4da7c 100644 --- a/core/shared/mem-alloc/ems/ems_alloc.c +++ b/core/shared/mem-alloc/ems/ems_alloc.c @@ -24,19 +24,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) { @@ -67,9 +71,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; } @@ -80,9 +86,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; @@ -92,14 +100,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*/ @@ -111,15 +123,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; } @@ -127,27 +143,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)) { @@ -156,10 +180,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 */ @@ -205,7 +231,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; @@ -219,8 +247,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); @@ -228,10 +258,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); @@ -265,10 +297,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; } @@ -321,15 +355,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*/ @@ -365,10 +403,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; @@ -462,10 +502,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 os_mutex_lock(&heap->lock); @@ -522,10 +564,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); @@ -647,10 +691,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); @@ -767,11 +813,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", @@ -788,8 +836,12 @@ 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 } diff --git a/core/shared/mem-alloc/ems/ems_gc_internal.h b/core/shared/mem-alloc/ems/ems_gc_internal.h index 68b505453..6abe2b12a 100644 --- a/core/shared/mem-alloc/ems/ems_gc_internal.h +++ b/core/shared/mem-alloc/ems/ems_gc_internal.h @@ -271,9 +271,11 @@ typedef struct gc_heap_struct { size[left] <= size[cur] < size[right] */ hmu_tree_node_t *kfc_tree_root; +#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; diff --git a/core/shared/mem-alloc/ems/ems_hmu.c b/core/shared/mem-alloc/ems/ems_hmu.c index 41745e161..f9d7c0f4a 100644 --- a/core/shared/mem-alloc/ems/ems_hmu.c +++ b/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 } } } diff --git a/core/shared/mem-alloc/ems/ems_kfc.c b/core/shared/mem-alloc/ems/ems_kfc.c index 80d202679..1dda3ae03 100644 --- a/core/shared/mem-alloc/ems/ems_kfc.c +++ b/core/shared/mem-alloc/ems/ems_kfc.c @@ -133,8 +133,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; @@ -186,10 +189,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; @@ -211,11 +216,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; @@ -238,11 +245,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; } @@ -250,9 +261,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 diff --git a/core/shared/mem-alloc/mem_alloc.cmake b/core/shared/mem-alloc/mem_alloc.cmake index c0b4157f4..1754a1aca 100644 --- a/core/shared/mem-alloc/mem_alloc.cmake +++ b/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 diff --git a/core/shared/platform/alios/alios_platform.c b/core/shared/platform/alios/alios_platform.c index 60393ae52..24bf9c7ff 100644 --- a/core/shared/platform/alios/alios_platform.c +++ b/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; diff --git a/core/shared/platform/alios/platform_internal.h b/core/shared/platform/alios/platform_internal.h index f6a4ba11e..d2897a6b5 100644 --- a/core/shared/platform/alios/platform_internal.h +++ b/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 */ diff --git a/core/shared/platform/android/platform_internal.h b/core/shared/platform/android/platform_internal.h index c28a7b9be..42e4e726c 100644 --- a/core/shared/platform/android/platform_internal.h +++ b/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 diff --git a/core/shared/platform/common/libc-util/libc_errno.c b/core/shared/platform/common/libc-util/libc_errno.c new file mode 100644 index 000000000..e6c26c839 --- /dev/null +++ b/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; +} \ No newline at end of file diff --git a/core/shared/platform/common/libc-util/libc_errno.h b/core/shared/platform/common/libc-util/libc_errno.h new file mode 100644 index 000000000..b0a8b78c6 --- /dev/null +++ b/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 */ \ No newline at end of file diff --git a/core/shared/platform/common/libc-util/platform_common_libc_util.cmake b/core/shared/platform/common/libc-util/platform_common_libc_util.cmake new file mode 100644 index 000000000..a7c7645ce --- /dev/null +++ b/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) \ No newline at end of file diff --git a/core/shared/platform/common/posix/platform_api_posix.cmake b/core/shared/platform/common/posix/platform_api_posix.cmake index 4abefff1e..2bf9fab4a 100644 --- a/core/shared/platform/common/posix/platform_api_posix.cmake +++ b/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} ) diff --git a/core/shared/platform/common/posix/posix_clock.c b/core/shared/platform/common/posix/posix_clock.c new file mode 100644 index 000000000..280306c42 --- /dev/null +++ b/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; +} diff --git a/core/shared/platform/common/posix/posix_file.c b/core/shared/platform/common/posix/posix_file.c new file mode 100644 index 000000000..8c4f7aa9d --- /dev/null +++ b/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 + +#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 (int 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 (int 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 (int 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 (int 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); +} \ No newline at end of file diff --git a/core/shared/platform/common/posix/posix_memmap.c b/core/shared/platform/common/posix/posix_memmap.c index 5d33dcc81..583557bb8 100644 --- a/core/shared/platform/common/posix/posix_memmap.c +++ b/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 -} \ No newline at end of file +} diff --git a/core/shared/platform/common/posix/posix_socket.c b/core/shared/platform/common/posix/posix_socket.c index 11c56e723..7bdcb529e 100644 --- a/core/shared/platform/common/posix/posix_socket.c +++ b/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 #include @@ -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 diff --git a/core/shared/platform/common/posix/posix_thread.c b/core/shared/platform/common/posix/posix_thread.c index 6c16ba29b..ac87b1dde 100644 --- a/core/shared/platform/common/posix/posix_thread.c +++ b/core/shared/platform/common/posix/posix_thread.c @@ -340,6 +340,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) { @@ -452,8 +507,14 @@ static os_thread_local_attribute bool thread_signal_inited = false; /* The signal alternate stack base addr */ static os_thread_local_attribute uint8 *sigalt_stack_base_addr; +/* + * ASAN is not designed to work with custom stack unwind or other low-level + * things. Ignore a function that does some low-level magic. (e.g. walking + * through the thread's stack bypassing the frame boundaries) + */ #if defined(__clang__) #pragma clang optimize off +__attribute__((no_sanitize_address)) #elif defined(__GNUC__) #pragma GCC push_options #pragma GCC optimize("O0") @@ -514,10 +575,12 @@ destroy_stack_guard_pages() } #endif /* end of WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 */ -/* ASAN is not designed to work with custom stack unwind or other low-level \ - things. > Ignore a function that does some low-level magic. (e.g. walking \ - through the thread's stack bypassing the frame boundaries) */ -#if defined(__GNUC__) +/* + * ASAN is not designed to work with custom stack unwind or other low-level + * things. Ignore a function that does some low-level magic. (e.g. walking + * through the thread's stack bypassing the frame boundaries) + */ +#if defined(__GNUC__) || defined(__clang__) __attribute__((no_sanitize_address)) #endif static void @@ -534,10 +597,12 @@ mask_signals(int how) static struct sigaction prev_sig_act_SIGSEGV; static struct sigaction prev_sig_act_SIGBUS; -/* ASAN is not designed to work with custom stack unwind or other low-level \ - things. > Ignore a function that does some low-level magic. (e.g. walking \ - through the thread's stack bypassing the frame boundaries) */ -#if defined(__GNUC__) +/* + * ASAN is not designed to work with custom stack unwind or other low-level + * things. Ignore a function that does some low-level magic. (e.g. walking + * through the thread's stack bypassing the frame boundaries) + */ +#if defined(__GNUC__) || defined(__clang__) __attribute__((no_sanitize_address)) #endif static void @@ -610,7 +675,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; } diff --git a/core/shared/platform/cosmopolitan/platform_internal.h b/core/shared/platform/cosmopolitan/platform_internal.h index ed2545436..02cd78be4 100644 --- a/core/shared/platform/cosmopolitan/platform_internal.h +++ b/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) \ diff --git a/core/shared/platform/darwin/platform_internal.h b/core/shared/platform/darwin/platform_internal.h index d72d48b53..30b89624e 100644 --- a/core/shared/platform/darwin/platform_internal.h +++ b/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 diff --git a/core/shared/platform/esp-idf/espidf_memmap.c b/core/shared/platform/esp-idf/espidf_memmap.c index ce94a9549..9f3ec47a6 100644 --- a/core/shared/platform/esp-idf/espidf_memmap.c +++ b/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) diff --git a/core/shared/platform/esp-idf/espidf_socket.c b/core/shared/platform/esp-idf/espidf_socket.c index 83a24f435..a75d82975 100644 --- a/core/shared/platform/esp-idf/espidf_socket.c +++ b/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 @@ -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 diff --git a/core/shared/platform/esp-idf/platform_internal.h b/core/shared/platform/esp-idf/platform_internal.h index 81304ea80..70c4fe7b1 100644 --- a/core/shared/platform/esp-idf/platform_internal.h +++ b/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 diff --git a/core/shared/platform/freebsd/platform_internal.h b/core/shared/platform/freebsd/platform_internal.h index 50cabd344..5241c6456 100644 --- a/core/shared/platform/freebsd/platform_internal.h +++ b/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 diff --git a/core/shared/platform/include/platform_api_extension.h b/core/shared/platform/include/platform_api_extension.h index 06bd9ee89..7c6120ba2 100644 --- a/core/shared/platform/include/platform_api_extension.h +++ b/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 diff --git a/core/shared/platform/include/platform_api_vmcore.h b/core/shared/platform/include/platform_api_vmcore.h index c6df1dac8..c6b56f12c 100644 --- a/core/shared/platform/include/platform_api_vmcore.h +++ b/core/shared/platform/include/platform_api_vmcore.h @@ -133,7 +133,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 diff --git a/core/shared/platform/include/platform_wasi_types.h b/core/shared/platform/include/platform_wasi_types.h new file mode 100644 index 000000000..ac1a95ea1 --- /dev/null +++ b/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 +#include + +/* 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 */ \ No newline at end of file diff --git a/core/shared/platform/linux-sgx/platform_internal.h b/core/shared/platform/linux-sgx/platform_internal.h index d18f015ee..c96768e32 100644 --- a/core/shared/platform/linux-sgx/platform_internal.h +++ b/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 diff --git a/core/shared/platform/linux-sgx/sgx_ipfs.h b/core/shared/platform/linux-sgx/sgx_ipfs.h index e4de90274..3a911d2b6 100644 --- a/core/shared/platform/linux-sgx/sgx_ipfs.h +++ b/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" { diff --git a/core/shared/platform/linux-sgx/sgx_platform.c b/core/shared/platform/linux-sgx/sgx_platform.c index 1a90af4c6..32b956826 100644 --- a/core/shared/platform/linux-sgx/sgx_platform.c +++ b/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) -{} \ No newline at end of file +{} diff --git a/core/shared/platform/linux-sgx/sgx_socket.c b/core/shared/platform/linux-sgx/sgx_socket.c index 4d3f9a6b5..cd1a6cead 100644 --- a/core/shared/platform/linux-sgx/sgx_socket.c +++ b/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 diff --git a/core/shared/platform/linux-sgx/sgx_thread.c b/core/shared/platform/linux-sgx/sgx_thread.c index e20c341c7..b3fece64f 100644 --- a/core/shared/platform/linux-sgx/sgx_thread.c +++ b/core/shared/platform/linux-sgx/sgx_thread.c @@ -223,4 +223,69 @@ os_thread_get_stack_boundary() void os_thread_jit_write_protect_np(bool enabled) -{} \ No newline at end of file +{} + +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; +} diff --git a/core/shared/platform/linux-sgx/shared_platform.cmake b/core/shared/platform/linux-sgx/shared_platform.cmake index b2de1ab06..e8e167005 100644 --- a/core/shared/platform/linux-sgx/shared_platform.cmake +++ b/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}) diff --git a/core/shared/platform/linux/platform_internal.h b/core/shared/platform/linux/platform_internal.h index 337cdd9cc..335070bf8 100644 --- a/core/shared/platform/linux/platform_internal.h +++ b/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 diff --git a/core/shared/platform/nuttx/nuttx_platform.c b/core/shared/platform/nuttx/nuttx_platform.c index 92c17ed48..38e70076d 100644 --- a/core/shared/platform/nuttx/nuttx_platform.c +++ b/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; diff --git a/core/shared/platform/nuttx/platform_internal.h b/core/shared/platform/nuttx/platform_internal.h index 97ab5f697..2fb80a6e3 100644 --- a/core/shared/platform/nuttx/platform_internal.h +++ b/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 diff --git a/core/shared/platform/nuttx/shared_platform.cmake b/core/shared/platform/nuttx/shared_platform.cmake index 7b29b5f09..1cbe2218b 100644 --- a/core/shared/platform/nuttx/shared_platform.cmake +++ b/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}) diff --git a/core/shared/platform/riot/platform_internal.h b/core/shared/platform/riot/platform_internal.h index 8fec6dd0b..e88b25d40 100644 --- a/core/shared/platform/riot/platform_internal.h +++ b/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 */ diff --git a/core/shared/platform/riot/riot_platform.c b/core/shared/platform/riot/riot_platform.c index 6fd6617b4..ad5927e51 100644 --- a/core/shared/platform/riot/riot_platform.c +++ b/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; diff --git a/core/shared/platform/rt-thread/platform_internal.h b/core/shared/platform/rt-thread/platform_internal.h index 5f9cc8bc8..4ebdabb10 100644 --- a/core/shared/platform/rt-thread/platform_internal.h +++ b/core/shared/platform/rt-thread/platform_internal.h @@ -38,6 +38,12 @@ typedef struct rt_thread korp_cond; typedef struct rt_thread korp_thread; 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 rt_uint8_t uint8_t; typedef rt_int8_t int8_t; typedef rt_uint16_t uint16_t; @@ -45,4 +51,16 @@ typedef rt_int16_t int16_t; typedef rt_uint64_t uint64_t; typedef rt_int64_t int64_t; +/* 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 /* RTTHREAD_PLATFORM_INTERNAL_H */ diff --git a/core/shared/platform/rt-thread/rtt_platform.c b/core/shared/platform/rt-thread/rtt_platform.c index 5a5a78e94..e5a574595 100644 --- a/core/shared/platform/rt-thread/rtt_platform.c +++ b/core/shared/platform/rt-thread/rtt_platform.c @@ -198,7 +198,7 @@ os_cond_wait(korp_cond *cond, korp_mutex *mutex) } 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) { return rt_malloc(size); } diff --git a/core/shared/platform/vxworks/platform_internal.h b/core/shared/platform/vxworks/platform_internal.h index f72f60322..930ff7777 100644 --- a/core/shared/platform/vxworks/platform_internal.h +++ b/core/shared/platform/vxworks/platform_internal.h @@ -54,12 +54,17 @@ 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 #define os_thread_local_attribute __thread +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) @@ -95,6 +100,12 @@ os_sigreturn(); #endif /* end of BUILD_TARGET_X86_64/AMD_64/AARCH64 */ #endif /* end of WASM_DISABLE_HW_BOUND_CHECK */ +static inline os_file_handle +os_get_invalid_handle() +{ + return -1; +} + #ifdef __cplusplus } #endif diff --git a/core/shared/platform/windows/platform_internal.h b/core/shared/platform/windows/platform_internal.h index 500ab200c..8bb77e7cb 100644 --- a/core/shared/platform/windows/platform_internal.h +++ b/core/shared/platform/windows/platform_internal.h @@ -25,10 +25,14 @@ #include #include #include +#include #include #include #include #include +#include + +#include "platform_wasi_types.h" #ifdef __cplusplus extern "C" { @@ -57,6 +61,11 @@ typedef void *korp_tid; typedef void *korp_mutex; typedef void *korp_sem; +typedef struct { + SRWLOCK lock; + bool exclusive; +} korp_rwlock; + /** * Create the mutex when os_mutex_lock is called, and no need to * CloseHandle() for the static lock's lifetime, since @@ -76,8 +85,6 @@ typedef struct korp_cond { struct os_thread_wait_node *thread_wait_list_end; } korp_cond; -#define bh_socket_t SOCKET - unsigned os_getpagesize(); void * @@ -131,6 +138,61 @@ bh_atomic_thread_fence(int mem_order); #define os_atomic_thread_fence bh_atomic_thread_fence +typedef enum windows_handle_type { + windows_handle_type_socket, + windows_handle_type_file +} windows_handle_type; + +typedef enum windows_access_mode { + windows_access_mode_read = 1 << 0, + windows_access_mode_write = 1 << 1 +} windows_access_mode; + +typedef struct windows_handle { + windows_handle_type type; + __wasi_fdflags_t fdflags; + windows_access_mode access_mode; + union { + HANDLE handle; + SOCKET socket; + } raw; +} windows_handle; + +typedef struct windows_dir_stream { + // Enough space for the wide filename and the info struct itself + char info_buf[PATH_MAX * sizeof(wchar_t) + sizeof(FILE_ID_BOTH_DIR_INFO)]; + char current_entry_name[PATH_MAX]; + // An offset into info_buf to read the next entry from + DWORD cursor; + int cookie; + windows_handle *handle; +} windows_dir_stream; + +typedef windows_handle *os_file_handle; +typedef windows_dir_stream *os_dir_stream; + +#if WASM_ENABLE_UVWASI != 1 +typedef HANDLE os_raw_file_handle; +#else +typedef uint32_t os_raw_file_handle; +#endif + +#define bh_socket_t windows_handle * + +// UWP apps do not have stdout/stderr handles so provide a default +// implementation of vprintf on debug builds so output from WASI libc is sent to +// the debugger and not lost completely. +#if !defined(BH_VPRINTF) && !defined(NDEBUG) && WINAPI_PARTITION_DESKTOP == 0 +#define BH_VPRINTF uwp_print_to_debugger +#define UWP_DEFAULT_VPRINTF +#endif + +static inline os_file_handle +os_get_invalid_handle() +{ + return NULL; +} + #ifdef __cplusplus } #endif diff --git a/core/shared/platform/windows/shared_platform.cmake b/core/shared/platform/windows/shared_platform.cmake index a68d63177..3c531c17c 100644 --- a/core/shared/platform/windows/shared_platform.cmake +++ b/core/shared/platform/windows/shared_platform.cmake @@ -13,6 +13,13 @@ include_directories(${PLATFORM_SHARED_DIR}/../include) file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c ${PLATFORM_SHARED_DIR}/*.cpp) +if (NOT WAMR_BUILD_LIBC_WASI EQUAL 1) + list(REMOVE_ITEM source_all ${PLATFORM_SHARED_DIR}/win_file.c) +else() + 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}) file (GLOB header ${PLATFORM_SHARED_DIR}/../include/*.h) diff --git a/core/shared/platform/windows/win_atomic.cpp b/core/shared/platform/windows/win_atomic.cpp index 80e8ef518..4e09405bb 100644 --- a/core/shared/platform/windows/win_atomic.cpp +++ b/core/shared/platform/windows/win_atomic.cpp @@ -14,8 +14,8 @@ void bh_atomic_thread_fence(int mem_order) { std::memory_order order = - (std::memory_order)(std::memory_order::memory_order_relaxed + mem_order - - os_memory_order_relaxed); + (std::memory_order)((int)std::memory_order::memory_order_relaxed + + mem_order - os_memory_order_relaxed); std::atomic_thread_fence(order); } diff --git a/core/shared/platform/windows/win_clock.c b/core/shared/platform/windows/win_clock.c new file mode 100644 index 000000000..c96bdfb3b --- /dev/null +++ b/core/shared/platform/windows/win_clock.c @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2023 Amazon Inc. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_extension.h" +#include +#include "win_util.h" + +#define NANOSECONDS_PER_SECOND 1000000000ULL +#define NANOSECONDS_PER_TICK 100 + +static __wasi_errno_t +calculate_monotonic_clock_frequency(uint64 *out_frequency) +{ + LARGE_INTEGER frequency; + if (!QueryPerformanceFrequency(&frequency)) + return convert_windows_error_code(GetLastError()); + + *out_frequency = (uint64)frequency.QuadPart; + return __WASI_ESUCCESS; +} + +static __wasi_errno_t +get_performance_counter_value(uint64 *out_counter) +{ + LARGE_INTEGER counter; + if (!QueryPerformanceCounter(&counter)) + return convert_windows_error_code(GetLastError()); + + *out_counter = counter.QuadPart; + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_clock_res_get(__wasi_clockid_t clock_id, __wasi_timestamp_t *resolution) +{ + __wasi_errno_t error = __WASI_ESUCCESS; + + switch (clock_id) { + case __WASI_CLOCK_MONOTONIC: + { + uint64 frequency; + error = calculate_monotonic_clock_frequency(&frequency); + + if (error != __WASI_ESUCCESS) + return error; + + const uint64 result = (uint64)NANOSECONDS_PER_SECOND / frequency; + *resolution = result; + return error; + } + case __WASI_CLOCK_REALTIME: + case __WASI_CLOCK_PROCESS_CPUTIME_ID: + case __WASI_CLOCK_THREAD_CPUTIME_ID: + { +#if WINAPI_PARTITION_DESKTOP + ULONG maximum_time; + ULONG minimum_time; + ULONG current_time; + NTSTATUS + status = NtQueryTimerResolution(&maximum_time, &minimum_time, + ¤t_time); + uint64 result = (uint64)current_time * NANOSECONDS_PER_TICK; + *resolution = result / (uint64)NANOSECONDS_PER_SECOND; + return error; +#else + return __WASI_ENOTSUP; +#endif + } + default: + return __WASI_EINVAL; + } +} + +__wasi_errno_t +os_clock_time_get(__wasi_clockid_t clock_id, __wasi_timestamp_t precision, + __wasi_timestamp_t *time) +{ + __wasi_errno_t error = __WASI_ESUCCESS; + + switch (clock_id) { + case __WASI_CLOCK_REALTIME: + { + FILETIME sys_now; +#if NTDDI_VERSION >= NTDDI_WIN8 + GetSystemTimePreciseAsFileTime(&sys_now); +#else + GetSystemTimeAsFileTime(&sys_now); +#endif + *time = convert_filetime_to_wasi_timestamp(&sys_now); + return BHT_OK; + } + case __WASI_CLOCK_MONOTONIC: + { + uint64 frequency; + error = calculate_monotonic_clock_frequency(&frequency); + + if (error != __WASI_ESUCCESS) + return error; + + uint64 counter; + error = get_performance_counter_value(&counter); + + if (error != __WASI_ESUCCESS) + return error; + + if (NANOSECONDS_PER_SECOND % frequency == 0) { + *time = counter * NANOSECONDS_PER_SECOND / frequency; + } + else { + uint64 seconds = counter / frequency; + uint64 fractions = counter % frequency; + *time = seconds * NANOSECONDS_PER_SECOND + + (fractions * NANOSECONDS_PER_SECOND) / frequency; + } + return error; + } + case __WASI_CLOCK_PROCESS_CPUTIME_ID: + case __WASI_CLOCK_THREAD_CPUTIME_ID: + { + FILETIME creation_time; + FILETIME exit_time; + FILETIME kernel_time; + FILETIME user_time; + + HANDLE handle = (clock_id == __WASI_CLOCK_PROCESS_CPUTIME_ID) + ? GetCurrentProcess() + : GetCurrentThread(); + + if (!GetProcessTimes(handle, &creation_time, &exit_time, + &kernel_time, &user_time)) + return convert_windows_error_code(GetLastError()); + + *time = convert_filetime_to_wasi_timestamp(&kernel_time) + + convert_filetime_to_wasi_timestamp(&user_time); + + return error; + } + default: + return __WASI_EINVAL; + } +} \ No newline at end of file diff --git a/core/shared/platform/windows/win_file.c b/core/shared/platform/windows/win_file.c new file mode 100644 index 000000000..2c4e19f8b --- /dev/null +++ b/core/shared/platform/windows/win_file.c @@ -0,0 +1,1447 @@ +/* + * 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 "win_util.h" + +#include "PathCch.h" + +#pragma comment(lib, "Pathcch.lib") + +#define CHECK_VALID_HANDLE_WITH_RETURN_VALUE(win_handle, ret) \ + do { \ + if ((win_handle) == NULL \ + || ((win_handle)->type == windows_handle_type_socket \ + && (win_handle)->raw.socket == INVALID_SOCKET) \ + || ((win_handle)->type == windows_handle_type_file \ + && (win_handle)->raw.handle == INVALID_HANDLE_VALUE)) \ + return (ret); \ + \ + } while (0) + +#define CHECK_VALID_HANDLE(win_handle) \ + CHECK_VALID_HANDLE_WITH_RETURN_VALUE(win_handle, __WASI_EBADF) + +#define CHECK_VALID_FILE_HANDLE(win_handle) \ + do { \ + if ((win_handle) == NULL) \ + return __WASI_EBADF; \ + \ + if ((win_handle)->type == windows_handle_type_socket) \ + return __WASI_EINVAL; \ + \ + if (((win_handle)->type == windows_handle_type_file \ + && (win_handle)->raw.handle == INVALID_HANDLE_VALUE)) \ + return __WASI_EBADF; \ + \ + } while (0) + +#define CHECK_VALID_WIN_DIR_STREAM(win_dir_stream) \ + do { \ + if ((win_dir_stream) == NULL) \ + return __WASI_EINVAL; \ + CHECK_VALID_FILE_HANDLE((win_dir_stream)->handle); \ + } while (0) + +static __wasi_filetype_t +get_disk_filetype(DWORD attribute) +{ + if (attribute == INVALID_FILE_ATTRIBUTES) + return __WASI_FILETYPE_UNKNOWN; + if (attribute & FILE_ATTRIBUTE_REPARSE_POINT) + return __WASI_FILETYPE_SYMBOLIC_LINK; + if (attribute & FILE_ATTRIBUTE_DIRECTORY) + return __WASI_FILETYPE_DIRECTORY; + + return __WASI_FILETYPE_REGULAR_FILE; +} + +static __wasi_filetype_t +get_socket_filetype(SOCKET socket) +{ + char socket_type = 0; + int size = sizeof(socket_type); + + if (getsockopt(socket, SOL_SOCKET, SO_TYPE, &socket_type, &size) == 0) { + switch (socket_type) { + case SOCK_STREAM: + return __WASI_FILETYPE_SOCKET_STREAM; + case SOCK_DGRAM: + return __WASI_FILETYPE_SOCKET_DGRAM; + } + } + return __WASI_FILETYPE_UNKNOWN; +} + +static __wasi_errno_t +convert_windows_filetype(os_file_handle handle, DWORD filetype, + __wasi_filetype_t *out_filetype) +{ + __wasi_errno_t error = __WASI_ESUCCESS; + + switch (filetype) { + case FILE_TYPE_DISK: + FILE_ATTRIBUTE_TAG_INFO file_info; + + bool success = GetFileInformationByHandleEx( + handle->raw.handle, FileAttributeTagInfo, &file_info, + sizeof(file_info)); + + if (!success + || file_info.FileAttributes == INVALID_FILE_ATTRIBUTES) { + error = convert_windows_error_code(GetLastError()); + break; + } + + *out_filetype = get_disk_filetype(file_info.FileAttributes); + break; + case FILE_TYPE_CHAR: + *out_filetype = __WASI_FILETYPE_CHARACTER_DEVICE; + break; + case FILE_TYPE_PIPE: + if (handle->type == windows_handle_type_socket) + *out_filetype = get_socket_filetype(handle->raw.socket); + else + *out_filetype = __WASI_FILETYPE_BLOCK_DEVICE; + + break; + case FILE_TYPE_REMOTE: + case FILE_TYPE_UNKNOWN: + default: + *out_filetype = __WASI_FILETYPE_UNKNOWN; + } + + return error; +} + +// Converts the input string to a wchar string. +static __wasi_errno_t +convert_to_wchar(const char *str, wchar_t *buf, size_t buf_size) +{ + int converted_chars = + MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, (int)buf_size); + + if (converted_chars == 0) + return convert_windows_error_code(GetLastError()); + + return __WASI_ESUCCESS; +} + +// Get the filepath for a handle. The size of the buffer should be specified in +// terms of wchar. +static __wasi_errno_t +get_handle_filepath(HANDLE handle, wchar_t *buf, DWORD buf_size) +{ + DWORD bufsize_in_chars = buf_size * (sizeof(wchar_t) / sizeof(char)); + DWORD size = GetFinalPathNameByHandleW( + handle, buf, bufsize_in_chars, FILE_NAME_NORMALIZED | VOLUME_NAME_NONE); + + if (size > bufsize_in_chars) + return __WASI_ENAMETOOLONG; + + if (size == 0) + return convert_windows_error_code(GetLastError()); + + return __WASI_ESUCCESS; +} + +static __wasi_errno_t +convert_hresult_error_code(HRESULT error_code) +{ + switch (error_code) { + case E_OUTOFMEMORY: + return __WASI_ENOMEM; + case E_INVALIDARG: + default: + return __WASI_EINVAL; + } +} + +// Returns the absolute filepath from the relative path to the directory +// associated with the provided handle. +static __wasi_errno_t +get_absolute_filepath(HANDLE handle, const char *relative_path, + wchar_t *absolute_path, size_t buf_len) +{ + wchar_t handle_path[PATH_MAX]; + + __wasi_errno_t error = get_handle_filepath(handle, handle_path, PATH_MAX); + + if (error != __WASI_ESUCCESS) + return error; + + wchar_t relative_wpath[PATH_MAX]; + error = convert_to_wchar(relative_path, relative_wpath, PATH_MAX); + + if (error != __WASI_ESUCCESS) + return error; + + HRESULT ret = + PathCchCombine(absolute_path, buf_len, handle_path, relative_wpath); + if (ret != S_OK) + error = convert_hresult_error_code(ret); + + return error; +} + +static bool +has_directory_attribute(DWORD attributes) +{ + if (attributes == INVALID_FILE_ATTRIBUTES) + return false; + + return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; +} + +static bool +is_directory(const wchar_t *path) +{ + DWORD attributes = GetFileAttributesW(path); + + return has_directory_attribute(attributes); +} + +static bool +has_symlink_attribute(DWORD attributes) +{ + if (attributes == INVALID_FILE_ATTRIBUTES) + return false; + + return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0; +} + +static bool +is_symlink(const wchar_t *path) +{ + DWORD attributes = GetFileAttributesW(path); + + return has_symlink_attribute(attributes); +} + +static void +init_dir_stream(os_dir_stream dir_stream, os_file_handle handle) +{ + dir_stream->cursor = 0; + dir_stream->handle = handle; + dir_stream->cookie = 0; +} + +// Advances to the next directory entry and optionally reads into to the +// provided buffer if not NULL. +static __wasi_errno_t +read_next_dir_entry(os_dir_stream dir_stream, FILE_ID_BOTH_DIR_INFO **out_entry) +{ + FILE_INFO_BY_HANDLE_CLASS file_info_class; + + if (dir_stream->cookie == 0) + file_info_class = FileIdBothDirectoryRestartInfo; + else + file_info_class = FileIdBothDirectoryInfo; + + if (dir_stream->cursor == 0 + && !GetFileInformationByHandleEx(dir_stream->handle->raw.handle, + file_info_class, dir_stream->info_buf, + sizeof(dir_stream->info_buf))) { + if (out_entry != NULL) + *out_entry = NULL; + DWORD win_error = GetLastError(); + // We've reached the end of the directory - return success + if (win_error == ERROR_NO_MORE_FILES) { + dir_stream->cookie = 0; + dir_stream->cursor = 0; + return __WASI_ESUCCESS; + } + + return convert_windows_error_code(win_error); + } + + FILE_ID_BOTH_DIR_INFO *current_info = + (FILE_ID_BOTH_DIR_INFO *)(dir_stream->info_buf + dir_stream->cursor); + + if (current_info->NextEntryOffset == 0) + dir_stream->cursor = 0; + else + dir_stream->cursor += current_info->NextEntryOffset; + + ++dir_stream->cookie; + + if (out_entry != NULL) + *out_entry = current_info; + else + return __WASI_ESUCCESS; + + // Convert and copy over the wchar filename into the entry_name buf + int ret = WideCharToMultiByte( + CP_UTF8, 0, current_info->FileName, + current_info->FileNameLength / (sizeof(wchar_t) / sizeof(char)), + dir_stream->current_entry_name, sizeof(dir_stream->current_entry_name), + NULL, NULL); + + if (ret == 0) + return convert_windows_error_code(GetLastError()); + + return __WASI_ESUCCESS; +} + +static HANDLE +create_handle(wchar_t *path, bool is_dir, bool follow_symlink, bool readonly) +{ + CREATEFILE2_EXTENDED_PARAMETERS create_params; + + create_params.dwSize = sizeof(create_params); + create_params.dwFileAttributes = FILE_ATTRIBUTE_NORMAL; + create_params.dwSecurityQosFlags = 0; + create_params.dwFileFlags = 0; + create_params.lpSecurityAttributes = NULL; + create_params.hTemplateFile = NULL; + + if (is_dir) { + create_params.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY; + create_params.dwFileFlags |= FILE_FLAG_BACKUP_SEMANTICS; + } + + if (!follow_symlink) + create_params.dwFileFlags |= FILE_FLAG_OPEN_REPARSE_POINT; + + DWORD desired_access = GENERIC_READ; + + if (!readonly) + desired_access |= GENERIC_WRITE; + else + create_params.dwFileAttributes |= FILE_ATTRIBUTE_READONLY; + + return CreateFile2(path, desired_access, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + OPEN_EXISTING, &create_params); +} + +#if WINAPI_PARTITION_DESKTOP == 0 +// Modifies the given path in place and replaces it with the filename component +// (including the extension) of the path. +static __wasi_errno_t +extract_filename_from_path(wchar_t *path, size_t buf_size) +{ + wchar_t extension[256]; + wchar_t filename[256]; + __wasi_errno_t error = __WASI_ESUCCESS; + + // Get the filename from the fullpath. + errno_t ret = + _wsplitpath_s(path, NULL, 0, NULL, 0, filename, 256, extension, 256); + if (ret != 0) { + error = convert_errno(ret); + return error; + } + + ret = wcscat_s(filename, 256, extension); + + if (ret != 0) { + error = convert_errno(ret); + return error; + } + + ret = wcscpy_s(path, buf_size, filename); + + if (ret != 0) + error = convert_errno(ret); + + return error; +} + +static __wasi_errno_t +get_handle_to_parent_directory(HANDLE handle, HANDLE *out_dir_handle) +{ + wchar_t path[PATH_MAX]; + __wasi_errno_t error = get_handle_filepath(handle, path, PATH_MAX); + + if (error != __WASI_ESUCCESS) + return error; + + wchar_t parent_dir_path[PATH_MAX]; + errno_t ret = wcscpy_s(parent_dir_path, PATH_MAX, path); + + if (ret != 0) { + error = convert_errno(ret); + return error; + } + + ret = wcscat_s(parent_dir_path, PATH_MAX, L"/.."); + + if (ret != 0) { + error = convert_errno(ret); + return error; + } + + HANDLE dir_handle = create_handle(parent_dir_path, true, true, true); + + if (dir_handle == INVALID_HANDLE_VALUE) { + error = convert_windows_error_code(GetLastError()); + return error; + } + + *out_dir_handle = dir_handle; + return error; +} + +// The easiest way to get all the necessary file information for files is to +// open a handle to the parent directory and iterate through the entries via +// FileIdBothDirectoryInfo. Other file information classes are only +// available on desktop. +static __wasi_errno_t +get_disk_file_information(HANDLE handle, __wasi_filestat_t *buf) +{ + __wasi_errno_t error = __WASI_ESUCCESS; + HANDLE raw_dir_handle = INVALID_HANDLE_VALUE; + + wchar_t path[PATH_MAX] = L"."; + + if (buf->st_filetype != __WASI_FILETYPE_DIRECTORY) { + error = get_handle_filepath(handle, path, PATH_MAX); + + if (error != __WASI_ESUCCESS) + goto fail; + + error = get_handle_to_parent_directory(handle, &raw_dir_handle); + + if (error != __WASI_ESUCCESS) + goto fail; + + error = extract_filename_from_path(path, PATH_MAX); + + if (error != __WASI_ESUCCESS) + goto fail; + } + else { + raw_dir_handle = handle; + } + + windows_handle dir_handle = { .access_mode = windows_access_mode_read, + .raw = { .handle = raw_dir_handle }, + .fdflags = 0, + .type = windows_handle_type_file }; + windows_dir_stream dir_stream; + init_dir_stream(&dir_stream, &dir_handle); + + do { + FILE_ID_BOTH_DIR_INFO *file_id_both_dir_info = NULL; + __wasi_errno_t error = + read_next_dir_entry(&dir_stream, &file_id_both_dir_info); + + if (error != __WASI_ESUCCESS || file_id_both_dir_info == NULL) + goto fail; + + const DWORD filename_length = file_id_both_dir_info->FileNameLength + / (sizeof(wchar_t) / sizeof(char)); + + if (wcsncmp(file_id_both_dir_info->FileName, path, filename_length) + == 0) { + buf->st_ino = + (__wasi_inode_t)(file_id_both_dir_info->FileId.QuadPart); + buf->st_atim = convert_filetime_to_wasi_timestamp( + (LPFILETIME)&file_id_both_dir_info->LastAccessTime.QuadPart); + buf->st_mtim = convert_filetime_to_wasi_timestamp( + (LPFILETIME)&file_id_both_dir_info->LastWriteTime.QuadPart); + buf->st_ctim = convert_filetime_to_wasi_timestamp( + (LPFILETIME)&file_id_both_dir_info->ChangeTime.QuadPart); + buf->st_size = + (__wasi_filesize_t)(file_id_both_dir_info->EndOfFile.QuadPart); + + break; + } + } while (dir_stream.cookie != 0); + + FILE_STANDARD_INFO file_standard_info; + + bool success = GetFileInformationByHandleEx(handle, FileStandardInfo, + &file_standard_info, + sizeof(file_standard_info)); + + if (!success) { + error = convert_windows_error_code(GetLastError()); + goto fail; + } + + buf->st_nlink = (__wasi_linkcount_t)file_standard_info.NumberOfLinks; +fail: + if (buf->st_filetype != __WASI_FILETYPE_DIRECTORY + && raw_dir_handle != INVALID_HANDLE_VALUE) + CloseHandle(raw_dir_handle); + + return error; +} + +#else + +static __wasi_errno_t +get_disk_file_information(HANDLE handle, __wasi_filestat_t *buf) +{ + __wasi_errno_t error = __WASI_ESUCCESS; + FILE_BASIC_INFO file_basic_info; + + int ret = GetFileInformationByHandleEx( + handle, FileBasicInfo, &file_basic_info, sizeof(file_basic_info)); + + if (ret == 0) { + error = convert_windows_error_code(GetLastError()); + return error; + } + + buf->st_atim = convert_filetime_to_wasi_timestamp( + (LPFILETIME)&file_basic_info.LastAccessTime.QuadPart); + buf->st_mtim = convert_filetime_to_wasi_timestamp( + (LPFILETIME)&file_basic_info.LastWriteTime.QuadPart); + buf->st_ctim = convert_filetime_to_wasi_timestamp( + (LPFILETIME)&file_basic_info.ChangeTime.QuadPart); + + BY_HANDLE_FILE_INFORMATION file_info; + ret = GetFileInformationByHandle(handle, &file_info); + + if (ret == 0) { + error = convert_windows_error_code(GetLastError()); + return error; + } + + ULARGE_INTEGER file_size = { .LowPart = file_info.nFileSizeLow, + .HighPart = file_info.nFileSizeHigh }; + buf->st_size = (__wasi_filesize_t)(file_size.QuadPart); + + ULARGE_INTEGER file_id = { .LowPart = file_info.nFileIndexLow, + .HighPart = file_info.nFileIndexHigh }; + buf->st_ino = (__wasi_inode_t)(file_id.QuadPart); + + buf->st_dev = (__wasi_device_t)file_info.dwVolumeSerialNumber; + buf->st_nlink = (__wasi_linkcount_t)file_info.nNumberOfLinks; + + return error; +} + +#endif /* end of WINAPI_PARTITION_DESKTOP == 0 */ + +static __wasi_errno_t +get_file_information(os_file_handle handle, __wasi_filestat_t *buf) +{ + __wasi_errno_t error = __WASI_ESUCCESS; + + DWORD windows_filetype = GetFileType(handle->raw.handle); + error = + convert_windows_filetype(handle, windows_filetype, &buf->st_filetype); + + if (error != __WASI_ESUCCESS) + return error; + + buf->st_dev = 0; + + if (windows_filetype != FILE_TYPE_DISK) { + buf->st_atim = 0; + buf->st_ctim = 0; + buf->st_mtim = 0; + buf->st_nlink = 0; + buf->st_size = 0; + buf->st_ino = 0; + + return error; + } + + return get_disk_file_information(handle->raw.handle, buf); +} + +__wasi_errno_t +os_fstat(os_file_handle handle, struct __wasi_filestat_t *buf) +{ + CHECK_VALID_HANDLE(handle); + + return get_file_information(handle, buf); +} + +__wasi_errno_t +os_fstatat(os_file_handle handle, const char *path, + struct __wasi_filestat_t *buf, __wasi_lookupflags_t lookup_flags) +{ + CHECK_VALID_FILE_HANDLE(handle); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_file_get_fdflags(os_file_handle handle, __wasi_fdflags_t *flags) +{ + CHECK_VALID_HANDLE(handle); + + *flags = handle->fdflags; + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_file_set_fdflags(os_file_handle handle, __wasi_fdflags_t flags) +{ + CHECK_VALID_HANDLE(handle); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_file_get_access_mode(os_file_handle handle, + wasi_libc_file_access_mode *access_mode) +{ + CHECK_VALID_HANDLE(handle); + + if ((handle->access_mode & windows_access_mode_read) != 0 + && (handle->access_mode & windows_access_mode_write) != 0) + *access_mode = WASI_LIBC_ACCESS_MODE_READ_WRITE; + else if ((handle->access_mode & windows_access_mode_write) != 0) + *access_mode = WASI_LIBC_ACCESS_MODE_WRITE_ONLY; + else + *access_mode = WASI_LIBC_ACCESS_MODE_READ_ONLY; + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +os_fdatasync(os_file_handle handle) +{ + CHECK_VALID_FILE_HANDLE(handle); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_fsync(os_file_handle handle) +{ + CHECK_VALID_FILE_HANDLE(handle); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_open_preopendir(const char *path, os_file_handle *out) +{ + *out = NULL; + + wchar_t wpath[PATH_MAX]; + __wasi_errno_t error = convert_to_wchar(path, wpath, PATH_MAX); + + if (error != __WASI_ESUCCESS) + return error; + + HANDLE dir_handle = create_handle(wpath, true, true, true); + + if (dir_handle == INVALID_HANDLE_VALUE) + return convert_windows_error_code(GetLastError()); + + *out = BH_MALLOC(sizeof(windows_handle)); + + if (*out == NULL) { + CloseHandle(dir_handle); + return __WASI_ENOMEM; + } + + (*out)->type = windows_handle_type_file; + (*out)->raw.handle = dir_handle; + (*out)->fdflags = 0; + (*out)->access_mode = windows_access_mode_read; + + return error; +} + +__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 access_mode, os_file_handle *out) +{ + CHECK_VALID_FILE_HANDLE(handle); + *out = BH_MALLOC(sizeof(windows_handle)); + + if (*out == NULL) + return __WASI_ENOMEM; + + (*out)->type = windows_handle_type_file; + (*out)->fdflags = fs_flags; + (*out)->raw.handle = INVALID_HANDLE_VALUE; + + DWORD attributes = FILE_FLAG_BACKUP_SEMANTICS; + + if ((fs_flags & (__WASI_FDFLAG_SYNC | __WASI_FDFLAG_RSYNC)) != 0) + attributes |= (FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING); + if ((fs_flags & __WASI_FDFLAG_DSYNC) != 0) + attributes |= FILE_FLAG_WRITE_THROUGH; + + if ((oflags & __WASI_O_DIRECTORY) != 0) { + attributes |= FILE_ATTRIBUTE_DIRECTORY; + oflags &= ~(__WASI_O_DIRECTORY); + } + // Use async operations on the handle if it's not a directory + else { + attributes |= FILE_FLAG_OVERLAPPED; + } + + __wasi_errno_t error = __WASI_ESUCCESS; + + DWORD access_flags = 0; + if ((fs_flags & __WASI_FDFLAG_APPEND) != 0) { + if ((attributes & (FILE_FLAG_NO_BUFFERING)) != 0) { + // FILE_APPEND_DATA and FILE_FLAG_NO_BUFFERING are mutually + // exclusive - CreateFile2 returns 87 (invalid parameter) when they + // are combined. + error = __WASI_ENOTSUP; + goto fail; + } + access_flags |= FILE_APPEND_DATA; + } + + switch (access_mode) { + case WASI_LIBC_ACCESS_MODE_READ_ONLY: + access_flags |= GENERIC_READ; + (*out)->access_mode = windows_access_mode_read; + break; + case WASI_LIBC_ACCESS_MODE_WRITE_ONLY: + access_flags |= GENERIC_WRITE; + (*out)->access_mode = windows_access_mode_write; + break; + case WASI_LIBC_ACCESS_MODE_READ_WRITE: + access_flags |= GENERIC_WRITE | GENERIC_READ; + (*out)->access_mode = + windows_access_mode_read | windows_access_mode_write; + break; + } + + DWORD creation_disposition = 0; + + switch (oflags) { + case __WASI_O_CREAT | __WASI_O_EXCL: + case __WASI_O_CREAT | __WASI_O_EXCL | __WASI_O_TRUNC: + creation_disposition = CREATE_NEW; + break; + case __WASI_O_CREAT | __WASI_O_TRUNC: + creation_disposition = CREATE_ALWAYS; + break; + case __WASI_O_CREAT: + creation_disposition = OPEN_ALWAYS; + break; + case 0: + case __WASI_O_EXCL: + creation_disposition = OPEN_EXISTING; + break; + case __WASI_O_TRUNC: + case __WASI_O_EXCL | __WASI_O_TRUNC: + creation_disposition = TRUNCATE_EXISTING; + // CreateFile2 requires write access if we truncate the file upon + // opening + access_flags |= GENERIC_WRITE; + break; + } + + wchar_t absolute_path[PATH_MAX]; + error = get_absolute_filepath(handle->raw.handle, path, absolute_path, + PATH_MAX); + + if (error != __WASI_ESUCCESS) + goto fail; + + if ((lookup_flags & __WASI_LOOKUP_SYMLINK_FOLLOW) == 0) + attributes |= FILE_FLAG_OPEN_REPARSE_POINT; + + // Check that we're not trying to open an existing file as a directory. + // Windows doesn't seem to throw an error in this case so add an + // explicit check. + if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0 + && creation_disposition == OPEN_EXISTING + && !is_directory(absolute_path)) { + error = __WASI_ENOTDIR; + goto fail; + } + + CREATEFILE2_EXTENDED_PARAMETERS create_params; + create_params.dwSize = sizeof(create_params); + create_params.dwFileAttributes = attributes & 0xFFF; + create_params.dwFileFlags = attributes & 0xFFF00000; + create_params.dwSecurityQosFlags = 0; + create_params.lpSecurityAttributes = NULL; + create_params.hTemplateFile = NULL; + + (*out)->raw.handle = + CreateFile2(absolute_path, access_flags, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + creation_disposition, &create_params); + + if ((*out)->raw.handle == INVALID_HANDLE_VALUE) { + error = convert_windows_error_code(GetLastError()); + goto fail; + } + + return error; +fail: + if (*out != NULL) { + if ((*out)->raw.handle != INVALID_HANDLE_VALUE) + CloseHandle((*out)->raw.handle); + + BH_FREE(*out); + } + + return error; +} + +__wasi_errno_t +os_close(os_file_handle handle, bool is_stdio) +{ + CHECK_VALID_HANDLE(handle); + + // We don't own the underlying raw handle so just free the handle and return + // success. + if (is_stdio) { + BH_FREE(handle); + return __WASI_ESUCCESS; + } + + switch (handle->type) { + case windows_handle_type_file: + bool success = CloseHandle(handle->raw.handle); + + if (!success) + return convert_windows_error_code(GetLastError()); + + break; + case windows_handle_type_socket: + int ret = closesocket(handle->raw.socket); + + if (ret != 0) + return convert_winsock_error_code(WSAGetLastError()); + + break; + default: + assert(false && "unreachable"); + } + + BH_FREE(handle); + + return __WASI_ESUCCESS; +} + +static __wasi_errno_t +read_data_at_offset(HANDLE handle, const struct __wasi_iovec_t *iov, int iovcnt, + __wasi_filesize_t offset, size_t *nwritten) +{ + OVERLAPPED *read_operations = + BH_MALLOC((uint32_t)(sizeof(OVERLAPPED) * (uint32_t)iovcnt)); + + if (read_operations == NULL) + return __WASI_ENOMEM; + + ULARGE_INTEGER query_offset = { .QuadPart = offset }; + __wasi_errno_t error = __WASI_ESUCCESS; + size_t total_bytes_read = 0; + + const __wasi_iovec_t *current = iov; + int successful_read_count = 0; + + for (int i = 0; i < iovcnt; ++i, ++current) { + read_operations[i].Internal = 0; + read_operations[i].InternalHigh = 0; + read_operations[i].Offset = query_offset.LowPart; + read_operations[i].OffsetHigh = query_offset.HighPart; + read_operations[i].hEvent = NULL; + + if (!ReadFileEx(handle, current->buf, (DWORD)current->buf_len, + &read_operations[i], NULL)) { + DWORD win_error = GetLastError(); + if (win_error != ERROR_IO_PENDING) { + error = convert_windows_error_code(win_error); + break; + } + } + ++successful_read_count; + query_offset.QuadPart += (DWORD)current->buf_len; + } + + // Get the result of all the asynchronous read operations + for (int i = 0; i < successful_read_count; ++i) { + DWORD bytes_transferred = 0; + if (!GetOverlappedResult(handle, &read_operations[i], + &bytes_transferred, true)) { + DWORD win_error = GetLastError(); + + if (win_error != ERROR_HANDLE_EOF) + error = convert_windows_error_code(win_error); + else + total_bytes_read += (size_t)bytes_transferred; + + CancelIo(handle); + + for (int j = i + 1; j < iovcnt; ++j) { + GetOverlappedResult(handle, &read_operations[j], + &bytes_transferred, true); + } + break; + } + + total_bytes_read += (size_t)bytes_transferred; + } + + *nwritten = total_bytes_read; + + BH_FREE(read_operations); + return error; +} + +__wasi_errno_t +os_preadv(os_file_handle handle, const struct __wasi_iovec_t *iov, int iovcnt, + __wasi_filesize_t offset, size_t *nread) +{ + CHECK_VALID_FILE_HANDLE(handle); + + return read_data_at_offset(handle->raw.handle, iov, iovcnt, offset, nread); +} + +__wasi_errno_t +os_readv(os_file_handle handle, const struct __wasi_iovec_t *iov, int iovcnt, + size_t *nread) +{ + CHECK_VALID_HANDLE(handle); + + LARGE_INTEGER current_offset = { .QuadPart = 0 }; + + // Seek to the current offset before reading + int ret = SetFilePointerEx(handle->raw.handle, current_offset, + ¤t_offset, FILE_CURRENT); + if (ret == 0) + return convert_windows_error_code(GetLastError()); + + __wasi_errno_t error = + read_data_at_offset(handle->raw.handle, iov, iovcnt, + (__wasi_filesize_t)current_offset.QuadPart, nread); + + if (error != __WASI_ESUCCESS) + return error; + + current_offset.QuadPart += (LONGLONG)(*nread); + + // Update the current offset to match how many bytes we've read + ret = + SetFilePointerEx(handle->raw.handle, current_offset, NULL, FILE_BEGIN); + + if (ret == 0) + error = convert_windows_error_code(GetLastError()); + + return error; +} + +static __wasi_errno_t +write_data_at_offset(HANDLE handle, const struct __wasi_ciovec_t *iov, + int iovcnt, __wasi_filesize_t offset, size_t *nwritten) +{ + OVERLAPPED *write_operations = + BH_MALLOC((uint32_t)(sizeof(OVERLAPPED) * (uint32_t)iovcnt)); + + if (write_operations == NULL) + return __WASI_ENOMEM; + + ULARGE_INTEGER query_offset = { .QuadPart = offset }; + __wasi_errno_t error = __WASI_ESUCCESS; + size_t total_bytes_written = 0; + + const __wasi_ciovec_t *current = iov; + int successful_write_count = 0; + for (int i = 0; i < iovcnt; ++i, ++current) { + write_operations[i].Internal = 0; + write_operations[i].InternalHigh = 0; + write_operations[i].Offset = query_offset.LowPart; + write_operations[i].OffsetHigh = query_offset.HighPart; + write_operations[i].hEvent = NULL; + + if (!WriteFileEx(handle, current->buf, (DWORD)current->buf_len, + &write_operations[i], NULL)) { + DWORD win_error = GetLastError(); + if (win_error != ERROR_IO_PENDING) { + error = convert_windows_error_code(win_error); + break; + } + } + ++successful_write_count; + query_offset.QuadPart += (DWORD)current->buf_len; + } + + // Get the result of all the asynchronous writes + for (int i = 0; i < successful_write_count; ++i) { + DWORD bytes_transferred = 0; + if (!GetOverlappedResult(handle, &write_operations[i], + &bytes_transferred, true)) { + error = convert_windows_error_code(GetLastError()); + CancelIo(handle); + + for (int j = i + 1; j < iovcnt; ++j) { + GetOverlappedResult(handle, &write_operations[j], + &bytes_transferred, true); + } + break; + } + + total_bytes_written += (size_t)bytes_transferred; + } + + *nwritten = total_bytes_written; + + BH_FREE(write_operations); + return error; +} + +__wasi_errno_t +os_pwritev(os_file_handle handle, const struct __wasi_ciovec_t *iov, int iovcnt, + __wasi_filesize_t offset, size_t *nwritten) +{ + CHECK_VALID_FILE_HANDLE(handle); + + return write_data_at_offset(handle->raw.handle, iov, iovcnt, offset, + nwritten); +} + +__wasi_errno_t +os_writev(os_file_handle handle, const struct __wasi_ciovec_t *iov, int iovcnt, + size_t *nwritten) +{ + CHECK_VALID_HANDLE(handle); + + bool append = (handle->fdflags & __WASI_FDFLAG_APPEND) != 0; + LARGE_INTEGER write_offset = { .QuadPart = 0 }; + DWORD move_method = append ? FILE_END : FILE_CURRENT; + + int ret = SetFilePointerEx(handle->raw.handle, write_offset, &write_offset, + move_method); + if (ret == 0) + return convert_windows_error_code(GetLastError()); + + __wasi_errno_t error = write_data_at_offset( + handle->raw.handle, iov, iovcnt, + (__wasi_filesize_t)write_offset.QuadPart, nwritten); + + if (error != __WASI_ESUCCESS) + return error; + + write_offset.QuadPart += (LONGLONG)(*nwritten); + + // Update the write offset to match how many bytes we've written + ret = SetFilePointerEx(handle->raw.handle, write_offset, NULL, FILE_BEGIN); + + if (ret == 0) + error = convert_windows_error_code(GetLastError()); + + return error; +} + +__wasi_errno_t +os_fallocate(os_file_handle handle, __wasi_filesize_t offset, + __wasi_filesize_t length) +{ + CHECK_VALID_FILE_HANDLE(handle); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_ftruncate(os_file_handle handle, __wasi_filesize_t size) +{ + CHECK_VALID_FILE_HANDLE(handle); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_futimens(os_file_handle handle, __wasi_timestamp_t access_time, + __wasi_timestamp_t modification_time, __wasi_fstflags_t fstflags) +{ + CHECK_VALID_FILE_HANDLE(handle); + + return __WASI_ENOSYS; +} + +__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) +{ + CHECK_VALID_FILE_HANDLE(handle); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_readlinkat(os_file_handle handle, const char *path, char *buf, + size_t bufsize, size_t *nread) +{ + CHECK_VALID_FILE_HANDLE(handle); + + wchar_t symlink_path[PATH_MAX]; + __wasi_errno_t error = + get_absolute_filepath(handle->raw.handle, path, symlink_path, PATH_MAX); + + if (error != __WASI_ESUCCESS) + return error; + + DWORD symlink_attributes = GetFileAttributesW(symlink_path); + + if (!has_symlink_attribute(symlink_attributes)) + return __WASI_EINVAL; + + HANDLE link_handle = create_handle( + symlink_path, has_directory_attribute(symlink_attributes), false, true); + + if (link_handle == INVALID_HANDLE_VALUE) + return convert_windows_error_code(GetLastError()); + +#if WINAPI_PARTITION_DESKTOP != 0 +// MinGW32 already has a definition for REPARSE_DATA_BUFFER +#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR) + // See + // https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_reparse_data_buffer + // for more details. + typedef struct _REPARSE_DATA_BUFFER { + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union { + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + } DUMMYUNIONNAME; + } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; +#endif + + char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + + REPARSE_DATA_BUFFER *reparse_data = (REPARSE_DATA_BUFFER *)buffer; + + if (!DeviceIoControl(link_handle, FSCTL_GET_REPARSE_POINT, NULL, 0, &buffer, + sizeof(buffer), NULL, NULL)) { + error = convert_windows_error_code(GetLastError()); + goto fail; + } + + int wbufsize = 0; + wchar_t *wbuf = NULL; + + // The following checks are taken from the libuv windows filesystem + // implementation, + // https://github.com/libuv/libuv/blob/v1.x/src/win/fs.c#L181-L244. Real + // symlinks can contain pretty much anything, but the only thing we really + // care about is undoing the implicit conversion to an NT namespaced path + // that CreateSymbolicLink will perform on absolute paths. + if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) { + wbuf = reparse_data->SymbolicLinkReparseBuffer.PathBuffer + + (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset + / sizeof(wchar_t)); + wbufsize = reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength + / sizeof(wchar_t); + + if (wbufsize >= 4 && wbuf[0] == L'\\' && wbuf[1] == L'?' + && wbuf[2] == L'?' && wbuf[3] == L'\\') { + // Starts with \??\ + if (wbufsize >= 6 + && ((wbuf[4] >= L'A' && wbuf[4] <= L'Z') + || (wbuf[4] >= L'a' && wbuf[4] <= L'z')) + && wbuf[5] == L':' && (wbufsize == 6 || wbuf[6] == L'\\')) + { + // \??\:\ + wbuf += 4; + wbufsize -= 4; + } + else if (wbufsize >= 8 && (wbuf[4] == L'U' || wbuf[4] == L'u') + && (wbuf[5] == L'N' || wbuf[5] == L'n') + && (wbuf[6] == L'C' || wbuf[6] == L'c') + && wbuf[7] == L'\\') + { + // \??\UNC\\\ - make sure the final path looks like \\\\ + wbuf += 6; + wbuf[0] = L'\\'; + wbufsize -= 6; + } + } + } + else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { + // Junction + wbuf = reparse_data->MountPointReparseBuffer.PathBuffer + + (reparse_data->MountPointReparseBuffer.SubstituteNameOffset + / sizeof(wchar_t)); + wbufsize = reparse_data->MountPointReparseBuffer.SubstituteNameLength + / sizeof(wchar_t); + + // Only treat junctions that look like \??\:\ as a symlink. + if (!(wbufsize >= 6 && wbuf[0] == L'\\' && wbuf[1] == L'?' + && wbuf[2] == L'?' && wbuf[3] == L'\\' + && ((wbuf[4] >= L'A' && wbuf[4] <= L'Z') + || (wbuf[4] >= L'a' && wbuf[4] <= L'z')) + && wbuf[5] == L':' && (wbufsize == 6 || wbuf[6] == L'\\'))) { + error = __WASI_EINVAL; + goto fail; + } + + /* Remove leading \??\ */ + wbuf += 4; + wbufsize -= 4; + } + else { + error = __WASI_EINVAL; + goto fail; + } + + if (wbuf != NULL) + *nread = (size_t)WideCharToMultiByte(CP_UTF8, 0, wbuf, wbufsize, buf, + (int)bufsize, NULL, NULL); + + if (*nread == 0 && wbuf != NULL) { + DWORD win_error = GetLastError(); + if (win_error == ERROR_INSUFFICIENT_BUFFER) + *nread = bufsize; + else + error = convert_windows_error_code(win_error); + } +#else + error = __WASI_ENOTSUP; +#endif +fail: + CloseHandle(link_handle); + return error; +} + +__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) +{ + CHECK_VALID_FILE_HANDLE(from_handle); + CHECK_VALID_FILE_HANDLE(to_handle); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_symlinkat(const char *old_path, os_file_handle handle, const char *new_path) +{ + CHECK_VALID_FILE_HANDLE(handle); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_mkdirat(os_file_handle handle, const char *path) +{ + CHECK_VALID_FILE_HANDLE(handle); + + wchar_t absolute_path[PATH_MAX]; + __wasi_errno_t error = get_absolute_filepath(handle->raw.handle, path, + absolute_path, PATH_MAX); + + if (error != __WASI_ESUCCESS) + return error; + + bool success = CreateDirectoryW(absolute_path, NULL); + + if (!success) + error = convert_windows_error_code(GetLastError()); + + return error; +} + +__wasi_errno_t +os_renameat(os_file_handle old_handle, const char *old_path, + os_file_handle new_handle, const char *new_path) +{ + CHECK_VALID_FILE_HANDLE(old_handle); + CHECK_VALID_FILE_HANDLE(new_handle); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_unlinkat(os_file_handle handle, const char *path, bool is_dir) +{ + CHECK_VALID_FILE_HANDLE(handle); + + wchar_t absolute_path[PATH_MAX]; + __wasi_errno_t error = get_absolute_filepath(handle->raw.handle, path, + absolute_path, PATH_MAX); + + if (error != __WASI_ESUCCESS) + return error; + + DWORD attributes = GetFileAttributesW(absolute_path); + + if (has_symlink_attribute(attributes)) { + // Override is_dir for symlinks. A symlink to a directory counts + // as a directory itself in Windows. + is_dir = has_directory_attribute(attributes); + } + + int ret = + is_dir ? RemoveDirectoryW(absolute_path) : DeleteFileW(absolute_path); + + if (ret == 0) + error = convert_windows_error_code(GetLastError()); + + return error; +} + +__wasi_errno_t +os_lseek(os_file_handle handle, __wasi_filedelta_t offset, + __wasi_whence_t whence, __wasi_filesize_t *new_offset) +{ + CHECK_VALID_FILE_HANDLE(handle); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_fadvise(os_file_handle handle, __wasi_filesize_t offset, + __wasi_filesize_t length, __wasi_advice_t advice) +{ + CHECK_VALID_FILE_HANDLE(handle); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_isatty(os_file_handle handle) +{ + CHECK_VALID_HANDLE(handle); + + DWORD console_mode; + return GetConsoleMode(handle->raw.handle, &console_mode) ? __WASI_ESUCCESS + : __WASI_ENOTTY; +} + +static os_file_handle +create_stdio_handle(HANDLE raw_stdio_handle, DWORD stdio) +{ + os_file_handle stdio_handle = BH_MALLOC(sizeof(windows_handle)); + + if (stdio_handle == NULL) + return NULL; + + stdio_handle->type = windows_handle_type_file; + stdio_handle->access_mode = + windows_access_mode_read | windows_access_mode_write; + stdio_handle->fdflags = 0; + + if (raw_stdio_handle == INVALID_HANDLE_VALUE) + raw_stdio_handle = GetStdHandle(stdio); + + stdio_handle->raw.handle = raw_stdio_handle; + + return stdio_handle; +} + +os_file_handle +os_convert_stdin_handle(os_raw_file_handle raw_stdin) +{ + return create_stdio_handle(raw_stdin, STD_INPUT_HANDLE); +} + +os_file_handle +os_convert_stdout_handle(os_raw_file_handle raw_stdout) +{ + return create_stdio_handle(raw_stdout, STD_OUTPUT_HANDLE); +} + +os_file_handle +os_convert_stderr_handle(os_raw_file_handle raw_stderr) +{ + return create_stdio_handle(raw_stderr, STD_ERROR_HANDLE); +} + +__wasi_errno_t +os_fdopendir(os_file_handle handle, os_dir_stream *dir_stream) +{ + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_rewinddir(os_dir_stream dir_stream) +{ + CHECK_VALID_WIN_DIR_STREAM(dir_stream); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_seekdir(os_dir_stream dir_stream, __wasi_dircookie_t position) +{ + CHECK_VALID_WIN_DIR_STREAM(dir_stream); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_readdir(os_dir_stream dir_stream, __wasi_dirent_t *entry, + const char **d_name) +{ + CHECK_VALID_WIN_DIR_STREAM(dir_stream); + + return __WASI_ENOSYS; +} + +__wasi_errno_t +os_closedir(os_dir_stream dir_stream) +{ + CHECK_VALID_WIN_DIR_STREAM(dir_stream); + + return __WASI_ENOSYS; +} + +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); + + if (((*dir_stream) == NULL) || ((*dir_stream)->handle == NULL) + || ((*dir_stream)->handle->type != windows_handle_type_file) + || ((*dir_stream)->handle->raw.handle == INVALID_HANDLE_VALUE)) + return false; + + return true; +} + +bool +os_is_handle_valid(os_file_handle *handle) +{ + assert(handle != NULL); + + CHECK_VALID_HANDLE_WITH_RETURN_VALUE(*handle, false); + + return true; +} + +char * +os_realpath(const char *path, char *resolved_path) +{ + resolved_path = _fullpath(resolved_path, path, PATH_MAX); + + // Check the file/directory actually exists + DWORD attributes = GetFileAttributesA(resolved_path); + + if (attributes == INVALID_FILE_ATTRIBUTES) + return NULL; + + return resolved_path; +} diff --git a/core/shared/platform/windows/win_memmap.c b/core/shared/platform/windows/win_memmap.c index c4a6b0756..db0f38a56 100644 --- a/core/shared/platform/windows/win_memmap.c +++ b/core/shared/platform/windows/win_memmap.c @@ -29,7 +29,7 @@ access_to_win32_flags(int prot) } 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) { DWORD alloc_type = MEM_RESERVE; DWORD protect; diff --git a/core/shared/platform/windows/win_socket.c b/core/shared/platform/windows/win_socket.c index 9a1c7a3c9..91d38fd8b 100644 --- a/core/shared/platform/windows/win_socket.c +++ b/core/shared/platform/windows/win_socket.c @@ -5,12 +5,30 @@ #include "platform_api_vmcore.h" #include "platform_api_extension.h" +#include "platform_wasi_types.h" +#include "win_util.h" /* link with Ws2_32.lib */ #pragma comment(lib, "ws2_32.lib") static bool is_winsock_inited = false; +#define CHECK_VALID_SOCKET_HANDLE(win_handle) \ + do { \ + if ((win_handle) == NULL) { \ + errno = EBADF; \ + return BHT_ERROR; \ + } \ + if ((win_handle)->type != windows_handle_type_socket) { \ + errno = ENOTSOCK; \ + return BHT_ERROR; \ + } \ + if ((win_handle)->raw.socket == INVALID_SOCKET) { \ + errno = EBADF; \ + return BHT_ERROR; \ + } \ + } while (0) + int init_winsock() { @@ -45,6 +63,17 @@ os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp) return BHT_ERROR; } + *(sock) = BH_MALLOC(sizeof(windows_handle)); + + if ((*sock) == NULL) { + errno = ENOMEM; + return BHT_ERROR; + } + + (*sock)->type = windows_handle_type_socket; + (*sock)->access_mode = windows_access_mode_read | windows_access_mode_write; + (*sock)->fdflags = 0; + if (is_ipv4) { af = AF_INET; } @@ -54,18 +83,24 @@ os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp) } if (is_tcp) { - *sock = socket(af, SOCK_STREAM, IPPROTO_TCP); + (*sock)->raw.socket = socket(af, SOCK_STREAM, IPPROTO_TCP); } else { - *sock = socket(af, SOCK_DGRAM, 0); + (*sock)->raw.socket = socket(af, SOCK_DGRAM, 0); } - return (*sock == -1) ? BHT_ERROR : BHT_OK; + if ((*sock)->raw.socket == INVALID_SOCKET) { + BH_FREE(*sock); + return BHT_ERROR; + } + + return BHT_OK; } int os_socket_bind(bh_socket_t socket, const char *host, int *port) { + CHECK_VALID_SOCKET_HANDLE(socket); struct sockaddr_in addr; int socklen, ret; @@ -76,13 +111,13 @@ os_socket_bind(bh_socket_t socket, const char *host, int *port) addr.sin_port = htons(*port); addr.sin_family = AF_INET; - ret = bind(socket, (struct sockaddr *)&addr, sizeof(addr)); + ret = bind(socket->raw.socket, (struct sockaddr *)&addr, sizeof(addr)); if (ret < 0) { goto fail; } socklen = sizeof(addr); - if (getsockname(socket, (void *)&addr, &socklen) == -1) { + if (getsockname(socket->raw.socket, (void *)&addr, &socklen) == -1) { os_printf("getsockname failed with error %d\n", WSAGetLastError()); goto fail; } @@ -98,10 +133,12 @@ fail: int os_socket_settimeout(bh_socket_t socket, uint64 timeout_us) { + CHECK_VALID_SOCKET_HANDLE(socket); + DWORD tv = (DWORD)(timeout_us / 1000UL); - if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, - sizeof(tv)) + if (setsockopt(socket->raw.socket, SOL_SOCKET, SO_RCVTIMEO, + (const char *)&tv, sizeof(tv)) != 0) { return BHT_ERROR; } @@ -112,7 +149,9 @@ os_socket_settimeout(bh_socket_t socket, uint64 timeout_us) int os_socket_listen(bh_socket_t socket, int max_client) { - if (listen(socket, max_client) != 0) { + CHECK_VALID_SOCKET_HANDLE(socket); + + if (listen(socket->raw.socket, max_client) != 0) { os_printf("socket listen failed with error %d\n", WSAGetLastError()); return BHT_ERROR; } @@ -124,12 +163,26 @@ int os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr, unsigned int *addrlen) { + CHECK_VALID_SOCKET_HANDLE(server_sock); + struct sockaddr addr_tmp; unsigned int len = sizeof(struct sockaddr); - *sock = accept(server_sock, (struct sockaddr *)&addr_tmp, &len); + *sock = BH_MALLOC(sizeof(windows_handle)); - if (*sock < 0) { + if (*sock == NULL) { + errno = ENOMEM; + return BHT_ERROR; + } + + (*sock)->type = windows_handle_type_socket; + (*sock)->access_mode = windows_access_mode_read | windows_access_mode_write; + (*sock)->fdflags = 0; + (*sock)->raw.socket = + accept(server_sock->raw.socket, (struct sockaddr *)&addr_tmp, &len); + + if ((*sock)->raw.socket == INVALID_SOCKET) { + BH_FREE(*sock); os_printf("socket accept failed with error %d\n", WSAGetLastError()); return BHT_ERROR; } @@ -140,13 +193,17 @@ os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr, int os_socket_recv(bh_socket_t socket, void *buf, unsigned int len) { - return recv(socket, buf, len, 0); + CHECK_VALID_SOCKET_HANDLE(socket); + + return recv(socket->raw.socket, buf, len, 0); } int os_socket_recv_from(bh_socket_t socket, void *buf, unsigned int len, int flags, bh_sockaddr_t *src_addr) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -155,13 +212,17 @@ os_socket_recv_from(bh_socket_t socket, void *buf, unsigned int len, int flags, int os_socket_send(bh_socket_t socket, const void *buf, unsigned int len) { - return send(socket, buf, len, 0); + CHECK_VALID_SOCKET_HANDLE(socket); + + return send(socket->raw.socket, buf, len, 0); } int os_socket_send_to(bh_socket_t socket, const void *buf, unsigned int len, int flags, const bh_sockaddr_t *dest_addr) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -170,15 +231,24 @@ os_socket_send_to(bh_socket_t socket, const void *buf, unsigned int len, int os_socket_close(bh_socket_t socket) { - closesocket(socket); + CHECK_VALID_SOCKET_HANDLE(socket); + + closesocket(socket->raw.socket); + + BH_FREE(socket); + return BHT_OK; } -int +__wasi_errno_t os_socket_shutdown(bh_socket_t socket) { - shutdown(socket, SD_BOTH); - return BHT_OK; + CHECK_VALID_SOCKET_HANDLE(socket); + + if (shutdown(socket->raw.socket, SD_BOTH) != 0) { + return convert_winsock_error_code(WSAGetLastError()); + } + return __WASI_ESUCCESS; } int @@ -206,6 +276,16 @@ os_socket_inet_network(bool is_ipv4, const char *cp, bh_ip_addr_buffer_t *out) return BHT_OK; } +int +os_socket_connect(bh_socket_t socket, const char *addr, int port) +{ + CHECK_VALID_SOCKET_HANDLE(socket); + + errno = ENOSYS; + + return BHT_ERROR; +} + int os_socket_addr_resolve(const char *host, const char *service, uint8_t *hint_is_tcp, uint8_t *hint_is_ipv4, @@ -220,6 +300,8 @@ os_socket_addr_resolve(const char *host, const char *service, int os_socket_addr_local(bh_socket_t socket, bh_sockaddr_t *sockaddr) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -228,6 +310,8 @@ os_socket_addr_local(bh_socket_t socket, bh_sockaddr_t *sockaddr) int os_socket_set_send_timeout(bh_socket_t socket, uint64 timeout_us) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -236,6 +320,8 @@ os_socket_set_send_timeout(bh_socket_t socket, uint64 timeout_us) int os_socket_get_send_timeout(bh_socket_t socket, uint64 *timeout_us) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -244,6 +330,8 @@ os_socket_get_send_timeout(bh_socket_t socket, uint64 *timeout_us) int os_socket_set_recv_timeout(bh_socket_t socket, uint64 timeout_us) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -252,6 +340,8 @@ os_socket_set_recv_timeout(bh_socket_t socket, uint64 timeout_us) int os_socket_get_recv_timeout(bh_socket_t socket, uint64 *timeout_us) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -260,6 +350,8 @@ os_socket_get_recv_timeout(bh_socket_t socket, uint64 *timeout_us) int os_socket_addr_remote(bh_socket_t socket, bh_sockaddr_t *sockaddr) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -268,6 +360,8 @@ os_socket_addr_remote(bh_socket_t socket, bh_sockaddr_t *sockaddr) int os_socket_set_send_buf_size(bh_socket_t socket, size_t bufsiz) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -276,6 +370,8 @@ os_socket_set_send_buf_size(bh_socket_t socket, size_t bufsiz) int os_socket_get_send_buf_size(bh_socket_t socket, size_t *bufsiz) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -284,6 +380,8 @@ os_socket_get_send_buf_size(bh_socket_t socket, size_t *bufsiz) int os_socket_set_recv_buf_size(bh_socket_t socket, size_t bufsiz) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -292,6 +390,8 @@ os_socket_set_recv_buf_size(bh_socket_t socket, size_t bufsiz) int os_socket_get_recv_buf_size(bh_socket_t socket, size_t *bufsiz) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -300,6 +400,8 @@ os_socket_get_recv_buf_size(bh_socket_t socket, size_t *bufsiz) int os_socket_set_keep_alive(bh_socket_t socket, bool is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -308,6 +410,8 @@ os_socket_set_keep_alive(bh_socket_t socket, bool is_enabled) int os_socket_get_keep_alive(bh_socket_t socket, bool *is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -316,6 +420,8 @@ os_socket_get_keep_alive(bh_socket_t socket, bool *is_enabled) int os_socket_set_reuse_addr(bh_socket_t socket, bool is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -324,6 +430,8 @@ os_socket_set_reuse_addr(bh_socket_t socket, bool is_enabled) int os_socket_get_reuse_addr(bh_socket_t socket, bool *is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -332,6 +440,8 @@ os_socket_get_reuse_addr(bh_socket_t socket, bool *is_enabled) int os_socket_set_reuse_port(bh_socket_t socket, bool is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -340,6 +450,8 @@ os_socket_set_reuse_port(bh_socket_t socket, bool is_enabled) int os_socket_get_reuse_port(bh_socket_t socket, bool *is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -348,6 +460,8 @@ os_socket_get_reuse_port(bh_socket_t socket, bool *is_enabled) int os_socket_set_linger(bh_socket_t socket, bool is_enabled, int linger_s) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -356,6 +470,8 @@ os_socket_set_linger(bh_socket_t socket, bool is_enabled, int linger_s) int os_socket_get_linger(bh_socket_t socket, bool *is_enabled, int *linger_s) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -364,6 +480,8 @@ os_socket_get_linger(bh_socket_t socket, bool *is_enabled, int *linger_s) int os_socket_set_tcp_no_delay(bh_socket_t socket, bool is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -372,6 +490,8 @@ os_socket_set_tcp_no_delay(bh_socket_t socket, bool is_enabled) int os_socket_get_tcp_no_delay(bh_socket_t socket, bool *is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -380,6 +500,8 @@ os_socket_get_tcp_no_delay(bh_socket_t socket, bool *is_enabled) int os_socket_set_tcp_quick_ack(bh_socket_t socket, bool is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -388,6 +510,8 @@ os_socket_set_tcp_quick_ack(bh_socket_t socket, bool is_enabled) int os_socket_get_tcp_quick_ack(bh_socket_t socket, bool *is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -396,6 +520,8 @@ os_socket_get_tcp_quick_ack(bh_socket_t socket, bool *is_enabled) int os_socket_set_tcp_keep_idle(bh_socket_t socket, uint32 time_s) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -404,6 +530,8 @@ os_socket_set_tcp_keep_idle(bh_socket_t socket, uint32 time_s) int os_socket_get_tcp_keep_idle(bh_socket_t socket, uint32 *time_s) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -412,6 +540,8 @@ os_socket_get_tcp_keep_idle(bh_socket_t socket, uint32 *time_s) int os_socket_set_tcp_keep_intvl(bh_socket_t socket, uint32 time_s) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -420,6 +550,8 @@ os_socket_set_tcp_keep_intvl(bh_socket_t socket, uint32 time_s) int os_socket_get_tcp_keep_intvl(bh_socket_t socket, uint32 *time_s) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -428,6 +560,8 @@ os_socket_get_tcp_keep_intvl(bh_socket_t socket, uint32 *time_s) int os_socket_set_tcp_fastopen_connect(bh_socket_t socket, bool is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -436,6 +570,8 @@ os_socket_set_tcp_fastopen_connect(bh_socket_t socket, bool is_enabled) int os_socket_get_tcp_fastopen_connect(bh_socket_t socket, bool *is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -444,6 +580,8 @@ os_socket_get_tcp_fastopen_connect(bh_socket_t socket, bool *is_enabled) int os_socket_set_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -452,6 +590,8 @@ os_socket_set_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool is_enabled) int os_socket_get_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool *is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -462,6 +602,8 @@ os_socket_set_ip_add_membership(bh_socket_t socket, bh_ip_addr_buffer_t *imr_multiaddr, uint32_t imr_interface, bool is_ipv6) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -472,6 +614,8 @@ os_socket_set_ip_drop_membership(bh_socket_t socket, bh_ip_addr_buffer_t *imr_multiaddr, uint32_t imr_interface, bool is_ipv6) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -480,6 +624,8 @@ os_socket_set_ip_drop_membership(bh_socket_t socket, int os_socket_set_ip_ttl(bh_socket_t socket, uint8_t ttl_s) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -488,6 +634,8 @@ os_socket_set_ip_ttl(bh_socket_t socket, uint8_t ttl_s) int os_socket_get_ip_ttl(bh_socket_t socket, uint8_t *ttl_s) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -496,6 +644,8 @@ os_socket_get_ip_ttl(bh_socket_t socket, uint8_t *ttl_s) int os_socket_set_ip_multicast_ttl(bh_socket_t socket, uint8_t ttl_s) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -504,6 +654,8 @@ os_socket_set_ip_multicast_ttl(bh_socket_t socket, uint8_t ttl_s) int os_socket_get_ip_multicast_ttl(bh_socket_t socket, uint8_t *ttl_s) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -512,6 +664,8 @@ os_socket_get_ip_multicast_ttl(bh_socket_t socket, uint8_t *ttl_s) int os_socket_set_ipv6_only(bh_socket_t socket, bool option) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -520,6 +674,8 @@ os_socket_set_ipv6_only(bh_socket_t socket, bool option) int os_socket_get_ipv6_only(bh_socket_t socket, bool *option) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -528,6 +684,8 @@ os_socket_get_ipv6_only(bh_socket_t socket, bool *option) int os_socket_set_broadcast(bh_socket_t socket, bool is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; @@ -536,6 +694,8 @@ os_socket_set_broadcast(bh_socket_t socket, bool is_enabled) int os_socket_get_broadcast(bh_socket_t socket, bool *is_enabled) { + CHECK_VALID_SOCKET_HANDLE(socket); + errno = ENOSYS; return BHT_ERROR; } diff --git a/core/shared/platform/windows/win_thread.c b/core/shared/platform/windows/win_thread.c index f750b01da..f6e6e59a5 100644 --- a/core/shared/platform/windows/win_thread.c +++ b/core/shared/platform/windows/win_thread.c @@ -548,6 +548,62 @@ os_mutex_unlock(korp_mutex *mutex) return ReleaseMutex(*mutex) ? BHT_OK : BHT_ERROR; } +int +os_rwlock_init(korp_rwlock *lock) +{ + bh_assert(lock); + + InitializeSRWLock(&(lock->lock)); + lock->exclusive = false; + + return BHT_OK; +} + +int +os_rwlock_rdlock(korp_rwlock *lock) +{ + bh_assert(lock); + + AcquireSRWLockShared(&(lock->lock)); + + return BHT_OK; +} + +int +os_rwlock_wrlock(korp_rwlock *lock) +{ + bh_assert(lock); + + AcquireSRWLockExclusive(&(lock->lock)); + lock->exclusive = true; + + return BHT_OK; +} + +int +os_rwlock_unlock(korp_rwlock *lock) +{ + bh_assert(lock); + + if (lock->exclusive) { + lock->exclusive = false; + ReleaseSRWLockExclusive(&(lock->lock)); + } + else { + ReleaseSRWLockShared(&(lock->lock)); + } + + return BHT_OK; +} + +int +os_rwlock_destroy(korp_rwlock *lock) +{ + (void)lock; + + return BHT_OK; +} + int os_cond_init(korp_cond *cond) { diff --git a/core/shared/platform/windows/win_util.c b/core/shared/platform/windows/win_util.c new file mode 100644 index 000000000..ee0e82fb9 --- /dev/null +++ b/core/shared/platform/windows/win_util.c @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2023 Amazon Inc. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_common.h" +#include "win_util.h" + +__wasi_timestamp_t +convert_filetime_to_wasi_timestamp(LPFILETIME filetime) +{ + // From 1601-01-01 to 1970-01-01 there are 134774 days. + static const uint64_t NT_to_UNIX_epoch = + 134774ull * 86400ull * 1000ull * 1000ull * 1000ull; + + ULARGE_INTEGER temp = { .HighPart = filetime->dwHighDateTime, + .LowPart = filetime->dwLowDateTime }; + + // WASI timestamps are measured in nanoseconds whereas FILETIME structs are + // represented in terms 100-nanosecond intervals. + return (temp.QuadPart * 100ull) - NT_to_UNIX_epoch; +} + +__wasi_errno_t +convert_windows_error_code(DWORD windows_error_code) +{ + switch (windows_error_code) { + case ERROR_INVALID_PARAMETER: + case ERROR_INVALID_HANDLE: + case ERROR_NEGATIVE_SEEK: + return __WASI_EINVAL; + case ERROR_SHARING_VIOLATION: + case ERROR_PIPE_BUSY: + return __WASI_EBUSY; + case ERROR_ACCESS_DENIED: + return __WASI_EACCES; + case ERROR_ALREADY_EXISTS: + case ERROR_FILE_EXISTS: + return __WASI_EEXIST; + case ERROR_NO_MORE_FILES: + case ERROR_FILE_NOT_FOUND: + case ERROR_INVALID_NAME: + return __WASI_ENOENT; + case ERROR_PRIVILEGE_NOT_HELD: + return __WASI_EPERM; + case ERROR_NOT_ENOUGH_MEMORY: + return __WASI_ENOMEM; + case ERROR_NOACCESS: + return __WASI_EFAULT; + case ERROR_DIR_NOT_EMPTY: + return __WASI_ENOTEMPTY; + case ERROR_DIRECTORY: + return __WASI_ENOTDIR; + case ERROR_IO_PENDING: + case ERROR_INSUFFICIENT_BUFFER: + case ERROR_INVALID_FLAGS: + case ERROR_NO_UNICODE_TRANSLATION: + default: + return __WASI_EINVAL; + } +} + +#ifdef UWP_DEFAULT_VPRINTF +int +uwp_print_to_debugger(const char *format, va_list ap) +{ + // Provide a stack buffer which should be large enough for any realistic + // string so we avoid making an allocation on every printf call. + char stack_buf[2048]; + char *buf = stack_buf; + int ret = vsnprintf(stack_buf, sizeof(stack_buf), format, ap); + + if ((size_t)ret >= sizeof(stack_buf)) { + // Allocate an extra byte for the null terminator. + char *heap_buf = BH_MALLOC((unsigned int)(ret) + 1); + buf = heap_buf; + + if (heap_buf == NULL) { + // Output as much as we can to the debugger if allocating a buffer + // fails. + OutputDebugStringA(stack_buf); + return ret; + } + + ret = vsnprintf(heap_buf, (size_t)ret + 1, format, ap); + } + + if (ret >= 0) + OutputDebugStringA(buf); + + if (buf != stack_buf) + BH_FREE(buf); + + return ret; +} +#endif + +__wasi_errno_t +convert_winsock_error_code(int error_code) +{ + switch (error_code) { + case WSASYSNOTREADY: + case WSAEWOULDBLOCK: + return __WASI_EAGAIN; + case WSAVERNOTSUPPORTED: + return __WASI_ENOTSUP; + case WSAEINPROGRESS: + return __WASI_EINPROGRESS; + case WSAEPROCLIM: + return __WASI_EBUSY; + case WSAEFAULT: + return __WASI_EFAULT; + case WSAENETDOWN: + return __WASI_ENETDOWN; + case WSAENOTSOCK: + return __WASI_ENOTSOCK; + case WSAEINTR: + return __WASI_EINTR; + case WSAEAFNOSUPPORT: + return __WASI_EAFNOSUPPORT; + case WSAEMFILE: + return __WASI_ENFILE; + case WSAEINVAL: + return __WASI_EINVAL; + case WSAENOBUFS: + return __WASI_ENOBUFS; + case WSAEPROTONOSUPPORT: + return __WASI_EPROTONOSUPPORT; + case WSAEPROTOTYPE: + return __WASI_EPROTOTYPE; + case WSAESOCKTNOSUPPORT: + return __WASI_ENOTSUP; + case WSAECONNABORTED: + return __WASI_ECONNABORTED; + case WSAECONNRESET: + return __WASI_ECONNRESET; + case WSAENOTCONN: + return __WASI_ENOTCONN; + case WSAEINVALIDPROCTABLE: + case WSAEINVALIDPROVIDER: + case WSAEPROVIDERFAILEDINIT: + case WSANOTINITIALISED: + default: + return __WASI_EINVAL; + } +} diff --git a/core/shared/platform/windows/win_util.h b/core/shared/platform/windows/win_util.h new file mode 100644 index 000000000..3960fe946 --- /dev/null +++ b/core/shared/platform/windows/win_util.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2023 Amazon Inc. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _WIN_UTIL_H +#define _WIN_UTIL_H + +#include "platform_wasi_types.h" +#include "windows.h" + +__wasi_timestamp_t +convert_filetime_to_wasi_timestamp(LPFILETIME filetime); + +/* Convert a Windows error code to a WASI error code */ +__wasi_errno_t +convert_windows_error_code(DWORD windows_error_code); + +/* Convert a Winsock error code to a WASI error code */ +__wasi_errno_t +convert_winsock_error_code(int error_code); + +#endif /* end of _WIN_UTIL_H */ \ No newline at end of file diff --git a/core/shared/platform/zephyr/platform_internal.h b/core/shared/platform/zephyr/platform_internal.h index d2a94e4ad..a5d563a6c 100644 --- a/core/shared/platform/zephyr/platform_internal.h +++ b/core/shared/platform/zephyr/platform_internal.h @@ -42,21 +42,23 @@ #include #include #include - -#ifdef CONFIG_ARM_MPU -#include -#endif #else /* else of KERNEL_VERSION_NUMBER < 0x030200 */ #include #include #include #include #include +#endif /* end of KERNEL_VERSION_NUMBER < 0x030200 */ #ifdef CONFIG_ARM_MPU +#if KERNEL_VERSION_NUMBER < 0x030200 /* version 3.2.0 */ +#include +#elif KERNEL_VERSION_NUMBER < 0x030400 /* version 3.4.0 */ #include +#else /* > 3.4.0 */ +#include +#endif #endif -#endif /* end of KERNEL_VERSION_NUMBER < 0x030200 */ #ifndef BH_PLATFORM_ZEPHYR #define BH_PLATFORM_ZEPHYR @@ -72,6 +74,12 @@ typedef korp_thread *korp_tid; typedef struct k_mutex 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; + struct os_thread_wait_node; typedef struct os_thread_wait_node *os_thread_wait_list; typedef struct korp_cond { @@ -123,7 +131,7 @@ float strtof(const char *nptr, char **endptr); #endif /** - * @brief Allocate executable memroy + * @brief Allocate executable memory * * @param size size of the memory to be allocated * @@ -132,7 +140,7 @@ float strtof(const char *nptr, char **endptr); typedef void *(*exec_mem_alloc_func_t)(unsigned int size); /** - * @brief Release executable memroy + * @brief Release executable memory * * @param the address of the executable memory to be released */ @@ -146,4 +154,16 @@ void set_exec_mem_alloc_func(exec_mem_alloc_func_t alloc_func, exec_mem_free_func_t free_func); +/* 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 diff --git a/core/shared/platform/zephyr/zephyr_platform.c b/core/shared/platform/zephyr/zephyr_platform.c index 715be8b94..1a5b6621d 100644 --- a/core/shared/platform/zephyr/zephyr_platform.c +++ b/core/shared/platform/zephyr/zephyr_platform.c @@ -173,7 +173,7 @@ strcspn(const char *s, const char *reject) #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 ((uint64)size >= UINT32_MAX) return NULL; diff --git a/core/shared/utils/bh_atomic.h b/core/shared/utils/bh_atomic.h index 64dfee1b6..5744a64c0 100644 --- a/core/shared/utils/bh_atomic.h +++ b/core/shared/utils/bh_atomic.h @@ -45,6 +45,20 @@ extern "C" { */ typedef uint32 bh_atomic_32_t; +typedef uint16 bh_atomic_16_t; + +/* The flag can be defined by the user if the platform + * supports atomic 32-bit operations. + * If left undefined, it will be automatically defined + * according to the platform. + */ +#ifdef WASM_UINT32_IS_ATOMIC +#define BH_ATOMIC_32_IS_ATOMIC WASM_UINT32_IS_ATOMIC +#endif /* WASM_UINT32_IS_ATOMIC */ + +#ifdef WASM_UINT16_IS_ATOMIC +#define BH_ATOMIC_16_IS_ATOMIC WASM_UINT16_IS_ATOMIC +#endif /* WASM_UINT16_IS_ATOMIC */ #if defined(__GNUC_PREREQ) #if __GNUC_PREREQ(4, 7) @@ -57,8 +71,40 @@ typedef uint32 bh_atomic_32_t; #endif #if defined(CLANG_GCC_HAS_ATOMIC_BUILTIN) +#ifndef BH_ATOMIC_32_IS_ATOMIC #define BH_ATOMIC_32_IS_ATOMIC 1 +#endif +#ifndef BH_ATOMIC_16_IS_ATOMIC +#define BH_ATOMIC_16_IS_ATOMIC 1 +#endif +#else +#ifndef BH_ATOMIC_32_IS_ATOMIC +#define BH_ATOMIC_32_IS_ATOMIC 0 +#endif +#ifndef BH_ATOMIC_16_IS_ATOMIC +#define BH_ATOMIC_16_IS_ATOMIC 0 +#endif +#endif + +/* Force disable atomic 16-bit operations on bare-metal RISC-V + * because the 16-bit atomic operations is emulated by 32-bit + * atomic operations, which has linkage problem on current toolchain: + * in function `shared_memory_inc_reference': + * wasm_shared_memory.c:85:(.text.shared_memory_inc_reference+0x10): undefined + * reference to `__atomic_fetch_add_2' + */ +#ifndef WASM_UINT16_IS_ATOMIC +#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) \ + && !defined(__OpenBSD__) && defined(__riscv) +#undef BH_ATOMIC_16_IS_ATOMIC +#define BH_ATOMIC_16_IS_ATOMIC 0 +#endif +#endif + +#if BH_ATOMIC_32_IS_ATOMIC != 0 + #define BH_ATOMIC_32_LOAD(v) __atomic_load_n(&(v), __ATOMIC_SEQ_CST) +#define BH_ATOMIC_32_STORE(v, val) __atomic_store_n(&(v), val, __ATOMIC_SEQ_CST) #define BH_ATOMIC_32_FETCH_OR(v, val) \ __atomic_fetch_or(&(v), (val), __ATOMIC_SEQ_CST) #define BH_ATOMIC_32_FETCH_AND(v, val) \ @@ -67,8 +113,11 @@ typedef uint32 bh_atomic_32_t; __atomic_fetch_add(&(v), (val), __ATOMIC_SEQ_CST) #define BH_ATOMIC_32_FETCH_SUB(v, val) \ __atomic_fetch_sub(&(v), (val), __ATOMIC_SEQ_CST) -#else /* else of defined(CLANG_GCC_HAS_ATOMIC_BUILTIN) */ + +#else /* else of BH_ATOMIC_32_IS_ATOMIC != 0 */ + #define BH_ATOMIC_32_LOAD(v) (v) +#define BH_ATOMIC_32_STORE(v, val) (v) = val #define BH_ATOMIC_32_FETCH_OR(v, val) nonatomic_32_fetch_or(&(v), val) #define BH_ATOMIC_32_FETCH_AND(v, val) nonatomic_32_fetch_and(&(v), val) #define BH_ATOMIC_32_FETCH_ADD(v, val) nonatomic_32_fetch_add(&(v), val) @@ -106,13 +155,62 @@ nonatomic_32_fetch_sub(bh_atomic_32_t *p, uint32 val) return old; } -/* The flag can be defined by the user if the platform - supports atomic access to uint32 aligned memory. */ -#ifdef WASM_UINT32_IS_ATOMIC -#define BH_ATOMIC_32_IS_ATOMIC 1 -#else /* else of WASM_UINT32_IS_ATOMIC */ -#define BH_ATOMIC_32_IS_ATOMIC 0 -#endif /* WASM_UINT32_IS_ATOMIC */ +#endif + +#if BH_ATOMIC_16_IS_ATOMIC != 0 + +#define BH_ATOMIC_16_IS_ATOMIC 1 +#define BH_ATOMIC_16_LOAD(v) __atomic_load_n(&(v), __ATOMIC_SEQ_CST) +#define BH_ATOMIC_16_STORE(v, val) __atomic_store_n(&(v), val, __ATOMIC_SEQ_CST) +#define BH_ATOMIC_16_FETCH_OR(v, val) \ + __atomic_fetch_or(&(v), (val), __ATOMIC_SEQ_CST) +#define BH_ATOMIC_16_FETCH_AND(v, val) \ + __atomic_fetch_and(&(v), (val), __ATOMIC_SEQ_CST) +#define BH_ATOMIC_16_FETCH_ADD(v, val) \ + __atomic_fetch_add(&(v), (val), __ATOMIC_SEQ_CST) +#define BH_ATOMIC_16_FETCH_SUB(v, val) \ + __atomic_fetch_sub(&(v), (val), __ATOMIC_SEQ_CST) + +#else /* else of BH_ATOMIC_16_IS_ATOMIC != 0 */ + +#define BH_ATOMIC_16_LOAD(v) (v) +#define BH_ATOMIC_16_STORE(v) (v) = val +#define BH_ATOMIC_16_FETCH_OR(v, val) nonatomic_16_fetch_or(&(v), val) +#define BH_ATOMIC_16_FETCH_AND(v, val) nonatomic_16_fetch_and(&(v), val) +#define BH_ATOMIC_16_FETCH_ADD(v, val) nonatomic_16_fetch_add(&(v), val) +#define BH_ATOMIC_16_FETCH_SUB(v, val) nonatomic_16_fetch_sub(&(v), val) + +static inline uint16 +nonatomic_16_fetch_or(bh_atomic_16_t *p, uint16 val) +{ + uint16 old = *p; + *p |= val; + return old; +} + +static inline uint16 +nonatomic_16_fetch_and(bh_atomic_16_t *p, uint16 val) +{ + uint16 old = *p; + *p &= val; + return old; +} + +static inline uint16 +nonatomic_16_fetch_add(bh_atomic_16_t *p, uint16 val) +{ + uint16 old = *p; + *p += val; + return old; +} + +static inline uint16 +nonatomic_16_fetch_sub(bh_atomic_16_t *p, uint16 val) +{ + uint16 old = *p; + *p -= val; + return old; +} #endif diff --git a/core/shared/utils/bh_bitmap.c b/core/shared/utils/bh_bitmap.c new file mode 100644 index 000000000..2ee918049 --- /dev/null +++ b/core/shared/utils/bh_bitmap.c @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2021 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "bh_bitmap.h" + +bh_bitmap * +bh_bitmap_new(uintptr_t begin_index, unsigned bitnum) +{ + bh_bitmap *bitmap; + uint32 bitmap_size = (bitnum + 7) / 8; + uint32 total_size = offsetof(bh_bitmap, map) + bitmap_size; + + if (bitnum > UINT32_MAX - 7 || total_size < offsetof(bh_bitmap, map) + || (total_size - offsetof(bh_bitmap, map)) != bitmap_size) { + return NULL; /* integer overflow */ + } + + if ((bitmap = BH_MALLOC(total_size)) != NULL) { + memset(bitmap, 0, total_size); + bitmap->begin_index = begin_index; + bitmap->end_index = begin_index + bitnum; + } + + return bitmap; +} diff --git a/core/shared/utils/bh_bitmap.h b/core/shared/utils/bh_bitmap.h new file mode 100644 index 000000000..c0e56cb99 --- /dev/null +++ b/core/shared/utils/bh_bitmap.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2021 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _BH_BITMAP_H +#define _BH_BITMAP_H + +#include "bh_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * A simple fixed size bitmap. + */ +typedef struct bh_bitmap { + /* 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]; +} bh_bitmap; + +/** + * 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. + */ +bh_bitmap * +bh_bitmap_new(uintptr_t begin_index, unsigned bitnum); + +/** + * Delete a bitmap. + * + * @param bitmap the bitmap to be deleted + */ +static inline void +bh_bitmap_delete(bh_bitmap *bitmap) +{ + if (bitmap != NULL) + BH_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 +bh_bitmap_is_in_range(bh_bitmap *bitmap, uintptr_t 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 +bh_bitmap_get_bit(bh_bitmap *bitmap, uintptr_t n) +{ + uintptr_t 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 +bh_bitmap_set_bit(bh_bitmap *bitmap, uintptr_t n) +{ + uintptr_t 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 +bh_bitmap_clear_bit(bh_bitmap *bitmap, uintptr_t n) +{ + uintptr_t 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 + +#endif diff --git a/core/version.h b/core/version.h index 925779b31..9bb76b262 100644 --- a/core/version.h +++ b/core/version.h @@ -6,6 +6,6 @@ #ifndef _WAMR_VERSION_H_ #define _WAMR_VERSION_H_ #define WAMR_VERSION_MAJOR 1 -#define WAMR_VERSION_MINOR 2 -#define WAMR_VERSION_PATCH 3 +#define WAMR_VERSION_MINOR 3 +#define WAMR_VERSION_PATCH 0 #endif diff --git a/doc/build_wamr.md b/doc/build_wamr.md index 9938eadcb..12cbb4125 100644 --- a/doc/build_wamr.md +++ b/doc/build_wamr.md @@ -27,8 +27,8 @@ The script `runtime_lib.cmake` defines a number of variables for configuring the - **WAMR_BUILD_TARGET**: set the target CPU architecture. Current supported targets are: X86_64, X86_32, AARCH64, ARM, THUMB, XTENSA, ARC, RISCV32, RISCV64 and MIPS. - For ARM and THUMB, the format is \\[\]\[_VFP], where \ is the ARM sub-architecture and the "_VFP" suffix means using VFP coprocessor registers s0-s15 (d0-d7) for passing arguments or returning results in standard procedure-call. Both \ and "_VFP" are optional, e.g. ARMV7, ARMV7_VFP, THUMBV7, THUMBV7_VFP and so on. - For AARCH64, the format is\[\], VFP is enabled by default. \ is optional, e.g. AARCH64, AARCH64V8, AARCH64V8.1 and so on. - - For RISCV64, the format is \[_abi], where "_abi" is optional, currently the supported formats are RISCV64, RISCV64_LP64D and RISCV64_LP64: RISCV64 and RISCV64_LP64D are identical, using [LP64D](https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#-named-abis) as abi (LP64 with hardware floating-point calling convention for FLEN=64). And RISCV64_LP64 uses [LP64](https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#-named-abis) as abi (Integer calling-convention only, and hardware floating-point calling convention is not used). - - For RISCV32, the format is \[_abi], where "_abi" is optional, currently the supported formats are RISCV32, RISCV32_ILP32D and RISCV32_ILP32: RISCV32 and RISCV32_ILP32D are identical, using [ILP32D](https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#-named-abis) as abi (ILP32 with hardware floating-point calling convention for FLEN=64). And RISCV32_ILP32 uses [ILP32](https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#-named-abis) as abi (Integer calling-convention only, and hardware floating-point calling convention is not used). + - For RISCV64, the format is \[_abi], where "_abi" is optional, currently the supported formats are RISCV64, RISCV64_LP64D and RISCV64_LP64: RISCV64 and RISCV64_LP64D are identical, using [LP64D](https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#named-abis) as abi (LP64 with hardware floating-point calling convention for FLEN=64). And RISCV64_LP64 uses [LP64](https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#named-abis) as abi (Integer calling-convention only, and hardware floating-point calling convention is not used). + - For RISCV32, the format is \[_abi], where "_abi" is optional, currently the supported formats are RISCV32, RISCV32_ILP32D and RISCV32_ILP32: RISCV32 and RISCV32_ILP32D are identical, using [ILP32D](https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#named-abis) as abi (ILP32 with hardware floating-point calling convention for FLEN=64). And RISCV32_ILP32 uses [ILP32](https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#named-abis) as abi (Integer calling-convention only, and hardware floating-point calling convention is not used). ```bash cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM diff --git a/doc/export_native_api.md b/doc/export_native_api.md index e293e5c0d..ed7385539 100644 --- a/doc/export_native_api.md +++ b/doc/export_native_api.md @@ -155,7 +155,7 @@ As function parameters are always passed in 32 bits numbers, you can also use 'i // // If the function signature used i32 data type ("i") // for buffer address or string parameters, here -// is how to do address conversation and boundary check manually +// is how to do address conversion and boundary check manually // void foo2(wasm_exec_env_t exec_env, uint32 msg_offset, diff --git a/doc/perf_tune.md b/doc/perf_tune.md index 2cc428984..f57abe068 100644 --- a/doc/perf_tune.md +++ b/doc/perf_tune.md @@ -2,7 +2,7 @@ Normally there are some methods to tune the performance: -## 1. Use `wasm-opt` tool +## 1. Use `wasm-opt` tool Download the [binaryen release](https://github.com/WebAssembly/binaryen/releases), and use the `wasm-opt` tool in it to optimize the wasm file, for example: @@ -23,16 +23,19 @@ emcc -msimd128 -O3 -o ## 3. Enable segue optimization for wamrc when generating the aot file [Segue](https://plas2022.github.io/files/pdf/SegueColorGuard.pdf) is an optimization technology which uses x86 segment register to store the WebAssembly linear memory base address, so as to remove most of the cost of SFI (Software-based Fault Isolation) base addition and free up a general purpose register, by this way it may: + - Improve the performance of JIT/AOT - Reduce the footprint of JIT/AOT, the JIT/AOT code generated is smaller - Reduce the compilation time of JIT/AOT Currently it is supported on linux x86-64, developer can use `--enable-segue=[]` for wamrc: + ```bash wamrc --enable-segue -o aot_file wasm_file # or wamrc --enable-segue=[] -o aot_file wasm_file ``` + `flags` can be: i32.load, i64.load, f32.load, f64.load, v128.load, i32.store, i64.store, f32.store, f64.store and v128.store, use comma to separate them, e.g. `--enable-segue=i32.load,i64.store`, and `--enable-segue` means all flags are added. > Note: Normally for most cases, using `--enable-segue` is enough, but for some cases, using `--enable-segue=` may be better, for example for CoreMark benchmark, `--enable-segue=i32.store` may lead to better performance than `--enable-segue`. @@ -40,7 +43,8 @@ wamrc --enable-segue=[] -o aot_file wasm_file ## 4. Enable segue optimization for iwasm when running wasm file Similar to segue optimization for wamrc, run: -``` bash + +```bash iwasm --enable-segue wasm_file (iwasm is built with llvm-jit enabled) # or iwasm --enable-segue=[] wasm_file @@ -55,6 +59,7 @@ LLVM PGO (Profile-Guided Optimization) allows the compiler to better optimize co 2. Compile iwasm with `cmake -DWAMR_BUILD_STATIC_PGO=1` and run `iwasm --gen-prof-file= ` to generate the raw profile file. > Note: Directly dumping raw profile data to file system may be unsupported in some environments, developer can dump the profile data into memory buffer instead and try outputting it through network (e.g. uart or socket): + ```C uint32_t wasm_runtime_get_pgo_prof_data_size(wasm_module_inst_t module_inst); @@ -84,6 +89,91 @@ Please notice that this method is not a general solution since it may lead to se 3. Run the AOT module by iwasm with `--disable-bounds-checks` option. > Note: The size of AOT file will be much smaller than the default, and some tricks are possible such as let the wasm application access the memory of host os directly. -Please notice that if this option is enabled, the wasm spec test will fail since it requires the memory boundary check. For example, the runtime will crash when accessing the memory out of the boundary in some cases instead of throwing an exception as the spec requires. +> Please notice that if this option is enabled, the wasm spec test will fail since it requires the memory boundary check. For example, the runtime will crash when accessing the memory out of the boundary in some cases instead of throwing an exception as the spec requires. You should only use this method for well tested wasm applications and make sure the memory access is safe. + +## 7. Use linux-perf + +Linux perf is a powerful tool to analyze the performance of a program, developer can use it to find the hot functions and optimize them. It is one profiler supported by WAMR. In order to use it, you need to add `--perf-profile` while running _iwasm_. By default, it is disabled. + +> [!CAUTION] +> For now, only llvm-jit mode supports linux-perf. + +Here is a basic example, if there is a Wasm application _foo.wasm_, you'll execute. + +``` +$ perf record --output=perf.data.raw -- iwasm --perf-profile foo.wasm +``` + +This will create a _perf.data_ and a _jit-xxx.dump_ under _~/.debug.jit/_ folder. This extra file is WAMR generated at runtime, and it contains the mapping between the JIT code and the original Wasm function names. + +The next thing need to do is to merge _jit-xxx.dump_ file into the _perf.data_. + +``` +$ perf inject --jit --input=perf.data.raw --output=perf.data +``` + +This step will create a lot of _jitted-xxxx-N.so_ which are ELF images for all JIT functions created at runtime. + +> [!TIP] +> add `-v` and check if there is output likes _write ELF image ..._. If yes, it means above merge is successful. + +Finally, you can use _perf report_ to analyze the performance. + +``` +$ perf report --input=perf.data +``` + +> [!CAUTION] +> Using release builds of llvm and iwasm will produce "[unknown]" functions in the call graph. It is not only because +> of the missing debug information, but also because of removing frame pointers. To get the complete result, please +> use debug builds of both llvm and iwasm. +> +> Wasm functions names are stored in _the custom name section_. Toolchains always generate the custom name section in both debug and release builds. However, the custom name section is stripped to pursue smallest size in release build. So, if you want to get a understandable result, please search the manual of toolchain to look for a way to keep the custom name section. +> +> For example, with EMCC, you can add `-g2`. +> +> If not able to get the context of the custom name section, WAMR will use `aot_func#N` to represent the function name. `N` is from 0. `aot_func#0` represents the first *not imported wasm function*. + +### 7.1 Flamegraph + +[Flamegraph](https://www.brendangregg.com/flamegraphs.html) is a powerful tool to visualize stack traces of profiled software so that the most frequent code-paths can be identified quickly and accurately. In order to use it, you need to [capture graphs](https://github.com/brendangregg/FlameGraph#1-capture-stacks) when running `perf record` + +``` +$ perf record -k mono --call-graph=fp --output=perf.data.raw -- iwasm --perf-profile foo.wasm +``` + +merge the _jit-xxx.dump_ file into the _perf.data.raw_. + +``` +$ perf inject --jit --input=perf.data.raw --output=perf.data +``` + +generate the stack trace file. + +``` +$ perf script > out.perf +``` + +[fold stacks](https://github.com/brendangregg/FlameGraph#2-fold-stacks). + +``` +$ ./FlameGraph/stackcollapse-perf.pl out.perf > out.folded +``` + +[render a flamegraph](https://github.com/brendangregg/FlameGraph#3-flamegraphpl) + +``` +$ ./FlameGraph/flamegraph.pl out.folded > perf.foo.wasm.svg +``` + +> [!TIP] +> use `grep` to pick up folded stacks you are interested in or filter out something. +> +> For example, if just want to see stacks of wasm functions, you can use +> +> ```bash +> # only jitted functions +> $ grep "wasm_runtime_invoke_native" out.folded | ./FlameGraph/flamegraph.pl > perf.foo.wasm.only.svg +> ``` diff --git a/doc/socket_api.md b/doc/socket_api.md index 9e65d33cd..eff937617 100644 --- a/doc/socket_api.md +++ b/doc/socket_api.md @@ -58,7 +58,7 @@ enabled. _iwasm_ accepts address ranges via an option, `--addr-pool`, to implement the capability control. All IP address the WebAssembly application may need to `bind()` or `connect()` -should be announced first. Every IP address should be in CIRD notation. +should be announced first. Every IP address should be in CIDR notation. ```bash $ iwasm --addr-pool=1.2.3.4/15,2.3.4.6/16 socket_example.wasm diff --git a/language-bindings/go/go.mod b/language-bindings/go/go.mod index 60afebbff..b7e428654 100644 --- a/language-bindings/go/go.mod +++ b/language-bindings/go/go.mod @@ -1,4 +1,4 @@ -module gitlab.alipay-inc.com/TNT_Runtime/ant-runtime/bindings/go +module github.com/bytecodealliance/wasm-micro-runtime/language-bindings/go go 1.15 diff --git a/language-bindings/go/samples/build.sh b/language-bindings/go/samples/build.sh index 1b0a80719..0799fe5a0 100755 --- a/language-bindings/go/samples/build.sh +++ b/language-bindings/go/samples/build.sh @@ -3,19 +3,11 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -PLATFORM=$(uname -s | tr A-Z a-z) CUR_DIR=$PWD -WAMR_DIR=$PWD/../../.. -WAMR_GO_DIR=$PWD/../wamr -cp -a ${WAMR_DIR}/core/iwasm/include/*.h ${WAMR_GO_DIR}/packaged/include - -mkdir -p build && cd build -cmake ${WAMR_DIR}/product-mini/platforms/${PLATFORM} \ - -DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_DUMP_CALL_STACK=1 \ - -DWAMR_BUILD_MEMORY_PROFILING=1 -make -j ${nproc} -cp -a libvmlib.a ${WAMR_GO_DIR}/packaged/lib/${PLATFORM}-amd64 +pushd ${CUR_DIR}/.. > /dev/null 2>&1 +./build.sh +popd > /dev/null 2>& 1 cd ${CUR_DIR} rm -f test diff --git a/language-bindings/go/samples/test.go b/language-bindings/go/samples/test.go index aacb4a950..d0fc7d8b2 100644 --- a/language-bindings/go/samples/test.go +++ b/language-bindings/go/samples/test.go @@ -6,7 +6,7 @@ package main import ( - "gitlab.alipay-inc.com/TNT_Runtime/ant-runtime/bindings/go/wamr" + "github.com/bytecodealliance/wasm-micro-runtime/language-bindings/go/wamr" "fmt" ) diff --git a/language-bindings/go/wamr/instance.go b/language-bindings/go/wamr/instance.go index 08757f4dc..7c761ee99 100644 --- a/language-bindings/go/wamr/instance.go +++ b/language-bindings/go/wamr/instance.go @@ -272,7 +272,9 @@ func (self *Instance) CallFuncV(funcName string, for i = 0; i < result_count; i++ { switch result_types[i] { case C.WASM_I32: + fallthrough case C.WASM_FUNCREF: + fallthrough case C.WASM_ANYREF: i32 := (int32)(argv[argc]) results[i] = i32 diff --git a/product-mini/platforms/alios-things/aos.mk b/product-mini/platforms/alios-things/aos.mk index 383e0b239..3f25cb980 100644 --- a/product-mini/platforms/alios-things/aos.mk +++ b/product-mini/platforms/alios-things/aos.mk @@ -98,6 +98,7 @@ $(NAME)_SOURCES := ${SHARED_ROOT}/platform/alios/alios_platform.c \ ${SHARED_ROOT}/mem-alloc/ems/ems_alloc.c \ ${SHARED_ROOT}/mem-alloc/ems/ems_hmu.c \ ${SHARED_ROOT}/utils/bh_assert.c \ + ${SHARED_ROOT}/utils/bh_bitmap.c \ ${SHARED_ROOT}/utils/bh_common.c \ ${SHARED_ROOT}/utils/bh_hashmap.c \ ${SHARED_ROOT}/utils/bh_list.c \ diff --git a/product-mini/platforms/common/libc_wasi.c b/product-mini/platforms/common/libc_wasi.c new file mode 100644 index 000000000..84e133bc0 --- /dev/null +++ b/product-mini/platforms/common/libc_wasi.c @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include + +#include "bh_platform.h" +#include "wasm_export.h" + +typedef struct { + const char *dir_list[8]; + uint32 dir_list_size; + const char *map_dir_list[8]; + uint32 map_dir_list_size; + const char *env_list[8]; + uint32 env_list_size; + const char *addr_pool[8]; + uint32 addr_pool_size; + const char *ns_lookup_pool[8]; + uint32 ns_lookup_pool_size; +} libc_wasi_parse_context_t; + +typedef enum { + LIBC_WASI_PARSE_RESULT_OK = 0, + LIBC_WASI_PARSE_RESULT_NEED_HELP, + LIBC_WASI_PARSE_RESULT_BAD_PARAM +} libc_wasi_parse_result_t; + +static void +libc_wasi_print_help() +{ + printf(" --env= Pass wasi environment variables with " + "\"key=value\"\n"); + printf(" to the program, for example:\n"); + printf(" --env=\"key1=value1\" " + "--env=\"key2=value2\"\n"); + printf(" --dir= Grant wasi access to the given host " + "directories\n"); + printf(" to the program, for example:\n"); + printf(" --dir= --dir=\n"); + printf(" --map-dir= Grant wasi access to the given host " + "directories\n"); + printf(" to the program at a specific guest " + "path, for example:\n"); + printf(" --map-dir= " + "--map-dir=\n"); + printf(" --addr-pool= Grant wasi access to the given network " + "addresses in\n"); + printf(" CIDR notation to the program, seperated " + "with ',',\n"); + printf(" for example:\n"); + printf(" --addr-pool=1.2.3.4/15,2.3.4.5/16\n"); + printf(" --allow-resolve= Allow the lookup of the specific domain " + "name or domain\n"); + printf(" name suffixes using a wildcard, for " + "example:\n"); + printf(" --allow-resolve=example.com # allow the " + "lookup of the specific domain\n"); + printf(" --allow-resolve=*.example.com # allow " + "the lookup of all subdomains\n"); + printf(" --allow-resolve=* # allow any lookup\n"); +} + +static bool +validate_env_str(char *env) +{ + char *p = env; + int key_len = 0; + + while (*p != '\0' && *p != '=') { + key_len++; + p++; + } + + if (*p != '=' || key_len == 0) + return false; + + return true; +} + +libc_wasi_parse_result_t +libc_wasi_parse(char *arg, libc_wasi_parse_context_t *ctx) +{ + if (!strncmp(arg, "--dir=", 6)) { + if (arg[6] == '\0') + return LIBC_WASI_PARSE_RESULT_NEED_HELP; + if (ctx->dir_list_size >= sizeof(ctx->dir_list) / sizeof(char *)) { + printf("Only allow max dir number %d\n", + (int)(sizeof(ctx->dir_list) / sizeof(char *))); + return LIBC_WASI_PARSE_RESULT_BAD_PARAM; + } + ctx->dir_list[ctx->dir_list_size++] = arg + 6; + } + else if (!strncmp(arg, "--map-dir=", 10)) { + if (arg[10] == '\0') + return LIBC_WASI_PARSE_RESULT_NEED_HELP; + if (ctx->map_dir_list_size + >= sizeof(ctx->map_dir_list) / sizeof(char *)) { + printf("Only allow max map dir number %d\n", + (int)(sizeof(ctx->map_dir_list) / sizeof(char *))); + return 1; + } + ctx->map_dir_list[ctx->map_dir_list_size++] = arg + 10; + } + else if (!strncmp(arg, "--env=", 6)) { + char *tmp_env; + + if (arg[6] == '\0') + return LIBC_WASI_PARSE_RESULT_NEED_HELP; + if (ctx->env_list_size >= sizeof(ctx->env_list) / sizeof(char *)) { + printf("Only allow max env number %d\n", + (int)(sizeof(ctx->env_list) / sizeof(char *))); + return LIBC_WASI_PARSE_RESULT_BAD_PARAM; + } + tmp_env = arg + 6; + if (validate_env_str(tmp_env)) + ctx->env_list[ctx->env_list_size++] = tmp_env; + else { + printf("Wasm parse env string failed: expect \"key=value\", " + "got \"%s\"\n", + tmp_env); + return LIBC_WASI_PARSE_RESULT_NEED_HELP; + } + } + /* TODO: parse the configuration file via --addr-pool-file */ + else if (!strncmp(arg, "--addr-pool=", strlen("--addr-pool="))) { + /* like: --addr-pool=100.200.244.255/30 */ + char *token = NULL; + + if ('\0' == arg[12]) + return LIBC_WASI_PARSE_RESULT_NEED_HELP; + + token = strtok(arg + strlen("--addr-pool="), ","); + while (token) { + if (ctx->addr_pool_size + >= sizeof(ctx->addr_pool) / sizeof(char *)) { + printf("Only allow max address number %d\n", + (int)(sizeof(ctx->addr_pool) / sizeof(char *))); + return LIBC_WASI_PARSE_RESULT_BAD_PARAM; + } + + ctx->addr_pool[ctx->addr_pool_size++] = token; + token = strtok(NULL, ";"); + } + } + else if (!strncmp(arg, "--allow-resolve=", 16)) { + if (arg[16] == '\0') + return LIBC_WASI_PARSE_RESULT_NEED_HELP; + if (ctx->ns_lookup_pool_size + >= sizeof(ctx->ns_lookup_pool) / sizeof(ctx->ns_lookup_pool[0])) { + printf("Only allow max ns lookup number %d\n", + (int)(sizeof(ctx->ns_lookup_pool) + / sizeof(ctx->ns_lookup_pool[0]))); + return LIBC_WASI_PARSE_RESULT_BAD_PARAM; + } + ctx->ns_lookup_pool[ctx->ns_lookup_pool_size++] = arg + 16; + } + else { + return LIBC_WASI_PARSE_RESULT_NEED_HELP; + } + return LIBC_WASI_PARSE_RESULT_OK; +} + +void +libc_wasi_init(wasm_module_t wasm_module, int argc, char **argv, + libc_wasi_parse_context_t *ctx) +{ + wasm_runtime_set_wasi_args(wasm_module, ctx->dir_list, ctx->dir_list_size, + ctx->map_dir_list, ctx->map_dir_list_size, + ctx->env_list, ctx->env_list_size, argv, argc); + + wasm_runtime_set_wasi_addr_pool(wasm_module, ctx->addr_pool, + ctx->addr_pool_size); + wasm_runtime_set_wasi_ns_lookup_pool(wasm_module, ctx->ns_lookup_pool, + ctx->ns_lookup_pool_size); +} diff --git a/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp b/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp index 2b5300ff3..9f24cdaa0 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp +++ b/product-mini/platforms/linux-sgx/enclave-sample/App/App.cpp @@ -228,7 +228,7 @@ print_help() printf(" to the program, for example:\n"); printf(" --dir= --dir=\n"); printf(" --addr-pool= Grant wasi access to the given network addresses in\n"); - printf(" CIRD notation to the program, seperated with ',',\n"); + printf(" CIDR notation to the program, seperated with ',',\n"); printf(" for example:\n"); printf(" --addr-pool=1.2.3.4/15,2.3.4.5/16\n"); printf(" --max-threads=n Set maximum thread number per cluster, default is 4\n"); diff --git a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp index 164fa0b7d..b854c70b4 100644 --- a/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp +++ b/product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.cpp @@ -250,7 +250,8 @@ handle_cmd_load_module(uint64 *args, uint32 argc) if (total_size >= UINT32_MAX || !(enclave_module = (EnclaveModule *)os_mmap( - NULL, (uint32)total_size, map_prot, map_flags))) { + NULL, (uint32)total_size, map_prot, map_flags, + os_get_invalid_handle()))) { set_error_buf(error_buf, error_buf_size, "WASM module load failed: mmap memory failed."); *(void **)args_org = NULL; diff --git a/product-mini/platforms/nuttx/wamr.mk b/product-mini/platforms/nuttx/wamr.mk index 04a6db91f..b91fac9a8 100644 --- a/product-mini/platforms/nuttx/wamr.mk +++ b/product-mini/platforms/nuttx/wamr.mk @@ -13,6 +13,8 @@ else ifeq ($(CONFIG_ARCH_ARMV7M),y) WAMR_BUILD_TARGET := THUMBV7EM else ifeq ($(CONFIG_ARCH_ARMV8M),y) WAMR_BUILD_TARGET := THUMBV8M +else ifeq ($(CONFIG_ARCH_ARM64),y) +WAMR_BUILD_TARGET := AARCH64 else ifeq ($(CONFIG_ARCH_X86),y) WAMR_BUILD_TARGET := X86_32 else ifeq ($(CONFIG_ARCH_X86_64),y) @@ -236,18 +238,22 @@ else CFLAGS += -DWASM_ENABLE_LIBC_BUILTIN=0 endif -ifeq ($(CONFIG_INTERPRETERS_WAMR_CONFIGUABLE_BOUNDS_CHECKS),y) -CFLAGS += -DWASM_CONFIGUABLE_BOUNDS_CHECKS=1 +ifeq ($(CONFIG_INTERPRETERS_WAMR_CONFIGURABLE_BOUNDS_CHECKS),y) +CFLAGS += -DWASM_CONFIGURABLE_BOUNDS_CHECKS=1 else -CFLAGS += -DWASM_CONFIGUABLE_BOUNDS_CHECKS=0 +CFLAGS += -DWASM_CONFIGURABLE_BOUNDS_CHECKS=0 endif ifeq ($(CONFIG_INTERPRETERS_WAMR_LIBC_WASI),y) CFLAGS += -DWASM_ENABLE_LIBC_WASI=1 CFLAGS += -I$(IWASM_ROOT)/libraries/libc-wasi/sandboxed-system-primitives/src CFLAGS += -I$(IWASM_ROOT)/libraries/libc-wasi/sandboxed-system-primitives/include +CFLAGS += -I${SHARED_ROOT}/platform/common/libc-util CSRCS += blocking_op.c CSRCS += posix_socket.c +CSRCS += posix_file.c +CSRCS += posix_clock.c +CSRCS += libc_errno.c CSRCS += libc_wasi_wrapper.c VPATH += $(IWASM_ROOT)/libraries/libc-wasi CSRCS += posix.c @@ -313,6 +319,12 @@ endif # REVISIT: is this worth to have a Kconfig? CFLAGS += -DWASM_DISABLE_WAKEUP_BLOCKING_OP=0 +ifeq ($(CONFIG_INTERPRETERS_WAMR_LOAD_CUSTOM_SECTIONS),y) +CFLAGS += -DWASM_ENABLE_LOAD_CUSTOM_SECTION=1 +else +CFLAGS += -DWASM_ENABLE_LOAD_CUSTOM_SECTION=0 +endif + ifeq ($(CONFIG_INTERPRETERS_WAMR_CUSTOM_NAME_SECTIONS),y) CFLAGS += -DWASM_ENABLE_CUSTOM_NAME_SECTION=1 else @@ -367,6 +379,7 @@ CSRCS += nuttx_platform.c \ ems_alloc.c \ ems_hmu.c \ bh_assert.c \ + bh_bitmap.c \ bh_common.c \ bh_hashmap.c \ bh_list.c \ @@ -387,6 +400,7 @@ ASRCS += $(INVOKE_NATIVE) VPATH += $(SHARED_ROOT)/platform/nuttx VPATH += $(SHARED_ROOT)/platform/common/posix +VPATH += $(SHARED_ROOT)/platform/common/libc-util VPATH += $(SHARED_ROOT)/mem-alloc VPATH += $(SHARED_ROOT)/mem-alloc/ems VPATH += $(SHARED_ROOT)/utils diff --git a/product-mini/platforms/posix/main.c b/product-mini/platforms/posix/main.c index b27bd8c2e..851855497 100644 --- a/product-mini/platforms/posix/main.c +++ b/product-mini/platforms/posix/main.c @@ -14,6 +14,10 @@ #include "bh_read_file.h" #include "wasm_export.h" +#if WASM_ENABLE_LIBC_WASI != 0 +#include "../common/libc_wasi.c" +#endif + #if BH_HAS_DLFCN #include #endif @@ -54,6 +58,7 @@ print_help() #if WASM_ENABLE_JIT != 0 printf(" --llvm-jit-size-level=n Set LLVM JIT size level, default is 3\n"); printf(" --llvm-jit-opt-level=n Set LLVM JIT optimization level, default is 3\n"); + printf(" --perf-profile Enable linux perf support. For now, it only works in llvm-jit.\n"); #if defined(os_writegsbase) printf(" --enable-segue[=] Enable using segment register GS as the base address of\n"); printf(" linear memory, which may improve performance, flags can be:\n"); @@ -65,25 +70,11 @@ print_help() #endif printf(" --repl Start a very simple REPL (read-eval-print-loop) mode\n" " that runs commands in the form of \"FUNC ARG...\"\n"); -#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0 +#if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0 printf(" --disable-bounds-checks Disable bounds checks for memory accesses\n"); #endif #if WASM_ENABLE_LIBC_WASI != 0 - printf(" --env= Pass wasi environment variables with \"key=value\"\n"); - printf(" to the program, for example:\n"); - printf(" --env=\"key1=value1\" --env=\"key2=value2\"\n"); - printf(" --dir= Grant wasi access to the given host directories\n"); - printf(" to the program, for example:\n"); - printf(" --dir= --dir=\n"); - printf(" --addr-pool= Grant wasi access to the given network addresses in\n"); - printf(" CIRD notation to the program, seperated with ',',\n"); - printf(" for example:\n"); - printf(" --addr-pool=1.2.3.4/15,2.3.4.5/16\n"); - printf(" --allow-resolve= Allow the lookup of the specific domain name or domain\n"); - printf(" name suffixes using a wildcard, for example:\n"); - printf(" --allow-resolve=example.com # allow the lookup of the specific domain\n"); - printf(" --allow-resolve=*.example.com # allow the lookup of all subdomains\n"); - printf(" --allow-resolve=* # allow any lookup\n"); + libc_wasi_print_help(); #endif #if BH_HAS_DLFCN printf(" --native-lib= Register native libraries to the WASM module, which\n"); @@ -204,8 +195,11 @@ app_instance_repl(wasm_module_inst_t module_inst) break; } if (app_argc != 0) { + const char *exception; wasm_application_execute_func(module_inst, app_argv[0], app_argc - 1, app_argv + 1); + if ((exception = wasm_runtime_get_exception(module_inst))) + printf("%s\n", exception); } free(app_argv); } @@ -266,25 +260,6 @@ resolve_segue_flags(char *str_flags) } #endif /* end of WASM_ENABLE_JIT != 0 */ -#if WASM_ENABLE_LIBC_WASI != 0 -static bool -validate_env_str(char *env) -{ - char *p = env; - int key_len = 0; - - while (*p != '\0' && *p != '=') { - key_len++; - p++; - } - - if (*p != '=' || key_len == 0) - return false; - - return true; -} -#endif - #if BH_HAS_DLFCN struct native_lib { void *handle; @@ -435,7 +410,7 @@ module_reader_callback(package_type_t module_type, const char *module_name, const char *format = "%s/%s%s"; int sz = strlen(module_search_path) + strlen("/") + strlen(module_name) + strlen(file_format) + 1; - char *wasm_file_name = BH_MALLOC(sz); + char *wasm_file_name = wasm_runtime_malloc(sz); if (!wasm_file_name) { return false; } @@ -461,7 +436,37 @@ moudle_destroyer(uint8 *buffer, uint32 size) #if WASM_ENABLE_GLOBAL_HEAP_POOL != 0 static char global_heap_buf[WASM_GLOBAL_HEAP_SIZE] = { 0 }; +#else +static void * +malloc_func( +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + void *user_data, #endif + unsigned int size) +{ + return malloc(size); +} + +static void * +realloc_func( +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + void *user_data, +#endif + void *ptr, unsigned int size) +{ + return realloc(ptr, size); +} + +static void +free_func( +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + void *user_data, +#endif + void *ptr) +{ + free(ptr); +} +#endif /* end of WASM_ENABLE_GLOBAL_HEAP_POOL */ #if WASM_ENABLE_STATIC_PGO != 0 static void @@ -556,6 +561,7 @@ main(int argc, char *argv[]) uint32 llvm_jit_size_level = 3; uint32 llvm_jit_opt_level = 3; uint32 segue_flags = 0; + bool enable_linux_perf_support = false; #endif wasm_module_t wasm_module = NULL; wasm_module_inst_t wasm_module_inst = NULL; @@ -567,18 +573,11 @@ main(int argc, char *argv[]) #endif bool is_repl_mode = false; bool is_xip_file = false; -#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0 +#if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0 bool disable_bounds_checks = false; #endif #if WASM_ENABLE_LIBC_WASI != 0 - const char *dir_list[8] = { NULL }; - uint32 dir_list_size = 0; - const char *env_list[8] = { NULL }; - uint32 env_list_size = 0; - const char *addr_pool[8] = { NULL }; - uint32 addr_pool_size = 0; - const char *ns_lookup_pool[8] = { NULL }; - uint32 ns_lookup_pool_size = 0; + libc_wasi_parse_context_t wasi_parse_ctx; #endif #if BH_HAS_DLFCN const char *native_lib_list[8] = { NULL }; @@ -597,6 +596,10 @@ main(int argc, char *argv[]) int timeout_ms = -1; #endif +#if WASM_ENABLE_LIBC_WASI != 0 + memset(&wasi_parse_ctx, 0, sizeof(wasi_parse_ctx)); +#endif + /* Process options. */ for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) { if (!strcmp(argv[0], "-f") || !strcmp(argv[0], "--function")) { @@ -637,7 +640,7 @@ main(int argc, char *argv[]) else if (!strcmp(argv[0], "--repl")) { is_repl_mode = true; } -#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0 +#if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0 else if (!strcmp(argv[0], "--disable-bounds-checks")) { disable_bounds_checks = true; } @@ -699,71 +702,10 @@ main(int argc, char *argv[]) if (segue_flags == (uint32)-1) return print_help(); } + else if (!strncmp(argv[0], "--perf-profile", 14)) { + enable_linux_perf_support = true; + } #endif /* end of WASM_ENABLE_JIT != 0 */ -#if WASM_ENABLE_LIBC_WASI != 0 - else if (!strncmp(argv[0], "--dir=", 6)) { - if (argv[0][6] == '\0') - return print_help(); - if (dir_list_size >= sizeof(dir_list) / sizeof(char *)) { - printf("Only allow max dir number %d\n", - (int)(sizeof(dir_list) / sizeof(char *))); - return 1; - } - dir_list[dir_list_size++] = argv[0] + 6; - } - else if (!strncmp(argv[0], "--env=", 6)) { - char *tmp_env; - - if (argv[0][6] == '\0') - return print_help(); - if (env_list_size >= sizeof(env_list) / sizeof(char *)) { - printf("Only allow max env number %d\n", - (int)(sizeof(env_list) / sizeof(char *))); - return 1; - } - tmp_env = argv[0] + 6; - if (validate_env_str(tmp_env)) - env_list[env_list_size++] = tmp_env; - else { - printf("Wasm parse env string failed: expect \"key=value\", " - "got \"%s\"\n", - tmp_env); - return print_help(); - } - } - /* TODO: parse the configuration file via --addr-pool-file */ - else if (!strncmp(argv[0], "--addr-pool=", strlen("--addr-pool="))) { - /* like: --addr-pool=100.200.244.255/30 */ - char *token = NULL; - - if ('\0' == argv[0][12]) - return print_help(); - - token = strtok(argv[0] + strlen("--addr-pool="), ","); - while (token) { - if (addr_pool_size >= sizeof(addr_pool) / sizeof(char *)) { - printf("Only allow max address number %d\n", - (int)(sizeof(addr_pool) / sizeof(char *))); - return 1; - } - - addr_pool[addr_pool_size++] = token; - token = strtok(NULL, ";"); - } - } - else if (!strncmp(argv[0], "--allow-resolve=", 16)) { - if (argv[0][16] == '\0') - return print_help(); - if (ns_lookup_pool_size - >= sizeof(ns_lookup_pool) / sizeof(ns_lookup_pool[0])) { - printf( - "Only allow max ns lookup number %d\n", - (int)(sizeof(ns_lookup_pool) / sizeof(ns_lookup_pool[0]))); - return 1; - } - ns_lookup_pool[ns_lookup_pool_size++] = argv[0] + 16; - } -#endif /* WASM_ENABLE_LIBC_WASI */ #if BH_HAS_DLFCN else if (!strncmp(argv[0], "--native-lib=", 13)) { if (argv[0][13] == '\0') @@ -826,8 +768,22 @@ main(int argc, char *argv[]) patch); return 0; } - else + else { +#if WASM_ENABLE_LIBC_WASI != 0 + libc_wasi_parse_result_t result = + libc_wasi_parse(argv[0], &wasi_parse_ctx); + switch (result) { + case LIBC_WASI_PARSE_RESULT_OK: + continue; + case LIBC_WASI_PARSE_RESULT_NEED_HELP: + return print_help(); + case LIBC_WASI_PARSE_RESULT_BAD_PARAM: + return 1; + } +#else return print_help(); +#endif + } } if (argc == 0) @@ -846,9 +802,13 @@ main(int argc, char *argv[]) init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); #else init_args.mem_alloc_type = Alloc_With_Allocator; - init_args.mem_alloc_option.allocator.malloc_func = malloc; - init_args.mem_alloc_option.allocator.realloc_func = realloc; - init_args.mem_alloc_option.allocator.free_func = free; +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + /* Set user data for the allocator is needed */ + /* init_args.mem_alloc_option.allocator.user_data = user_data; */ +#endif + init_args.mem_alloc_option.allocator.malloc_func = malloc_func; + init_args.mem_alloc_option.allocator.realloc_func = realloc_func; + init_args.mem_alloc_option.allocator.free_func = free_func; #endif #if WASM_ENABLE_FAST_JIT != 0 @@ -859,6 +819,7 @@ main(int argc, char *argv[]) init_args.llvm_jit_size_level = llvm_jit_size_level; init_args.llvm_jit_opt_level = llvm_jit_opt_level; init_args.segue_flags = segue_flags; + init_args.linux_perf_support = enable_linux_perf_support; #endif #if WASM_ENABLE_DEBUG_INTERP != 0 @@ -893,8 +854,8 @@ main(int argc, char *argv[]) int map_prot = MMAP_PROT_READ | MMAP_PROT_WRITE | MMAP_PROT_EXEC; int map_flags = MMAP_MAP_32BIT; - if (!(wasm_file_mapped = - os_mmap(NULL, (uint32)wasm_file_size, map_prot, map_flags))) { + if (!(wasm_file_mapped = os_mmap(NULL, (uint32)wasm_file_size, map_prot, + map_flags, os_get_invalid_handle()))) { printf("mmap memory failed\n"); wasm_runtime_free(wasm_file_buf); goto fail1; @@ -920,12 +881,7 @@ main(int argc, char *argv[]) } #if WASM_ENABLE_LIBC_WASI != 0 - wasm_runtime_set_wasi_args(wasm_module, dir_list, dir_list_size, NULL, 0, - env_list, env_list_size, argv, argc); - - wasm_runtime_set_wasi_addr_pool(wasm_module, addr_pool, addr_pool_size); - wasm_runtime_set_wasi_ns_lookup_pool(wasm_module, ns_lookup_pool, - ns_lookup_pool_size); + libc_wasi_init(wasm_module, argc, argv, &wasi_parse_ctx); #endif /* instantiate the module */ @@ -936,7 +892,7 @@ main(int argc, char *argv[]) goto fail3; } -#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0 +#if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0 if (disable_bounds_checks) { wasm_runtime_set_bounds_checks(wasm_module_inst, false); } diff --git a/product-mini/platforms/windows/CMakeLists.txt b/product-mini/platforms/windows/CMakeLists.txt index db88f42bc..02aa3f31b 100644 --- a/product-mini/platforms/windows/CMakeLists.txt +++ b/product-mini/platforms/windows/CMakeLists.txt @@ -4,7 +4,6 @@ cmake_minimum_required (VERSION 2.9) project (iwasm C ASM CXX) -enable_language(ASM_MASM) # set (CMAKE_VERBOSE_MAKEFILE 1) set (WAMR_BUILD_PLATFORM "windows") @@ -13,8 +12,6 @@ set (WAMR_BUILD_PLATFORM "windows") set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") -set (CMAKE_C_STANDARD 99) - add_definitions(-DCOMPILING_WASM_RUNTIME_API=1) # Set WAMR_BUILD_TARGET, currently values supported: @@ -96,6 +93,15 @@ if (WAMR_BUILD_DEBUG_INTERP EQUAL 1) set (WAMR_BUILD_SIMD 0) endif () +if (WAMR_BUILD_LIBC_WASI EQUAL 1) + set (CMAKE_C_STANDARD 11) + if (MSVC) + add_compile_options(/experimental:c11atomics) + endif() +else() + set (CMAKE_C_STANDARD 99) +endif() + set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) @@ -147,3 +153,9 @@ target_link_libraries (libiwasm ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS}) if (MINGW) target_link_libraries (libiwasm ws2_32) endif () + +if (WIN32) + target_link_libraries(libiwasm ntdll) + + target_link_libraries(iwasm ntdll) +endif() diff --git a/product-mini/platforms/windows/main.c b/product-mini/platforms/windows/main.c index f6347919b..921b77265 100644 --- a/product-mini/platforms/windows/main.c +++ b/product-mini/platforms/windows/main.c @@ -10,6 +10,10 @@ #include "bh_read_file.h" #include "wasm_export.h" +#if WASM_ENABLE_LIBC_WASI != 0 +#include "../common/libc_wasi.c" +#endif + static int app_argc; static char **app_argv; @@ -48,12 +52,7 @@ print_help() printf(" --repl Start a very simple REPL (read-eval-print-loop) mode\n" " that runs commands in the form of `FUNC ARG...`\n"); #if WASM_ENABLE_LIBC_WASI != 0 - printf(" --env= Pass wasi environment variables with \"key=value\"\n"); - printf(" to the program, for example:\n"); - printf(" --env=\"key1=value1\" --env=\"key2=value2\"\n"); - printf(" --dir= Grant wasi access to the given host directories\n"); - printf(" to the program, for example:\n"); - printf(" --dir= --dir=\n"); + libc_wasi_print_help(); #endif #if WASM_ENABLE_MULTI_MODULE != 0 printf(" --module-path= Indicate a module search path. default is current\n" @@ -141,7 +140,8 @@ app_instance_repl(wasm_module_inst_t module_inst) char *cmd; size_t n; - while ((printf("webassembly> "), cmd = fgets(buffer, sizeof(buffer), stdin)) + while ((printf("webassembly> "), fflush(stdout), + cmd = fgets(buffer, sizeof(buffer), stdin)) != NULL) { bh_assert(cmd); n = strlen(cmd); @@ -161,8 +161,11 @@ app_instance_repl(wasm_module_inst_t module_inst) break; } if (app_argc != 0) { + const char *exception; wasm_application_execute_func(module_inst, app_argv[0], app_argc - 1, app_argv + 1); + if ((exception = wasm_runtime_get_exception(module_inst))) + printf("%s\n", exception); } free(app_argv); } @@ -170,28 +173,39 @@ app_instance_repl(wasm_module_inst_t module_inst) return NULL; } -#if WASM_ENABLE_LIBC_WASI != 0 -static bool -validate_env_str(char *env) -{ - char *p = env; - int key_len = 0; - - while (*p != '\0' && *p != '=') { - key_len++; - p++; - } - - if (*p != '=' || key_len == 0) - return false; - - return true; -} -#endif - #if WASM_ENABLE_GLOBAL_HEAP_POOL != 0 static char global_heap_buf[WASM_GLOBAL_HEAP_SIZE] = { 0 }; +#else +static void * +malloc_func( +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + void *user_data, #endif + unsigned int size) +{ + return malloc(size); +} + +static void * +realloc_func( +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + void *user_data, +#endif + void *ptr, unsigned int size) +{ + return realloc(ptr, size); +} + +static void +free_func( +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + void *user_data, +#endif + void *ptr) +{ + free(ptr); +} +#endif /* end of WASM_ENABLE_GLOBAL_HEAP_POOL */ #if WASM_ENABLE_MULTI_MODULE != 0 static char * @@ -219,7 +233,7 @@ module_reader_callback(package_type_t module_type, const char *module_name, const char *format = "%s/%s%s"; int sz = strlen(module_search_path) + strlen("/") + strlen(module_name) + strlen(file_format) + 1; - char *wasm_file_name = BH_MALLOC(sz); + char *wasm_file_name = wasm_runtime_malloc(sz); if (!wasm_file_name) { return false; } @@ -272,16 +286,17 @@ main(int argc, char *argv[]) bool is_repl_mode = false; bool is_xip_file = false; #if WASM_ENABLE_LIBC_WASI != 0 - const char *dir_list[8] = { NULL }; - uint32 dir_list_size = 0; - const char *env_list[8] = { NULL }; - uint32 env_list_size = 0; + libc_wasi_parse_context_t wasi_parse_ctx; #endif #if WASM_ENABLE_DEBUG_INTERP != 0 char *ip_addr = NULL; int instance_port = 0; #endif +#if WASM_ENABLE_LIBC_WASI != 0 + memset(&wasi_parse_ctx, 0, sizeof(wasi_parse_ctx)); +#endif + /* Process options. */ for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) { if (!strcmp(argv[0], "-f") || !strcmp(argv[0], "--function")) { @@ -363,38 +378,6 @@ main(int argc, char *argv[]) } } #endif -#if WASM_ENABLE_LIBC_WASI != 0 - else if (!strncmp(argv[0], "--dir=", 6)) { - if (argv[0][6] == '\0') - return print_help(); - if (dir_list_size >= sizeof(dir_list) / sizeof(char *)) { - printf("Only allow max dir number %d\n", - (int)(sizeof(dir_list) / sizeof(char *))); - return 1; - } - dir_list[dir_list_size++] = argv[0] + 6; - } - else if (!strncmp(argv[0], "--env=", 6)) { - char *tmp_env; - - if (argv[0][6] == '\0') - return print_help(); - if (env_list_size >= sizeof(env_list) / sizeof(char *)) { - printf("Only allow max env number %d\n", - (int)(sizeof(env_list) / sizeof(char *))); - return 1; - } - tmp_env = argv[0] + 6; - if (validate_env_str(tmp_env)) - env_list[env_list_size++] = tmp_env; - else { - printf("Wasm parse env string failed: expect \"key=value\", " - "got \"%s\"\n", - tmp_env); - return print_help(); - } - } -#endif /* WASM_ENABLE_LIBC_WASI */ #if WASM_ENABLE_MULTI_MODULE != 0 else if (!strncmp(argv[0], MODULE_PATH, strlen(MODULE_PATH))) { module_search_path = handle_module_path(argv[0]); @@ -430,8 +413,22 @@ main(int argc, char *argv[]) patch); return 0; } - else + else { +#if WASM_ENABLE_LIBC_WASI != 0 + libc_wasi_parse_result_t result = + libc_wasi_parse(argv[0], &wasi_parse_ctx); + switch (result) { + case LIBC_WASI_PARSE_RESULT_OK: + continue; + case LIBC_WASI_PARSE_RESULT_NEED_HELP: + return print_help(); + case LIBC_WASI_PARSE_RESULT_BAD_PARAM: + return 1; + } +#else return print_help(); +#endif + } } if (argc == 0) @@ -450,9 +447,13 @@ main(int argc, char *argv[]) init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); #else init_args.mem_alloc_type = Alloc_With_Allocator; - init_args.mem_alloc_option.allocator.malloc_func = malloc; - init_args.mem_alloc_option.allocator.realloc_func = realloc; - init_args.mem_alloc_option.allocator.free_func = free; +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + /* Set user data for the allocator is needed */ + /* init_args.mem_alloc_option.allocator.user_data = user_data; */ +#endif + init_args.mem_alloc_option.allocator.malloc_func = malloc_func; + init_args.mem_alloc_option.allocator.realloc_func = realloc_func; + init_args.mem_alloc_option.allocator.free_func = free_func; #endif #if WASM_ENABLE_JIT != 0 @@ -487,8 +488,8 @@ main(int argc, char *argv[]) int map_prot = MMAP_PROT_READ | MMAP_PROT_WRITE | MMAP_PROT_EXEC; int map_flags = MMAP_MAP_32BIT; - if (!(wasm_file_mapped = - os_mmap(NULL, (uint32)wasm_file_size, map_prot, map_flags))) { + if (!(wasm_file_mapped = os_mmap(NULL, (uint32)wasm_file_size, map_prot, + map_flags, os_get_invalid_handle()))) { printf("mmap memory failed\n"); wasm_runtime_free(wasm_file_buf); goto fail1; @@ -514,8 +515,7 @@ main(int argc, char *argv[]) } #if WASM_ENABLE_LIBC_WASI != 0 - wasm_runtime_set_wasi_args(wasm_module, dir_list, dir_list_size, NULL, 0, - env_list, env_list_size, argv, argc); + libc_wasi_init(wasm_module, argc, argv, &wasi_parse_ctx); #endif /* instantiate the module */ diff --git a/product-mini/platforms/windows/wasi_filtered_tests.json b/product-mini/platforms/windows/wasi_filtered_tests.json new file mode 100644 index 000000000..492a746eb --- /dev/null +++ b/product-mini/platforms/windows/wasi_filtered_tests.json @@ -0,0 +1,51 @@ +{ + "WASI C tests": { + "fdopendir-with-access": "Not implemented", + "lseek": "Not implemented" + }, + "WASI Rust tests": { + "dangling_symlink": "Not implemented", + "directory_seek": "Not implemented", + "dir_fd_op_failures": "Not implemented", + "fd_advise": "Not implemented", + "fd_fdstat_set_rights": "Not implemented", + "fd_filestat_set": "Not implemented", + "fd_flags_set": "Not implemented", + "fd_readdir": "Not implemented", + "file_allocate": "Not implemented", + "file_seek_tell": "Not implemented", + "file_truncation": "Not implemented", + "nofollow_errors": "Not implemented", + "path_exists": "Not implemented", + "path_filestat": "Not implemented", + "path_link": "Not implemented", + "path_open_preopen": "Not implemented", + "path_rename": "Not implemented", + "path_rename_dir_trailing_slashes": "Not implemented", + "path_symlink_trailing_slashes": "Not implemented", + "poll_oneoff_stdio": "Not implemented", + "readlink": "Not implemented (path_symlink)", + "symlink_create": "Not implemented", + "symlink_filestat": "Not implemented", + "symlink_loop": "Not implemented", + "truncation_rights": "Not implemented" + }, + "WASI threads proposal": { + "wasi_threads_exit_main_wasi_read": "Blocking ops not implemented", + "wasi_threads_exit_nonmain_wasi_read": "Blocking ops not implemented", + "wasi_threads_return_main_wasi_read": "Blocking ops not implemented", + "wasi_threads_return_main_wasi": "Blocking ops not implemented", + "wasi_threads_exit_nonmain_wasi": "Blocking ops not implemented", + "wasi_threads_exit_main_wasi": "Blocking ops not implemented" + }, + "WAMR lib-socket tests": { + "nslookup": "Not implemented", + "tcp_udp": "Not implemented" + }, + "lib-wasi-threads tests": { + "nonmain_proc_exit_sleep": "poll_oneoff not implemented", + "main_proc_exit_sleep": "poll_oneoff not implemented", + "main_trap_sleep": "poll_oneoff not implemented", + "nonmain_trap_sleep": "poll_oneoff not implemented" + } +} \ No newline at end of file diff --git a/product-mini/platforms/zephyr/simple/Dockerfile b/product-mini/platforms/zephyr/simple/Dockerfile index 9c8e6e5a0..a4c69a8ff 100644 --- a/product-mini/platforms/zephyr/simple/Dockerfile +++ b/product-mini/platforms/zephyr/simple/Dockerfile @@ -1,49 +1,32 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -FROM ubuntu:20.04 +FROM ubuntu:22.04 ARG DEBIAN_FRONTEND=noninteractive ENV TZ=Asian/Shanghai -# Install dependencies for Zephyr and ESPRESSIF +# Install dependencies for Zephyr # hadolint ignore=DL3008 -RUN apt-get update && apt-get install -y git wget flex bison gperf python3 python3-pip python3-venv\ - python3-dev python3-setuptools python3-tk python3-wheel xz-utils file libpython3.8-dev \ - ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0 device-tree-compiler \ - make gcc gcc-multilib g++-multilib libsdl2-dev libmagic1 qemu udev --no-install-recommends \ +RUN apt-get update && apt-get install -y --no-install-recommends git cmake ninja-build gperf \ + ccache dfu-util device-tree-compiler wget \ + python3-dev python3-pip python3-setuptools python3-tk python3-wheel xz-utils file \ + make gcc gcc-multilib g++-multilib libsdl2-dev libmagic1 \ && apt-get clean -y && rm -rf /var/lib/apt/lists/* -# Install recent CMake version -WORKDIR /tmp -RUN mkdir /opt/cmake \ - && wget --progress=dot:giga https://github.com/Kitware/CMake/releases/download/v3.22.1/cmake-3.22.1-linux-x86_64.sh \ - && sh cmake-3.22.1-linux-x86_64.sh --skip-license --prefix=/opt/cmake && rm cmake-3.22.1-linux-x86_64.sh -ENV PATH="/opt/cmake/bin:$PATH" - # Install the Zephyr Software Development Kit (SDK) WORKDIR /opt # hadolint ignore=DL4006 -RUN wget --progress=dot:giga https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.1/zephyr-sdk-0.16.1_linux-x86_64.tar.xz \ - && wget --progress=dot:giga -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.1/sha256.sum | shasum --check --ignore-missing \ - && tar xvf zephyr-sdk-0.16.1_linux-x86_64.tar.xz && rm zephyr-sdk-0.16.1_linux-x86_64.tar.xz +RUN wget --progress=dot:giga https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/zephyr-sdk-0.16.3_linux-x86_64.tar.xz \ + && wget --progress=dot:giga -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/sha256.sum | shasum --check --ignore-missing \ + && tar xvf zephyr-sdk-0.16.3_linux-x86_64.tar.xz && rm zephyr-sdk-0.16.3_linux-x86_64.tar.xz -WORKDIR /opt/zephyr-sdk-0.16.1 +WORKDIR /opt/zephyr-sdk-0.16.3 # hadolint ignore=DL4006 RUN yes | ./setup.sh -# Get ESP-IDF -RUN ln -s /usr/bin/python3 /usr/bin/python && mkdir -p ~/esp -WORKDIR /root/esp -RUN git clone https://github.com/espressif/esp-idf.git -WORKDIR /root/esp/esp-idf -RUN git checkout 03d4fa28694ee15ccfd5a97447575de2d1655026 \ - && git submodule update --init --recursive -# Set up the sep-idf tools -RUN ./install.sh esp32 esp32c3 - # Get Zephyr # hadolint ignore=DL3013 -RUN pip3 install --no-cache-dir west && west init -m https://github.com/zephyrproject-rtos/zephyr --mr v3.4.0 /root/zephyrproject +RUN pip3 install --no-cache-dir west && west init -m https://github.com/zephyrproject-rtos/zephyr --mr v3.5.0 /root/zephyrproject WORKDIR /root/zephyrproject RUN west update diff --git a/product-mini/platforms/zephyr/simple/Dockerfile.old b/product-mini/platforms/zephyr/simple/Dockerfile.old deleted file mode 100644 index e223f315a..000000000 --- a/product-mini/platforms/zephyr/simple/Dockerfile.old +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -FROM ubuntu:20.04 - -ARG DEBIAN_FRONTEND=noninteractive -ENV TZ=Asian/Shanghai - -# Install dependencies for Zephyr and ESPRESSIF -# hadolint ignore=DL3008 -RUN apt-get update && apt-get install -y git wget flex bison gperf python3 python3-pip python3-venv\ - python3-dev python3-setuptools python3-tk python3-wheel xz-utils file libpython3.8-dev \ - ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0 device-tree-compiler \ - make gcc gcc-multilib g++-multilib libsdl2-dev libmagic1 qemu udev --no-install-recommends \ - && apt-get clean -y && rm -rf /var/lib/apt/lists/* - -# Install recent CMake version -WORKDIR /tmp -RUN mkdir /opt/cmake \ - && wget --progress=dot:giga https://github.com/Kitware/CMake/releases/download/v3.22.1/cmake-3.22.1-linux-x86_64.sh \ - && sh cmake-3.22.1-linux-x86_64.sh --skip-license --prefix=/opt/cmake && rm cmake-3.22.1-linux-x86_64.sh -ENV PATH="/opt/cmake/bin:$PATH" - -# Install the Zephyr Software Development Kit (SDK) -WORKDIR /opt -# hadolint ignore=DL4006 -RUN wget --progress=dot:giga https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.11.3/zephyr-sdk-0.11.3-setup.run \ - && chmod +x ./zephyr-sdk-0.11.3-setup.run \ - && ./zephyr-sdk-0.11.3-setup.run -- -d /opt/zephyr-sdk-0.11.3 -ENV ZEPHYR_TOOLCHAIN_VARIANT=zephyr -ENV ZEPHYR_SDK_INSTALL_DIR=/opt/zephyr-sdk-0.11.3 - -# Get ESP-IDF -RUN ln -s /usr/bin/python3 /usr/bin/python && mkdir -p ~/esp -WORKDIR /root/esp -RUN git clone https://github.com/espressif/esp-idf.git -WORKDIR /root/esp/esp-idf -RUN git checkout v4.0 \ - && pip install --no-cache-dir virtualenv==16.7.12 \ - && git submodule update --init --recursive \ - && ./install.sh esp32 esp32c3 - -# Get Zephyr -# hadolint ignore=DL3013 -RUN pip3 install --no-cache-dir west && west init -m https://github.com/zephyrproject-rtos/zephyr --mr v2.3.0 /root/zephyrproject - -WORKDIR /root/zephyrproject -RUN west update - -WORKDIR /root/zephyrproject/zephyr -RUN west zephyr-export && pip install --no-cache-dir -r ~/zephyrproject/zephyr/scripts/requirements.txt - -# Git clone wamr -WORKDIR /root -RUN git clone https://github.com/bytecodealliance/wasm-micro-runtime.git - -WORKDIR /root/wasm-micro-runtime/product-mini/platforms/zephyr/simple - -ENV ZEPHYR_BASE="/root/zephyrproject/zephyr" diff --git a/product-mini/platforms/zephyr/simple/README.md b/product-mini/platforms/zephyr/simple/README.md index acb955258..5f8bd41ae 100644 --- a/product-mini/platforms/zephyr/simple/README.md +++ b/product-mini/platforms/zephyr/simple/README.md @@ -1,106 +1,108 @@ # How to use WAMR with Zephyr -## Build with Docker(recommend approach) +[Zephyr](https://www.zephyrproject.org/) is an open source real-time operating +system (RTOS) with a focus on security and broad hardware support. WAMR is +compatible with Zephyr via the [Zephyr WAMR +port](../../../../core/shared/platform/zephyr). -To have a quicker start, a Docker container of the Zephyr setup can be generated. The current docker image would be considerably large(~15GB), it would take some time to build it and enough disk space to store it. +## Setup -### Build Docker images +Using WAMR with Zephyr can be accomplished by either using the provided Docker +image, or by installing Zephyr locally. Both approaches are described below. + +### Docker + +The provided Docker image sets up Zephyr and its dependencies for all +architectures, meaning that you are ready to build for any [supported +board](https://docs.zephyrproject.org/latest/boards/index.html). This comes at +the expense of building a rather large image, which both can take a long time to +build and uses up a large amount of storage (~15 GB). + +Execute the following command to build the Docker image. This may take an +extended period of time to complete. ```shell docker build -t wamr-zephyr . ``` -> PS: currently, the esp32 custom linker script only works with a lower version of Zephyr, if you want to use an esp32 board, you can build the Dockerfile with a lower version of Zephyr, Zephyr SDE, ESP-IDF. The old version of Docker image can also build other targets, but probably it's a better choice to use the new Dockerfile for other boards +Execute the following command to run the image built in the previous step. If +you are planning to flash a device after building, make sure to specify it with +[`--device`](https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities). ```shell -# If you want to build on esp32 platform -docker build -f Dockerfile.old -t wamr-zephyr . +docker run -it --rm --device=/dev/ttyUSB0 wamr-zephyr ``` -### Run Docker images +### Local Environment -Adopt the device or remove if not needed. +Zephyr can also be setup locally to enable building this sample application. +This allows you have have more control over what modules and tools are +installed, which can drastically reduce the storage required compared to the +Docker image. + +Follow the steps provided in the [Zephyr Getting Started +guide](https://docs.zephyrproject.org/latest/develop/getting_started/index.html) +to setup for local development. + +## Building for a Specific Board + +With an environment setup either locally or in a Docker container, you can build +for a Zephyr suppported board using +[`west`](https://docs.zephyrproject.org/latest/develop/west/index.html). There +are already [configuaration files](./boards) for a few boards in this sample. +However, if you are using a new board, you will need to add your own file for +the board, or define configuration in the [`prj.conf](./prj.conf). After doing +so, use the following command with your board identifier to build the sample +application. ```shell -docker run -ti --device=/dev/ttyUSB0 wamr-zephyr +west build . -b --pristine -- -DWAMR_BUILD_TARGET= ``` -And then inside the docker container: +The `` can be found in the Zephyr supported boards +documentation. It must also be used as the name of the board configuration file. +You must define the architecture for WAMR to target with `WAMR_BUILD_TARGET`. +The list of supported architectures can be found in the main project +[README.md](../../../../README.md#supported-architectures-and-platforms). + +It may be necessary to define additional symbols for some boards. For example, +WAMR AOT execution may not be supported on all architectures. It and other +options can be disabled by modifying the [CMakeLists.txt](./CMakeLists.txt) +file, or by passing additional arguments at build (e.g. `-DWAMR_BUILD_AOT=0`). + +### Example Targets + +[ESP32-C3](https://docs.zephyrproject.org/latest/boards/riscv/esp32c3_devkitm/doc/index.html) +is a 32-bit RISC-V target that does not currently support AOT. ```shell -# copy the corresponding board conf file to current directory -cp boards/qemu_x86_nommu.conf prj.conf -# then build -./build_and_run.sh x86 +west build . -b esp32c3_devkitm -p always -- -DWAMR_BUILD_TARGET=RISCV32_ILP32 -DWAMR_BUILD_AOT=0 ``` -> PS: for boards esp32, need to configure some environment first +[ARM Cortex-A53 QEMU +(ARM)](https://docs.zephyrproject.org/latest/boards/arm64/qemu_cortex_a53/doc/index.html) +is a 64-bit ARM target for emulating the Cortex-A53 platform. ```shell -# configure zephyr with espressif -export ZEPHYR_TOOLCHAIN_VARIANT="espressif" -export ESPRESSIF_TOOLCHAIN_PATH="/root/.espressif/tools/xtensa-esp32-elf/esp-2019r2-8.2.0/xtensa-esp32-elf/" -export ESP_IDF_PATH="/root/esp/esp-idf" -# copy the corresponding board conf file to current directory -cp boards/esp32.conf prj.conf -# then build -./build_and_run.sh esp32 +west build . -b qemu_cortex_a53 -p always -- -DWAMR_BUILD_TARGET=AARCH64 ``` -## Build on local environment -### Dependencies installation +## Flashing or Running Image -Following the Zephyr and Espressif official document: - -1. Zephyr installation: - - - -2. ESP32 installation: - - - -And setup the Zephyr for esp32: - - - -Then Installing QEMU, for example, on Linux: +The board can be flashed with the built image with the following command. ```shell -sudo apt-get install qemu +west flash ``` -### Run the build script +`west` will automatically identify the board if it is connected to the host +machine. -Make sure you have the environment variable ready, you can use the command `env` to check: +When using emulated targets, such as those that utilize QEMU, there is no +physical device to flash, but `west` can be used to run the image under +emulation. ```shell -env -``` - -```shell -# export ZEPHYR_BASE if it's not present -export ZEPHYR_BASE=~/zephyrproject/zephyr -# and if you install zephyr in virtual environment rather than global -source ~/zephyrproject/.venv/bin/activate -``` - -For boards esp32, need to configure some extra environment first, check the following env variable whether in the env list, if not, add them like: - -> Noted: The esp32 custom linker script doesn't work with the recent version of Zephyr, if you want to use it in the local environment, please install Zephyr 2.3.0 with the corresponding SDK, and ESP-IDF 4.0 - -```shell -export ZEPHYR_TOOLCHAIN_VARIANT="espressif" -export ESPRESSIF_TOOLCHAIN_PATH="~/.espressif/tools/xtensa-esp32-elf/esp-{the version you installed}/xtensa-esp32-elf/" -export ESP_IDF_PATH="~/esp/esp-idf" -``` - -Then you can run the build script: - -```shell -# copy the corresponding board conf file to current directory -cp boards/qemu_x86_nommu.conf prj.conf -# then build -./build_and_run.sh x86 +west build -t run ``` diff --git a/product-mini/platforms/zephyr/simple/boards/esp32.conf b/product-mini/platforms/zephyr/simple/boards/esp32.conf deleted file mode 100644 index 5d6a67f9d..000000000 --- a/product-mini/platforms/zephyr/simple/boards/esp32.conf +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -CONFIG_STACK_SENTINEL=y -CONFIG_PRINTK=y -CONFIG_LOG=y -CONFIG_HAVE_CUSTOM_LINKER_SCRIPT=y -CONFIG_CUSTOM_LINKER_SCRIPT="esp32_custom_linker.ld" diff --git a/product-mini/platforms/zephyr/simple/boards/nucleo767zi.conf b/product-mini/platforms/zephyr/simple/boards/nucleo_f767zi.conf similarity index 72% rename from product-mini/platforms/zephyr/simple/boards/nucleo767zi.conf rename to product-mini/platforms/zephyr/simple/boards/nucleo_f767zi.conf index c495644b7..c920e6fd0 100644 --- a/product-mini/platforms/zephyr/simple/boards/nucleo767zi.conf +++ b/product-mini/platforms/zephyr/simple/boards/nucleo_f767zi.conf @@ -2,6 +2,3 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception CONFIG_ARM_MPU=y -CONFIG_STACK_SENTINEL=y -CONFIG_PRINTK=y -CONFIG_LOG=y diff --git a/product-mini/platforms/zephyr/simple/boards/qemu_cortex_a53.conf b/product-mini/platforms/zephyr/simple/boards/qemu_cortex_a53.conf index d248565fa..2cc2dd4b4 100644 --- a/product-mini/platforms/zephyr/simple/boards/qemu_cortex_a53.conf +++ b/product-mini/platforms/zephyr/simple/boards/qemu_cortex_a53.conf @@ -2,6 +2,3 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception CONFIG_ARM_MMU=n -CONFIG_STACK_SENTINEL=y -CONFIG_PRINTK=y -CONFIG_LOG=y diff --git a/product-mini/platforms/zephyr/simple/boards/qemu_riscv32.conf b/product-mini/platforms/zephyr/simple/boards/qemu_riscv32.conf deleted file mode 100644 index f3705504b..000000000 --- a/product-mini/platforms/zephyr/simple/boards/qemu_riscv32.conf +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -CONFIG_STACK_SENTINEL=y -CONFIG_PRINTK=y -CONFIG_LOG=n diff --git a/product-mini/platforms/zephyr/simple/boards/qemu_riscv64.conf b/product-mini/platforms/zephyr/simple/boards/qemu_riscv64.conf deleted file mode 100644 index f3705504b..000000000 --- a/product-mini/platforms/zephyr/simple/boards/qemu_riscv64.conf +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -CONFIG_STACK_SENTINEL=y -CONFIG_PRINTK=y -CONFIG_LOG=n diff --git a/product-mini/platforms/zephyr/simple/boards/qemu_x86_nommu.conf b/product-mini/platforms/zephyr/simple/boards/qemu_x86_nommu.conf deleted file mode 100644 index 7f4a32832..000000000 --- a/product-mini/platforms/zephyr/simple/boards/qemu_x86_nommu.conf +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -CONFIG_STACK_SENTINEL=y -CONFIG_PRINTK=y -CONFIG_LOG=y diff --git a/product-mini/platforms/zephyr/simple/boards/qemu_xtensa.conf b/product-mini/platforms/zephyr/simple/boards/qemu_xtensa.conf deleted file mode 100644 index 7f4a32832..000000000 --- a/product-mini/platforms/zephyr/simple/boards/qemu_xtensa.conf +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -CONFIG_STACK_SENTINEL=y -CONFIG_PRINTK=y -CONFIG_LOG=y diff --git a/product-mini/platforms/zephyr/simple/build_and_run.sh b/product-mini/platforms/zephyr/simple/build_and_run.sh index 921f88363..6b8fb4f87 100755 --- a/product-mini/platforms/zephyr/simple/build_and_run.sh +++ b/product-mini/platforms/zephyr/simple/build_and_run.sh @@ -5,7 +5,6 @@ X86_TARGET="x86" STM32_TARGET="stm32" -ESP32_TARGET="esp32" ESP32C3_TARGET="esp32c3" PARTICLE_ARGON_TARGET="particle_argon" QEMU_CORTEX_A53="qemu_cortex_a53" @@ -17,11 +16,10 @@ QEMU_ARC_TARGET="qemu_arc" usage () { echo "USAGE:" - echo "$0 $X86_TARGET|$STM32_TARGET|$ESP32_TARGET|$ESP32C3_TARGET|$PARTICLE_ARGON_TARGET|$QEMU_CORTEX_A53|$QEMU_XTENSA_TARGET|$QEMU_RISCV64_TARGET|$QEMU_RISCV32_TARGET|$QEMU_ARC_TARGET" + echo "$0 $X86_TARGET|$STM32_TARGET|$ESP32C3_TARGET|$PARTICLE_ARGON_TARGET|$QEMU_CORTEX_A53|$QEMU_XTENSA_TARGET|$QEMU_RISCV64_TARGET|$QEMU_RISCV32_TARGET|$QEMU_ARC_TARGET" echo "Example:" echo " $0 $X86_TARGET" echo " $0 $STM32_TARGET" - echo " $0 $ESP32_TARGET" echo " $0 $ESP32C3_TARGET" echo " $0 $PARTICLE_ARGON_TARGET" echo " $0 $QEMU_CORTEX_A53" @@ -51,27 +49,11 @@ case $TARGET in -DWAMR_BUILD_TARGET=THUMBV7 west flash ;; - $ESP32_TARGET) - export ZEPHYR_TOOLCHAIN_VARIANT="espressif" - if [[ -z "${ESPRESSIF_TOOLCHAIN_PATH}" ]]; then - echo "Set ESPRESSIF_TOOLCHAIN_PATH to your espressif toolchain" - exit 1 - fi - west build -b esp32 \ - . -p always -- \ - -DWAMR_BUILD_TARGET=XTENSA - # west flash will discover the device - west flash - ;; $ESP32C3_TARGET) - export ZEPHYR_TOOLCHAIN_VARIANT="espressif" - if [[ -z "${ESPRESSIF_TOOLCHAIN_PATH}" ]]; then - echo "Set ESPRESSIF_TOOLCHAIN_PATH to your espressif toolchain" - exit 1 - fi west build -b esp32c3_devkitm \ . -p always -- \ - -DWAMR_BUILD_TARGET=RISCV32_ILP32 + -DWAMR_BUILD_TARGET=RISCV32_ILP32 \ + -DWAMR_BUILD_AOT=0 # west flash will discover the device west flash ;; diff --git a/product-mini/platforms/zephyr/simple/esp32_custom_linker.ld b/product-mini/platforms/zephyr/simple/esp32_custom_linker.ld deleted file mode 100644 index 35932050f..000000000 --- a/product-mini/platforms/zephyr/simple/esp32_custom_linker.ld +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright (c) 2016 Cadence Design Systems, Inc. - * Copyright (c) 2017 Intel Corporation - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * Linker script for the Xtensa platform. - */ - -#include -#include -#include -#include -#include - -#define RAMABLE_REGION dram0_0_seg :dram0_0_phdr -#define RAMABLE_REGION1 dram0_1_seg :dram0_0_phdr -#define ROMABLE_REGION iram0_0_seg :iram0_0_phdr - -PROVIDE ( __stack = 0x3ffe3f20 ); - -PROVIDE ( esp32_rom_uart_tx_one_char = 0x40009200 ); -PROVIDE ( esp32_rom_uart_rx_one_char = 0x400092d0 ); -PROVIDE ( esp32_rom_uart_attach = 0x40008fd0 ); -PROVIDE ( esp32_rom_intr_matrix_set = 0x4000681c ); -PROVIDE ( esp32_rom_gpio_matrix_in = 0x40009edc ); -PROVIDE ( esp32_rom_gpio_matrix_out = 0x40009f0c ); -PROVIDE ( esp32_rom_Cache_Flush = 0x40009a14 ); -PROVIDE ( esp32_rom_Cache_Read_Enable = 0x40009a84 ); -PROVIDE ( esp32_rom_ets_set_appcpu_boot_addr = 0x4000689c ); - -MEMORY -{ - iram0_0_seg(RX): org = 0x40080000, len = 0x20000 - iram0_2_seg(RX): org = 0x400D0018, len = 0x330000 - dram0_0_seg(RW): org = 0x3FFB0000, len = 0x30000 - dram0_1_seg(RWX):org = 0x400A0000, len = 0x20000 - drom0_0_seg(R): org = 0x3F400010, len = 0x800000 - rtc_iram_seg(RWX): org = 0x400C0000, len = 0x2000 - rtc_slow_seg(RW): org = 0x50000000, len = 0x1000 -#ifdef CONFIG_GEN_ISR_TABLES - IDT_LIST(RW): org = 0x3ebfe010, len = 0x2000 -#endif -} - -PHDRS -{ - iram0_0_phdr PT_LOAD; - dram0_0_phdr PT_LOAD; -} - -/* Default entry point: */ -PROVIDE ( _ResetVector = 0x40000400 ); -ENTRY(CONFIG_KERNEL_ENTRY) - -_rom_store_table = 0; - -PROVIDE(_memmap_vecbase_reset = 0x40000450); -PROVIDE(_memmap_reset_vector = 0x40000400); - -SECTIONS -{ - -#include - - /* RTC fast memory holds RTC wake stub code, - including from any source file named rtc_wake_stub*.c - */ - .rtc.text : - { - . = ALIGN(4); - *(.rtc.literal .rtc.text) - *rtc_wake_stub*.o(.literal .text .literal.* .text.*) - } >rtc_iram_seg - - /* RTC slow memory holds RTC wake stub - data/rodata, including from any source file - named rtc_wake_stub*.c - */ - .rtc.data : - { - _rtc_data_start = ABSOLUTE(.); - *(.rtc.data) - *(.rtc.rodata) - *rtc_wake_stub*.o(.data .rodata .data.* .rodata.* .bss .bss.*) - _rtc_data_end = ABSOLUTE(.); - } > rtc_slow_seg - - /* RTC bss, from any source file named rtc_wake_stub*.c */ - .rtc.bss (NOLOAD) : - { - _rtc_bss_start = ABSOLUTE(.); - *rtc_wake_stub*.o(.bss .bss.*) - *rtc_wake_stub*.o(COMMON) - _rtc_bss_end = ABSOLUTE(.); - } > rtc_slow_seg - - /* Send .iram0 code to iram */ - .iram0.vectors : ALIGN(4) - { - /* Vectors go to IRAM */ - _init_start = ABSOLUTE(.); - /* Vectors according to builds/RF-2015.2-win32/esp108_v1_2_s5_512int_2/config.html */ - . = 0x0; - KEEP(*(.WindowVectors.text)); - . = 0x180; - KEEP(*(.Level2InterruptVector.text)); - . = 0x1c0; - KEEP(*(.Level3InterruptVector.text)); - . = 0x200; - KEEP(*(.Level4InterruptVector.text)); - . = 0x240; - KEEP(*(.Level5InterruptVector.text)); - . = 0x280; - KEEP(*(.DebugExceptionVector.text)); - . = 0x2c0; - KEEP(*(.NMIExceptionVector.text)); - . = 0x300; - KEEP(*(.KernelExceptionVector.text)); - . = 0x340; - KEEP(*(.UserExceptionVector.text)); - . = 0x3C0; - KEEP(*(.DoubleExceptionVector.text)); - . = 0x400; - *(.*Vector.literal) - - *(.UserEnter.literal); - *(.UserEnter.text); - . = ALIGN (16); - *(.entry.text) - *(.init.literal) - *(.init) - _init_end = ABSOLUTE(.); - - /* This goes here, not at top of linker script, so addr2line finds it last, - and uses it in preference to the first symbol in IRAM */ - _iram_start = ABSOLUTE(0); - } GROUP_LINK_IN(ROMABLE_REGION) - -#include -#include - - SECTION_PROLOGUE(_TEXT_SECTION_NAME, , ALIGN(4)) - { - /* Code marked as running out of IRAM */ - _iram_text_start = ABSOLUTE(.); - *(.iram1 .iram1.*) - *(.iram0.literal .iram.literal .iram.text.literal .iram0.text .iram.text) - *(.literal .text .literal.* .text.*) - _iram_text_end = ABSOLUTE(.); - } GROUP_LINK_IN(ROMABLE_REGION) - - .dram0.text : - { - _data_start = ABSOLUTE(.); - *(.aot_code_buf) - _data_end = ABSOLUTE(.); - . = ALIGN(4); - } GROUP_LINK_IN(RAMABLE_REGION1) - - - .dram0.data : - { - _data_start = ABSOLUTE(.); - *(.data) - *(.data.*) - *(.gnu.linkonce.d.*) - *(.data1) - *(.sdata) - *(.sdata.*) - *(.gnu.linkonce.s.*) - *(.sdata2) - *(.sdata2.*) - *(.gnu.linkonce.s2.*) - KEEP(*(.jcr)) - *(.dram1 .dram1.*) - _data_end = ABSOLUTE(.); - . = ALIGN(4); - } GROUP_LINK_IN(RAMABLE_REGION) - - SECTION_PROLOGUE(_RODATA_SECTION_NAME,,ALIGN(4)) - { - _rodata_start = ABSOLUTE(.); - *(.rodata) - *(.rodata.*) - *(.gnu.linkonce.r.*) - *(.rodata1) - __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); - KEEP (*(.xt_except_table)) - KEEP (*(.gcc_except_table .gcc_except_table.*)) - *(.gnu.linkonce.e.*) - *(.gnu.version_r) - KEEP (*(.eh_frame)) - /* C++ constructor and destructor tables, properly ordered: */ - KEEP (*crtbegin.o(.ctors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) - KEEP (*crtbegin.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*(.dtors)) - /* C++ exception handlers table: */ - __XT_EXCEPTION_DESCS__ = ABSOLUTE(.); - *(.xt_except_desc) - *(.gnu.linkonce.h.*) - __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); - *(.xt_except_desc_end) - *(.dynamic) - *(.gnu.version_d) - . = ALIGN(4); /* this table MUST be 4-byte aligned */ - _rodata_end = ABSOLUTE(.); - } GROUP_LINK_IN(RAMABLE_REGION) - - - /* Shared RAM */ - SECTION_DATA_PROLOGUE(_BSS_SECTION_NAME,(NOLOAD),) - { - . = ALIGN (8); - _bss_start = ABSOLUTE(.); - *(.dynsbss) - *(.sbss) - *(.sbss.*) - *(.gnu.linkonce.sb.*) - *(.scommon) - *(.sbss2) - *(.sbss2.*) - *(.gnu.linkonce.sb2.*) - *(.dynbss) - *(.bss) - *(.bss.*) - *(.share.mem) - *(.gnu.linkonce.b.*) - *(COMMON) - . = ALIGN (8); - _bss_end = ABSOLUTE(.); - } GROUP_LINK_IN(RAMABLE_REGION) - - - SECTION_DATA_PROLOGUE(_APP_NOINIT_SECTION_NAME, (NOLOAD),) - { - . = ALIGN (8); - *(.app_noinit) - *("app_noinit.*") - . = ALIGN (8); - _app_end = ABSOLUTE(.); - } GROUP_LINK_IN(RAMABLE_REGION) - - - SECTION_DATA_PROLOGUE(_NOINIT_SECTION_NAME, (NOLOAD),) - { - . = ALIGN (8); - *(.noinit) - *(".noinit.*") - . = ALIGN (8); - _heap_start = ABSOLUTE(.); - } GROUP_LINK_IN(RAMABLE_REGION) - -#ifdef CONFIG_GEN_ISR_TABLES -#include -#endif - -#include - - SECTION_PROLOGUE(.xtensa.info, 0,) - { - *(.xtensa.info) - } - -} diff --git a/product-mini/platforms/zephyr/simple/boards/qemu_arc.conf b/product-mini/platforms/zephyr/simple/prj.conf similarity index 100% rename from product-mini/platforms/zephyr/simple/boards/qemu_arc.conf rename to product-mini/platforms/zephyr/simple/prj.conf diff --git a/product-mini/platforms/zephyr/simple/src/main.c b/product-mini/platforms/zephyr/simple/src/main.c index 8799e737a..5d209a868 100644 --- a/product-mini/platforms/zephyr/simple/src/main.c +++ b/product-mini/platforms/zephyr/simple/src/main.c @@ -68,7 +68,7 @@ app_instance_main(wasm_module_inst_t module_inst) if (wasm_runtime_lookup_function(module_inst, "main", NULL) || wasm_runtime_lookup_function(module_inst, "__main_argc_argv", NULL)) { - LOG_VERBOSE("Calling main funciton\n"); + LOG_VERBOSE("Calling main function\n"); wasm_application_execute_main(module_inst, app_argc, app_argv); } else if ((func = wasm_runtime_lookup_function(module_inst, "app_main", @@ -80,7 +80,7 @@ app_instance_main(wasm_module_inst_t module_inst) return NULL; } - LOG_VERBOSE("Calling app_main funciton\n"); + LOG_VERBOSE("Calling app_main function\n"); wasm_runtime_call_wasm(exec_env, func, 0, argv); if (!wasm_runtime_get_exception(module_inst)) { @@ -104,56 +104,6 @@ app_instance_main(wasm_module_inst_t module_inst) static char global_heap_buf[CONFIG_GLOBAL_HEAP_BUF_SIZE] = { 0 }; #endif -#ifdef CONFIG_BOARD_ESP32 -#include "mem_alloc.h" -/* -esp32_technical_reference_manual: -" -The capacity of Internal SRAM 1 is 128 KB. Either CPU can read and write this -memory at addresses 0x3FFE_0000 ~ 0x3FFF_FFFF of the data bus, and also at -addresses 0x400A_0000 ~ 0x400B_FFFF of the instruction bus. -" - -The custom linker script defines dram0_1_seg and map it to 0x400A_0000 ~ -0x400B_FFFF for instruction bus access. Here we define the buffer that will be -placed to dram0_1_seg. -*/ -static char esp32_executable_memory_buf[100 * 1024] - __attribute__((section(".aot_code_buf"))) = { 0 }; - -/* the poll allocator for executable memory */ -static mem_allocator_t esp32_exec_mem_pool_allocator; - -static int -esp32_exec_mem_init() -{ - if (!(esp32_exec_mem_pool_allocator = - mem_allocator_create(esp32_executable_memory_buf, - sizeof(esp32_executable_memory_buf)))) - return -1; - - return 0; -} - -static void -esp32_exec_mem_destroy() -{ - mem_allocator_destroy(esp32_exec_mem_pool_allocator); -} - -static void * -esp32_exec_mem_alloc(unsigned int size) -{ - return mem_allocator_malloc(esp32_exec_mem_pool_allocator, size); -} - -static void -esp32_exec_mem_free(void *addr) -{ - mem_allocator_free(esp32_exec_mem_pool_allocator, addr); -} -#endif /* end of #ifdef CONFIG_BOARD_ESP32 */ - void iwasm_main(void *arg1, void *arg2, void *arg3) { @@ -189,16 +139,6 @@ iwasm_main(void *arg1, void *arg2, void *arg3) return; } -#ifdef CONFIG_BOARD_ESP32 - /* Initialize executable memory */ - if (esp32_exec_mem_init() != 0) { - printf("Init executable memory failed.\n"); - goto fail1; - } - /* Set hook functions for executable memory management */ - set_exec_mem_alloc_func(esp32_exec_mem_alloc, esp32_exec_mem_free); -#endif - #if WASM_ENABLE_LOG != 0 bh_log_set_verbose_level(log_verbose_level); #endif @@ -211,11 +151,7 @@ iwasm_main(void *arg1, void *arg2, void *arg3) if (!(wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf, sizeof(error_buf)))) { printf("%s\n", error_buf); -#ifdef CONFIG_BOARD_ESP32 - goto fail1_1; -#else goto fail1; -#endif } /* instantiate the module */ @@ -236,19 +172,13 @@ fail2: /* unload the module */ wasm_runtime_unload(wasm_module); -#ifdef CONFIG_BOARD_ESP32 -fail1_1: - /* destroy executable memory */ - esp32_exec_mem_destroy(); -#endif - fail1: /* destroy runtime environment */ wasm_runtime_destroy(); end = k_uptime_get_32(); - printf("elpase: %d\n", (end - start)); + printf("elapsed: %d\n", (end - start)); } #define MAIN_THREAD_STACK_SIZE (CONFIG_MAIN_THREAD_STACK_SIZE) @@ -265,8 +195,18 @@ iwasm_init(void) iwasm_main, NULL, NULL, NULL, MAIN_THREAD_PRIORITY, 0, K_NO_WAIT); return tid ? true : false; } + +#if KERNEL_VERSION_NUMBER < 0x030400 /* version 3.4.0 */ void main(void) { iwasm_init(); } +#else +int +main(void) +{ + iwasm_init(); + return 0; +} +#endif diff --git a/samples/basic/CMakeLists.txt b/samples/basic/CMakeLists.txt index 4191ad15d..62edf08fb 100644 --- a/samples/basic/CMakeLists.txt +++ b/samples/basic/CMakeLists.txt @@ -9,7 +9,6 @@ if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") project (basic) else() project (basic C ASM) - enable_language (ASM_MASM) endif() ################ runtime settings ################ diff --git a/samples/basic/wasm-apps/testapp.c b/samples/basic/wasm-apps/testapp.c index ea575e20c..8db293071 100644 --- a/samples/basic/wasm-apps/testapp.c +++ b/samples/basic/wasm-apps/testapp.c @@ -58,7 +58,7 @@ float_to_string(float n, char *res, int res_size, int afterpoint) // is needed to handle cases like 233.007 fpart = fpart * get_pow(10, afterpoint); - intToStr((int)fpart, res + i + 1, sizeof(res + i + 1), afterpoint); + intToStr((int)fpart, res + i + 1, res_size - i - 1, afterpoint); } } diff --git a/samples/file/src/CMakeLists.txt b/samples/file/src/CMakeLists.txt index 2bc3bec64..1f7a2435f 100644 --- a/samples/file/src/CMakeLists.txt +++ b/samples/file/src/CMakeLists.txt @@ -9,7 +9,6 @@ if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") project (iwasm) else() project (iwasm C ASM) - enable_language (ASM_MASM) endif() ################ runtime settings ################ diff --git a/samples/gui/wasm-apps/decrease/src/main.c b/samples/gui/wasm-apps/decrease/src/main.c index a6c30aa1a..9635ebea8 100644 --- a/samples/gui/wasm-apps/decrease/src/main.c +++ b/samples/gui/wasm-apps/decrease/src/main.c @@ -46,14 +46,14 @@ on_init() count_label = lv_label_create(NULL, NULL); lv_obj_align(count_label, NULL, LV_ALIGN_IN_TOP_MID, 0, 0); - btn1 = lv_btn_create( - NULL, NULL); /*Create a button on the currently loaded screen*/ - lv_obj_set_event_cb( - btn1, - btn_event_cb); /*Set function to be called when the button is released*/ - lv_obj_align(btn1, NULL, LV_ALIGN_CENTER, 0, 0); /*Align below the label*/ + /* Create a button on the currently loaded screen */ + btn1 = lv_btn_create(NULL, NULL); + /* Set function to be called when the button is released */ + lv_obj_set_event_cb(btn1, (lv_event_cb_t)btn_event_cb); + /* Align below the label */ + lv_obj_align(btn1, NULL, LV_ALIGN_CENTER, 0, 0); - /*Create a label on the button*/ + /* Create a label on the button */ lv_obj_t *btn_label = lv_label_create(btn1, NULL); lv_label_set_text(btn_label, "Click --"); @@ -61,7 +61,7 @@ on_init() lv_label_set_text(label_count1, "100"); lv_obj_align(label_count1, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, 0); - /* set up a timer */ + /* Set up a timer */ user_timer_t timer; timer = api_timer_create(10, true, false, timer1_update); if (timer) diff --git a/samples/gui/wasm-apps/increase/src/main.c b/samples/gui/wasm-apps/increase/src/main.c index b5271830a..31118f7be 100644 --- a/samples/gui/wasm-apps/increase/src/main.c +++ b/samples/gui/wasm-apps/increase/src/main.c @@ -46,14 +46,14 @@ on_init() count_label = lv_label_create(NULL, NULL); lv_obj_align(count_label, NULL, LV_ALIGN_IN_TOP_MID, 0, 0); - btn1 = lv_btn_create( - NULL, NULL); /*Create a button on the currently loaded screen*/ - lv_obj_set_event_cb( - btn1, - btn_event_cb); /*Set function to be called when the button is released*/ - lv_obj_align(btn1, NULL, LV_ALIGN_CENTER, 0, 0); /*Align below the label*/ + /* Create a button on the current loaded screen */ + btn1 = lv_btn_create(NULL, NULL); + /* Set function to be called when the button is released */ + lv_obj_set_event_cb(btn1, (lv_event_cb_t)btn_event_cb); + /* Align below the label */ + lv_obj_align(btn1, NULL, LV_ALIGN_CENTER, 0, 0); - /*Create a label on the button*/ + /* Create a label on the button */ lv_obj_t *btn_label = lv_label_create(btn1, NULL); lv_label_set_text(btn_label, "Click ++"); @@ -61,7 +61,7 @@ on_init() lv_label_set_text(label_count1, "1"); lv_obj_align(label_count1, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, 0); - /* set up a timer */ + /* Set up a timer */ user_timer_t timer; timer = api_timer_create(10, true, false, timer1_update); if (timer) diff --git a/samples/gui/wasm-runtime-wgl/src/platform/zephyr/XPT2046.c b/samples/gui/wasm-runtime-wgl/src/platform/zephyr/XPT2046.c index cdad9dac2..5502cfd89 100644 --- a/samples/gui/wasm-runtime-wgl/src/platform/zephyr/XPT2046.c +++ b/samples/gui/wasm-runtime-wgl/src/platform/zephyr/XPT2046.c @@ -10,8 +10,12 @@ #include #include "drivers/spi.h" -#include "zephyr.h" -#include "kernel.h" +#if KERNEL_VERSION_NUMBER < 0x030200 /* version 3.2.0 */ +#include +#include +#else +#include +#endif #if USE_XPT2046 diff --git a/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display_ili9340.h b/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display_ili9340.h index f72279d69..ddc396e1d 100644 --- a/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display_ili9340.h +++ b/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display_ili9340.h @@ -7,7 +7,12 @@ #define ZEPHYR_DRIVERS_DISPLAY_DISPLAY_ILI9340_H_ #include "board_config.h" #include + +#if KERNEL_VERSION_NUMBER < 0x030200 /* version 3.2.0 */ #include +#else +#include +#endif #define ILI9340_CMD_ENTER_SLEEP 0x10 #define ILI9340_CMD_EXIT_SLEEP 0x11 diff --git a/samples/gui/wasm-runtime-wgl/src/platform/zephyr/iwasm_main.c b/samples/gui/wasm-runtime-wgl/src/platform/zephyr/iwasm_main.c index 6a88f8007..9ce0c11cd 100644 --- a/samples/gui/wasm-runtime-wgl/src/platform/zephyr/iwasm_main.c +++ b/samples/gui/wasm-runtime-wgl/src/platform/zephyr/iwasm_main.c @@ -31,7 +31,12 @@ xpt2046_init(void); extern void wgl_init(); +#if KERNEL_VERSION_NUMBER < 0x030200 /* version 3.2.0 */ #include +#else +#include +#endif + #include #include diff --git a/samples/inst-context-threads/CMakeLists.txt b/samples/inst-context-threads/CMakeLists.txt index 7326a5436..5ce8696d8 100644 --- a/samples/inst-context-threads/CMakeLists.txt +++ b/samples/inst-context-threads/CMakeLists.txt @@ -9,7 +9,6 @@ if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") project (inst-context) else() project (inst-context C ASM) - enable_language (ASM_MASM) endif() ################ runtime settings ################ diff --git a/samples/inst-context/CMakeLists.txt b/samples/inst-context/CMakeLists.txt index b1167d277..af387ca26 100644 --- a/samples/inst-context/CMakeLists.txt +++ b/samples/inst-context/CMakeLists.txt @@ -9,7 +9,6 @@ if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") project (inst-context) else() project (inst-context C ASM) - enable_language (ASM_MASM) endif() ################ runtime settings ################ diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.c index d59b6c9b7..e3948e2f2 100644 --- a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.c +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.c @@ -10,8 +10,12 @@ #include #include "drivers/spi.h" -#include "zephyr.h" -#include "kernel.h" +#if KERNEL_VERSION_NUMBER < 0x030200 /* version 3.2.0 */ +#include +#include +#else +#include +#endif #if USE_XPT2046 diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.h b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.h index 4eb11e2d1..39257a29a 100644 --- a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.h +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.h @@ -7,7 +7,12 @@ #define ZEPHYR_DRIVERS_DISPLAY_DISPLAY_ILI9340_H_ #include "board_config.h" #include + +#if KERNEL_VERSION_NUMBER < 0x030200 /* version 3.2.0 */ #include +#else +#include +#endif #define ILI9340_CMD_ENTER_SLEEP 0x10 #define ILI9340_CMD_EXIT_SLEEP 0x11 diff --git a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c index dceb5786b..10f498026 100644 --- a/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c +++ b/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c @@ -16,7 +16,12 @@ #include "connection_native_api.h" #include "display_indev.h" +#if KERNEL_VERSION_NUMBER < 0x030200 /* version 3.2.0 */ #include +#else +#include +#endif + #include #include diff --git a/samples/multi-module/README.md b/samples/multi-module/README.md index 1ec92620c..731ba62c2 100644 --- a/samples/multi-module/README.md +++ b/samples/multi-module/README.md @@ -9,12 +9,12 @@ $ mkdir build $ cd build $ cmake .. $ make -$ # It will build multi-module runtime and +$ # It will build multi_module runtime and $ # wasm file under the ./build . $ # If you have built wamrc, $ # aot file will also genrate. -$ ./multi-module mC.wasm +$ ./multi_module mC.wasm $ ... -$ ./multi-module mC.aot +$ ./multi_module mC.aot $ ... diff --git a/samples/multi-module/src/main.c b/samples/multi-module/src/main.c index 361856136..c63cf6b8c 100644 --- a/samples/multi-module/src/main.c +++ b/samples/multi-module/src/main.c @@ -11,7 +11,7 @@ static bool module_reader_callback(package_type_t module_type, const char *module_name, uint8 **p_buffer, uint32 *p_size) { - char *file_format; + char *file_format = NULL; #if WASM_ENABLE_INTERP != 0 if (module_type == Wasm_Module_Bytecode) file_format = ".wasm"; @@ -21,10 +21,11 @@ module_reader_callback(package_type_t module_type, const char *module_name, file_format = ".aot"; #endif + bh_assert(file_format != NULL); const char *format = "%s/%s%s"; int sz = strlen(module_search_path) + strlen("/") + strlen(module_name) + strlen(file_format) + 1; - char *wasm_file_name = BH_MALLOC(sz); + char *wasm_file_name = wasm_runtime_malloc(sz); if (!wasm_file_name) { return false; } diff --git a/samples/ref-types/CMakeLists.txt b/samples/ref-types/CMakeLists.txt index 325699b20..fd18e6378 100644 --- a/samples/ref-types/CMakeLists.txt +++ b/samples/ref-types/CMakeLists.txt @@ -9,7 +9,6 @@ if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") project(ref-types) else() project (ref-types C ASM) - enable_language (ASM_MASM) endif() ################ runtime settings ################ diff --git a/samples/sgx-ra/wasm-app/main.c b/samples/sgx-ra/wasm-app/main.c index 89c4144aa..6f506e06a 100644 --- a/samples/sgx-ra/wasm-app/main.c +++ b/samples/sgx-ra/wasm-app/main.c @@ -106,7 +106,7 @@ main(int argc, char **argv) err: if (evidence_json) { - free(evidence_json); + librats_dispose_evidence_json(evidence_json); } if (evidence) { diff --git a/samples/shared-module/.gitignore b/samples/shared-module/.gitignore new file mode 100644 index 000000000..0fa8a76bd --- /dev/null +++ b/samples/shared-module/.gitignore @@ -0,0 +1 @@ +/out/ \ No newline at end of file diff --git a/samples/shared-module/CMakeLists.txt b/samples/shared-module/CMakeLists.txt new file mode 100644 index 000000000..c094b071c --- /dev/null +++ b/samples/shared-module/CMakeLists.txt @@ -0,0 +1,95 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 3.14) + +include(CheckPIESupported) + +project (shared-module) + +set (CMAKE_CXX_STANDARD 17) + +################ runtime settings ################ +string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM) +if (APPLE) + add_definitions(-DBH_PLATFORM_DARWIN) +endif () + +# Reset default linker flags +set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +# WAMR features switch + +# Set WAMR_BUILD_TARGET, currently values supported: +# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", +# "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]" +if (NOT DEFINED WAMR_BUILD_TARGET) + if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)") + set (WAMR_BUILD_TARGET "AARCH64") + elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") + set (WAMR_BUILD_TARGET "RISCV64") + elseif (CMAKE_SIZEOF_VOID_P EQUAL 8) + # Build as X86_64 by default in 64-bit platform + set (WAMR_BUILD_TARGET "X86_64") + elseif (CMAKE_SIZEOF_VOID_P EQUAL 4) + # Build as X86_32 by default in 32-bit platform + set (WAMR_BUILD_TARGET "X86_32") + else () + message(SEND_ERROR "Unsupported build target platform!") + endif () +endif () + +if (NOT CMAKE_BUILD_TYPE) + set (CMAKE_BUILD_TYPE Debug) +endif () + +set (WAMR_BUILD_INTERP 1) +set (WAMR_BUILD_AOT 1) +set (WAMR_BUILD_JIT 0) + +# fast interpreter +# set (WAMR_BUILD_FAST_INTERP 1) + +# fast-jit +# set (WAMR_BUILD_FAST_JIT 1) + +# llvm jit +# set (WAMR_BUILD_JIT 1) +# set (LLVM_DIR /usr/local/opt/llvm@14/lib/cmake/llvm) + +set (WAMR_BUILD_REF_TYPES 1) + +if (NOT MSVC) + # linker flags + if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") + endif () + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") + if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") + if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register") + endif () + endif () +endif () + +# build out vmlib +set (WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) +include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) + +add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) + +################ application related ################ +include_directories(${CMAKE_CURRENT_LIST_DIR}/src) +include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) + +add_executable (shared-module src/main.c ${UNCOMMON_SHARED_SOURCE}) + +check_pie_supported() +set_target_properties (shared-module PROPERTIES POSITION_INDEPENDENT_CODE ON) + +if (APPLE) + target_link_libraries (shared-module vmlib -lm -ldl -lpthread ${LLVM_AVAILABLE_LIBS}) +else () + target_link_libraries (shared-module vmlib -lm -ldl -lpthread -lrt ${LLVM_AVAILABLE_LIBS}) +endif () diff --git a/samples/shared-module/README.md b/samples/shared-module/README.md new file mode 100644 index 000000000..14baa8cbf --- /dev/null +++ b/samples/shared-module/README.md @@ -0,0 +1,5 @@ +The "shared-module" sample project +================================== + +This sample demonstrates a bug described in: +https://github.com/bytecodealliance/wasm-micro-runtime/issues/2735. diff --git a/samples/shared-module/build.sh b/samples/shared-module/build.sh new file mode 100755 index 000000000..9af5b3edd --- /dev/null +++ b/samples/shared-module/build.sh @@ -0,0 +1,63 @@ +# +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +#!/bin/bash + +CURR_DIR=$PWD +WAMR_DIR=${PWD}/../.. +OUT_DIR=${PWD}/out + +WASM_APPS=${PWD}/wasm-apps + + +rm -rf ${OUT_DIR} +mkdir ${OUT_DIR} +mkdir ${OUT_DIR}/wasm-apps + + +echo "##################### build shared-module project" +cd ${CURR_DIR} +mkdir -p cmake_build +cd cmake_build +cmake .. +make -j ${nproc} +if [ $? != 0 ];then + echo "BUILD_FAIL shared-module exit as $?\n" + exit 2 +fi + +cp -a shared-module ${OUT_DIR} + +printf "\n" + +echo "##################### build wasm apps" + +cd ${WASM_APPS} + +for i in `ls *.wat` +do +APP_SRC="$i" +OUT_FILE=${i%.*}.wasm + +# Note: the CI installs wabt in /opt/wabt +if type wat2wasm; then + WAT2WASM=${WAT2WASM:-wat2wasm} +elif [ -x /opt/wabt/bin/wat2wasm ]; then + WAT2WASM=${WAT2WASM:-/opt/wabt/bin/wat2wasm} +fi + +${WAT2WASM} -o ${OUT_DIR}/wasm-apps/${OUT_FILE} ${APP_SRC} + +# aot +# wamrc -o ${OUT_DIR}/wasm-apps/${OUT_FILE}.aot ${OUT_DIR}/wasm-apps/${OUT_FILE} +# mv ${OUT_DIR}/wasm-apps/${OUT_FILE}.aot ${OUT_DIR}/wasm-apps/${OUT_FILE} + +if [ -f ${OUT_DIR}/wasm-apps/${OUT_FILE} ]; then + echo "build ${OUT_FILE} success" +else + echo "build ${OUT_FILE} fail" +fi +done +echo "##################### build wasm apps done" diff --git a/samples/shared-module/run.sh b/samples/shared-module/run.sh new file mode 100755 index 000000000..3cb2e623e --- /dev/null +++ b/samples/shared-module/run.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +out/shared-module -f out/wasm-apps/testapp.wasm diff --git a/samples/shared-module/src/main.c b/samples/shared-module/src/main.c new file mode 100644 index 000000000..ebea0c6bf --- /dev/null +++ b/samples/shared-module/src/main.c @@ -0,0 +1,206 @@ + +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "wasm_export.h" +#include "bh_read_file.h" +#include "bh_getopt.h" + +void +print_usage(void) +{ + fprintf(stdout, "Options:\r\n"); + fprintf(stdout, " -f [path of wasm file] \n"); +} + +int +main(int argc, char *argv_main[]) +{ + int exit_code = 1; + static char global_heap_buf[512 * 1024]; + char *buffer; + char error_buf[128]; + int opt; + char *wasm_path = NULL; + + const unsigned int N = 4; + wasm_module_t module = NULL; + wasm_module_inst_t module_inst[N]; + wasm_exec_env_t exec_env[N]; + const char *name_test_data_drop = "test_data_drop"; + const char *name_test_elem_drop = "test_elem_drop"; + wasm_function_inst_t func_test_data_drop[N]; + wasm_function_inst_t func_test_elem_drop[N]; + unsigned int i; + unsigned int iter; + uint32 buf_size, stack_size = 8092, heap_size = 8092; + + for (i = 0; i < N; i++) { + module_inst[i] = NULL; + exec_env[i] = NULL; + func_test_data_drop[i] = NULL; + func_test_elem_drop[i] = NULL; + } + + RuntimeInitArgs init_args; + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + + while ((opt = getopt(argc, argv_main, "hf:")) != -1) { + switch (opt) { + case 'f': + wasm_path = optarg; + break; + case 'h': + print_usage(); + return 0; + case '?': + print_usage(); + return 0; + } + } + if (optind == 1) { + print_usage(); + return 0; + } + + memset(&init_args, 0, sizeof(init_args)); + init_args.mem_alloc_type = Alloc_With_Pool; + init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; + init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); + + if (!wasm_runtime_full_init(&init_args)) { + printf("Init runtime environment failed.\n"); + return -1; + } + + buffer = bh_read_file_to_buffer(wasm_path, &buf_size); + + if (!buffer) { + printf("Open wasm app file [%s] failed.\n", wasm_path); + goto fail; + } + + module = wasm_runtime_load((uint8 *)buffer, buf_size, error_buf, + sizeof(error_buf)); + if (!module) { + printf("Load wasm module failed. error: %s\n", error_buf); + goto fail; + } + + for (i = 0; i < N; i++) { + module_inst[i] = wasm_runtime_instantiate(module, stack_size, heap_size, + error_buf, sizeof(error_buf)); + + if (!module_inst[i]) { + printf("Instantiate wasm module failed. error: %s\n", error_buf); + goto fail; + } + + exec_env[i] = wasm_runtime_create_exec_env(module_inst[i], stack_size); + if (!exec_env[i]) { + printf("Create wasm execution environment failed.\n"); + goto fail; + } + + func_test_data_drop[i] = wasm_runtime_lookup_function( + module_inst[i], name_test_data_drop, NULL); + if (!func_test_data_drop[i]) { + printf("The wasm function %s is not found.\n", name_test_data_drop); + goto fail; + } + + func_test_elem_drop[i] = wasm_runtime_lookup_function( + module_inst[i], name_test_elem_drop, NULL); + if (!func_test_elem_drop[i]) { + printf("The wasm function %s is not found.\n", name_test_elem_drop); + goto fail; + } + } + + for (iter = 0; iter < 2; iter++) { + /* + * as we drop data/table in the first iteration, + * the later iterations should trap. + */ + const bool should_trap = iter > 0; + + for (i = 0; i < N; i++) { + uint32_t argv[1] = {}; + if (wasm_runtime_call_wasm(exec_env[i], func_test_data_drop[i], 0, + argv)) { + uint32_t result = argv[0]; + printf( + "Native finished calling wasm function: %s, return: %x\n", + name_test_data_drop, result); + if (result != 0x64636261) { /* "abcd" */ + printf("unexpected return value\n"); + goto fail; + } + if (should_trap) { + printf("a trap is expected\n"); + goto fail; + } + } + else if (should_trap) { + printf("call wasm function %s failed as expected. error: %s\n", + name_test_data_drop, + wasm_runtime_get_exception(module_inst[i])); + } + else { + printf("call wasm function %s failed. error: %s\n", + name_test_data_drop, + wasm_runtime_get_exception(module_inst[i])); + goto fail; + } + } + + for (i = 0; i < N; i++) { + wasm_runtime_clear_exception(module_inst[i]); + + uint32_t argv[1] = {}; + if (wasm_runtime_call_wasm(exec_env[i], func_test_elem_drop[i], 0, + argv)) { + uint32_t result = argv[0]; + printf( + "Native finished calling wasm function: %s, return: %x\n", + name_test_elem_drop, result); + if (result != 0) { + printf("unexpected return value\n"); + goto fail; + } + if (should_trap) { + printf("a trap is expected\n"); + goto fail; + } + } + else if (should_trap) { + printf("call wasm function %s failed as expected. error: %s\n", + name_test_elem_drop, + wasm_runtime_get_exception(module_inst[i])); + } + else { + printf("call wasm function %s failed. error: %s\n", + name_test_elem_drop, + wasm_runtime_get_exception(module_inst[i])); + goto fail; + } + } + } + + exit_code = 0; +fail: + for (i = 0; i < N; i++) { + if (exec_env[i]) + wasm_runtime_destroy_exec_env(exec_env[i]); + if (module_inst[i]) + wasm_runtime_deinstantiate(module_inst[i]); + } + if (module) + wasm_runtime_unload(module); + if (buffer) + BH_FREE(buffer); + wasm_runtime_destroy(); + return exit_code; +} diff --git a/samples/shared-module/wasm-apps/testapp.wat b/samples/shared-module/wasm-apps/testapp.wat new file mode 100644 index 000000000..263a87036 --- /dev/null +++ b/samples/shared-module/wasm-apps/testapp.wat @@ -0,0 +1,22 @@ +;; Copyright (C) 2023 Midokura Japan KK. All rights reserved. +;; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +(module + (func (export "test_data_drop") (result i32) + (memory.init 0 (i32.const 0) (i32.const 0) (i32.const 4)) + data.drop 0 + (i32.load (i32.const 0)) + ) + (func (export "test_elem_drop") (result i32) + (table.init 0 (i32.const 0) (i32.const 0) (i32.const 4)) + elem.drop 0 + i32.const 3 + table.get 0 + ref.is_null + ) + (func $f) + (memory 1 1) + (table 4 4 funcref) + (data "abcd") + (elem func $f $f $f $f) +) diff --git a/samples/spawn-thread/CMakeLists.txt b/samples/spawn-thread/CMakeLists.txt index 7b76311d7..29c4dc429 100644 --- a/samples/spawn-thread/CMakeLists.txt +++ b/samples/spawn-thread/CMakeLists.txt @@ -45,9 +45,9 @@ endif () set(WAMR_BUILD_INTERP 1) set(WAMR_BUILD_AOT 1) set(WAMR_BUILD_JIT 0) -set(WAMR_BUILD_LIBC_BUILTIN 1) set(WAMR_BUILD_FAST_INTERP 1) -set(WAMR_BUILD_LIB_PTHREAD 1) +set(WAMR_BUILD_THREAD_MGR 1) +set(WAMR_BUILD_SHARED_MEMORY 1) # compiling and linking flags if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) diff --git a/samples/spawn-thread/wasm-apps/CMakeLists.txt b/samples/spawn-thread/wasm-apps/CMakeLists.txt index 52ee7d752..0996d5841 100644 --- a/samples/spawn-thread/wasm-apps/CMakeLists.txt +++ b/samples/spawn-thread/wasm-apps/CMakeLists.txt @@ -29,6 +29,7 @@ set (DEFINED_SYMBOLS set (CMAKE_EXE_LINKER_FLAGS "-Wl,--shared-memory,--max-memory=131072, \ -Wl,--no-entry,--strip-all,--export=sum, \ + -Wl,--export=return_bss, \ -Wl,--export=__heap_base,--export=__data_end \ -Wl,--export=__wasm_call_ctors \ -Wl,--allow-undefined-file=${DEFINED_SYMBOLS}" diff --git a/samples/spawn-thread/wasm-apps/sum.c b/samples/spawn-thread/wasm-apps/sum.c index 0bcb8918d..6f8b8f218 100644 --- a/samples/spawn-thread/wasm-apps/sum.c +++ b/samples/spawn-thread/wasm-apps/sum.c @@ -3,6 +3,17 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ +/* + * have something in bss so that llvm synthesizes + * wasm start function for this module. + */ +char * +return_bss() +{ + static char bss[4096]; + return bss; +} + int sum(int start, int length) { @@ -13,4 +24,4 @@ sum(int start, int length) } return sum; -} \ No newline at end of file +} diff --git a/samples/wasm-c-api/CMakeLists.txt b/samples/wasm-c-api/CMakeLists.txt index 4dab0185c..4189f7280 100644 --- a/samples/wasm-c-api/CMakeLists.txt +++ b/samples/wasm-c-api/CMakeLists.txt @@ -9,7 +9,6 @@ if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") project(c-api) else() project (c-api C ASM) - enable_language (ASM_MASM) endif() if(NOT CMAKE_BUILD_TYPE) diff --git a/tests/benchmarks/libsodium/build.sh b/tests/benchmarks/libsodium/build.sh index 3049f2c73..c949375b2 100755 --- a/tests/benchmarks/libsodium/build.sh +++ b/tests/benchmarks/libsodium/build.sh @@ -12,9 +12,9 @@ libsodium_CASES="aead_aes256gcm2 aead_aes256gcm aead_chacha20poly13052 aead_chac pwhash_scrypt_ll pwhash_scrypt randombytes scalarmult2 scalarmult5 \ scalarmult6 scalarmult7 scalarmult8 scalarmult_ed25519 scalarmult_ristretto255 \ scalarmult secretbox2 secretbox7 secretbox8 secretbox_easy2 secretbox_easy \ - secretbox secretstream shorthash sign siphashx24 sodium_core sodium_utils2 \ - sodium_utils3 sodium_utils sodium_version stream2 stream3 stream4 stream verify1 \ - xchacha20" + secretbox secretstream_xchacha20poly1305 shorthash sign siphashx24 sodium_core \ + sodium_utils2 sodium_utils3 sodium_utils sodium_version stream2 stream3 stream4 \ + stream verify1 xchacha20" PLATFORM=$(uname -s | tr A-Z a-z) @@ -22,16 +22,19 @@ readonly WAMRC_CMD=$PWD/../../../wamr-compiler/build/wamrc readonly OUT_DIR=$PWD/libsodium/zig-out/bin if [ ! -d libsodium ]; then - git clone -b stable https://github.com/jedisct1/libsodium.git + git clone https://github.com/jedisct1/libsodium.git + cd libsodium + git checkout 1.0.19 + cd .. fi cd libsodium echo "Build libsodium native" -zig build -Drelease-fast -Denable_benchmarks=true +zig build -Doptimize=ReleaseFast -Denable_benchmarks=true echo "Build libsodium wasm32-wasi" -zig build -Drelease-fast -Denable_benchmarks=true -Dtarget=wasm32-wasi +zig build -Doptimize=ReleaseFast -Denable_benchmarks=true -Dtarget=wasm32-wasi for case in ${libsodium_CASES} do diff --git a/tests/benchmarks/libsodium/run_aot.sh b/tests/benchmarks/libsodium/run_aot.sh index 8859d0634..3623deb2c 100755 --- a/tests/benchmarks/libsodium/run_aot.sh +++ b/tests/benchmarks/libsodium/run_aot.sh @@ -12,8 +12,8 @@ libsodium_CASES="aead_aes256gcm2 aead_aes256gcm aead_chacha20poly13052 aead_chac pwhash_scrypt_ll pwhash_scrypt randombytes scalarmult2 scalarmult5 \ scalarmult6 scalarmult7 scalarmult8 scalarmult_ed25519 scalarmult_ristretto255 \ scalarmult secretbox2 secretbox7 secretbox8 secretbox_easy2 secretbox_easy \ - secretbox secretstream shorthash sign siphashx24 sodium_core sodium_utils2 \ - sodium_utils stream2 stream3 stream4 stream verify1 xchacha20" + secretbox secretstream_xchacha20poly1305 shorthash sign siphashx24 sodium_core \ + sodium_utils2 sodium_utils stream2 stream3 stream4 stream verify1 xchacha20" PLATFORM=$(uname -s | tr A-Z a-z) diff --git a/tests/benchmarks/libsodium/test_pgo.sh b/tests/benchmarks/libsodium/test_pgo.sh index 2dda6a5f9..3f9ee2eae 100755 --- a/tests/benchmarks/libsodium/test_pgo.sh +++ b/tests/benchmarks/libsodium/test_pgo.sh @@ -12,8 +12,8 @@ libsodium_CASES="aead_aes256gcm2 aead_aes256gcm aead_chacha20poly13052 aead_chac pwhash_scrypt_ll pwhash_scrypt randombytes scalarmult2 scalarmult5 \ scalarmult6 scalarmult7 scalarmult8 scalarmult_ed25519 scalarmult_ristretto255 \ scalarmult secretbox2 secretbox7 secretbox8 secretbox_easy2 secretbox_easy \ - secretbox secretstream shorthash sign siphashx24 sodium_core sodium_utils2 \ - sodium_utils stream2 stream3 stream4 stream verify1 xchacha20" + secretbox secretstream_xchacha20poly1305 shorthash sign siphashx24 sodium_core \ + sodium_utils2 sodium_utils stream2 stream3 stream4 stream verify1 xchacha20" PLATFORM=$(uname -s | tr A-Z a-z) diff --git a/tests/wamr-compiler/test_shift_negative_constants.wat b/tests/wamr-compiler/test_shift_negative_constants.wat index 030cc8983..83bc3c44d 100644 --- a/tests/wamr-compiler/test_shift_negative_constants.wat +++ b/tests/wamr-compiler/test_shift_negative_constants.wat @@ -7,6 +7,7 @@ ;; any problems. See: https://github.com/bytecodealliance/wasm-micro-runtime/pull/2619 (module (memory (export "memory") 1 1) + (func $assert_eq (param i32 i32) (i32.ne (local.get 0) (local.get 1)) if @@ -23,7 +24,7 @@ (func $i32_shr_s (call $assert_eq - (i32.shr_u (i32.const 32) (i32.const -30)) + (i32.shr_s (i32.const 32) (i32.const -30)) (i32.const 8) ) ) @@ -35,9 +36,43 @@ ) ) + (func $const_ret (result i32) + i32.const -5 + ) + + ;; *_func_call tests validate the potential LLVM optimizations + ;; where the right parameter of the shift operation is an + ;; indirect constant value. + (func $i32_shr_u_func_call + (call $assert_eq + (i32.shr_u (i32.const -1) (call $const_ret)) + (i32.const 31) + ) + ) + + (func $i32_shr_s_func_call + (call $assert_eq + (i32.shr_s + (i32.const 1073741824) ;; 2^30 + (call $const_ret) + ) + (i32.const 8) + ) + ) + + (func $i32_shl_func_call + (call $assert_eq + (i32.shl (i32.const -1) (call $const_ret)) + (i32.const -134217728) + ) + ) + (func (export "_start") call $i32_shr_u call $i32_shr_s call $i32_shl + call $i32_shr_u_func_call + call $i32_shr_s_func_call + call $i32_shl_func_call ) ) diff --git a/tests/wamr-test-suites/spec-test-script/all.py b/tests/wamr-test-suites/spec-test-script/all.py index 12ac005bb..551a3176c 100644 --- a/tests/wamr-test-suites/spec-test-script/all.py +++ b/tests/wamr-test-suites/spec-test-script/all.py @@ -6,7 +6,7 @@ import argparse import multiprocessing as mp -import os +import platform import pathlib import subprocess import sys @@ -28,34 +28,45 @@ To run a single GC case: --aot-compiler wamrc --gc spec/test/core/xxx.wast """ -PLATFORM_NAME = os.uname().sysname.lower() -IWASM_CMD = "../../../product-mini/platforms/" + PLATFORM_NAME + "/build/iwasm" +def exe_file_path(base_path: str) -> str: + if platform.system().lower() == "windows": + base_path += ".exe" + return base_path + +def get_iwasm_cmd(platform: str) -> str: + build_path = "../../../product-mini/platforms/" + platform + "/build/" + exe_name = "iwasm" + + if platform == "windows": + build_path += "RelWithDebInfo/" + + return exe_file_path(build_path + exe_name) + +PLATFORM_NAME = platform.uname().system.lower() +IWASM_CMD = get_iwasm_cmd(PLATFORM_NAME) IWASM_SGX_CMD = "../../../product-mini/platforms/linux-sgx/enclave-sample/iwasm" IWASM_QEMU_CMD = "iwasm" SPEC_TEST_DIR = "spec/test/core" -WAST2WASM_CMD = "./wabt/out/gcc/Release/wat2wasm" +WAST2WASM_CMD = exe_file_path("./wabt/out/gcc/Release/wat2wasm") SPEC_INTERPRETER_CMD = "spec/interpreter/wasm" WAMRC_CMD = "../../../wamr-compiler/build/wamrc" - - -class TargetAction(argparse.Action): - TARGET_MAP = { - "ARMV7_VFP": "armv7", - "RISCV32": "riscv32_ilp32", - "RISCV32_ILP32": "riscv32_ilp32", - "RISCV32_ILP32D": "riscv32_ilp32d", - "RISCV64": "riscv64_lp64", - "RISCV64_LP64": "riscv64_lp64", - "RISCV64_LP64D": "riscv64_lp64", - "THUMBV7_VFP": "thumbv7", - "X86_32": "i386", - "X86_64": "x86_64", - "AARCH64": "arm64" - } - - def __call__(self, parser, namespace, values, option_string=None): - setattr(namespace, self.dest, self.TARGET_MAP.get(values, "x86_64")) - +AVAILABLE_TARGETS = [ + "I386", + "X86_32", + "X86_64", + "AARCH64", + "AARCH64_VFP", + "ARMV7", + "ARMV7_VFP", + "RISCV32", + "RISCV32_ILP32F", + "RISCV32_ILP32D", + "RISCV64", + "RISCV64_LP64F", + "RISCV64_LP64D", + "THUMBV7", + "THUMBV7_VFP", +] def ignore_the_case( case_name, @@ -146,8 +157,9 @@ def test_case( qemu_flag=False, qemu_firmware="", log="", + no_pty=False ): - CMD = ["python3", "runtest.py"] + CMD = [sys.executable, "runtest.py"] CMD.append("--wast2wasm") CMD.append(WAST2WASM_CMD if not gc_flag else SPEC_INTERPRETER_CMD) CMD.append("--interpreter") @@ -157,6 +169,8 @@ def test_case( CMD.append(IWASM_QEMU_CMD) else: CMD.append(IWASM_CMD) + if no_pty: + CMD.append("--no-pty") CMD.append("--aot-compiler") CMD.append(WAMRC_CMD) @@ -261,6 +275,7 @@ def test_suite( qemu_flag=False, qemu_firmware="", log="", + no_pty=False, ): suite_path = pathlib.Path(SPEC_TEST_DIR).resolve() if not suite_path.exists(): @@ -322,6 +337,7 @@ def test_suite( qemu_flag, qemu_firmware, log, + no_pty, ], ) @@ -359,6 +375,7 @@ def test_suite( qemu_flag, qemu_firmware, log, + no_pty, ) successful_case += 1 except Exception as e: @@ -384,8 +401,7 @@ def main(): ) parser.add_argument( "-m", - action=TargetAction, - choices=list(TargetAction.TARGET_MAP.keys()), + choices=AVAILABLE_TARGETS, type=str, dest="target", default="X86_64", @@ -480,9 +496,18 @@ def main(): nargs="*", help=f"Specify all wanted cases. If not the script will go through all cases under {SPEC_TEST_DIR}", ) + parser.add_argument('--no-pty', action='store_true', + help="Use direct pipes instead of pseudo-tty") options = parser.parse_args() + # Convert target to lower case for internal use, e.g. X86_64 -> x86_64 + # target is always exist, so no need to check it + options.target = options.target.lower() + + if options.target == "x86_32": + options.target = "i386" + if not preflight_check(options.aot_flag): return False @@ -509,6 +534,7 @@ def main(): options.qemu_flag, options.qemu_firmware, options.log, + options.no_pty ) end = time.time_ns() print( @@ -532,6 +558,7 @@ def main(): options.qemu_flag, options.qemu_firmware, options.log, + options.no_pty, ) else: ret = True diff --git a/tests/wamr-test-suites/spec-test-script/muti_module_aot_ignore_cases.patch b/tests/wamr-test-suites/spec-test-script/multi_module_aot_ignore_cases.patch similarity index 100% rename from tests/wamr-test-suites/spec-test-script/muti_module_aot_ignore_cases.patch rename to tests/wamr-test-suites/spec-test-script/multi_module_aot_ignore_cases.patch diff --git a/tests/wamr-test-suites/spec-test-script/runtest.py b/tests/wamr-test-suites/spec-test-script/runtest.py index 566a165f3..dcc0c3361 100755 --- a/tests/wamr-test-suites/spec-test-script/runtest.py +++ b/tests/wamr-test-suites/spec-test-script/runtest.py @@ -5,22 +5,21 @@ from __future__ import print_function import argparse import array import atexit -import fcntl import math import os -# Pseudo-TTY and terminal manipulation -import pty import re import shutil import struct import subprocess import sys import tempfile -import termios import time +import threading import traceback from select import select +from queue import Queue from subprocess import PIPE, STDOUT, Popen +from typing import BinaryIO, Optional, Tuple if sys.version_info[0] == 2: IS_PY_3 = False @@ -28,7 +27,9 @@ else: IS_PY_3 = True test_aot = False -# "x86_64", "i386", "aarch64", "armv7", "thumbv7", "riscv32_ilp32", "riscv32_ilp32d", "riscv32_lp64", "riscv64_lp64d" +# Available targets: +# "aarch64" "aarch64_vfp" "armv7" "armv7_vfp" "thumbv7" "thumbv7_vfp" +# "riscv32" "riscv32_ilp32f" "riscv32_ilp32d" "riscv64" "riscv64_lp64f" "riscv64_lp64d" test_target = "x86_64" debug_file = None @@ -40,6 +41,25 @@ temp_file_repo = [] # to save the mapping of module files in /tmp by name temp_module_table = {} +# AOT compilation options mapping +aot_target_options_map = { + "i386": ["--target=i386"], + "x86_32": ["--target=i386"], + "x86_64": ["--target=x86_64", "--cpu=skylake"], + "aarch64": ["--target=aarch64", "--target-abi=eabi", "--cpu=cortex-a53"], + "aarch64_vfp": ["--target=aarch64", "--target-abi=gnueabihf", "--cpu=cortex-a53"], + "armv7": ["--target=armv7", "--target-abi=eabi", "--cpu=cortex-a9", "--cpu-features=-neon"], + "armv7_vfp": ["--target=armv7", "--target-abi=gnueabihf", "--cpu=cortex-a9"], + "thumbv7": ["--target=thumbv7", "--target-abi=eabi", "--cpu=cortex-a9", "--cpu-features=-neon,-vfpv3"], + "thumbv7_vfp": ["--target=thumbv7", "--target-abi=gnueabihf", "--cpu=cortex-a9", "--cpu-features=-neon"], + "riscv32": ["--target=riscv32", "--target-abi=ilp32", "--cpu=generic-rv32", "--cpu-features=+m,+a,+c"], + "riscv32_ilp32f": ["--target=riscv32", "--target-abi=ilp32f", "--cpu=generic-rv32", "--cpu-features=+m,+a,+c,+f"], + "riscv32_ilp32d": ["--target=riscv32", "--target-abi=ilp32d", "--cpu=generic-rv32", "--cpu-features=+m,+a,+c,+f,+d"], + "riscv64": ["--target=riscv64", "--target-abi=lp64", "--cpu=generic-rv64", "--cpu-features=+m,+a,+c"], + "riscv64_lp64f": ["--target=riscv64", "--target-abi=lp64f", "--cpu=generic-rv64", "--cpu-features=+m,+a,+c,+f"], + "riscv64_lp64d": ["--target=riscv64", "--target-abi=lp64d", "--cpu=generic-rv64", "--cpu-features=+m,+a,+c,+f,+d"], +} + def debug(data): if debug_file: debug_file.write(data) @@ -52,6 +72,10 @@ def log(data, end='\n'): print(data, end=end) sys.stdout.flush() +def create_tmp_file(suffix: str) -> str: + with tempfile.NamedTemporaryFile(suffix=suffix, delete=False) as tmp_file: + return tmp_file.name + # TODO: do we need to support '\n' too import platform @@ -62,6 +86,34 @@ else: sep = "\r\n" rundir = None + +class AsyncStreamReader: + def __init__(self, stream: BinaryIO) -> None: + self._queue = Queue() + self._reader_thread = threading.Thread( + daemon=True, + target=AsyncStreamReader._stdout_reader, + args=(self._queue, stream)) + self._reader_thread.start() + + def read(self) -> Optional[bytes]: + return self._queue.get() + + def cleanup(self) -> None: + self._reader_thread.join() + + @staticmethod + def _stdout_reader(queue: Queue, stdout: BinaryIO) -> None: + while True: + try: + queue.put(stdout.read(1)) + except ValueError as e: + if stdout.closed: + queue.put(None) + break + raise e + + class Runner(): def __init__(self, args, no_pty=False): self.no_pty = no_pty @@ -77,11 +129,14 @@ class Runner(): if no_pty: self.process = Popen(args, bufsize=0, stdin=PIPE, stdout=PIPE, stderr=STDOUT, - preexec_fn=os.setsid, env=env) self.stdin = self.process.stdin self.stdout = self.process.stdout else: + import fcntl + # Pseudo-TTY and terminal manipulation + import pty + import termios # Use tty to setup an interactive environment master, slave = pty.openpty() @@ -101,35 +156,53 @@ class Runner(): self.stdin = os.fdopen(master, 'r+b', 0) self.stdout = self.stdin + if platform.system().lower() == "windows": + self._stream_reader = AsyncStreamReader(self.stdout) + else: + self._stream_reader = None + self.buf = "" + def _read_stdout_byte(self) -> Tuple[bool, Optional[bytes]]: + if self._stream_reader: + return True, self._stream_reader.read() + else: + # select doesn't work on file descriptors on Windows. + # however, this method is much faster than using + # queue, so we keep it for non-windows platforms. + [outs,_,_] = select([self.stdout], [], [], 1) + if self.stdout in outs: + return True, self.stdout.read(1) + else: + return False, None + def read_to_prompt(self, prompts, timeout): wait_until = time.time() + timeout while time.time() < wait_until: - [outs,_,_] = select([self.stdout], [], [], 1) - if self.stdout in outs: - read_byte = self.stdout.read(1) - if not read_byte: - # EOF on macOS ends up here. - break - read_byte = read_byte.decode('utf-8') if IS_PY_3 else read_byte + has_value, read_byte = self._read_stdout_byte() + if not has_value: + continue + if not read_byte: + # EOF on macOS ends up here. + break + read_byte = read_byte.decode('utf-8') if IS_PY_3 else read_byte - debug(read_byte) - if self.no_pty: - self.buf += read_byte.replace('\n', '\r\n') - else: - self.buf += read_byte - self.buf = self.buf.replace('\r\r', '\r') + debug(read_byte) + if self.no_pty: + self.buf += read_byte.replace('\n', '\r\n') + else: + self.buf += read_byte + self.buf = self.buf.replace('\r\r', '\r') - # filter the prompts - for prompt in prompts: - pattern = re.compile(prompt) - match = pattern.search(self.buf) - if match: - end = match.end() - buf = self.buf[0:end-len(prompt)] - self.buf = self.buf[end:] - return buf + # filter the prompts + for prompt in prompts: + pattern = re.compile(prompt) + match = pattern.search(self.buf) + if match: + end = match.end() + buf = self.buf[0:end-len(prompt)] + self.buf = self.buf[end:] + return buf return None def writeline(self, str): @@ -140,6 +213,8 @@ class Runner(): self.stdin.write(str_to_write) def cleanup(self): + atexit.unregister(self.cleanup) + if self.process: try: self.writeline("__exit__") @@ -157,6 +232,8 @@ class Runner(): self.stdout = None if not IS_PY_3: sys.exc_clear() + if self._stream_reader: + self._stream_reader.cleanup() def assert_prompt(runner, prompts, timeout, is_need_execute_result): # Wait for the initial prompt @@ -402,9 +479,9 @@ def cast_v128_to_i64x2(numbers, type, lane_type): unpacked = struct.unpack("Q Q", packed) return unpacked, f"[{unpacked[0]:#x} {unpacked[1]:#x}]:{lane_type}:v128" - def parse_simple_const_w_type(number, type): number = number.replace('_', '') + number = re.sub(r"nan\((ind|snan)\)", "nan", number) if type in ["i32", "i64"]: number = int(number, 16) if '0x' in number else int(number) return number, "0x{:x}:{}".format(number, type) \ @@ -941,7 +1018,8 @@ def skip_test(form, skip_list): def compile_wast_to_wasm(form, wast_tempfile, wasm_tempfile, opts): log("Writing WAST module to '%s'" % wast_tempfile) - open(wast_tempfile, 'w').write(form) + with open(wast_tempfile, 'w') as file: + file.write(form) log("Compiling WASM to '%s'" % wasm_tempfile) # default arguments @@ -968,27 +1046,8 @@ def compile_wasm_to_aot(wasm_tempfile, aot_tempfile, runner, opts, r, output = ' log("Compiling AOT to '%s'" % aot_tempfile) cmd = [opts.aot_compiler] - if test_target == "x86_64": - cmd.append("--target=x86_64") - cmd.append("--cpu=skylake") - elif test_target == "i386": - cmd.append("--target=i386") - elif test_target == "aarch64": - cmd += ["--target=aarch64", "--cpu=cortex-a57"] - elif test_target == "armv7": - cmd += ["--target=armv7", "--target-abi=gnueabihf"] - elif test_target == "thumbv7": - cmd += ["--target=thumbv7", "--target-abi=gnueabihf", "--cpu=cortex-a9", "--cpu-features=-neon"] - elif test_target == "riscv32_ilp32": - cmd += ["--target=riscv32", "--target-abi=ilp32", "--cpu=generic-rv32", "--cpu-features=+m,+a,+c"] - elif test_target == "riscv32_ilp32d": - cmd += ["--target=riscv32", "--target-abi=ilp32d", "--cpu=generic-rv32", "--cpu-features=+m,+a,+c"] - elif test_target == "riscv64_lp64": - cmd += ["--target=riscv64", "--target-abi=lp64", "--cpu=generic-rv64", "--cpu-features=+m,+a,+c"] - elif test_target == "riscv64_lp64d": - cmd += ["--target=riscv64", "--target-abi=lp64d", "--cpu=generic-rv32", "--cpu-features=+m,+a,+c"] - else: - pass + if test_target in aot_target_options_map: + cmd += aot_target_options_map[test_target] if opts.sgx: cmd.append("-sgx") @@ -1013,6 +1072,17 @@ def compile_wasm_to_aot(wasm_tempfile, aot_tempfile, runner, opts, r, output = ' # exception isn't thrown in several cases cmd.append("--disable-llvm-lto") + # Bounds checks is disabled by default for 64-bit targets, to + # use the hardware based bounds checks. But it is not supported + # in QEMU with NuttX. + # Enable bounds checks explicitly for all targets if running in QEMU. + if opts.qemu: + cmd.append("--bounds-checks=1") + + # RISCV64 requires -mcmodel=medany, which can be set by --size-level=1 + if test_target.startswith("riscv64"): + cmd.append("--size-level=1") + cmd += ["-o", aot_tempfile, wasm_tempfile] log("Running: %s" % " ".join(cmd)) @@ -1037,12 +1107,20 @@ def run_wasm_with_repl(wasm_tempfile, aot_tempfile, opts, r): if opts.qemu_firmware == '': raise Exception("QEMU firmware missing") - if opts.target == "thumbv7": - cmd = ["qemu-system-arm", "-semihosting", "-M", "sabrelite", "-m", "1024", "-smp", "4", "-nographic", "-kernel", opts.qemu_firmware] - elif opts.target == "riscv32_ilp32": - cmd = ["qemu-system-riscv32", "-semihosting", "-M", "virt,aclint=on", "-cpu", "rv32", "-smp", "8", "-nographic", "-bios", "none", "-kernel", opts.qemu_firmware] - elif opts.target == "riscv64_lp64": - cmd = ["qemu-system-riscv64", "-semihosting", "-M", "virt,aclint=on", "-cpu", "rv64", "-smp", "8", "-nographic", "-bios", "none", "-kernel", opts.qemu_firmware] + if opts.target.startswith("aarch64"): + cmd = "qemu-system-aarch64 -cpu cortex-a53 -nographic -machine virt,virtualization=on,gic-version=3 -net none -chardev stdio,id=con,mux=on -serial chardev:con -mon chardev=con,mode=readline -kernel".split() + cmd.append(opts.qemu_firmware) + elif opts.target.startswith("thumbv7"): + cmd = "qemu-system-arm -semihosting -M sabrelite -m 1024 -smp 1 -nographic -kernel".split() + cmd.append(opts.qemu_firmware) + elif opts.target.startswith("riscv32"): + cmd = "qemu-system-riscv32 -semihosting -M virt,aclint=on -cpu rv32 -smp 1 -nographic -bios none -kernel".split() + cmd.append(opts.qemu_firmware) + elif opts.target.startswith("riscv64"): + cmd = "qemu-system-riscv64 -semihosting -M virt,aclint=on -cpu rv64 -smp 1 -nographic -bios none -kernel".split() + cmd.append(opts.qemu_firmware) + else: + raise Exception("Unknwon target for QEMU: %s" % opts.target) else: cmd = cmd_iwasm @@ -1063,13 +1141,10 @@ def run_wasm_with_repl(wasm_tempfile, aot_tempfile, opts, r): def create_tmpfiles(wast_name): tempfiles = [] - (t1fd, wast_tempfile) = tempfile.mkstemp(suffix=".wast") - (t2fd, wasm_tempfile) = tempfile.mkstemp(suffix=".wasm") - tempfiles.append(wast_tempfile) - tempfiles.append(wasm_tempfile) + tempfiles.append(create_tmp_file(".wast")) + tempfiles.append(create_tmp_file(".wasm")) if test_aot: - (t3fd, aot_tempfile) = tempfile.mkstemp(suffix=".aot") - tempfiles.append(aot_tempfile) + tempfiles.append(create_tmp_file(".aot")) # add these temp file to temporal repo, will be deleted when finishing the test temp_file_repo.extend(tempfiles) @@ -1138,10 +1213,10 @@ if __name__ == "__main__": else: SKIP_TESTS = C_SKIP_TESTS - (t1fd, wast_tempfile) = tempfile.mkstemp(suffix=".wast") - (t2fd, wasm_tempfile) = tempfile.mkstemp(suffix=".wasm") + wast_tempfile = create_tmp_file(".wast") + wasm_tempfile = create_tmp_file(".wasm") if test_aot: - (t3fd, aot_tempfile) = tempfile.mkstemp(suffix=".aot") + aot_tempfile = create_tmp_file(".aot") ret_code = 0 try: @@ -1172,17 +1247,16 @@ if __name__ == "__main__": # workaround: spec test changes error message to "malformed" while iwasm still use "invalid" error_msg = m.group(2).replace("malformed", "invalid") log("Testing(malformed)") - f = open(wasm_tempfile, 'wb') - s = m.group(1) - while s: - res = re.match("[^\"]*\"([^\"]*)\"(.*)", s, re.DOTALL) - if IS_PY_3: - context = res.group(1).replace("\\", "\\x").encode("latin1").decode("unicode-escape").encode("latin1") - f.write(context) - else: - f.write(res.group(1).replace("\\", "\\x").decode("string-escape")) - s = res.group(2) - f.close() + with open(wasm_tempfile, 'wb') as f: + s = m.group(1) + while s: + res = re.match("[^\"]*\"([^\"]*)\"(.*)", s, re.DOTALL) + if IS_PY_3: + context = res.group(1).replace("\\", "\\x").encode("latin1").decode("unicode-escape").encode("latin1") + f.write(context) + else: + f.write(res.group(1).replace("\\", "\\x").decode("string-escape")) + s = res.group(2) # compile wasm to aot if test_aot: diff --git a/tests/wamr-test-suites/test_wamr.sh b/tests/wamr-test-suites/test_wamr.sh index 81844f0e7..76b235d49 100755 --- a/tests/wamr-test-suites/test_wamr.sh +++ b/tests/wamr-test-suites/test_wamr.sh @@ -15,7 +15,9 @@ function help() echo "test_wamr.sh [options]" echo "-c clean previous test results, not start test" echo "-s {suite_name} test only one suite (spec|wasi_certification|wamr_compiler)" - echo "-m set compile target of iwasm(x86_64|x86_32|armv7_vfp|thumbv7_vfp|riscv64_lp64d|riscv64_lp64|aarch64)" + echo "-m set compile target of iwasm(x86_64|x86_32|armv7|armv7_vfp|thumbv7|thumbv7_vfp|" + echo " riscv32|riscv32_ilp32f|riscv32_ilp32d|riscv64|" + echo " riscv64_lp64f|riscv64_lp64d|aarch64|aarch64_vfp)" echo "-t set compile type of iwasm(classic-interp|fast-interp|jit|aot|fast-jit|multi-tier-jit)" echo "-M enable multi module feature" echo "-p enable multi thread feature" @@ -32,6 +34,7 @@ function help() echo "-F set the firmware path used by qemu" echo "-C enable code coverage collect" echo "-j set the platform to test" + echo "-T set sanitizer to use in tests(ubsan|tsan|asan)" } OPT_PARSED="" @@ -52,14 +55,22 @@ ENABLE_GC_HEAP_VERIFY=0 #unit test case arrary TEST_CASE_ARR=() SGX_OPT="" -PLATFORM=$(uname -s | tr A-Z a-z) +if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" ]]; then + PLATFORM=windows + PYTHON_EXE=python +else + PLATFORM=$(uname -s | tr A-Z a-z) + PYTHON_EXE=python3 +fi PARALLELISM=0 ENABLE_QEMU=0 QEMU_FIRMWARE="" # prod/testsuite-all branch WASI_TESTSUITE_COMMIT="ee807fc551978490bf1c277059aabfa1e589a6c2" +TARGET_LIST=("AARCH64" "AARCH64_VFP" "ARMV7" "ARMV7_VFP" "THUMBV7" "THUMBV7_VFP" \ + "RISCV32" "RISCV32_ILP32F" "RISCV32_ILP32D" "RISCV64" "RISCV64_LP64F" "RISCV64_LP64D") -while getopts ":s:cabgvt:m:MCpSXxwPGQF:j:" opt +while getopts ":s:cabgvt:m:MCpSXxwPGQF:j:T:" opt do OPT_PARSED="TRUE" case $opt in @@ -165,9 +176,14 @@ do echo "test platform " ${OPTARG} PLATFORM=${OPTARG} ;; + T) + echo "sanitizer is " ${OPTARG} + WAMR_BUILD_SANITIZER=${OPTARG} + ;; ?) help - exit 1;; + exit 1 + ;; esac done @@ -317,12 +333,15 @@ function setup_wabt() if [ ! -f ${WAT2WASM} ]; then case ${PLATFORM} in cosmopolitan) - ;& + ;; linux) WABT_PLATFORM=ubuntu ;; darwin) - WABT_PLATFORM=macos + WABT_PLATFORM=macos-12 + ;; + windows) + WABT_PLATFORM=windows ;; *) echo "wabt platform for ${PLATFORM} in unknown" @@ -330,9 +349,9 @@ function setup_wabt() ;; esac if [ ! -f /tmp/wabt-1.0.31-${WABT_PLATFORM}.tar.gz ]; then - wget \ + curl -L \ https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-${WABT_PLATFORM}.tar.gz \ - -P /tmp + -o /tmp/wabt-1.0.31-${WABT_PLATFORM}.tar.gz fi cd /tmp \ @@ -386,7 +405,7 @@ function spec_test() git apply ../../spec-test-script/simd_ignore_cases.patch fi if [[ ${ENABLE_MULTI_MODULE} == 1 && $1 == 'aot' ]]; then - git apply ../../spec-test-script/muti_module_aot_ignore_cases.patch + git apply ../../spec-test-script/multi_module_aot_ignore_cases.patch fi # udpate thread cases @@ -487,12 +506,16 @@ function spec_test() ARGS_FOR_SPEC_TEST+="--qemu-firmware ${QEMU_FIRMWARE} " fi + if [[ ${PLATFORM} == "windows" ]]; then + ARGS_FOR_SPEC_TEST+="--no-pty " + fi + # set log directory ARGS_FOR_SPEC_TEST+="--log ${REPORT_DIR}" cd ${WORK_DIR} - echo "python3 ./all.py ${ARGS_FOR_SPEC_TEST} | tee -a ${REPORT_DIR}/spec_test_report.txt" - python3 ./all.py ${ARGS_FOR_SPEC_TEST} | tee -a ${REPORT_DIR}/spec_test_report.txt + echo "${PYTHON_EXE} ./all.py ${ARGS_FOR_SPEC_TEST} | tee -a ${REPORT_DIR}/spec_test_report.txt" + ${PYTHON_EXE} ./all.py ${ARGS_FOR_SPEC_TEST} | tee -a ${REPORT_DIR}/spec_test_report.txt if [[ ${PIPESTATUS[0]} -ne 0 ]];then echo -e "\nspec tests FAILED" | tee -a ${REPORT_DIR}/spec_test_report.txt exit 1 @@ -553,7 +576,7 @@ function wasi_certification_test() cd wasi-testsuite git reset --hard ${WASI_TESTSUITE_COMMIT} - bash ../../wasi-test-script/run_wasi_tests.sh $1 $TARGET \ + TSAN_OPTIONS=${TSAN_OPTIONS} bash ../../wasi-test-script/run_wasi_tests.sh $1 $TARGET $WASI_TEST_FILTER \ | tee -a ${REPORT_DIR}/wasi_test_report.txt ret=${PIPESTATUS[0]} @@ -683,7 +706,7 @@ function build_iwasm_with_cfg() && if [ -d build ]; then rm -rf build/*; else mkdir build; fi \ && cd build \ && cmake $* .. \ - && make -j 4 + && cmake --build . -j 4 --config RelWithDebInfo --target iwasm fi if [ "$?" != 0 ];then @@ -708,9 +731,7 @@ function build_iwasm_with_cfg() function build_wamrc() { - if [[ $TARGET == "ARMV7_VFP" || $TARGET == "THUMBV7_VFP" - || $TARGET == "RISCV32" || $TARGET == "RISCV32_ILP32" || $TARGET == "RISCV32_ILP32D" - || $TARGET == "RISCV64" || $TARGET == "RISCV64_LP64D" || $TARGET == "RISCV64_LP64" ]];then + if [[ "${TARGET_LIST[*]}" =~ "${TARGET}" ]]; then echo "suppose wamrc is already built" return fi @@ -823,6 +844,17 @@ function trigger() EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_SANITIZER=tsan" fi + # Make sure we're using the builtin WASI libc implementation + # if we're running the wasi certification tests. + if [[ $TEST_CASE_ARR ]]; then + for test in "${TEST_CASE_ARR[@]}"; do + if [[ "$test" == "wasi_certification" ]]; then + EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_LIBC_UVWASI=0 -DWAMR_BUILD_LIBC_WASI=1" + break + fi + done + fi + for t in "${TYPE[@]}"; do case $t in "classic-interp") @@ -948,4 +980,4 @@ fi echo -e "Test finish. Reports are under ${REPORT_DIR}" DEBUG set +xv pipefail echo "TEST SUCCESSFUL" -exit 0 \ No newline at end of file +exit 0 diff --git a/tests/wamr-test-suites/tsan_suppressions.txt b/tests/wamr-test-suites/tsan_suppressions.txt new file mode 100644 index 000000000..dd903a605 --- /dev/null +++ b/tests/wamr-test-suites/tsan_suppressions.txt @@ -0,0 +1,8 @@ +# Proposing to accept this risk for now. It might be wasi-libc related. +# https://github.com/bytecodealliance/wasm-micro-runtime/pull/1963#issuecomment-1455342931 +race:STORE_U32 +race:STORE_U8 + +# Suppressing signal-unsafe inside of a signal for AOT mode +# see https://github.com/bytecodealliance/wasm-micro-runtime/issues/2248#issuecomment-1630189656 +signal:* \ No newline at end of file diff --git a/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh b/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh index 61db39db0..4cfe6c29b 100755 --- a/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh +++ b/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh @@ -9,11 +9,25 @@ THIS_DIR=$(cd $(dirname $0) && pwd -P) readonly MODE=$1 readonly TARGET=$2 +readonly TEST_FILTER=$3 readonly WORK_DIR=$PWD -readonly PLATFORM=$(uname -s | tr A-Z a-z) + +if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" ]]; then + readonly PLATFORM=windows + readonly PYTHON_EXE=python + # see https://github.com/pypa/virtualenv/commit/993ba1316a83b760370f5a3872b3f5ef4dd904c1 + readonly VENV_BIN_DIR=Scripts + readonly IWASM_EXE=$(cygpath -m "${WORK_DIR}/../../../../product-mini/platforms/${PLATFORM}/build/RelWithDebInfo/iwasm.exe") +else + readonly PLATFORM=$(uname -s | tr A-Z a-z) + readonly VENV_BIN_DIR=bin + readonly PYTHON_EXE=python3 + readonly IWASM_EXE="${WORK_DIR}/../../../../product-mini/platforms/${PLATFORM}/build/iwasm" +fi + readonly WAMR_DIR="${WORK_DIR}/../../../.." -readonly IWASM_CMD="${WORK_DIR}/../../../../product-mini/platforms/${PLATFORM}/build/iwasm \ +readonly IWASM_CMD="${IWASM_EXE} \ --allow-resolve=google-public-dns-a.google.com \ --addr-pool=::1/128,127.0.0.1/32" @@ -28,8 +42,21 @@ readonly THREAD_STRESS_TESTS="${WAMR_DIR}/core/iwasm/libraries/lib-wasi-threads/ readonly LIB_SOCKET_TESTS="${WAMR_DIR}/core/iwasm/libraries/lib-socket/test/" run_aot_tests () { - local tests=("$@") + local -n tests=$1 + local -n excluded_tests=$2 + for test_wasm in ${tests[@]}; do + # get the base file name from the filepath + local test_name=${test_wasm##*/} + test_name=${test_name%.wasm} + + for excluded_test in "${excluded_tests[@]}"; do + if [[ $excluded_test == "\"$test_name\"" ]]; then + echo "Skipping test $test_name" + continue 2 + fi + done + local iwasm="${IWASM_CMD}" if [[ $test_wasm =~ "stress" ]]; then iwasm="${IWASM_CMD_STRESS}" @@ -52,7 +79,7 @@ run_aot_tests () { expected=$(jq .exit_code ${test_json}) fi - python3 ${THIS_DIR}/pipe.py | ${iwasm} $test_aot + $PYTHON_EXE ${THIS_DIR}/pipe.py | ${iwasm} $test_aot ret=${PIPESTATUS[1]} echo "expected=$expected, actual=$ret" @@ -63,23 +90,29 @@ run_aot_tests () { } if [[ $MODE != "aot" ]];then - python3 -m venv wasi-env && source wasi-env/bin/activate - python3 -m pip install -r test-runner/requirements.txt + $PYTHON_EXE -m venv wasi-env && source wasi-env/${VENV_BIN_DIR}/activate + $PYTHON_EXE -m pip install -r test-runner/requirements.txt export TEST_RUNTIME_EXE="${IWASM_CMD}" - python3 ${THIS_DIR}/pipe.py | python3 test-runner/wasi_test_runner.py \ - -r adapters/wasm-micro-runtime.py \ - -t \ - ${C_TESTS} \ - ${RUST_TESTS} \ - ${ASSEMBLYSCRIPT_TESTS} \ - ${THREAD_PROPOSAL_TESTS} \ - ${THREAD_INTERNAL_TESTS} \ - ${LIB_SOCKET_TESTS} \ + + TEST_OPTIONS="-r adapters/wasm-micro-runtime.py \ + -t \ + ${C_TESTS} \ + ${RUST_TESTS} \ + ${ASSEMBLYSCRIPT_TESTS} \ + ${THREAD_PROPOSAL_TESTS} \ + ${THREAD_INTERNAL_TESTS} \ + ${LIB_SOCKET_TESTS}" + + if [ -n "$TEST_FILTER" ]; then + TEST_OPTIONS="${TEST_OPTIONS} --exclude-filter ${TEST_FILTER}" + fi + + $PYTHON_EXE ${THIS_DIR}/pipe.py | TSAN_OPTIONS=${TSAN_OPTIONS} $PYTHON_EXE test-runner/wasi_test_runner.py $TEST_OPTIONS ret=${PIPESTATUS[1]} - TEST_RUNTIME_EXE="${IWASM_CMD_STRESS}" python3 test-runner/wasi_test_runner.py \ + TEST_RUNTIME_EXE="${IWASM_CMD_STRESS}" TSAN_OPTIONS=${TSAN_OPTIONS} $PYTHON_EXE test-runner/wasi_test_runner.py \ -r adapters/wasm-micro-runtime.py \ -t \ ${THREAD_STRESS_TESTS} @@ -101,7 +134,17 @@ else for testsuite in ${THREAD_STRESS_TESTS} ${THREAD_PROPOSAL_TESTS} ${THREAD_INTERNAL_TESTS}; do tests=$(ls ${testsuite}*.wasm) tests_array=($tests) - run_aot_tests "${tests_array[@]}" + + if [ -n "$TEST_FILTER" ]; then + readarray -t excluded_tests_array < <(jq -c \ + --slurpfile testsuite_manifest $testsuite/manifest.json \ + '.[$testsuite_manifest[0].name] // {} | keys[]' \ + $TEST_FILTER) + else + excluded_tests_array=() + fi + + run_aot_tests tests_array excluded_tests_array done fi diff --git a/wamr-compiler/CMakeLists.txt b/wamr-compiler/CMakeLists.txt index ba0902cdf..5fe8fae16 100644 --- a/wamr-compiler/CMakeLists.txt +++ b/wamr-compiler/CMakeLists.txt @@ -198,6 +198,12 @@ include_directories (${SHARED_DIR}/include enable_language (ASM) +if (NOT MINGW AND NOT MSVC) + set(WAMR_BUILD_LIBC_WASI 1) +else() + set(WAMR_BUILD_LIBC_UVWASI 1) +endif() + include (${SHARED_DIR}/platform/${WAMR_BUILD_PLATFORM}/shared_platform.cmake) include (${SHARED_DIR}/mem-alloc/mem_alloc.cmake) include (${SHARED_DIR}/utils/shared_utils.cmake)