diff --git a/.bazelrc b/.bazelrc index ab9a27f84..5a0373356 100644 --- a/.bazelrc +++ b/.bazelrc @@ -10,6 +10,7 @@ build --action_env=PATH build:clang --action_env=BAZEL_COMPILER=clang build:clang --action_env=CC=clang build:clang --action_env=CXX=clang++ +build:clang --copt -Wno-pragma-once-outside-header --cxxopt -Wno-pragma-once-outside-header # Common flags for Clang sanitizers. build:clang-xsan --config=clang @@ -54,6 +55,7 @@ build:clang-tsan --config=clang-xsan build:clang-tsan --copt -DTHREAD_SANITIZER=1 build:clang-tsan --copt -fsanitize=thread build:clang-tsan --linkopt -fsanitize=thread +build:clang-tsan --test_env=TSAN_OPTIONS=suppressions=bazel/tsan_suppressions.txt # Use Clang-Tidy tool. build:clang-tidy --config=clang @@ -66,24 +68,22 @@ build:gcc --action_env=BAZEL_COMPILER=gcc build:gcc --action_env=CC=gcc build:gcc --action_env=CXX=g++ -# Use Zig C/C++ compiler. -build:zig-cc --incompatible_enable_cc_toolchain_resolution -build:zig-cc --extra_toolchains @zig_sdk//:aarch64-linux-gnu.2.28_toolchain -build:zig-cc --extra_toolchains @zig_sdk//:x86_64-linux-gnu.2.28_toolchain -build:zig-cc --host_copt=-fno-sanitize=undefined +build:hermetic-llvm --incompatible_enable_cc_toolchain_resolution +build:hermetic-llvm --action_env BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1 +build:hermetic-llvm --extra_toolchains @emsdk//emscripten_toolchain:cc-toolchain-wasm -# Use Zig C/C++ compiler (cross-compile to Linux/aarch64). -build:zig-cc-linux-aarch64 --config=zig-cc -build:zig-cc-linux-aarch64 --platforms @zig_sdk//:linux_aarch64_platform -build:zig-cc-linux-aarch64 --run_under=qemu-aarch64-static -build:zig-cc-linux-aarch64 --test_env=QEMU_LD_PREFIX=/usr/aarch64-linux-gnu/ +build:hermetic-llvm-macos --config=hermetic-llvm +# Below flags mitigate https://github.com/bazel-contrib/toolchains_llvm/pull/229. +build:hermetic-llvm-macos --features=-libtool +build:hermetic-llvm-macos --features=-supports_dynamic_linker build --enable_platform_specific_config -# Use C++17. -build:linux --cxxopt=-std=c++17 -build:macos --cxxopt=-std=c++17 -build:windows --cxxopt="/std:c++17" +# Use C++20. +build:linux --cxxopt=-std=c++20 --host_cxxopt=-std=c++20 +build:macos --cxxopt=-std=c++20 --host_cxxopt=-std=c++20 +build:windows --cxxopt="/std:c++20" --host_cxxopt="/std:c++20" + # Enable symlinks and runfiles on Windows (enabled by default on other platforms). startup --windows_enable_symlinks diff --git a/.clang-tidy b/.clang-tidy index ceab9ad4a..df9f5c944 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,17 +1,28 @@ Checks: clang-*, + -clang-analyzer-core.CallAndMessage, -clang-analyzer-optin.portability.UnixAPI, -clang-analyzer-unix.Malloc, -clang-diagnostic-pragma-once-outside-header, + -clang-diagnostic-builtin-macro-redefined, cppcoreguidelines-pro-type-member-init, cppcoreguidelines-pro-type-static-cast-downcast, misc-*, -misc-non-private-member-variables-in-classes, + -misc-use-anonymous-namespace, + -misc-const-correctness, + -misc-include-cleaner, + -misc-unused-parameters, modernize-*, -modernize-avoid-c-arrays, -modernize-use-trailing-return-type, + -modernize-return-braced-init-list, + -modernize-use-default-member-init, + -modernize-type-traits, + -modernize-use-emplace, llvm-include-order, performance-*, -performance-no-int-to-ptr, + -performance-avoid-endl, portability-*, readability-*, -readability-convert-member-functions-to-static, @@ -19,5 +30,9 @@ Checks: clang-*, -readability-magic-numbers, -readability-make-member-function-const, -readability-simplify-boolean-expr, + -readability-identifier-length, + -readability-container-data-pointer, + -readability-redundant-casting, + -readability-avoid-return-with-void-value, WarningsAsErrors: '*' diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index de71b24cc..8f61d3582 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -31,6 +31,8 @@ on: schedule: - cron: '0 0 * * *' + workflow_dispatch: + concurrency: group: ${{ github.head_ref || github.run_id }}-${{ github.workflow }} @@ -41,7 +43,7 @@ jobs: addlicense: name: verify licenses - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04-16core steps: - uses: actions/checkout@v2 @@ -61,7 +63,7 @@ jobs: buildifier: name: check format with buildifier - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04-16core steps: - uses: actions/checkout@v2 @@ -99,73 +101,64 @@ jobs: clang_format: name: check format with clang-format - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04-16core steps: - uses: actions/checkout@v2 - name: Install dependencies (Linux) - run: sudo apt update -y && sudo apt install -y clang-format-12 + run: sudo apt update -y && sudo apt install -y clang-format-18 - name: Format (clang-format) run: | - find . -name "*.h" -o -name "*.cc" -o -name "*.proto" | grep -v ".pb." | xargs -n1 clang-format-12 -i + find . -name "*.h" -o -name "*.cc" -o -name "*.proto" | grep -v ".pb." | xargs -n1 clang-format-18 -i git diff --exit-code clang_tidy: name: check format with clang-tidy - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04-16core steps: - uses: actions/checkout@v2 - name: Install dependencies (Linux) - run: sudo apt update -y && sudo apt install -y clang-tidy-12 lld-12 && sudo ln -sf /usr/bin/lld-12 /usr/bin/lld - - - name: Bazel cache - uses: PiotrSikora/cache@v2.1.7-with-skip-cache + run: sudo apt update -y && sudo apt install -y clang-tidy-18 lld-18 && sudo ln -sf /usr/bin/lld-18 /usr/bin/lld + + - name: set cache name + id: vars + # The cache tag consists of the following parts: + # * clang-tidy- prefix + # * matrix.name, which separates the cache for each build type. + # * hash of WORKSPACE, .bazelrc, and .bazelversion, which is + # purely to differentiate caches for substantial changes in bazel. + # * github.sha, which is the commit hash of the commit used to generate + # the cache entry. + run: echo "CACHE_TAG=clang-tidy-${{ matrix.name }}-${{ hashFiles('WORKSPACE', '.bazelrc', '.bazelversion') }}" >> "$GITHUB_OUTPUT" + + - name: bazel cache + uses: actions/cache/restore@v3 with: - path: | - ~/.cache/bazel - key: clang_tidy-${{ hashFiles('WORKSPACE', '.bazelrc', '.bazelversion', 'bazel/dependencies.bzl', 'bazel/repositories.bzl', 'bazel/cargo/wasmsign/remote/crates.bzl') }} + path: /tmp/bazel/cache + key: ${{ steps.vars.outputs.CACHE_TAG }}-${{ github.sha }} + restore-keys: | + ${{ steps.vars.outputs.CACHE_TAG }}-${{ github.sha }} + ${{ steps.vars.outputs.CACHE_TAG }}- + clang-tidy-${{ matrix.name }}- + clang-tidy- - name: Bazel build run: > bazel build --config clang-tidy --define engine=multi + --disk_cache /tmp/bazel/cache --copt=-DPROXY_WASM_VERIFY_WITH_ED25519_PUBKEY=\"$(xxd -p -c 256 test/test_data/signature_key1.pub | cut -b9-)\" //... - - name: Skip Bazel cache update - if: ${{ github.ref != 'refs/heads/main' }} - run: echo "CACHE_SKIP_SAVE=true" >> $GITHUB_ENV - - - name: Cleanup Bazel cache - if: ${{ github.ref == 'refs/heads/main' }} - run: | - export OUTPUT=$(${{ matrix.run_under }} bazel info output_base) - echo "===== BEFORE =====" - du -s ${OUTPUT}/external/* $(dirname ${OUTPUT})/* | sort -rn | head -20 - # BoringSSL's test data (90 MiB). - rm -rf ${OUTPUT}/external/boringssl/crypto_test_data.cc - rm -rf ${OUTPUT}/external/boringssl/src/crypto/*/test/ - rm -rf ${OUTPUT}/external/boringssl/src/third_party/wycheproof_testvectors/ - # LLVM's tests (500 MiB). - rm -rf ${OUTPUT}/external/llvm*/test/ - # V8's tests (100 MiB). - if [ -d "${OUTPUT}/external/v8/test/torque" ]; then - mv ${OUTPUT}/external/v8/test/torque ${OUTPUT}/external/v8/test_torque - rm -rf ${OUTPUT}/external/v8/test/* - mv ${OUTPUT}/external/v8/test_torque ${OUTPUT}/external/v8/test/torque - fi - # Unnecessary CMake tools (65 MiB). - rm -rf ${OUTPUT}/external/cmake-*/bin/{ccmake,cmake-gui,cpack,ctest} - # Distfiles for Rust toolchains (350 MiB). - rm -rf ${OUTPUT}/external/rust_*/*.tar.gz - # Bazel's repository cache (650-800 MiB) and install base (155 MiB). - rm -rf ${OUTPUT}/../cache - rm -rf ${OUTPUT}/../install - echo "===== AFTER =====" - du -s ${OUTPUT}/external/* $(dirname ${OUTPUT})/* | sort -rn | head -20 + - name: save bazel cache + uses: actions/cache/save@v3 + if: always() + with: + path: /tmp/bazel/cache + key: ${{ steps.vars.outputs.CACHE_TAG }}-${{ github.sha }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 811c6a369..cc6ddbc5f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -31,6 +31,8 @@ on: schedule: - cron: '0 0 * * *' + workflow_dispatch: + concurrency: group: ${{ github.head_ref || github.run_id }}-${{ github.workflow }} @@ -41,17 +43,31 @@ jobs: test_data: name: build test data - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04-16core steps: - uses: actions/checkout@v2 - - name: Bazel cache - uses: PiotrSikora/cache@v2.1.7-with-skip-cache + - name: set cache name + id: vars + # The cache tag consists of the following parts: + # * test-deps-bazel-cache- prefix + # * hash of WORKSPACE, .bazelrc, and .bazelversion, which is + # purely to differentiate caches for substantial changes in bazel. + # * github.sha, which is the commit hash of the commit used to generate + # the cache entry. + run: echo "CACHE_TAG=test-deps-bazel-cache-${{ hashFiles('WORKSPACE', '.bazelrc', '.bazelversion') }}" >> "$GITHUB_OUTPUT" + + - name: bazel cache + uses: actions/cache/restore@v3 with: - path: | - ~/.cache/bazel - key: test_data-${{ hashFiles('WORKSPACE', '.bazelrc', '.bazelversion', 'bazel/dependencies.bzl', 'bazel/repositories.bzl', 'bazel/cargo/wasmsign/crates.bzl') }} + path: /tmp/bazel/cache + key: ${{ steps.vars.outputs.CACHE_TAG }}-${{ github.sha }} + restore-keys: | + ${{ steps.vars.outputs.CACHE_TAG }}-${{ github.sha }} + ${{ steps.vars.outputs.CACHE_TAG }}- + test-deps-bazel-cache-${{ matrix.name }}- + test-deps-bazel-cache- - name: Bazel build run: > @@ -59,6 +75,7 @@ jobs: --verbose_failures --test_output=errors --config=clang + --disk_cache /tmp/bazel/cache -c opt $(bazel query 'kind(was.*_rust_binary, //test/test_data/...)') $(bazel query 'kind(_optimized_wasm_cc_binary, //test/test_data/...)') @@ -82,19 +99,21 @@ jobs: if-no-files-found: error retention-days: 3 - - name: Skip Bazel cache update - if: ${{ github.ref != 'refs/heads/main' }} - run: echo "CACHE_SKIP_SAVE=true" >> $GITHUB_ENV - - - name: Cleanup Bazel cache - if: ${{ github.ref == 'refs/heads/main' }} - run: | - export OUTPUT=$(bazel info output_base) - # Distfiles for Rust toolchains (350 MiB). - rm -rf ${OUTPUT}/external/rust_*/*.tar.gz - # Bazel's repository cache (650-800 MiB) and install base (155 MiB). - rm -rf $(bazel info repository_cache) - rm -rf $(bazel info install_base) + - name: remove unaccessed files from cache + shell: bash + run: > + find /tmp/bazel/cache + -type f + -name '*' + -amin +360 + -exec rm {} \; + + - name: save bazel cache + uses: actions/cache/save@v3 + if: always() + with: + path: /tmp/bazel/cache + key: ${{ steps.vars.outputs.CACHE_TAG }}-${{ github.sha }} build: name: ${{ matrix.action }} with ${{ matrix.name }} @@ -109,56 +128,56 @@ jobs: include: - name: 'NullVM on Linux/x86_64' engine: 'null' - os: ubuntu-22.04 + os: ubuntu-24.04-16core arch: x86_64 action: test flags: --config=gcc - name: 'NullVM on Linux/x86_64 with ASan' engine: 'null' - os: ubuntu-22.04 + os: ubuntu-24.04-16core arch: x86_64 action: test - flags: --config=clang-asan-strict --define=crypto=system + flags: --config=clang-asan --define=crypto=system - name: 'NullVM on Linux/x86_64 with TSan' engine: 'null' - os: ubuntu-22.04 + os: ubuntu-24.04-16core arch: x86_64 action: test flags: --config=clang-tsan - name: 'NullVM on Windows/x86_64' engine: 'null' - os: windows-2019 + os: windows-2022 arch: x86_64 action: test targets: -//test/fuzz/... - name: 'V8 on Linux/x86_64' engine: 'v8' repo: 'v8' - os: ubuntu-22.04 + os: ubuntu-24.04-16core arch: x86_64 action: test - flags: --config=clang --define=crypto=system + flags: --config=hermetic-llvm --define=crypto=system cache: true - name: 'V8 on Linux/x86_64 with ASan' engine: 'v8' repo: 'v8' - os: ubuntu-22.04 + os: ubuntu-24.04-16core arch: x86_64 action: test - flags: --config=clang-asan + flags: --config=hermetic-llvm --config=clang-asan cache: true - name: 'V8 on Linux/x86_64 with TSan' engine: 'v8' repo: 'v8' - os: ubuntu-22.04 + os: ubuntu-24.04-16core arch: x86_64 action: test - flags: --config=clang-tsan + flags: --config=hermetic-llvm --config=clang-tsan cache: true - name: 'V8 on Linux/x86_64 with GCC' engine: 'v8' repo: 'v8' - os: ubuntu-22.04 + os: ubuntu-24.04-16core arch: x86_64 action: test flags: --config=gcc @@ -166,12 +185,11 @@ jobs: - name: 'V8 on Linux/aarch64' engine: 'v8' repo: 'v8' - os: ubuntu-22.04 + os: ubuntu-24.04-arm arch: aarch64 action: test targets: -//test/fuzz/... - flags: --config=zig-cc-linux-aarch64 --@v8//bazel/config:v8_target_cpu=arm64 - deps: qemu-user-static libc6-arm64-cross + flags: --config=hermetic-llvm --@v8//bazel/config:v8_target_cpu=arm64 cache: true - name: 'V8 on macOS/x86_64' engine: 'v8' @@ -179,11 +197,12 @@ jobs: os: macos-13 arch: x86_64 action: test + flags: --config=hermetic-llvm-macos cache: true - name: 'WAMR interp on Linux/x86_64' engine: 'wamr-interp' repo: 'com_github_bytecodealliance_wasm_micro_runtime' - os: ubuntu-22.04 + os: ubuntu-24.04-16core arch: x86_64 action: test flags: --config=clang @@ -196,11 +215,11 @@ jobs: - name: 'WAMR jit on Linux/x86_64' engine: 'wamr-jit' repo: 'com_github_bytecodealliance_wasm_micro_runtime' - os: ubuntu-22.04 + os: ubuntu-24.04-16core arch: x86_64 action: test flags: --config=clang - deps: lld-12 + deps: lld-18 cache: true - name: 'WAMR jit on macOS/x86_64' engine: 'wamr-jit' @@ -212,7 +231,7 @@ jobs: - name: 'WasmEdge on Linux/x86_64' engine: 'wasmedge' repo: 'com_github_wasmedge_wasmedge' - os: ubuntu-22.04 + os: ubuntu-24.04-16core arch: x86_64 action: test flags: --config=clang @@ -225,29 +244,28 @@ jobs: - name: 'Wasmtime on Linux/x86_64' engine: 'wasmtime' repo: 'com_github_bytecodealliance_wasmtime' - os: ubuntu-22.04 + os: ubuntu-24.04-16core arch: x86_64 action: test flags: --config=clang -c opt - name: 'Wasmtime on Linux/x86_64 with ASan' engine: 'wasmtime' repo: 'com_github_bytecodealliance_wasmtime' - os: ubuntu-22.04 + os: ubuntu-24.04-16core arch: x86_64 action: test - flags: --config=clang-asan-strict --define=crypto=system + flags: --config=clang-asan --define=crypto=system - name: 'Wasmtime on Linux/aarch64' engine: 'wasmtime' repo: 'com_github_bytecodealliance_wasmtime' - os: ubuntu-22.04 + os: ubuntu-24.04-arm arch: aarch64 action: build - flags: --config=zig-cc-linux-aarch64 - deps: qemu-user-static libc6-arm64-cross + flags: --config=hermetic-llvm - name: 'Wasmtime on Linux/s390x' engine: 'wasmtime' repo: 'com_github_bytecodealliance_wasmtime' - os: ubuntu-22.04 + os: ubuntu-24.04-16core arch: s390x action: test flags: --config=clang --test_timeout=1800 @@ -260,14 +278,6 @@ jobs: os: macos-13 arch: x86_64 action: test - - name: 'WAVM on Linux/x86_64' - engine: 'wavm' - repo: 'com_github_wavm_wavm' - os: ubuntu-22.04 - arch: x86_64 - action: test - flags: --config=clang - cache: true steps: - uses: actions/checkout@v2 @@ -289,21 +299,27 @@ jobs: if: startsWith(matrix.run_under, 'docker') run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes - - name: Set cache key - if: ${{ matrix.cache }} - run: echo "::set-output name=uniq::$(bazel query --output build //external:${{ matrix.repo }} | grep -E 'sha256|commit' | cut -d\" -f2)-$(echo ${{ matrix.flags }} | sha256sum)" - id: cache-key - - - name: Bazel cache - if: ${{ matrix.cache }} - uses: PiotrSikora/cache@v2.1.7-with-skip-cache + - name: set cache name + id: vars + # The cache tag consists of the following parts: + # * bazel-cache- prefix + # * matrix.name, which separates the cache for each build type. + # * hash of WORKSPACE, .bazelrc, and .bazelversion, which is + # purely to differentiate caches for substantial changes in bazel. + # * github.sha, which is the commit hash of the commit used to generate + # the cache entry. + run: echo "CACHE_TAG=bazel-cache-${{ matrix.name }}-${{ hashFiles('WORKSPACE', '.bazelrc', '.bazelversion') }}" >> "$GITHUB_OUTPUT" + + - name: bazel cache + uses: actions/cache/restore@v3 with: - path: | - ~/.cache/bazel - /private/var/tmp/_bazel_runner/ - key: ${{ matrix.arch }}-${{ matrix.os }}-${{ matrix.engine }}-${{ steps.cache-key.outputs.uniq }}-${{ hashFiles('WORKSPACE', '.bazelrc', '.bazelversion', 'bazel/dependencies.bzl', 'bazel/repositories.bzl') }} + path: /tmp/bazel/cache + key: ${{ steps.vars.outputs.CACHE_TAG }}-${{ github.sha }} restore-keys: | - ${{ matrix.arch }}-${{ matrix.os }}-${{ matrix.engine }}-${{ steps.cache-key.outputs.uniq }}- + ${{ steps.vars.outputs.CACHE_TAG }}-${{ github.sha }} + ${{ steps.vars.outputs.CACHE_TAG }}- + bazel-cache-${{ matrix.name }}- + bazel-cache- - name: Download test data uses: actions/download-artifact@v4 @@ -328,6 +344,7 @@ jobs: --verbose_failures --test_output=errors --define engine=${{ matrix.engine }} + --disk_cache /tmp/bazel/cache ${{ matrix.flags }} -- //test/... ${{ matrix.targets }} @@ -339,38 +356,24 @@ jobs: --verbose_failures --test_output=errors --define engine=${{ matrix.engine }} + --disk_cache /tmp/bazel/cache ${{ matrix.flags }} --per_file_copt=src/signature_util.cc,test/signature_util_test.cc@-DPROXY_WASM_VERIFY_WITH_ED25519_PUBKEY=\"$(xxd -p -c 256 test/test_data/signature_key1.pub | cut -b9-)\" //test:signature_util_test - - name: Skip Bazel cache update - if: ${{ matrix.cache && github.ref != 'refs/heads/main' }} - run: echo "CACHE_SKIP_SAVE=true" >> $GITHUB_ENV + - name: remove unaccessed files from cache + shell: bash + run: > + find /tmp/bazel/cache + -type f + -name '*' + -amin +360 + -exec rm {} \; + + - name: save bazel cache + uses: actions/cache/save@v3 + if: always() + with: + path: /tmp/bazel/cache + key: ${{ steps.vars.outputs.CACHE_TAG }}-${{ github.sha }} - - name: Cleanup Bazel cache - if: ${{ matrix.cache && github.ref == 'refs/heads/main' }} - run: | - export OUTPUT=$(${{ matrix.run_under }} bazel info output_base) - echo "===== BEFORE =====" - du -s ${OUTPUT}/external/* $(dirname ${OUTPUT})/* | sort -rn | head -20 - # BoringSSL's test data (90 MiB). - rm -rf ${OUTPUT}/external/boringssl/crypto_test_data.cc - rm -rf ${OUTPUT}/external/boringssl/src/crypto/*/test/ - rm -rf ${OUTPUT}/external/boringssl/src/third_party/wycheproof_testvectors/ - # LLVM's tests (500 MiB). - rm -rf ${OUTPUT}/external/llvm*/test/ - # V8's tests (100 MiB). - if [ -d "${OUTPUT}/external/v8/test/torque" ]; then - mv ${OUTPUT}/external/v8/test/torque ${OUTPUT}/external/v8/test_torque - rm -rf ${OUTPUT}/external/v8/test/* - mv ${OUTPUT}/external/v8/test_torque ${OUTPUT}/external/v8/test/torque - fi - # Unnecessary CMake tools (65 MiB). - rm -rf ${OUTPUT}/external/cmake-*/bin/{ccmake,cmake-gui,cpack,ctest} - # Distfiles for Rust toolchains (350 MiB). - rm -rf ${OUTPUT}/external/rust_*/*.tar.gz - # Bazel's repository cache (650-800 MiB) and install base (155 MiB). - rm -rf ${OUTPUT}/../cache - rm -rf ${OUTPUT}/../install - echo "===== AFTER =====" - du -s ${OUTPUT}/external/* $(dirname ${OUTPUT})/* | sort -rn | head -20 diff --git a/BUILD b/BUILD index 215459eb2..6db5fd903 100644 --- a/BUILD +++ b/BUILD @@ -19,7 +19,6 @@ load( "proxy_wasm_select_engine_wamr", "proxy_wasm_select_engine_wasmedge", "proxy_wasm_select_engine_wasmtime", - "proxy_wasm_select_engine_wavm", ) load("@rules_cc//cc:defs.bzl", "cc_library") @@ -281,34 +280,6 @@ cc_library( ], ) -cc_library( - name = "wavm_lib", - srcs = [ - "src/wavm/wavm.cc", - ], - hdrs = ["include/proxy-wasm/wavm.h"], - copts = [ - "-DWAVM_API=", - "-Wno-non-virtual-dtor", - "-Wno-old-style-cast", - ], - defines = [ - "PROXY_WASM_HAS_RUNTIME_WAVM", - "PROXY_WASM_HOST_ENGINE_WAVM", - ], - linkopts = select({ - "@platforms//os:macos": [], - "@platforms//os:windows": [], - "//conditions:default": [ - "-ldl", - ], - }), - deps = [ - ":wasm_vm_headers", - "//external:wavm", - ], -) - cc_library( name = "lib", deps = [ @@ -324,7 +295,5 @@ cc_library( ) + proxy_wasm_select_engine_wasmtime( [":wasmtime_lib"], [":prefixed_wasmtime_lib"], - ) + proxy_wasm_select_engine_wavm( - [":wavm_lib"], ), ) diff --git a/CODEOWNERS b/CODEOWNERS index e0a504f38..e4190bb47 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1 +1 @@ -* @PiotrSikora @martijneken @mpwarres +* @PiotrSikora @martijneken @mpwarres @leonm1 diff --git a/bazel/BUILD b/bazel/BUILD index 650fa29d8..15f323fa7 100644 --- a/bazel/BUILD +++ b/bazel/BUILD @@ -46,11 +46,6 @@ config_setting( values = {"define": "engine=wasmtime"}, ) -config_setting( - name = "engine_wavm", - values = {"define": "engine=wavm"}, -) - config_setting( name = "multiengine", values = {"define": "engine=multi"}, @@ -73,3 +68,5 @@ selects.config_setting_group( ":linux_s390x", ], ) + +exports_files(["tsan_suppressions.txt"]) diff --git a/bazel/cargo/wasmsign/Cargo.toml b/bazel/cargo/wasmsign/Cargo.toml index 815f8b03a..5267cb2d1 100644 --- a/bazel/cargo/wasmsign/Cargo.toml +++ b/bazel/cargo/wasmsign/Cargo.toml @@ -1,3 +1,17 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + [package] edition = "2018" name = "wasmsign-bazel" diff --git a/bazel/cargo/wasmtime/Cargo.toml b/bazel/cargo/wasmtime/Cargo.toml index 8abf88812..b038be7fd 100644 --- a/bazel/cargo/wasmtime/Cargo.toml +++ b/bazel/cargo/wasmtime/Cargo.toml @@ -1,3 +1,17 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + [package] edition = "2021" name = "wasmtime-c-api-bazel" diff --git a/bazel/cc_defs.bzl b/bazel/cc_defs.bzl new file mode 100644 index 000000000..5951de438 --- /dev/null +++ b/bazel/cc_defs.bzl @@ -0,0 +1,22 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("@rules_cc//cc:defs.bzl", _cc_test = "cc_test") +load("@rules_fuzzing//fuzzing:cc_defs.bzl", _cc_fuzz_test = "cc_fuzz_test") + +def cc_test(data = [], **kwargs): + _cc_test(data = data + ["//bazel:tsan_suppressions.txt"], **kwargs) + +def cc_fuzz_test(data = [], **kwargs): + _cc_fuzz_test(data = data + ["//bazel:tsan_suppressions.txt"], **kwargs) diff --git a/bazel/dependencies.bzl b/bazel/dependencies.bzl index 7b5c5fcbd..683fb9964 100644 --- a/bazel/dependencies.bzl +++ b/bazel/dependencies.bzl @@ -12,13 +12,15 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@bazel-zig-cc//toolchain:defs.bzl", zig_register_toolchains = "register_toolchains") load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") +load("@envoy_toolshed//sysroot:sysroot.bzl", "setup_sysroots") load("@proxy_wasm_cpp_host//bazel/cargo/wasmsign/remote:crates.bzl", wasmsign_crate_repositories = "crate_repositories") load("@proxy_wasm_cpp_host//bazel/cargo/wasmtime/remote:crates.bzl", wasmtime_crate_repositories = "crate_repositories") load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_toolchains") load("@rules_rust//crate_universe:repositories.bzl", "crate_universe_dependencies") load("@rules_rust//rust:repositories.bzl", "rust_repositories", "rust_repository_set") +load("@toolchains_llvm//toolchain:deps.bzl", "bazel_toolchain_dependencies") +load("@toolchains_llvm//toolchain:rules.bzl", "llvm_toolchain") def proxy_wasm_cpp_host_dependencies(): # Bazel extensions. @@ -52,14 +54,39 @@ def proxy_wasm_cpp_host_dependencies(): ) crate_universe_dependencies(bootstrap = True) - zig_register_toolchains( - version = "0.9.1", - url_format = "https://ziglang.org/download/%7Bversion%7D/zig-%7Bhost_platform%7D-%7Bversion%7D.tar.xz", - host_platform_sha256 = { - "linux-aarch64": "5d99a39cded1870a3fa95d4de4ce68ac2610cca440336cfd252ffdddc2b90e66", - "linux-x86_64": "be8da632c1d3273f766b69244d80669fe4f5e27798654681d77c992f17c237d7", - "macos-aarch64": "8c473082b4f0f819f1da05de2dbd0c1e891dff7d85d2c12b6ee876887d438287", - "macos-x86_64": "2d94984972d67292b55c1eb1c00de46580e9916575d083003546e9a01166754c", + setup_sysroots() + bazel_toolchain_dependencies() + llvm_toolchain( + name = "llvm_toolchain", + llvm_version = "19.1.0", + sha256 = { + "linux-x86_64": "cee77d641690466a193d9b88c89705de1c02bbad46bde6a3b126793c0a0f2923", + "linux-aarch64": "7bb54afd330fe1a1c2d4c593fa1e2dbe2abd9bf34fb3597994ff41e443cf144b", + "darwin-aarch64": "9da86f64a99f5ce9b679caf54e938736ca269c5e069d0c94ad08b995c5f25c16", + "darwin-x86_64": "264f2f1e8b67f066749349ae8b4943d346cd44e099464164ef21b42a57663540", + }, + strip_prefix = { + "linux-x86_64": "LLVM-19.1.0-Linux-X64", + "linux-aarch64": "clang+llvm-19.1.0-aarch64-linux-gnu", + "darwin-aarch64": "LLVM-19.1.0-macOS-ARM64", + "darwin-x86_64": "LLVM-19.1.0-macOS-X64", + }, + urls = { + "linux-x86_64": ["https://github.com/llvm/llvm-project/releases/download/llvmorg-19.1.0/LLVM-19.1.0-Linux-X64.tar.xz"], + "linux-aarch64": ["https://github.com/llvm/llvm-project/releases/download/llvmorg-19.1.0/clang+llvm-19.1.0-aarch64-linux-gnu.tar.xz"], + "darwin-aarch64": ["https://github.com/llvm/llvm-project/releases/download/llvmorg-19.1.0/LLVM-19.1.0-macOS-ARM64.tar.xz"], + "darwin-x86_64": ["https://github.com/llvm/llvm-project/releases/download/llvmorg-19.1.0/LLVM-19.1.0-macOS-X64.tar.xz"], + }, + ) + + llvm_toolchain( + name = "llvm_aarch64", + llvm_version = "19.1.0", + toolchain_roots = { + "": "@llvm_toolchain_llvm//", + }, + sysroot = { + "linux-aarch64": "@sysroot_linux_arm64//:sysroot", }, ) diff --git a/bazel/dependencies_import.bzl b/bazel/dependencies_import.bzl index 1f23f7d0b..e4cf5e879 100644 --- a/bazel/dependencies_import.bzl +++ b/bazel/dependencies_import.bzl @@ -13,11 +13,14 @@ # limitations under the License. load("@fuzzing_py_deps//:requirements.bzl", pip_fuzzing_dependencies = "install_deps") +load("@llvm_toolchain//:toolchains.bzl", "llvm_register_toolchains") load("@rules_foreign_cc//foreign_cc:repositories.bzl", "rules_foreign_cc_dependencies") load("@rules_fuzzing//fuzzing:repositories.bzl", "rules_fuzzing_dependencies") load("@v8_python_deps//:requirements.bzl", pip_v8_dependencies = "install_deps") def proxy_wasm_cpp_host_dependencies_import(): + llvm_register_toolchains() + rules_foreign_cc_dependencies() rules_fuzzing_dependencies() diff --git a/bazel/external/Dockerfile.bazel b/bazel/external/Dockerfile.bazel index 2c4bfbbfa..9b16abeb3 100644 --- a/bazel/external/Dockerfile.bazel +++ b/bazel/external/Dockerfile.bazel @@ -1,4 +1,18 @@ # syntax=docker/dockerfile:1 +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + # Prep: # docker run --rm --privileged tonistiigi/binfmt --install all diff --git a/bazel/external/bazel_clang_tidy.patch b/bazel/external/bazel_clang_tidy.patch index 9c84b3c7f..82711d83e 100644 --- a/bazel/external/bazel_clang_tidy.patch +++ b/bazel/external/bazel_clang_tidy.patch @@ -1,5 +1,4 @@ # 1. Treat .h files as C++ headers. -# 2. Hardcode clang-tidy-12. diff --git a/clang_tidy/clang_tidy.bzl b/clang_tidy/clang_tidy.bzl index 3a5ed07..5db5c6c 100644 @@ -15,13 +14,3 @@ index 3a5ed07..5db5c6c 100644 # start args passed to the compiler args.add("--") -diff --git a/clang_tidy/run_clang_tidy.sh b/clang_tidy/run_clang_tidy.sh -index 582bab1..b9ebb94 100755 ---- a/clang_tidy/run_clang_tidy.sh -+++ b/clang_tidy/run_clang_tidy.sh -@@ -11,4 +11,4 @@ shift - touch $OUTPUT - truncate -s 0 $OUTPUT - --clang-tidy "$@" -+clang-tidy-12 "$@" diff --git a/bazel/external/dragonbox.BUILD b/bazel/external/dragonbox.BUILD new file mode 100644 index 000000000..00f3ee074 --- /dev/null +++ b/bazel/external/dragonbox.BUILD @@ -0,0 +1,26 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("@rules_cc//cc:defs.bzl", "cc_library") + +licenses(["notice"]) # Apache 2 + +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "dragonbox", + srcs = [], + hdrs = ["include/dragonbox/dragonbox.h"], + includes = ["include/"], +) diff --git a/bazel/external/fp16.BUILD b/bazel/external/fp16.BUILD new file mode 100644 index 000000000..f82146cff --- /dev/null +++ b/bazel/external/fp16.BUILD @@ -0,0 +1,29 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("@rules_cc//cc:defs.bzl", "cc_library") + +licenses(["notice"]) # MIT + +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "FP16", + hdrs = [ + "include/fp16.h", + "include/fp16/bitcasts.h", + "include/fp16/fp16.h", + ], + includes = ["include/"], +) diff --git a/bazel/external/intel_ittapi.BUILD b/bazel/external/intel_ittapi.BUILD new file mode 100644 index 000000000..cc867842f --- /dev/null +++ b/bazel/external/intel_ittapi.BUILD @@ -0,0 +1,35 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("@rules_cc//cc:defs.bzl", "cc_library") + +licenses(["notice"]) + +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "lib_ittapi", + srcs = [ + "include/ittnotify.h", + "include/jitprofiling.h", + "src/ittnotify/ittnotify_config.h", + "src/ittnotify/jitprofiling.c", + ], + hdrs = [ + "include/ittnotify.h", + "src/ittnotify/ittnotify_types.h", + ], + includes = ["include/"], + visibility = ["//visibility:public"], +) diff --git a/bazel/external/llvm.BUILD b/bazel/external/llvm.BUILD index 38909ee9a..9dccf5c98 100644 --- a/bazel/external/llvm.BUILD +++ b/bazel/external/llvm.BUILD @@ -1,3 +1,17 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + load("@rules_foreign_cc//foreign_cc:defs.bzl", "cmake") licenses(["notice"]) # Apache 2 diff --git a/bazel/external/simdutf.BUILD b/bazel/external/simdutf.BUILD new file mode 100644 index 000000000..834467e35 --- /dev/null +++ b/bazel/external/simdutf.BUILD @@ -0,0 +1,25 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("@rules_cc//cc:defs.bzl", "cc_library") + +licenses(["notice"]) # Apache 2 + +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "simdutf", + srcs = ["simdutf.cpp"], + hdrs = ["simdutf.h"], +) diff --git a/bazel/external/v8.patch b/bazel/external/v8.patch index 58e7f9ba0..a124cf9a5 100644 --- a/bazel/external/v8.patch +++ b/bazel/external/v8.patch @@ -1,13 +1,20 @@ -# 1. Disable pointer compression (limits the maximum number of WasmVMs). -# 2. Don't expose Wasm C API (only Wasm C++ API). -# 3. Fix gcc build error by disabling nonnull warning. -# 4. Allow compiling v8 on macOS 10.15 to 13.0. TODO(dio): Will remove this patch when https://bugs.chromium.org/p/v8/issues/detail?id=13428 is fixed. +From bc2a85e39fd55879b9baed51429c08b27d5514c8 Mon Sep 17 00:00:00 2001 +From: Matt Leon +Date: Wed, 16 Jul 2025 16:55:02 -0400 +Subject: [PATCH 1/7] Disable pointer compression + +Pointer compression limits the maximum number of WasmVMs. + +Signed-off-by: Matt Leon +--- + BUILD.bazel | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILD.bazel b/BUILD.bazel -index 4e89f90e7e..3fcb38b3f3 100644 +index 3f5a87d054e..0a693b7ee10 100644 --- a/BUILD.bazel +++ b/BUILD.bazel -@@ -157,7 +157,7 @@ v8_int( +@@ -292,7 +292,7 @@ v8_int( # If no explicit value for v8_enable_pointer_compression, we set it to 'none'. v8_string( name = "v8_enable_pointer_compression", @@ -16,42 +23,80 @@ index 4e89f90e7e..3fcb38b3f3 100644 ) # Default setting for v8_enable_pointer_compression. +-- +2.50.0.727.gbf7dc18ff4-goog + + +From 61898e9a63ac89a37261c081b84714cfc400a4b1 Mon Sep 17 00:00:00 2001 +From: Matt Leon +Date: Wed, 16 Jul 2025 16:56:31 -0400 +Subject: [PATCH 2/7] Restore _allowlist_function_transition + +Reverts v8 commit b26554ec368e9553782012c96aa5e99b163eaff2, which removed use of +_allowlist_function_transition from v8 bazel/defs.bzl, since it is still required +by the version of Bazel we currently use (6.5.0). + +Signed-off-by: Matt Leon +--- + bazel/defs.bzl | 3 +++ + bazel/v8-non-pointer-compression.bzl | 11 +++++++++++ + 2 files changed, 14 insertions(+) + diff --git a/bazel/defs.bzl b/bazel/defs.bzl -index e957c0fad3..063627b72b 100644 +index 0539ea176ac..14d7ace5e59 100644 --- a/bazel/defs.bzl +++ b/bazel/defs.bzl -@@ -131,6 +131,7 @@ def _default_args(): - "-Wno-redundant-move", - "-Wno-return-type", - "-Wno-stringop-overflow", -+ "-Wno-nonnull", - # Use GNU dialect, because GCC doesn't allow using - # ##__VA_ARGS__ when in standards-conforming mode. - "-std=gnu++17", -@@ -151,6 +152,18 @@ def _default_args(): - "-fno-integrated-as", - ], - "//conditions:default": [], -+ }) + select({ -+ "@v8//bazel/config:is_macos": [ -+ # The clang available on macOS catalina has a warning that isn't clean on v8 code. -+ "-Wno-range-loop-analysis", -+ -+ # To supress warning on deprecated declaration on v8 code. For example: -+ # external/v8/src/base/platform/platform-darwin.cc:56:22: 'getsectdatafromheader_64' -+ # is deprecated: first deprecated in macOS 13.0. -+ # https://bugs.chromium.org/p/v8/issues/detail?id=13428. -+ "-Wno-deprecated-declarations", -+ ], -+ "//conditions:default": [], - }), - includes = ["include"], - linkopts = select({ +@@ -485,6 +485,9 @@ _v8_mksnapshot = rule( + cfg = "exec", + ), + "target_os": attr.string(mandatory = True), ++ "_allowlist_function_transition": attr.label( ++ default = "@bazel_tools//tools/allowlists/function_transition_allowlist", ++ ), + "prefix": attr.string(mandatory = True), + "suffix": attr.string(mandatory = True), + }, +diff --git a/bazel/v8-non-pointer-compression.bzl b/bazel/v8-non-pointer-compression.bzl +index 8c929454840..57336154cf7 100644 +--- a/bazel/v8-non-pointer-compression.bzl ++++ b/bazel/v8-non-pointer-compression.bzl +@@ -47,6 +47,17 @@ v8_binary_non_pointer_compression = rule( + # Note specificaly how it's configured with v8_target_cpu_transition, which + # ensures that setting propagates down the graph. + "binary": attr.label(cfg = v8_disable_pointer_compression), ++ # This is a stock Bazel requirement for any rule that uses Starlark ++ # transitions. It's okay to copy the below verbatim for all such rules. ++ # ++ # The purpose of this requirement is to give the ability to restrict ++ # which packages can invoke these rules, since Starlark transitions ++ # make much larger graphs possible that can have memory and performance ++ # consequences for your build. The whitelist defaults to "everything". ++ # But you can redefine it more strictly if you feel that's prudent. ++ "_allowlist_function_transition": attr.label( ++ default = "@bazel_tools//tools/allowlists/function_transition_allowlist", ++ ), + }, + # Making this executable means it works with "$ bazel run". + executable = True, +-- +2.50.0.727.gbf7dc18ff4-goog + + +From 4a6e7158fd4ca48c75c8e33ea15760c9beea1d2f Mon Sep 17 00:00:00 2001 +From: Matt Leon +Date: Wed, 16 Jul 2025 16:56:52 -0400 +Subject: [PATCH 3/7] Don't expose Wasm C API (only Wasm C++ API). + +Signed-off-by: Matt Leon +--- + src/wasm/c-api.cc | 4 ++++ + 1 file changed, 4 insertions(+) + diff --git a/src/wasm/c-api.cc b/src/wasm/c-api.cc -index 4473e205c0..65a6ec7e1d 100644 +index 05e4029f183..d705be96a16 100644 --- a/src/wasm/c-api.cc +++ b/src/wasm/c-api.cc -@@ -2247,6 +2247,8 @@ auto Instance::exports() const -> ownvec { +@@ -2472,6 +2472,8 @@ WASM_EXPORT auto Instance::exports() const -> ownvec { } // namespace wasm @@ -60,9 +105,242 @@ index 4473e205c0..65a6ec7e1d 100644 // BEGIN FILE wasm-c.cc extern "C" { -@@ -3274,3 +3276,5 @@ wasm_instance_t* wasm_frame_instance(const wasm_frame_t* frame) { +@@ -3518,3 +3520,5 @@ wasm_instance_t* wasm_frame_instance(const wasm_frame_t* frame) { #undef WASM_DEFINE_SHARABLE_REF } // extern "C" + +#endif +-- +2.50.0.727.gbf7dc18ff4-goog + + +From 7b593eb8086dcfe9012d4fa694d622f21dadb731 Mon Sep 17 00:00:00 2001 +From: Matt Leon +Date: Wed, 16 Jul 2025 16:58:02 -0400 +Subject: [PATCH 4/7] Stub out fast_float for bazel-supplied version + +Signed-off-by: Matt Leon +--- + BUILD.bazel | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/BUILD.bazel b/BUILD.bazel +index 0a693b7ee10..eafd9dad20c 100644 +--- a/BUILD.bazel ++++ b/BUILD.bazel +@@ -4438,7 +4438,7 @@ v8_library( + ], + deps = [ + ":lib_dragonbox", +- "//third_party/fast_float/src:fast_float", ++ "@fast_float//:fast_float", + ":lib_fp16", + ":simdutf", + ":v8_libbase", +-- +2.50.0.727.gbf7dc18ff4-goog + + +From b442d34b12dd513946f509d9db86839ce8aa4d7f Mon Sep 17 00:00:00 2001 +From: Matt Leon +Date: Wed, 16 Jul 2025 20:04:05 -0400 +Subject: [PATCH 5/7] Stub out vendored dependencies for bazel-sourced versions + +Signed-off-by: Matt Leon +--- + BUILD.bazel | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/BUILD.bazel b/BUILD.bazel +index eafd9dad20c..ce36666e36e 100644 +--- a/BUILD.bazel ++++ b/BUILD.bazel +@@ -4437,10 +4437,10 @@ v8_library( + ":noicu/generated_torque_definitions", + ], + deps = [ +- ":lib_dragonbox", ++ "@dragonbox//:dragonbox", + "@fast_float//:fast_float", +- ":lib_fp16", +- ":simdutf", ++ "@fp16//:FP16", ++ "@simdutf//:simdutf", + ":v8_libbase", + "@abseil-cpp//absl/container:btree", + "@abseil-cpp//absl/container:flat_hash_map", +-- +2.50.0.727.gbf7dc18ff4-goog + + +From e0b8f32cc057a3c0875437d5d54d012cabcab458 Mon Sep 17 00:00:00 2001 +From: Matt Leon +Date: Wed, 16 Jul 2025 20:29:10 -0400 +Subject: [PATCH 6/7] Add build flags to make V8 compile with GCC + +Signed-off-by: Matt Leon +--- + bazel/defs.bzl | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/bazel/defs.bzl b/bazel/defs.bzl +index 14d7ace5e59..c7a48d4e805 100644 +--- a/bazel/defs.bzl ++++ b/bazel/defs.bzl +@@ -117,6 +117,9 @@ def _default_args(): + "-Wno-implicit-int-float-conversion", + "-Wno-deprecated-copy", + "-Wno-non-virtual-dtor", ++ "-Wno-invalid-offsetof", ++ "-Wno-dangling-pointer", ++ "-Wno-dangling-reference", + "-isystem .", + ], + "//conditions:default": [], +-- +2.50.0.727.gbf7dc18ff4-goog + + +From 7ce2d6bd14b338ab91a8636a8694b9ef180b2f90 Mon Sep 17 00:00:00 2001 +From: Matt Leon +Date: Fri, 18 Jul 2025 17:28:42 -0400 +Subject: [PATCH 7/7] Hack out atomic simd support in V8. + +Atomic simdutf requires __cpp_lib_atomic_ref >= 201806, which is only +supported in clang libc++ 19+. The version of LLVM used in Envoy as of +2025-07-18 is libc++ 18, so this is not supported. + +The simdutf documentation indicates this atomic form is not tested and +is not recommended for use: +https://github.com/simdutf/simdutf/blob/5d1b6248f29a8ed0eb90f79be268be41730e39f8/include/simdutf/implementation.h#L3066-L3068 + +In addition, this is in the implementation of a JS array buffer. Since +proxy-wasm-cpp-host does not make use of JS array buffers or shared +memory between web workers, we're stubbing it out. + +Mostly reverts +https://github.com/v8/v8/commit/6d6c1e680c7b8ea5f62a76e9c3d88d3fb0a88df0. + +Signed-off-by: Matt Leon +--- + bazel/defs.bzl | 2 +- + src/builtins/builtins-typed-array.cc | 8 ++++++++ + src/objects/simd.cc | 10 ++++++++++ + 3 files changed, 19 insertions(+), 1 deletion(-) + +diff --git a/bazel/defs.bzl b/bazel/defs.bzl +index c7a48d4e805..a73b3812882 100644 +--- a/bazel/defs.bzl ++++ b/bazel/defs.bzl +@@ -180,7 +180,7 @@ def _default_args(): + "Advapi32.lib", + ], + "@v8//bazel/config:is_macos": ["-pthread"], +- "//conditions:default": ["-Wl,--no-as-needed -ldl -latomic -pthread"], ++ "//conditions:default": ["-Wl,--no-as-needed -ldl -pthread"], + }) + select({ + ":should_add_rdynamic": ["-rdynamic"], + "//conditions:default": [], +diff --git a/src/builtins/builtins-typed-array.cc b/src/builtins/builtins-typed-array.cc +index 918cb873481..bc933e8dc1d 100644 +--- a/src/builtins/builtins-typed-array.cc ++++ b/src/builtins/builtins-typed-array.cc +@@ -520,17 +520,21 @@ simdutf::result ArrayBufferSetFromBase64( + DirectHandle typed_array, size_t& output_length) { + output_length = array_length; + simdutf::result simd_result; ++#ifdef WANT_ATOMIC_REF + if (typed_array->buffer()->is_shared()) { + simd_result = simdutf::atomic_base64_to_binary_safe( + reinterpret_cast(input_vector), input_length, + reinterpret_cast(typed_array->DataPtr()), output_length, + alphabet, last_chunk_handling, /*decode_up_to_bad_char*/ true); + } else { ++#endif + simd_result = simdutf::base64_to_binary_safe( + reinterpret_cast(input_vector), input_length, + reinterpret_cast(typed_array->DataPtr()), output_length, + alphabet, last_chunk_handling, /*decode_up_to_bad_char*/ true); ++#ifdef WANT_ATOMIC_REF + } ++#endif + + return simd_result; + } +@@ -833,15 +837,19 @@ BUILTIN(Uint8ArrayPrototypeToBase64) { + // 11. Return CodePointsToString(outAscii). + + size_t simd_result_size; ++#ifdef WANT_ATOMIC_REF + if (uint8array->buffer()->is_shared()) { + simd_result_size = simdutf::atomic_binary_to_base64( + std::bit_cast(uint8array->DataPtr()), length, + reinterpret_cast(output->GetChars(no_gc)), alphabet); + } else { ++#endif + simd_result_size = simdutf::binary_to_base64( + std::bit_cast(uint8array->DataPtr()), length, + reinterpret_cast(output->GetChars(no_gc)), alphabet); ++#ifdef WANT_ATOMIC_REF + } ++#endif + DCHECK_EQ(simd_result_size, output_length); + USE(simd_result_size); + } +diff --git a/src/objects/simd.cc b/src/objects/simd.cc +index 0ef570ceb7d..9217fa76072 100644 +--- a/src/objects/simd.cc ++++ b/src/objects/simd.cc +@@ -477,6 +477,7 @@ void Uint8ArrayToHexSlow(const char* bytes, size_t length, + } + } + ++#ifdef WANT_ATOMIC_REF + void AtomicUint8ArrayToHexSlow(const char* bytes, size_t length, + DirectHandle string_output) { + int index = 0; +@@ -492,6 +493,7 @@ void AtomicUint8ArrayToHexSlow(const char* bytes, size_t length, + index += 2; + } + } ++#endif + + inline uint16_t ByteToHex(uint8_t byte) { + const uint16_t correction = (('a' - '0' - 10) << 8) + ('a' - '0' - 10); +@@ -645,11 +647,15 @@ Tagged Uint8ArrayToHex(const char* bytes, size_t length, bool is_shared, + } + #endif + ++#ifdef WANT_ATOMIC_REF + if (is_shared) { + AtomicUint8ArrayToHexSlow(bytes, length, string_output); + } else { ++#endif + Uint8ArrayToHexSlow(bytes, length, string_output); ++#ifdef WANT_ATOMIC_REF + } ++#endif + return *string_output; + } + +@@ -1082,12 +1088,16 @@ bool ArrayBufferFromHex(const base::Vector& input_vector, bool is_shared, + for (uint32_t i = 0; i < output_length * 2; i += 2) { + result = HandleRemainingHexValues(input_vector, i); + if (result.has_value()) { ++#ifdef WANT_ATOMIC_REF + if (is_shared) { + std::atomic_ref(buffer[index++]) + .store(result.value(), std::memory_order_relaxed); + } else { ++#endif + buffer[index++] = result.value(); ++#ifdef WANT_ATOMIC_REF + } ++#endif + } else { + return false; + } +-- +2.50.0.727.gbf7dc18ff4-goog + diff --git a/bazel/external/v8_include.patch b/bazel/external/v8_include.patch deleted file mode 100644 index 0d0fe210c..000000000 --- a/bazel/external/v8_include.patch +++ /dev/null @@ -1,41 +0,0 @@ -# fix include types for late clang (15.0.7) / gcc (13.2.1) -# for Arch linux / Fedora, like in -# In file included from external/v8/src/torque/torque.cc:5: -# In file included from external/v8/src/torque/source-positions.h:10: -# In file included from external/v8/src/torque/contextual.h:10: -# In file included from external/v8/src/base/macros.h:12: -# external/v8/src/base/logging.h:154:26: error: use of undeclared identifier 'uint16_t' - -diff --git a/src/base/logging.h b/src/base/logging.h ---- a/src/base/logging.h -+++ b/src/base/logging.h -@@ -5,6 +5,7 @@ - #ifndef V8_BASE_LOGGING_H_ - #define V8_BASE_LOGGING_H_ - -+#include - #include - #include - #include -diff --git a/src/base/macros.h b/src/base/macros.h ---- a/src/base/macros.h -+++ b/src/base/macros.h -@@ -5,6 +5,7 @@ - #ifndef V8_BASE_MACROS_H_ - #define V8_BASE_MACROS_H_ - -+#include - #include - #include - -diff --git a/src/inspector/v8-string-conversions.h b/src/inspector/v8-string-conversions.h ---- a/src/inspector/v8-string-conversions.h -+++ b/src/inspector/v8-string-conversions.h -@@ -5,6 +5,7 @@ - #ifndef V8_INSPECTOR_V8_STRING_CONVERSIONS_H_ - #define V8_INSPECTOR_V8_STRING_CONVERSIONS_H_ - -+#include - #include - - // Conversion routines between UT8 and UTF16, used by string-16.{h,cc}. You may diff --git a/bazel/external/wamr.BUILD b/bazel/external/wamr.BUILD index dcf8d87ef..a3375e2cb 100644 --- a/bazel/external/wamr.BUILD +++ b/bazel/external/wamr.BUILD @@ -1,3 +1,17 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + load("@rules_foreign_cc//foreign_cc:defs.bzl", "cmake") licenses(["notice"]) # Apache 2 @@ -55,7 +69,7 @@ cmake( "@proxy_wasm_cpp_host//bazel:engine_wamr_jit": ["-ldl"], "//conditions:default": [], }), - out_static_libs = ["libvmlib.a"], + out_static_libs = ["libiwasm.a"], deps = select({ "@proxy_wasm_cpp_host//bazel:engine_wamr_jit": ["@llvm-15_0_7//:llvm_wamr_lib"], "//conditions:default": [], diff --git a/bazel/external/wamr_llvm.BUILD b/bazel/external/wamr_llvm.BUILD index 789e5a442..6fe496145 100644 --- a/bazel/external/wamr_llvm.BUILD +++ b/bazel/external/wamr_llvm.BUILD @@ -1,3 +1,17 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + load("@rules_foreign_cc//foreign_cc:defs.bzl", "cmake") licenses(["notice"]) # Apache 2 diff --git a/bazel/external/wasmedge.BUILD b/bazel/external/wasmedge.BUILD index 1869bf969..e8fba783e 100644 --- a/bazel/external/wasmedge.BUILD +++ b/bazel/external/wasmedge.BUILD @@ -1,3 +1,17 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + load("@rules_foreign_cc//foreign_cc:defs.bzl", "cmake") licenses(["notice"]) # Apache 2 @@ -18,6 +32,9 @@ cmake( "WASMEDGE_BUILD_TOOLS": "Off", "WASMEDGE_FORCE_DISABLE_LTO": "On", }, + env = { + "CXXFLAGS": "-Wno-error=dangling-reference -Wno-error=maybe-uninitialized -Wno-error=array-bounds= -Wno-error=deprecated-declarations -std=c++20", + }, generate_args = ["-GNinja"], lib_source = ":srcs", out_static_libs = ["libwasmedge.a"], diff --git a/bazel/external/wasmtime.BUILD b/bazel/external/wasmtime.BUILD index 27da86e46..f359d9361 100644 --- a/bazel/external/wasmtime.BUILD +++ b/bazel/external/wasmtime.BUILD @@ -1,3 +1,17 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + load("@rules_cc//cc:defs.bzl", "cc_library") load("@rules_rust//rust:defs.bzl", "rust_static_library") diff --git a/bazel/external/wavm.BUILD b/bazel/external/wavm.BUILD deleted file mode 100644 index b315efdea..000000000 --- a/bazel/external/wavm.BUILD +++ /dev/null @@ -1,28 +0,0 @@ -load("@rules_foreign_cc//foreign_cc:defs.bzl", "cmake") - -licenses(["notice"]) # Apache 2 - -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "srcs", - srcs = glob(["**"]), -) - -cmake( - name = "wavm_lib", - cache_entries = { - "LLVM_DIR": "$EXT_BUILD_DEPS/copy_llvm/llvm/lib/cmake/llvm", - "WAVM_ENABLE_STATIC_LINKING": "on", - "WAVM_ENABLE_RELEASE_ASSERTS": "on", - "WAVM_ENABLE_UNWIND": "on", - "CMAKE_CXX_FLAGS": "-Wno-unused-command-line-argument", - }, - generate_args = ["-GNinja"], - lib_source = ":srcs", - out_static_libs = [ - "libWAVM.a", - "libWAVMUnwind.a", - ], - deps = ["@llvm//:llvm_lib"], -) diff --git a/bazel/repositories.bzl b/bazel/repositories.bzl index 908ffe492..09939a706 100644 --- a/bazel/repositories.bzl +++ b/bazel/repositories.bzl @@ -60,10 +60,18 @@ def proxy_wasm_cpp_host_repositories(): maybe( http_archive, - name = "bazel-zig-cc", - sha256 = "ff89e0220c72cdc774e451a35e5c3b9f1593d0df71341844b2108c181ac0eef9", - strip_prefix = "hermetic_cc_toolchain-0.4.4", - url = "https://github.com/uber/hermetic_cc_toolchain/archive/refs/tags/v0.4.4.tar.gz", + name = "envoy_toolshed", + sha256 = "e2252e46e64417d5cedd9f1eb34a622bce5e13b43837e5fe051c83066b0a400b", + strip_prefix = "toolshed-bazel-bins-v0.1.13/bazel", + url = "https://github.com/envoyproxy/toolshed/archive/refs/tags/bazel-bins-v0.1.13.tar.gz", + ) + maybe( + http_archive, + name = "toolchains_llvm", + sha256 = "b7cd301ef7b0ece28d20d3e778697a5e3b81828393150bed04838c0c52963a01", + strip_prefix = "toolchains_llvm-0.10.3", + canonical_id = "v0.10.3", + url = "https://github.com/grailbio/bazel-toolchain/releases/download/0.10.3/toolchains_llvm-0.10.3.tar.gz", ) maybe( @@ -130,9 +138,9 @@ def proxy_wasm_cpp_host_repositories(): maybe( http_archive, name = "proxy_wasm_cpp_sdk", - sha256 = "89792fc1abca331f29f99870476a04146de5e82ff903bdffca90e6729c1f2470", - strip_prefix = "proxy-wasm-cpp-sdk-95bb82ce45c41d9100fd1ec15d2ffc67f7f3ceee", - urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-sdk/archive/95bb82ce45c41d9100fd1ec15d2ffc67f7f3ceee.tar.gz"], + sha256 = "26c4c0f9f645de7e789dc92f113d7352ee54ac43bb93ae3a8a22945f1ce71590", + strip_prefix = "proxy-wasm-cpp-sdk-7465dee8b2953beebff99f6dc3720ad0c79bab99", + urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-sdk/archive/7465dee8b2953beebff99f6dc3720ad0c79bab99.tar.gz"], ) # Compile DB dependencies. @@ -149,11 +157,9 @@ def proxy_wasm_cpp_host_repositories(): maybe( http_archive, name = "com_google_googletest", - sha256 = "9dc9157a9a1551ec7a7e43daea9a694a0bb5fb8bec81235d8a1e6ef64c716dcb", - strip_prefix = "googletest-release-1.10.0", - urls = ["https://github.com/google/googletest/archive/release-1.10.0.tar.gz"], - patches = ["@proxy_wasm_cpp_host//bazel/external:googletest.patch"], - patch_args = ["-p1"], + sha256 = "65fab701d9829d38cb77c14acdc431d2108bfdbf8979e40eb8ae567edf10b27c", + strip_prefix = "googletest-1.17.0", + urls = ["https://github.com/google/googletest/releases/download/v1.17.0/googletest-1.17.0.tar.gz"], ) # NullVM dependencies. @@ -171,34 +177,89 @@ def proxy_wasm_cpp_host_repositories(): maybe( git_repository, name = "v8", - # 10.7.193.13 - commit = "6c8b357a84847a479cd329478522feefc1c3195a", + # 13.8.258.26 + commit = "de9d0f8b56ae61896e4d2ac577fc589efb14f87d", remote = "https://chromium.googlesource.com/v8/v8", - shallow_since = "1664374400 +0000", + shallow_since = "1752074621 -0400", patches = [ "@proxy_wasm_cpp_host//bazel/external:v8.patch", - "@proxy_wasm_cpp_host//bazel/external:v8_include.patch", ], patch_args = ["-p1"], + patch_cmds = [ + "find ./src ./include -type f -exec sed -i.bak -e 's!#include \"third_party/simdutf/simdutf.h\"!#include \"simdutf.h\"!' {} \\;", + "find ./src ./include -type f -exec sed -i.bak -e 's!#include \"third_party/fp16/src/include/fp16.h\"!#include \"fp16.h\"!' {} \\;", + "find ./src ./include -type f -exec sed -i.bak -e 's!#include \"third_party/dragonbox/src/include/dragonbox/dragonbox.h\"!#include \"dragonbox/dragonbox.h\"!' {} \\;", + "find ./src ./include -type f -exec sed -i.bak -e 's!#include \"third_party/fast_float/src/include/fast_float/!#include \"fast_float/!' {} \\;", + ], + repo_mapping = { + "@abseil-cpp": "@com_google_absl", + }, ) - native.bind( - name = "wee8", - actual = "@v8//:wee8", + maybe( + http_archive, + name = "highway", + sha256 = "7e0be78b8318e8bdbf6fa545d2ecb4c90f947df03f7aadc42c1967f019e63343", + urls = [ + "https://github.com/google/highway/archive/refs/tags/1.2.0.tar.gz", + ], + strip_prefix = "highway-1.2.0", + ) + + maybe( + http_archive, + name = "fast_float", + sha256 = "d2a08e722f461fe699ba61392cd29e6b23be013d0f56e50c7786d0954bffcb17", + urls = [ + "https://github.com/fastfloat/fast_float/archive/refs/tags/v7.0.0.tar.gz", + ], + strip_prefix = "fast_float-7.0.0", + ) + + maybe( + http_archive, + name = "dragonbox", + urls = [ + "https://github.com/jk-jeon/dragonbox/archive/6c7c925b571d54486b9ffae8d9d18a822801cbda.zip", + ], + strip_prefix = "dragonbox-6c7c925b571d54486b9ffae8d9d18a822801cbda", + sha256 = "2f10448d665355b41f599e869ac78803f82f13b070ce7ef5ae7b5cceb8a178f3", + build_file = "@proxy_wasm_cpp_host//bazel/external:dragonbox.BUILD", + ) + + maybe( + http_archive, + name = "fp16", + urls = [ + "https://github.com/Maratyszcza/FP16/archive/0a92994d729ff76a58f692d3028ca1b64b145d91.zip", + ], + strip_prefix = "FP16-0a92994d729ff76a58f692d3028ca1b64b145d91", + sha256 = "e66e65515fa09927b348d3d584c68be4215cfe664100d01c9dbc7655a5716d70", + build_file = "@proxy_wasm_cpp_host//bazel/external:fp16.BUILD", ) maybe( - new_git_repository, - name = "com_googlesource_chromium_base_trace_event_common", - build_file = "@v8//:bazel/BUILD.trace_event_common", - commit = "521ac34ebd795939c7e16b37d9d3ddb40e8ed556", - remote = "https://chromium.googlesource.com/chromium/src/base/trace_event/common.git", - shallow_since = "1662508800 +0000", + http_archive, + name = "simdutf", + sha256 = "512374f8291d3daf102ccd0ad223b1a8318358f7c1295efd4d9a3abbb8e4b6ff", + urls = [ + "https://github.com/simdutf/simdutf/releases/download/v7.3.0/singleheader.zip", + ], + build_file = "@proxy_wasm_cpp_host//bazel/external:simdutf.BUILD", + ) + + maybe( + http_archive, + name = "intel_ittapi", + strip_prefix = "ittapi-a3911fff01a775023a06af8754f9ec1e5977dd97", + sha256 = "1d0dddfc5abb786f2340565c82c6edd1cff10c917616a18ce62ee0b94dbc2ed4", + urls = ["https://github.com/intel/ittapi/archive/a3911fff01a775023a06af8754f9ec1e5977dd97.tar.gz"], + build_file = "@proxy_wasm_cpp_host//bazel/external:intel_ittapi.BUILD", ) native.bind( - name = "base_trace_event_common", - actual = "@com_googlesource_chromium_base_trace_event_common//:trace_event_common", + name = "wee8", + actual = "@v8//:wee8", ) # WAMR with dependencies. @@ -207,10 +268,10 @@ def proxy_wasm_cpp_host_repositories(): http_archive, name = "com_github_bytecodealliance_wasm_micro_runtime", build_file = "@proxy_wasm_cpp_host//bazel/external:wamr.BUILD", - # WAMR-2.1.1 - sha256 = "a0824762abbcbb3dd6b7bb07530f198ece5d792a12a879bc2a99100590fdb151", - strip_prefix = "wasm-micro-runtime-WAMR-2.1.1", - url = "https://github.com/bytecodealliance/wasm-micro-runtime/archive/refs/tags/WAMR-2.1.1.zip", + # WAMR-2.4.1 + sha256 = "ca18bbf304f47287bf43707564db63b8908dd6d0d6ac40bb39271a7144def4cc", + strip_prefix = "wasm-micro-runtime-WAMR-2.4.1", + url = "https://github.com/bytecodealliance/wasm-micro-runtime/archive/refs/tags/WAMR-2.4.1.zip", ) native.bind( @@ -263,30 +324,3 @@ def proxy_wasm_cpp_host_repositories(): name = "prefixed_wasmtime", actual = "@com_github_bytecodealliance_wasmtime//:prefixed_wasmtime_lib", ) - - # WAVM with dependencies. - - maybe( - http_archive, - name = "com_github_wavm_wavm", - build_file = "@proxy_wasm_cpp_host//bazel/external:wavm.BUILD", - sha256 = "7cfa3d7334c96f89553bb44eeee736a192826a78b4db114042d38d6882748f5b", - strip_prefix = "WAVM-nightly-2022-05-14", - url = "https://github.com/WAVM/WAVM/archive/refs/tags/nightly/2022-05-14.tar.gz", - ) - - native.bind( - name = "wavm", - actual = "@com_github_wavm_wavm//:wavm_lib", - ) - - maybe( - http_archive, - name = "llvm", - build_file = "@proxy_wasm_cpp_host//bazel/external:llvm.BUILD", - sha256 = "7d9a8405f557cefc5a21bf5672af73903b64749d9bc3a50322239f56f34ffddf", - strip_prefix = "llvm-12.0.1.src", - url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-12.0.1/llvm-12.0.1.src.tar.xz", - patches = ["@proxy_wasm_cpp_host//bazel/external:llvm.patch"], - patch_args = ["-p1"], - ) diff --git a/bazel/select.bzl b/bazel/select.bzl index 747aef33c..cc4da38d1 100644 --- a/bazel/select.bzl +++ b/bazel/select.bzl @@ -47,10 +47,3 @@ def proxy_wasm_select_engine_wasmedge(xs): "@proxy_wasm_cpp_host//bazel:multiengine": xs, "//conditions:default": [], }) - -def proxy_wasm_select_engine_wavm(xs): - return select({ - "@proxy_wasm_cpp_host//bazel:engine_wavm": xs, - "@proxy_wasm_cpp_host//bazel:multiengine": xs, - "//conditions:default": [], - }) diff --git a/bazel/tsan_suppressions.txt b/bazel/tsan_suppressions.txt new file mode 100644 index 000000000..8754c04f3 --- /dev/null +++ b/bazel/tsan_suppressions.txt @@ -0,0 +1,3 @@ +# False positive in V8 worker shutdown +race:v8::platform::DefaultJobHandle::Join +race:v8::platform::DefaultJobHandle::Cancel diff --git a/include/proxy-wasm/context.h b/include/proxy-wasm/context.h index 12937041f..208633acc 100644 --- a/include/proxy-wasm/context.h +++ b/include/proxy-wasm/context.h @@ -150,14 +150,14 @@ class ContextBase : public RootInterface, const std::shared_ptr &plugin_handle); // Stream context. virtual ~ContextBase(); - WasmBase *wasm() const { return wasm_; } + virtual WasmBase *wasm() const { return wasm_; } uint32_t id() const { return id_; } // The VM Context used for calling "malloc" has an id_ == 0. bool isVmContext() const { return id_ == 0; } // Root Contexts have the VM Context as a parent. bool isRootContext() const { return parent_context_id_ == 0; } - ContextBase *parent_context() const { return parent_context_; } - ContextBase *root_context() const { + virtual ContextBase *parent_context() const { return parent_context_; } + virtual ContextBase *root_context() const { const ContextBase *previous = this; ContextBase *parent = parent_context_; while (parent != previous) { @@ -170,7 +170,7 @@ class ContextBase : public RootInterface, std::string_view log_prefix() const { return isRootContext() ? root_log_prefix_ : plugin_->log_prefix(); } - WasmVm *wasmVm() const; + virtual WasmVm *wasmVm() const; // Called before deleting the context. virtual void destroy(); @@ -397,6 +397,13 @@ class ContextBase : public RootInterface, bool destroyed_ = false; bool stream_failed_ = false; // Set true after failStream is called in case of VM failure. + // If true, convertVmCallResultToFilterHeadersStatus() propagates + // FilterHeadersStatus::StopIteration unmodified to callers. If false, it + // translates FilterHeaderStatus::StopIteration to + // FilterHeadersStatus::StopAllIterationAndWatermark, which is the default + // behavior for v0.2.* of the Proxy-Wasm ABI. + bool allow_on_headers_stop_iteration_ = false; + private: // helper functions FilterHeadersStatus convertVmCallResultToFilterHeadersStatus(uint64_t result); diff --git a/include/proxy-wasm/null_vm.h b/include/proxy-wasm/null_vm.h index a0a3798ff..703266df3 100644 --- a/include/proxy-wasm/null_vm.h +++ b/include/proxy-wasm/null_vm.h @@ -63,6 +63,8 @@ struct NullVm : public WasmVm { void terminate() override {} bool usesWasmByteOrder() override { return false; } + void warm() override {} + std::string plugin_name_; std::unique_ptr plugin_; }; diff --git a/include/proxy-wasm/signature_util.h b/include/proxy-wasm/signature_util.h index 68579dcd1..a5c9c39df 100644 --- a/include/proxy-wasm/signature_util.h +++ b/include/proxy-wasm/signature_util.h @@ -14,6 +14,7 @@ #pragma once +#include #include namespace proxy_wasm { diff --git a/include/proxy-wasm/wasm.h b/include/proxy-wasm/wasm.h index 9fa2bda1f..9b85710bd 100644 --- a/include/proxy-wasm/wasm.h +++ b/include/proxy-wasm/wasm.h @@ -54,18 +54,18 @@ class WasmBase : public std::enable_shared_from_this { WasmBase(const std::shared_ptr &base_wasm_handle, const WasmVmFactory &factory); virtual ~WasmBase(); - bool load(const std::string &code, bool allow_precompiled = false); - bool initialize(); - void startVm(ContextBase *root_context); - bool configure(ContextBase *root_context, std::shared_ptr plugin); + virtual bool load(const std::string &code, bool allow_precompiled = false); + virtual bool initialize(); + virtual void startVm(ContextBase *root_context); + virtual bool configure(ContextBase *root_context, std::shared_ptr plugin); // Returns the root ContextBase or nullptr if onStart returns false. - ContextBase *start(const std::shared_ptr &plugin); + virtual ContextBase *start(const std::shared_ptr &plugin); std::string_view vm_id() const { return vm_id_; } std::string_view vm_key() const { return vm_key_; } WasmVm *wasm_vm() const { return wasm_vm_.get(); } - ContextBase *vm_context() const { return vm_context_.get(); } - ContextBase *getRootContext(const std::shared_ptr &plugin, bool allow_closed); + virtual ContextBase *vm_context() const { return vm_context_.get(); } + virtual ContextBase *getRootContext(const std::shared_ptr &plugin, bool allow_closed); ContextBase *getContext(uint32_t id) { auto it = contexts_.find(id); if (it != contexts_.end()) @@ -321,14 +321,14 @@ using WasmHandleCloneFactory = class WasmHandleBase : public std::enable_shared_from_this { public: explicit WasmHandleBase(std::shared_ptr wasm_base) : wasm_base_(wasm_base) {} - ~WasmHandleBase() { + virtual ~WasmHandleBase() { if (wasm_base_) { wasm_base_->startShutdown(); } } - bool canary(const std::shared_ptr &plugin, - const WasmHandleCloneFactory &clone_factory); + virtual bool canary(const std::shared_ptr &plugin, + const WasmHandleCloneFactory &clone_factory); void kill() { wasm_base_ = nullptr; } @@ -356,7 +356,7 @@ class PluginHandleBase : public std::enable_shared_from_this { explicit PluginHandleBase(std::shared_ptr wasm_handle, std::shared_ptr plugin) : plugin_(plugin), wasm_handle_(wasm_handle) {} - ~PluginHandleBase() { + virtual ~PluginHandleBase() { if (wasm_handle_) { wasm_handle_->wasm()->startShutdown(plugin_->key()); } @@ -373,7 +373,7 @@ class PluginHandleBase : public std::enable_shared_from_this { using PluginHandleFactory = std::function( std::shared_ptr base_wasm, std::shared_ptr plugin)>; -// Get an existing ThreadLocal VM matching 'vm_id' or create one using 'base_wavm' by cloning or by +// Get an existing ThreadLocal VM matching 'vm_id' or create one using 'base_wasm' by cloning or by // using it it as a template. std::shared_ptr getOrCreateThreadLocalPlugin( const std::shared_ptr &base_handle, const std::shared_ptr &plugin, diff --git a/include/proxy-wasm/wasm_vm.h b/include/proxy-wasm/wasm_vm.h index a573212e0..9a2f0a6a0 100644 --- a/include/proxy-wasm/wasm_vm.h +++ b/include/proxy-wasm/wasm_vm.h @@ -143,12 +143,25 @@ enum class AbiVersion { ProxyWasm_0_1_0, ProxyWasm_0_2_0, ProxyWasm_0_2_1, Unkno class NullPlugin; +enum class FailState : int { + Ok = 0, + UnableToCreateVm = 1, + UnableToCloneVm = 2, + MissingFunction = 3, + UnableToInitializeCode = 4, + StartFailed = 5, + ConfigureFailed = 6, + RuntimeError = 7, +}; + // Integrator specific WasmVm operations. struct WasmVmIntegration { virtual ~WasmVmIntegration() {} virtual WasmVmIntegration *clone() = 0; virtual proxy_wasm::LogLevel getLogLevel() = 0; virtual void error(std::string_view message) = 0; + // Allow integrations to handle specific FailStates differently. + virtual void error(FailState fail_state, std::string_view message) { error(message); } virtual void trace(std::string_view message) = 0; // Get a NullVm implementation of a function. // @param function_name is the name of the function with the implementation specific prefix. @@ -165,17 +178,6 @@ struct WasmVmIntegration { void *ptr_to_function_return) = 0; }; -enum class FailState : int { - Ok = 0, - UnableToCreateVm = 1, - UnableToCloneVm = 2, - MissingFunction = 3, - UnableToInitializeCode = 4, - StartFailed = 5, - ConfigureFailed = 6, - RuntimeError = 7, -}; - // Wasm VM instance. Provides the low level WASM interface. class WasmVm { public: @@ -189,10 +191,9 @@ class WasmVm { /** * Whether or not the VM implementation supports cloning. Cloning is VM system dependent. * When a VM is configured a single VM is instantiated to check that the .wasm file is valid and - * to do VM system specific initialization. In the case of WAVM this is potentially ahead-of-time - * compilation. Then, if cloning is supported, we clone that VM for each worker, potentially - * copying and sharing the initialized data structures for efficiency. Otherwise we create an new - * VM from scratch for each worker. + * to do VM system specific initialization. Then, if cloning is supported, we clone that VM for + * each worker, potentially copying and sharing the initialized data structures for efficiency. + * Otherwise we create an new VM from scratch for each worker. * @return one of enum Cloneable with the VMs cloneability. */ virtual Cloneable cloneable() = 0; @@ -309,9 +310,11 @@ class WasmVm { */ virtual bool usesWasmByteOrder() = 0; + virtual void warm() {} + bool isFailed() { return failed_ != FailState::Ok; } void fail(FailState fail_state, std::string_view message) { - integration()->error(message); + integration()->error(fail_state, message); failed_ = fail_state; for (auto &callback : fail_callbacks_) { callback(fail_state); diff --git a/include/proxy-wasm/wavm.h b/include/proxy-wasm/wavm.h deleted file mode 100644 index 1ebbe8397..000000000 --- a/include/proxy-wasm/wavm.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2016-2019 Envoy Project Authors -// Copyright 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include - -#include "include/proxy-wasm/wasm_vm.h" - -namespace proxy_wasm { - -std::unique_ptr createWavmVm(); - -} // namespace proxy_wasm diff --git a/src/context.cc b/src/context.cc index 5353a52a5..d8dbc9a2a 100644 --- a/src/context.cc +++ b/src/context.cc @@ -493,10 +493,12 @@ FilterHeadersStatus ContextBase::convertVmCallResultToFilterHeadersStatus(uint64 result > static_cast(FilterHeadersStatus::StopAllIterationAndWatermark)) { return FilterHeadersStatus::StopAllIterationAndWatermark; } - if (result == static_cast(FilterHeadersStatus::StopIteration)) { - // Always convert StopIteration (pause processing headers, but continue processing body) - // to StopAllIterationAndWatermark (pause all processing), since the former breaks all - // assumptions about HTTP processing. + if (result == static_cast(FilterHeadersStatus::StopIteration) && + !allow_on_headers_stop_iteration_) { + // Default behavior for Proxy-Wasm 0.2.* ABI is to translate StopIteration + // (pause processing headers, but continue processing body) to + // StopAllIterationAndWatermark (pause all processing), as described in + // https://github.com/proxy-wasm/proxy-wasm-cpp-host/issues/143. return FilterHeadersStatus::StopAllIterationAndWatermark; } return static_cast(result); diff --git a/src/null/null_plugin.cc b/src/null/null_plugin.cc index 0f74496a2..689225687 100644 --- a/src/null/null_plugin.cc +++ b/src/null/null_plugin.cc @@ -26,7 +26,6 @@ #include #include -#include "include/proxy-wasm/null_plugin.h" #include "include/proxy-wasm/null_vm.h" #include "include/proxy-wasm/wasm.h" diff --git a/src/pairs_util.cc b/src/pairs_util.cc index d21135788..b8121882f 100644 --- a/src/pairs_util.cc +++ b/src/pairs_util.cc @@ -15,6 +15,7 @@ #include "include/proxy-wasm/pairs_util.h" +#include #include #include #include @@ -25,6 +26,23 @@ namespace proxy_wasm { +namespace { + +// Read trivially copyable type from char buffer and return value. Does not +// check if char buffer is large enough to contain instance of `T`. +template inline T unalignedLoad(const char *buffer) { + // Checking for undefined behaviour wrt std::memcpy. + static_assert(std::is_trivially_copyable_v, + "type must be trivially copyable to use std::memcpy"); + T result; + // Use std::memcpy to get around strict type aliasing rules. + std::memcpy(&result, buffer, sizeof(T)); + + return result; +} + +} // namespace + using Sizes = std::vector>; size_t PairsUtil::pairsSize(const Pairs &pairs) { @@ -113,10 +131,13 @@ Pairs PairsUtil::toPairs(std::string_view buffer) { if (pos + sizeof(uint32_t) > end) { return {}; } - uint32_t num_pairs = wasmtoh(*reinterpret_cast(pos), - contextOrEffectiveContext() != nullptr - ? contextOrEffectiveContext()->wasmVm()->usesWasmByteOrder() - : false); + + // clang complains that this is unused when the wasmtoh macro drops its + // second argument on non-big-endian platforms. + [[maybe_unused]] const bool uses_wasm_byte_order = + contextOrEffectiveContext() != nullptr && + contextOrEffectiveContext()->wasmVm()->usesWasmByteOrder(); + uint32_t num_pairs = wasmtoh(unalignedLoad(pos), uses_wasm_byte_order); pos += sizeof(uint32_t); // Check if we're not going to exceed the limit. @@ -135,20 +156,14 @@ Pairs PairsUtil::toPairs(std::string_view buffer) { if (pos + sizeof(uint32_t) > end) { return {}; } - s.first = wasmtoh(*reinterpret_cast(pos), - contextOrEffectiveContext() != nullptr - ? contextOrEffectiveContext()->wasmVm()->usesWasmByteOrder() - : false); + s.first = wasmtoh(unalignedLoad(pos), uses_wasm_byte_order); pos += sizeof(uint32_t); // Read value length. if (pos + sizeof(uint32_t) > end) { return {}; } - s.second = wasmtoh(*reinterpret_cast(pos), - contextOrEffectiveContext() != nullptr - ? contextOrEffectiveContext()->wasmVm()->usesWasmByteOrder() - : false); + s.second = wasmtoh(unalignedLoad(pos), uses_wasm_byte_order); pos += sizeof(uint32_t); } diff --git a/src/v8/v8.cc b/src/v8/v8.cc index 61779c1d5..f5a73b130 100644 --- a/src/v8/v8.cc +++ b/src/v8/v8.cc @@ -28,9 +28,10 @@ #include "include/proxy-wasm/limits.h" +#include "absl/strings/str_format.h" +#include "include/v8-initialization.h" #include "include/v8-version.h" #include "include/v8.h" -#include "src/flags/flags.h" #include "src/wasm/c-api.h" #include "wasm-api/wasm.hh" @@ -42,10 +43,13 @@ wasm::Engine *engine() { static wasm::own engine; std::call_once(init, []() { - ::v8::internal::v8_flags.liftoff = false; - ::v8::internal::v8_flags.wasm_max_mem_pages = - PROXY_WASM_HOST_MAX_WASM_MEMORY_SIZE_BYTES / PROXY_WASM_HOST_WASM_MEMORY_PAGE_SIZE_BYTES; + // Disable the Liftoff compiler to force optimized JIT up-front. + std::string args = absl::StrFormat("--wasm_max_mem_pages=%u --no-liftoff", + PROXY_WASM_HOST_MAX_WASM_MEMORY_SIZE_BYTES / + PROXY_WASM_HOST_WASM_MEMORY_PAGE_SIZE_BYTES); + ::v8::V8::SetFlagsFromString(args.c_str(), args.size()); ::v8::V8::EnableWebAssemblyTrapHandler(true); + engine = wasm::Engine::make(); }); @@ -103,6 +107,8 @@ class V8 : public WasmVm { void terminate() override; bool usesWasmByteOrder() override { return true; } + void warm() override; + private: wasm::own trap(std::string message); @@ -124,6 +130,9 @@ class V8 : public WasmVm { void getModuleFunctionImpl(std::string_view function_name, std::function *function); + // Initialize the V8 engine and store if necessary. + void initStore(); + wasm::own store_; wasm::own module_; wasm::own> shared_module_; @@ -140,20 +149,20 @@ class V8 : public WasmVm { static std::string printValue(const wasm::Val &value) { switch (value.kind()) { - case wasm::I32: + case wasm::ValKind::I32: return std::to_string(value.get()); - case wasm::I64: + case wasm::ValKind::I64: return std::to_string(value.get()); - case wasm::F32: + case wasm::ValKind::F32: return std::to_string(value.get()); - case wasm::F64: + case wasm::ValKind::F64: return std::to_string(value.get()); default: return "unknown"; } } -static std::string printValues(const wasm::Val values[], size_t size) { +static std::string printValues(const wasm::vec &values, size_t size) { if (size == 0) { return ""; } @@ -170,17 +179,17 @@ static std::string printValues(const wasm::Val values[], size_t size) { static const char *printValKind(wasm::ValKind kind) { switch (kind) { - case wasm::I32: + case wasm::ValKind::I32: return "i32"; - case wasm::I64: + case wasm::ValKind::I64: return "i64"; - case wasm::F32: + case wasm::ValKind::F32: return "f32"; - case wasm::F64: + case wasm::ValKind::F64: return "f64"; - case wasm::ANYREF: - return "anyref"; - case wasm::FUNCREF: + case wasm::ValKind::EXTERNREF: + return "externref"; + case wasm::ValKind::FUNCREF: return "funcref"; default: return "unknown"; @@ -229,11 +238,11 @@ template wasm::Val makeVal(T t) { return wasm::Val::make(t); } template <> wasm::Val makeVal(Word t) { return wasm::Val::make(static_cast(t.u64_)); } template constexpr auto convertArgToValKind(); -template <> constexpr auto convertArgToValKind() { return wasm::I32; }; -template <> constexpr auto convertArgToValKind() { return wasm::I32; }; -template <> constexpr auto convertArgToValKind() { return wasm::I64; }; -template <> constexpr auto convertArgToValKind() { return wasm::I64; }; -template <> constexpr auto convertArgToValKind() { return wasm::F64; }; +template <> constexpr auto convertArgToValKind() { return wasm::ValKind::I32; }; +template <> constexpr auto convertArgToValKind() { return wasm::ValKind::I32; }; +template <> constexpr auto convertArgToValKind() { return wasm::ValKind::I64; }; +template <> constexpr auto convertArgToValKind() { return wasm::ValKind::I64; }; +template <> constexpr auto convertArgToValKind() { return wasm::ValKind::F64; }; template constexpr auto convertArgsTupleToValTypesImpl(std::index_sequence /*comptime*/) { @@ -260,9 +269,16 @@ template constexpr T convertValTypesToArgsTuple(const U // V8 implementation. +void V8::initStore() { + if (store_ != nullptr) { + return; + } + store_ = wasm::Store::make(engine()); +} + bool V8::load(std::string_view bytecode, std::string_view precompiled, const std::unordered_map &function_names) { - store_ = wasm::Store::make(engine()); + initStore(); if (store_ == nullptr) { return false; } @@ -343,7 +359,8 @@ bool V8::link(std::string_view /*debug_name*/) { assert(module_ != nullptr); const auto import_types = module_.get()->imports(); - std::vector imports; + wasm::vec imports = + wasm::vec::make_uninitialized(import_types.size()); for (size_t i = 0; i < import_types.size(); i++) { std::string_view module(import_types[i]->module().get(), import_types[i]->module().size()); @@ -352,7 +369,7 @@ bool V8::link(std::string_view /*debug_name*/) { switch (import_type->kind()) { - case wasm::EXTERN_FUNC: { + case wasm::ExternKind::FUNC: { auto it = host_functions_.find(std::string(module) + "." + std::string(name)); if (it == host_functions_.end()) { fail(FailState::UnableToInitializeCode, @@ -372,10 +389,10 @@ bool V8::link(std::string_view /*debug_name*/) { printValTypes(func->type()->results())); return false; } - imports.push_back(func); + imports[i] = func; } break; - case wasm::EXTERN_GLOBAL: { + case wasm::ExternKind::GLOBAL: { // TODO(PiotrSikora): add support when/if needed. fail(FailState::UnableToInitializeCode, "Failed to load Wasm module due to a missing import: " + std::string(module) + "." + @@ -383,7 +400,7 @@ bool V8::link(std::string_view /*debug_name*/) { return false; } break; - case wasm::EXTERN_MEMORY: { + case wasm::ExternKind::MEMORY: { assert(memory_ == nullptr); auto type = wasm::MemoryType::make(import_type->memory()->limits()); if (type == nullptr) { @@ -393,10 +410,10 @@ bool V8::link(std::string_view /*debug_name*/) { if (memory_ == nullptr) { return false; } - imports.push_back(memory_.get()); + imports[i] = memory_.get(); } break; - case wasm::EXTERN_TABLE: { + case wasm::ExternKind::TABLE: { assert(table_ == nullptr); auto type = wasm::TableType::make(wasm::ValType::make(import_type->table()->element()->kind()), @@ -408,16 +425,12 @@ bool V8::link(std::string_view /*debug_name*/) { if (table_ == nullptr) { return false; } - imports.push_back(table_.get()); + imports[i] = table_.get(); } break; } } - if (import_types.size() != imports.size()) { - return false; - } - - instance_ = wasm::Instance::make(store_.get(), module_.get(), imports.data()); + instance_ = wasm::Instance::make(store_.get(), module_.get(), imports); if (instance_ == nullptr) { fail(FailState::UnableToInitializeCode, "Failed to create new Wasm instance"); return false; @@ -435,16 +448,16 @@ bool V8::link(std::string_view /*debug_name*/) { switch (export_type->kind()) { - case wasm::EXTERN_FUNC: { + case wasm::ExternKind::FUNC: { assert(export_item->func() != nullptr); module_functions_.insert_or_assign(std::string(name), export_item->func()->copy()); } break; - case wasm::EXTERN_GLOBAL: { + case wasm::ExternKind::GLOBAL: { // TODO(PiotrSikora): add support when/if needed. } break; - case wasm::EXTERN_MEMORY: { + case wasm::ExternKind::MEMORY: { assert(export_item->memory() != nullptr); assert(memory_ == nullptr); memory_ = exports[i]->memory()->copy(); @@ -453,7 +466,7 @@ bool V8::link(std::string_view /*debug_name*/) { } } break; - case wasm::EXTERN_TABLE: { + case wasm::ExternKind::TABLE: { // TODO(PiotrSikora): add support when/if needed. } break; } @@ -531,7 +544,8 @@ void V8::registerHostFunctionImpl(std::string_view module_name, std::string_view convertArgsTupleToValTypes>()); auto func = wasm::Func::make( store_.get(), type.get(), - [](void *data, const wasm::Val params[], wasm::Val /*results*/[]) -> wasm::own { + [](void *data, const wasm::vec ¶ms, + wasm::vec & /*results*/) -> wasm::own { auto *func_data = reinterpret_cast(data); const bool log = func_data->vm_->cmpLogLevel(LogLevel::trace); if (log) { @@ -567,7 +581,8 @@ void V8::registerHostFunctionImpl(std::string_view module_name, std::string_view convertArgsTupleToValTypes>()); auto func = wasm::Func::make( store_.get(), type.get(), - [](void *data, const wasm::Val params[], wasm::Val results[]) -> wasm::own { + [](void *data, const wasm::vec ¶ms, + wasm::vec &results) -> wasm::own { auto *func_data = reinterpret_cast(data); const bool log = func_data->vm_->cmpLogLevel(LogLevel::trace); if (log) { @@ -621,20 +636,21 @@ void V8::getModuleFunctionImpl(std::string_view function_name, const bool log = cmpLogLevel(LogLevel::trace); SaveRestoreContext saved_context(context); wasm::own trap = nullptr; + wasm::vec results = wasm::vec::make_uninitialized(); // Workaround for MSVC++ not supporting zero-sized arrays. if constexpr (sizeof...(args) > 0) { - wasm::Val params[] = {makeVal(args)...}; + wasm::vec params = wasm::vec::make(makeVal(args)...); if (log) { integration()->trace("[host->vm] " + std::string(function_name) + "(" + printValues(params, sizeof...(Args)) + ")"); } - trap = func->call(params, nullptr); + trap = func->call(params, results); } else { if (log) { integration()->trace("[host->vm] " + std::string(function_name) + "()"); } - trap = func->call(nullptr, nullptr); + trap = func->call(wasm::vec::make_uninitialized(), results); } if (trap) { @@ -671,12 +687,12 @@ void V8::getModuleFunctionImpl(std::string_view function_name, *function = [func, function_name, this](ContextBase *context, Args... args) -> R { const bool log = cmpLogLevel(LogLevel::trace); SaveRestoreContext saved_context(context); - wasm::Val results[1]; + wasm::vec results = wasm::vec::make_uninitialized(1); wasm::own trap = nullptr; // Workaround for MSVC++ not supporting zero-sized arrays. if constexpr (sizeof...(args) > 0) { - wasm::Val params[] = {makeVal(args)...}; + wasm::vec params = wasm::vec::make(makeVal(args)...); if (log) { integration()->trace("[host->vm] " + std::string(function_name) + "(" + printValues(params, sizeof...(Args)) + ")"); @@ -686,7 +702,7 @@ void V8::getModuleFunctionImpl(std::string_view function_name, if (log) { integration()->trace("[host->vm] " + std::string(function_name) + "()"); } - trap = func->call(nullptr, results); + trap = func->call(wasm::vec::make_uninitialized(), results); } if (trap) { @@ -706,11 +722,10 @@ void V8::terminate() { auto *store_impl = reinterpret_cast(store_.get()); auto *isolate = store_impl->isolate(); isolate->TerminateExecution(); - while (isolate->IsExecutionTerminating()) { - std::this_thread::yield(); - } } +void V8::warm() { initStore(); } + std::string V8::getFailMessage(std::string_view function_name, wasm::own trap) { auto message = "Function: " + std::string(function_name) + " failed: "; message += std::string(trap->message().get(), trap->message().size()); diff --git a/src/wamr/wamr.cc b/src/wamr/wamr.cc index 482a59bf1..8eef73590 100644 --- a/src/wamr/wamr.cc +++ b/src/wamr/wamr.cc @@ -90,6 +90,8 @@ class Wamr : public WasmVm { void terminate() override {} bool usesWasmByteOrder() override { return true; } + void warm() override; + private: template void registerHostFunctionImpl(std::string_view module_name, std::string_view function_name, @@ -107,6 +109,9 @@ class Wamr : public WasmVm { void getModuleFunctionImpl(std::string_view function_name, std::function *function); + // Initialize the Wamr store if necessary. + void initStore(); + WasmStorePtr store_; WasmModulePtr module_; WasmSharedModulePtr shared_module_; @@ -119,9 +124,16 @@ class Wamr : public WasmVm { std::unordered_map module_functions_; }; +void Wamr::initStore() { + if (store_ != nullptr) { + return; + } + store_ = wasm_store_new(engine()); +} + bool Wamr::load(std::string_view bytecode, std::string_view precompiled, const std::unordered_map & /*function_names*/) { - store_ = wasm_store_new(engine()); + initStore(); if (store_ == nullptr) { return false; } @@ -697,6 +709,8 @@ void Wamr::getModuleFunctionImpl(std::string_view function_name, }; }; +void Wamr::warm() { initStore(); } + } // namespace wamr std::unique_ptr createWamrVm() { return std::make_unique(); } diff --git a/src/wasm.cc b/src/wasm.cc index e8a7ce436..a1b4c1836 100644 --- a/src/wasm.cc +++ b/src/wasm.cc @@ -378,7 +378,9 @@ ContextBase *WasmBase::getRootContext(const std::shared_ptr &plugin, void WasmBase::startVm(ContextBase *root_context) { // wasi_snapshot_preview1.clock_time_get wasm_vm_->setRestrictedCallback( - true, {// logging (Proxy-Wasm) + true, {// emscripten + "env.emscripten_notify_memory_growth", + // logging (Proxy-Wasm) "env.proxy_log", // logging (stdout/stderr) "wasi_unstable.fd_write", "wasi_snapshot_preview1.fd_write", diff --git a/src/wasmedge/wasmedge.cc b/src/wasmedge/wasmedge.cc index 38b8a9c9c..30fe78f5e 100644 --- a/src/wasmedge/wasmedge.cc +++ b/src/wasmedge/wasmedge.cc @@ -19,6 +19,7 @@ #include "wasmedge/wasmedge.h" +#include #include #include #include @@ -224,9 +225,6 @@ using HostModuleDataPtr = std::unique_ptr; class WasmEdge : public WasmVm { public: WasmEdge() { - loader_ = WasmEdge_LoaderCreate(nullptr); - validator_ = WasmEdge_ValidatorCreate(nullptr); - executor_ = WasmEdge_ExecutorCreate(nullptr, nullptr); store_ = nullptr; ast_module_ = nullptr; module_ = nullptr; @@ -263,6 +261,9 @@ class WasmEdge : public WasmVm { }; FOR_ALL_WASM_VM_EXPORTS(_GET_MODULE_FUNCTION) #undef _GET_MODULE_FUNCTION + + void warm() override; + private: template void registerHostFunctionImpl(std::string_view module_name, std::string_view function_name, @@ -283,6 +284,9 @@ class WasmEdge : public WasmVm { void terminate() override {} bool usesWasmByteOrder() override { return true; } + // Initialize the WasmEdge store if necessary. + void initStore(); + WasmEdgeLoaderPtr loader_; WasmEdgeValidatorPtr validator_; WasmEdgeExecutorPtr executor_; @@ -298,6 +302,7 @@ class WasmEdge : public WasmVm { bool WasmEdge::load(std::string_view bytecode, std::string_view /*precompiled*/, const std::unordered_map & /*function_names*/) { + initStore(); WasmEdge_ASTModuleContext *mod = nullptr; WasmEdge_Result res = WasmEdge_LoaderParseFromBuffer( loader_.get(), &mod, reinterpret_cast(bytecode.data()), bytecode.size()); @@ -313,13 +318,21 @@ bool WasmEdge::load(std::string_view bytecode, std::string_view /*precompiled*/, return true; } +void WasmEdge::initStore() { + if (store_ != nullptr) { + return; + } + loader_ = WasmEdge_LoaderCreate(nullptr); + validator_ = WasmEdge_ValidatorCreate(nullptr); + executor_ = WasmEdge_ExecutorCreate(nullptr, nullptr); + store_ = WasmEdge_StoreCreate(); +} + bool WasmEdge::link(std::string_view /*debug_name*/) { assert(ast_module_ != nullptr); // Create store and register imports. - if (store_ == nullptr) { - store_ = WasmEdge_StoreCreate(); - } + initStore(); if (store_ == nullptr) { return false; } @@ -608,6 +621,8 @@ void WasmEdge::getModuleFunctionImpl(std::string_view function_name, }; } +void WasmEdge::warm() { initStore(); } + } // namespace WasmEdge std::unique_ptr createWasmEdgeVm() { return std::make_unique(); } diff --git a/src/wasmtime/wasmtime.cc b/src/wasmtime/wasmtime.cc index c4a7646f0..a72a0361d 100644 --- a/src/wasmtime/wasmtime.cc +++ b/src/wasmtime/wasmtime.cc @@ -80,6 +80,9 @@ class Wasmtime : public WasmVm { }; FOR_ALL_WASM_VM_EXPORTS(_GET_MODULE_FUNCTION) #undef _GET_MODULE_FUNCTION + + void warm() override; + private: template void registerHostFunctionImpl(std::string_view module_name, std::string_view function_name, @@ -100,6 +103,9 @@ class Wasmtime : public WasmVm { void terminate() override {} bool usesWasmByteOrder() override { return true; } + // Initialize the Wasmtime store if necessary. + void initStore(); + WasmStorePtr store_; WasmModulePtr module_; WasmSharedModulePtr shared_module_; @@ -111,9 +117,16 @@ class Wasmtime : public WasmVm { std::unordered_map module_functions_; }; +void Wasmtime::initStore() { + if (store_ != nullptr) { + return; + } + store_ = wasm_store_new(engine()); +} + bool Wasmtime::load(std::string_view bytecode, std::string_view /*precompiled*/, const std::unordered_map & /*function_names*/) { - store_ = wasm_store_new(engine()); + initStore(); if (store_ == nullptr) { return false; } @@ -693,6 +706,8 @@ void Wasmtime::getModuleFunctionImpl(std::string_view function_name, }; }; +void Wasmtime::warm() { initStore(); } + } // namespace wasmtime std::unique_ptr createWasmtimeVm() { return std::make_unique(); } diff --git a/src/wavm/wavm.cc b/src/wavm/wavm.cc deleted file mode 100644 index 670eb7c41..000000000 --- a/src/wavm/wavm.cc +++ /dev/null @@ -1,492 +0,0 @@ -// Copyright 2016-2019 Envoy Project Authors -// Copyright 2020 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "include/proxy-wasm/wavm.h" -#include "include/proxy-wasm/wasm_vm.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "WAVM/IR/Module.h" -#include "WAVM/IR/Operators.h" -#include "WAVM/IR/Types.h" -#include "WAVM/IR/Validate.h" -#include "WAVM/IR/Value.h" -#include "WAVM/Inline/Assert.h" -#include "WAVM/Inline/BasicTypes.h" -#include "WAVM/Inline/Errors.h" -#include "WAVM/Inline/Hash.h" -#include "WAVM/Inline/HashMap.h" -#include "WAVM/Inline/IndexMap.h" -#include "WAVM/Inline/IntrusiveSharedPtr.h" -#include "WAVM/Platform/Mutex.h" -#include "WAVM/Platform/Thread.h" -#include "WAVM/Runtime/Intrinsics.h" -#include "WAVM/Runtime/Linker.h" -#include "WAVM/Runtime/Runtime.h" -#include "WAVM/RuntimeABI/RuntimeABI.h" -#include "WAVM/WASM/WASM.h" -#include "WAVM/WASTParse/WASTParse.h" - -#ifdef NDEBUG -#define ASSERT(_x) _x -#else -#define ASSERT(_x) \ - do { \ - if (!_x) \ - ::exit(1); \ - } while (0) -#endif - -using namespace WAVM; -using namespace WAVM::IR; - -namespace WAVM::IR { -template <> constexpr ValueType inferValueType() { return ValueType::i32; } -} // namespace WAVM::IR - -namespace proxy_wasm { - -// Forward declarations. -template -void getFunctionWavm(WasmVm *vm, std::string_view function_name, - std::function *function); -template -void getFunctionWavm(WasmVm *vm, std::string_view function_name, - std::function *function); -template -void registerCallbackWavm(WasmVm *vm, std::string_view module_name, std::string_view function_name, - R (*function)(Args...)); - -namespace Wavm { - -struct Wavm; - -namespace { - -#define CALL_WITH_CONTEXT(_x, _context, _wavm) \ - do { \ - try { \ - SaveRestoreContext _saved_context(static_cast(_context)); \ - WAVM::Runtime::catchRuntimeExceptions( \ - [&] { _x; }, \ - [&](WAVM::Runtime::Exception *exception) { \ - _wavm->fail(FailState::RuntimeError, getFailMessage(function_name, exception)); \ - throw std::exception(); \ - }); \ - } catch (...) { \ - } \ - } while (0) - -std::string getFailMessage(std::string_view function_name, WAVM::Runtime::Exception *exception) { - std::string message = "Function: " + std::string(function_name) + - " failed: " + WAVM::Runtime::describeExceptionType(exception->type) + - "\nProxy-Wasm plugin in-VM backtrace:\n"; - std::vector callstack_descriptions = - WAVM::Runtime::describeCallStack(exception->callStack); - - // Since the first frame is on host and useless for developers, e.g.: `host!envoy+112901013` - // we start with index 1 here - for (size_t i = 1; i < callstack_descriptions.size(); i++) { - std::ostringstream oss; - std::string description = callstack_descriptions[i]; - if (description.find("wasm!") == std::string::npos) { - // end of WASM's call stack - break; - } - oss << std::setw(3) << std::setfill(' ') << std::to_string(i); - message += oss.str() + ": " + description + "\n"; - } - - WAVM::Runtime::destroyException(exception); - return message; -} - -struct WasmUntaggedValue : public WAVM::IR::UntaggedValue { - WasmUntaggedValue() = default; - WasmUntaggedValue(I32 inI32) { i32 = inI32; } - WasmUntaggedValue(I64 inI64) { i64 = inI64; } - WasmUntaggedValue(U32 inU32) { u32 = inU32; } - WasmUntaggedValue(Word w) { u32 = static_cast(w.u64_); } - WasmUntaggedValue(U64 inU64) { u64 = inU64; } - WasmUntaggedValue(F32 inF32) { f32 = inF32; } - WasmUntaggedValue(F64 inF64) { f64 = inF64; } -}; - -class RootResolver : public WAVM::Runtime::Resolver { -public: - RootResolver(WAVM::Runtime::Compartment * /*compartment*/, WasmVm *vm) : vm_(vm) {} - - ~RootResolver() override { module_name_to_instance_map_.clear(); } - - bool resolve(const std::string &module_name, const std::string &export_name, ExternType type, - WAVM::Runtime::Object *&out_object) override { - auto *named_instance = module_name_to_instance_map_.get(module_name); - if (named_instance != nullptr) { - out_object = getInstanceExport(*named_instance, export_name); - if (out_object != nullptr) { - if (!isA(out_object, type)) { - vm_->fail(FailState::UnableToInitializeCode, - "Failed to load WASM module due to a type mismatch in an import: " + - std::string(module_name) + "." + export_name + " " + - asString(WAVM::Runtime::getExternType(out_object)) + - " but was expecting type: " + asString(type)); - return false; - } - return true; - } - } - for (auto *r : resolvers_) { - if (r->resolve(module_name, export_name, type, out_object)) { - return true; - } - } - vm_->fail(FailState::MissingFunction, - "Failed to load Wasm module due to a missing import: " + std::string(module_name) + - "." + std::string(export_name) + " " + asString(type)); - return false; - } - - HashMap &moduleNameToInstanceMap() { - return module_name_to_instance_map_; - } - - void addResolver(WAVM::Runtime::Resolver *r) { resolvers_.push_back(r); } - -private: - WasmVm *vm_; - HashMap module_name_to_instance_map_{}; - std::vector resolvers_{}; -}; - -const uint64_t WasmPageSize = 1 << 16; - -} // namespace - -template struct NativeWord { using type = T; }; -template <> struct NativeWord { using type = uint32_t; }; - -template typename NativeWord::type ToNative(const T &t) { return t; } -template <> typename NativeWord::type ToNative(const Word &t) { return t.u32(); } - -struct PairHash { - template std::size_t operator()(const std::pair &x) const { - return std::hash()(x.first) + std::hash()(x.second); - } -}; - -struct Wavm : public WasmVm { - Wavm() = default; - ~Wavm() override; - - // WasmVm - std::string_view getEngineName() override { return "wavm"; } - Cloneable cloneable() override { return Cloneable::InstantiatedModule; }; - std::unique_ptr clone() override; - bool load(std::string_view bytecode, std::string_view precompiled, - const std::unordered_map &function_names) override; - bool link(std::string_view debug_name) override; - uint64_t getMemorySize() override; - std::optional getMemory(uint64_t pointer, uint64_t size) override; - bool setMemory(uint64_t pointer, uint64_t size, const void *data) override; - bool getWord(uint64_t pointer, Word *data) override; - bool setWord(uint64_t pointer, Word data) override; - size_t getWordSize() override { return sizeof(uint32_t); }; - std::string_view getPrecompiledSectionName() override; - -#define _GET_FUNCTION(_T) \ - void getFunction(std::string_view function_name, _T *f) override { \ - getFunctionWavm(this, function_name, f); \ - }; - FOR_ALL_WASM_VM_EXPORTS(_GET_FUNCTION) -#undef _GET_FUNCTION - -#define _REGISTER_CALLBACK(_T) \ - void registerCallback(std::string_view module_name, std::string_view function_name, _T, \ - typename ConvertFunctionTypeWordToUint32<_T>::type f) override { \ - registerCallbackWavm(this, module_name, function_name, f); \ - }; - FOR_ALL_WASM_VM_IMPORTS(_REGISTER_CALLBACK) -#undef _REGISTER_CALLBACK - - void terminate() override {} - bool usesWasmByteOrder() override { return true; } - - IR::Module ir_module_; - WAVM::Runtime::ModuleRef module_ = nullptr; - WAVM::Runtime::GCPointer module_instance_; - WAVM::Runtime::Memory *memory_{}; - WAVM::Runtime::GCPointer compartment_; - WAVM::Runtime::GCPointer context_; - std::map intrinsic_modules_{}; - std::map> - intrinsic_module_instances_{}; - std::vector> host_functions_{}; - uint8_t *memory_base_ = nullptr; -}; - -Wavm::~Wavm() { - module_instance_ = nullptr; - context_ = nullptr; - intrinsic_module_instances_.clear(); - intrinsic_modules_.clear(); - host_functions_.clear(); - if (compartment_ != nullptr) { - ASSERT(tryCollectCompartment(std::move(compartment_))); - } -} - -std::unique_ptr Wavm::clone() { - auto wavm = std::make_unique(); - if (wavm == nullptr) { - return nullptr; - } - - wavm->compartment_ = WAVM::Runtime::cloneCompartment(compartment_); - if (wavm->compartment_ == nullptr) { - return nullptr; - } - - wavm->context_ = WAVM::Runtime::cloneContext(context_, wavm->compartment_); - if (wavm->context_ == nullptr) { - return nullptr; - } - - wavm->memory_ = WAVM::Runtime::remapToClonedCompartment(memory_, wavm->compartment_); - wavm->memory_base_ = WAVM::Runtime::getMemoryBaseAddress(wavm->memory_); - wavm->module_instance_ = - WAVM::Runtime::remapToClonedCompartment(module_instance_, wavm->compartment_); - - for (auto &p : intrinsic_module_instances_) { - wavm->intrinsic_module_instances_.emplace( - p.first, WAVM::Runtime::remapToClonedCompartment(p.second, wavm->compartment_)); - } - - auto *integration_clone = integration()->clone(); - if (integration_clone == nullptr) { - return nullptr; - } - wavm->integration().reset(integration_clone); - - return wavm; -} - -bool Wavm::load(std::string_view bytecode, std::string_view precompiled, - const std::unordered_map & /*function_names*/) { - compartment_ = WAVM::Runtime::createCompartment(); - if (compartment_ == nullptr) { - return false; - } - - context_ = WAVM::Runtime::createContext(compartment_); - if (context_ == nullptr) { - return false; - } - - if (!WASM::loadBinaryModule(reinterpret_cast(bytecode.data()), - bytecode.size(), ir_module_)) { - return false; - } - - if (!precompiled.empty()) { - module_ = WAVM::Runtime::loadPrecompiledModule( - ir_module_, {precompiled.data(), precompiled.data() + precompiled.size()}); - if (module_ == nullptr) { - return false; - } - - } else { - module_ = WAVM::Runtime::compileModule(ir_module_); - if (module_ == nullptr) { - return false; - } - } - - return true; -} - -bool Wavm::link(std::string_view debug_name) { - RootResolver rootResolver(compartment_, this); - for (auto &p : intrinsic_modules_) { - auto *instance = Intrinsics::instantiateModule(compartment_, {&intrinsic_modules_[p.first]}, - std::string(p.first)); - if (instance == nullptr) { - return false; - } - intrinsic_module_instances_.emplace(p.first, instance); - rootResolver.moduleNameToInstanceMap().set(p.first, instance); - } - - WAVM::Runtime::LinkResult link_result = linkModule(ir_module_, rootResolver); - if (!link_result.missingImports.empty()) { - for (auto &i : link_result.missingImports) { - integration()->error("Missing Wasm import " + i.moduleName + " " + i.exportName); - } - fail(FailState::MissingFunction, "Failed to load Wasm module due to a missing import(s)"); - return false; - } - - module_instance_ = instantiateModule( - compartment_, module_, std::move(link_result.resolvedImports), std::string(debug_name)); - if (module_instance_ == nullptr) { - return false; - } - - memory_ = getDefaultMemory(module_instance_); - if (memory_ == nullptr) { - return false; - } - - memory_base_ = WAVM::Runtime::getMemoryBaseAddress(memory_); - - return true; -} - -uint64_t Wavm::getMemorySize() { return WAVM::Runtime::getMemoryNumPages(memory_) * WasmPageSize; } - -std::optional Wavm::getMemory(uint64_t pointer, uint64_t size) { - auto memory_num_bytes = WAVM::Runtime::getMemoryNumPages(memory_) * WasmPageSize; - if (pointer + size > memory_num_bytes) { - return std::nullopt; - } - return std::string_view(reinterpret_cast(memory_base_ + pointer), size); -} - -bool Wavm::setMemory(uint64_t pointer, uint64_t size, const void *data) { - auto memory_num_bytes = WAVM::Runtime::getMemoryNumPages(memory_) * WasmPageSize; - if (pointer + size > memory_num_bytes) { - return false; - } - auto *p = reinterpret_cast(memory_base_ + pointer); - memcpy(p, data, size); - return true; -} - -bool Wavm::getWord(uint64_t pointer, Word *data) { - auto memory_num_bytes = WAVM::Runtime::getMemoryNumPages(memory_) * WasmPageSize; - if (pointer + sizeof(uint32_t) > memory_num_bytes) { - return false; - } - auto *p = reinterpret_cast(memory_base_ + pointer); - uint32_t data32; - memcpy(&data32, p, sizeof(uint32_t)); - data->u64_ = wasmtoh(data32, true); - return true; -} - -bool Wavm::setWord(uint64_t pointer, Word data) { - uint32_t data32 = htowasm(data.u32(), true); - return setMemory(pointer, sizeof(uint32_t), &data32); -} - -std::string_view Wavm::getPrecompiledSectionName() { return "wavm.precompiled_object"; } - -} // namespace Wavm - -std::unique_ptr createWavmVm() { return std::make_unique(); } - -template -IR::FunctionType inferHostFunctionType(R (*/*func*/)(Args...)) { - return IR::FunctionType(IR::inferResultType(), IR::TypeTuple({IR::inferValueType()...}), - IR::CallingConvention::c); -} - -using namespace Wavm; - -template -void registerCallbackWavm(WasmVm *vm, std::string_view module_name, std::string_view function_name, - R (*f)(Args...)) { - auto *wavm = dynamic_cast(vm); - wavm->host_functions_.emplace_back(new Intrinsics::Function( - &wavm->intrinsic_modules_[std::string(module_name)], function_name.data(), - reinterpret_cast(f), inferHostFunctionType(f))); -} - -template -IR::FunctionType inferStdFunctionType(std::function * /*func*/) { - return IR::FunctionType(IR::inferResultType(), IR::TypeTuple({IR::inferValueType()...})); -} - -static bool checkFunctionType(WAVM::Runtime::Function *f, IR::FunctionType t) { - return getFunctionType(f) == t; -} - -template -void getFunctionWavm(WasmVm *vm, std::string_view function_name, - std::function *function) { - auto *wavm = dynamic_cast(vm); - auto *f = - asFunctionNullable(getInstanceExport(wavm->module_instance_, std::string(function_name))); - if (!f) { - f = asFunctionNullable(getInstanceExport(wavm->module_instance_, std::string(function_name))); - } - if (!f) { - *function = nullptr; - return; - } - if (!checkFunctionType(f, inferStdFunctionType(function))) { - *function = nullptr; - wavm->fail(FailState::UnableToInitializeCode, - "Bad function signature for: " + std::string(function_name)); - return; - } - *function = [wavm, f, function_name](ContextBase *context, Args... args) -> R { - WasmUntaggedValue values[] = {args...}; - WasmUntaggedValue return_value; - CALL_WITH_CONTEXT( - invokeFunction(wavm->context_, f, getFunctionType(f), &values[0], &return_value), context, - wavm); - if (wavm->isFailed()) { - return 0; - } - return static_cast(return_value.i32); - }; -} - -template -void getFunctionWavm(WasmVm *vm, std::string_view function_name, - std::function *function) { - auto *wavm = dynamic_cast(vm); - auto *f = - asFunctionNullable(getInstanceExport(wavm->module_instance_, std::string(function_name))); - if (!f) { - f = asFunctionNullable(getInstanceExport(wavm->module_instance_, std::string(function_name))); - } - if (!f) { - *function = nullptr; - return; - } - if (!checkFunctionType(f, inferStdFunctionType(function))) { - *function = nullptr; - wavm->fail(FailState::UnableToInitializeCode, - "Bad function signature for: " + std::string(function_name)); - return; - } - *function = [wavm, f, function_name](ContextBase *context, Args... args) { - WasmUntaggedValue values[] = {args...}; - CALL_WITH_CONTEXT(invokeFunction(wavm->context_, f, getFunctionType(f), &values[0]), context, - wavm); - }; -} - -} // namespace proxy_wasm diff --git a/test/BUILD b/test/BUILD index 61973ce17..97e70558a 100644 --- a/test/BUILD +++ b/test/BUILD @@ -13,7 +13,8 @@ # limitations under the License. load("@proxy_wasm_cpp_host//bazel:select.bzl", "proxy_wasm_select_engine_null") -load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") +load("@rules_cc//cc:defs.bzl", "cc_library") +load("//bazel:cc_defs.bzl", "cc_test") licenses(["notice"]) # Apache 2 @@ -132,6 +133,21 @@ cc_test( ], ) +cc_test( + name = "stop_iteration_test", + srcs = ["stop_iteration_test.cc"], + data = [ + "//test/test_data:stop_iteration.wasm", + ], + linkstatic = 1, + deps = [ + ":utility_lib", + "//:lib", + "@com_google_googletest//:gtest", + "@com_google_googletest//:gtest_main", + ], +) + cc_test( name = "security_test", srcs = ["security_test.cc"], diff --git a/test/fuzz/BUILD b/test/fuzz/BUILD index 71b099007..2221f6367 100644 --- a/test/fuzz/BUILD +++ b/test/fuzz/BUILD @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@rules_fuzzing//fuzzing:cc_defs.bzl", "cc_fuzz_test") +load("//bazel:cc_defs.bzl", "cc_fuzz_test") licenses(["notice"]) # Apache 2 diff --git a/test/runtime_test.cc b/test/runtime_test.cc index 16b4f763a..2e9080978 100644 --- a/test/runtime_test.cc +++ b/test/runtime_test.cc @@ -53,12 +53,6 @@ TEST_P(TestVm, BadSignature) { } TEST_P(TestVm, StraceLogLevel) { - if (engine_ == "wavm") { - // TODO(mathetake): strace is yet to be implemented for WAVM. - // See https://github.com/proxy-wasm/proxy-wasm-cpp-host/issues/120. - return; - } - auto source = readTestWasmFile("clock.wasm"); ASSERT_FALSE(source.empty()); auto wasm = TestWasm(std::move(vm_)); @@ -108,7 +102,7 @@ TEST_P(TestVm, TerminateExecution) { // Check integration logs. auto *host = dynamic_cast(wasm.wasm_vm()->integration().get()); EXPECT_TRUE(host->isErrorLogged("Function: infinite_loop failed")); - EXPECT_TRUE(host->isErrorLogged("termination_exception")); + EXPECT_TRUE(host->isErrorLogged("TerminationException")); } TEST_P(TestVm, WasmMemoryLimit) { @@ -134,11 +128,7 @@ TEST_P(TestVm, WasmMemoryLimit) { auto *host = dynamic_cast(wasm.wasm_vm()->integration().get()); EXPECT_TRUE(host->isErrorLogged("Function: infinite_memory failed")); // Trap message - if (engine_ == "wavm") { - EXPECT_TRUE(host->isErrorLogged("wavm.reachedUnreachable")); - } else { - EXPECT_TRUE(host->isErrorLogged("unreachable")); - } + EXPECT_TRUE(host->isErrorLogged("unreachable")); // Backtrace if (engine_ == "v8") { EXPECT_TRUE(host->isErrorLogged("Proxy-Wasm plugin in-VM backtrace:")); @@ -163,11 +153,7 @@ TEST_P(TestVm, Trap) { auto *host = dynamic_cast(wasm.wasm_vm()->integration().get()); EXPECT_TRUE(host->isErrorLogged("Function: trigger failed")); // Trap message - if (engine_ == "wavm") { - EXPECT_TRUE(host->isErrorLogged("wavm.reachedUnreachable")); - } else { - EXPECT_TRUE(host->isErrorLogged("unreachable")); - } + EXPECT_TRUE(host->isErrorLogged("unreachable")); // Backtrace if (engine_ == "v8") { EXPECT_TRUE(host->isErrorLogged("Proxy-Wasm plugin in-VM backtrace:")); @@ -192,11 +178,7 @@ TEST_P(TestVm, Trap2) { auto *host = dynamic_cast(wasm.wasm_vm()->integration().get()); EXPECT_TRUE(host->isErrorLogged("Function: trigger2 failed")); // Trap message - if (engine_ == "wavm") { - EXPECT_TRUE(host->isErrorLogged("wavm.reachedUnreachable")); - } else { - EXPECT_TRUE(host->isErrorLogged("unreachable")); - } + EXPECT_TRUE(host->isErrorLogged("unreachable")); // Backtrace if (engine_ == "v8") { EXPECT_TRUE(host->isErrorLogged("Proxy-Wasm plugin in-VM backtrace:")); diff --git a/test/stop_iteration_test.cc b/test/stop_iteration_test.cc new file mode 100644 index 000000000..9ff443f24 --- /dev/null +++ b/test/stop_iteration_test.cc @@ -0,0 +1,81 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "gtest/gtest.h" +#include "include/proxy-wasm/wasm.h" +#include "test/utility.h" + +namespace proxy_wasm { + +INSTANTIATE_TEST_SUITE_P(WasmEngines, TestVm, testing::ValuesIn(getWasmEngines()), + [](const testing::TestParamInfo &info) { + return info.param; + }); + +// TestVm is parameterized for each engine and creates a VM on construction. +TEST_P(TestVm, AllowOnHeadersStopIteration) { + // Read the wasm source. + auto source = readTestWasmFile("stop_iteration.wasm"); + ASSERT_FALSE(source.empty()); + + // Create a WasmBase and load the plugin. + auto wasm = std::make_shared(std::move(vm_)); + ASSERT_TRUE(wasm->load(source, /*allow_precompiled=*/false)); + ASSERT_TRUE(wasm->initialize()); + + // Create a plugin. + const auto plugin = std::make_shared( + /*name=*/"test", /*root_id=*/"", /*vm_id=*/"", + /*engine=*/wasm->wasm_vm()->getEngineName(), /*plugin_config=*/"", + /*fail_open=*/false, /*key=*/""); + + // Create root context, call onStart() and onConfigure() + ContextBase *root_context = wasm->start(plugin); + ASSERT_TRUE(root_context != nullptr); + ASSERT_TRUE(wasm->configure(root_context, plugin)); + + auto wasm_handle = std::make_shared(wasm); + auto plugin_handle = std::make_shared(wasm_handle, plugin); + + // By default, stream context onRequestHeaders and onResponseHeaders + // translates FilterHeadersStatus::StopIteration to + // FilterHeadersStatus::StopAllIterationAndWatermark. + { + auto stream_context = TestContext(wasm.get(), root_context->id(), plugin_handle); + stream_context.onCreate(); + EXPECT_EQ(stream_context.onRequestHeaders(/*headers=*/0, /*end_of_stream=*/false), + FilterHeadersStatus::StopAllIterationAndWatermark); + EXPECT_EQ(stream_context.onResponseHeaders(/*headers=*/0, /*end_of_stream=*/false), + FilterHeadersStatus::StopAllIterationAndWatermark); + stream_context.onDone(); + stream_context.onDelete(); + } + ASSERT_FALSE(wasm->isFailed()); + + // Create a stream context that propagates FilterHeadersStatus::StopIteration. + { + auto stream_context = TestContext(wasm.get(), root_context->id(), plugin_handle); + stream_context.set_allow_on_headers_stop_iteration(true); + stream_context.onCreate(); + EXPECT_EQ(stream_context.onRequestHeaders(/*headers=*/0, /*end_of_stream=*/false), + FilterHeadersStatus::StopIteration); + EXPECT_EQ(stream_context.onResponseHeaders(/*headers=*/0, /*end_of_stream=*/false), + FilterHeadersStatus::StopIteration); + stream_context.onDone(); + stream_context.onDelete(); + } + ASSERT_FALSE(wasm->isFailed()); +} + +} // namespace proxy_wasm diff --git a/test/test_data/BUILD b/test/test_data/BUILD index bd70b8eb9..e5ecd439e 100644 --- a/test/test_data/BUILD +++ b/test/test_data/BUILD @@ -89,3 +89,8 @@ proxy_wasm_cc_binary( name = "http_logging.wasm", srcs = ["http_logging.cc"], ) + +proxy_wasm_cc_binary( + name = "stop_iteration.wasm", + srcs = ["stop_iteration.cc"], +) diff --git a/test/test_data/stop_iteration.cc b/test/test_data/stop_iteration.cc new file mode 100644 index 000000000..55594285f --- /dev/null +++ b/test/test_data/stop_iteration.cc @@ -0,0 +1,31 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "proxy_wasm_intrinsics.h" + +class StopIterationContext : public Context { +public: + explicit StopIterationContext(uint32_t id, RootContext *root) : Context(id, root) {} + + FilterHeadersStatus onRequestHeaders(uint32_t headers, bool end_of_stream) override { + return FilterHeadersStatus::StopIteration; + } + + FilterHeadersStatus onResponseHeaders(uint32_t headers, bool end_of_stream) override { + return FilterHeadersStatus::StopIteration; + } +}; + +static RegisterContextFactory register_StaticContext(CONTEXT_FACTORY(StopIterationContext), + ROOT_FACTORY(RootContext)); diff --git a/test/utility.cc b/test/utility.cc index ee6f2b951..7bdf9d2ad 100644 --- a/test/utility.cc +++ b/test/utility.cc @@ -21,22 +21,18 @@ std::string TestContext::global_log_; std::vector getWasmEngines() { std::vector engines = { #if defined(PROXY_WASM_HOST_ENGINE_V8) - "v8", + "v8", #endif #if defined(PROXY_WASM_HOST_ENGINE_WAMR) - "wamr", + "wamr", #endif #if defined(PROXY_WASM_HOST_ENGINE_WASMEDGE) - "wasmedge", + "wasmedge", #endif #if defined(PROXY_WASM_HOST_ENGINE_WASMTIME) - "wasmtime", + "wasmtime", #endif -#if defined(PROXY_WASM_HOST_ENGINE_WAVM) - "wavm", -#endif - "" - }; + ""}; engines.pop_back(); return engines; } diff --git a/test/utility.h b/test/utility.h index 27b3b0493..0eb743037 100644 --- a/test/utility.h +++ b/test/utility.h @@ -27,9 +27,6 @@ #if defined(PROXY_WASM_HOST_ENGINE_V8) #include "include/proxy-wasm/v8.h" #endif -#if defined(PROXY_WASM_HOST_ENGINE_WAVM) -#include "include/proxy-wasm/wavm.h" -#endif #if defined(PROXY_WASM_HOST_ENGINE_WASMTIME) #include "include/proxy-wasm/wasmtime.h" #endif @@ -133,6 +130,8 @@ class TestContext : public ContextBase { .count(); } + void set_allow_on_headers_stop_iteration(bool allow) { allow_on_headers_stop_iteration_ = allow; } + private: std::string log_; static std::string global_log_; @@ -170,10 +169,6 @@ class TestVm : public testing::TestWithParam { } else if (engine == "v8") { vm = proxy_wasm::createV8Vm(); #endif -#if defined(PROXY_WASM_HOST_ENGINE_WAVM) - } else if (engine == "wavm") { - vm = proxy_wasm::createWavmVm(); -#endif #if defined(PROXY_WASM_HOST_ENGINE_WASMTIME) } else if (engine == "wasmtime") { vm = proxy_wasm::createWasmtimeVm(); @@ -197,4 +192,7 @@ class TestVm : public testing::TestWithParam { std::string engine_; }; +// TODO: remove when #412 is fixed. +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TestVm); + } // namespace proxy_wasm diff --git a/test/wasm_vm_test.cc b/test/wasm_vm_test.cc index 6b4ece60f..346fe2a07 100644 --- a/test/wasm_vm_test.cc +++ b/test/wasm_vm_test.cc @@ -30,13 +30,44 @@ INSTANTIATE_TEST_SUITE_P(WasmEngines, TestVm, testing::ValuesIn(getWasmEngines() return info.param; }); +TEST_P(TestVm, Init) { + auto time1 = std::chrono::steady_clock::now(); + vm_->warm(); + auto time2 = std::chrono::steady_clock::now(); + vm_->warm(); + auto time3 = std::chrono::steady_clock::now(); + + auto cold = std::chrono::duration_cast(time2 - time1).count(); + auto warm = std::chrono::duration_cast(time3 - time2).count(); + + std::cout << "[" << engine_ << "] \"cold\" engine time: " << cold << "ns" << std::endl; + std::cout << "[" << engine_ << "] \"warm\" engine time: " << warm << "ns" << std::endl; + + // Default warm time in nanoseconds. + int warm_time_ns_limit = 10000; + +#if defined(__linux__) && defined(__s390x__) + // Linux 390x is significantly slower, so we use a more lenient limit. + warm_time_ns_limit = 75000; +#endif + + // Verify that getting a "warm" engine takes less than 10us. + EXPECT_LE(warm, warm_time_ns_limit); + + // Verify that getting a "warm" engine takes at least 50x less time than getting a "cold" one. + // We skip NullVM because warm() is a noop. + if (engine_ == "null") { + std::cout << "Skipping warm() performance assertions for NullVM." << std::endl; + return; + } + EXPECT_LE(warm * 50, cold); +} + TEST_P(TestVm, Basic) { if (engine_ == "wasmedge") { EXPECT_EQ(vm_->cloneable(), proxy_wasm::Cloneable::NotCloneable); } else if (engine_ == "wasmtime" || engine_ == "v8" || engine_ == "wamr") { EXPECT_EQ(vm_->cloneable(), proxy_wasm::Cloneable::CompiledBytecode); - } else if (engine_ == "wavm") { - EXPECT_EQ(vm_->cloneable(), proxy_wasm::Cloneable::InstantiatedModule); } else { FAIL(); } @@ -91,14 +122,10 @@ TEST_P(TestVm, Clone) { #if defined(__linux__) && defined(__x86_64__) -TEST_P(TestVm, CloneUntilOutOfMemory) { +TEST_P(TestVm, DISABLED_CloneUntilOutOfMemory) { if (vm_->cloneable() == proxy_wasm::Cloneable::NotCloneable) { return; } - if (engine_ == "wavm") { - // TODO(PiotrSikora): Figure out why this fails on the CI. - return; - } auto source = readTestWasmFile("abi_export.wasm"); ASSERT_TRUE(vm_->load(source, {}, {}));