mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a98ed797e | ||
|
|
ce5a8fefa6 | ||
|
|
0ce3c29db1 | ||
|
|
886b453b6d | ||
|
|
b206e7d5ac | ||
|
|
4bfc9cd193 | ||
|
|
32dd4aa025 | ||
|
|
2076981802 | ||
|
|
6d8485193b | ||
|
|
79ecc56d33 | ||
|
|
6d7653383a | ||
|
|
24faedab76 | ||
|
|
2eb7880cf1 | ||
|
|
8ca9e1543d | ||
|
|
fe869081b3 | ||
|
|
914d8f373e | ||
|
|
0bd7092e74 | ||
|
|
5cdfdcdffb | ||
|
|
fc5ee6d319 | ||
|
|
0529300980 | ||
|
|
3a142b6c4f | ||
|
|
3fd34fc4b6 | ||
|
|
dcf12182b8 | ||
|
|
537e8c3bea | ||
|
|
3041c956ce | ||
|
|
c57f515e43 | ||
|
|
4b3d3a5f07 | ||
|
|
0b51976cd2 | ||
|
|
4e1f54087d | ||
|
|
d2ffa6fe31 | ||
|
|
f7bb17ebd1 | ||
|
|
f9ed0eaee4 | ||
|
|
8933e7e2a9 | ||
|
|
262f4d34cf | ||
|
|
b721d420d5 |
@@ -33,7 +33,7 @@ parameters:
|
||||
macos-publish-arch-limit:
|
||||
type: enum
|
||||
default: all
|
||||
enum: ["all", "osx-x64", "osx-arm64", "mas-x64", "mas-arm64"]
|
||||
enum: ["all", "osx-arm64", "mas-arm64"]
|
||||
|
||||
medium-linux-executor:
|
||||
type: enum
|
||||
@@ -64,7 +64,7 @@ executors:
|
||||
size:
|
||||
description: "macOS executor size"
|
||||
type: enum
|
||||
enum: ["macos.x86.medium.gen2", "macos.m1.large.gen1", "macos.m1.medium.gen1"]
|
||||
enum: ["macos.m1.large.gen1", "macos.m1.medium.gen1"]
|
||||
version:
|
||||
description: "xcode version"
|
||||
type: enum
|
||||
@@ -260,9 +260,9 @@ step-depot-tools-get: &step-depot-tools-get
|
||||
index c305c248..e6e0fbdc 100755
|
||||
--- a/gclient.py
|
||||
+++ b/gclient.py
|
||||
@@ -735,7 +735,8 @@ class Dependency(gclient_utils.WorkItem, DependencySettings):
|
||||
|
||||
if dep_type == 'cipd':
|
||||
@@ -783,7 +783,8 @@ class Dependency(gclient_utils.WorkItem, DependencySettings):
|
||||
not condition or "non_git_source" not in condition):
|
||||
continue
|
||||
cipd_root = self.GetCipdRoot()
|
||||
- for package in dep_value.get('packages', []):
|
||||
+ packages = dep_value.get('packages', [])
|
||||
@@ -1808,26 +1808,6 @@ jobs:
|
||||
build-type: 'nil'
|
||||
could-be-aks: false
|
||||
|
||||
mac-make-src-cache-x64:
|
||||
executor:
|
||||
name: linux-docker
|
||||
size: xlarge
|
||||
environment:
|
||||
<<: *env-linux-2xlarge
|
||||
<<: *env-testing-build
|
||||
<<: *env-macos-build
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac'
|
||||
steps:
|
||||
- electron-build:
|
||||
persist: false
|
||||
build: false
|
||||
checkout: true
|
||||
save-git-cache: true
|
||||
checkout-to-create-src-cache: true
|
||||
artifact-key: 'nil'
|
||||
build-type: 'nil'
|
||||
could-be-aks: false
|
||||
|
||||
mac-make-src-cache-arm64:
|
||||
executor:
|
||||
name: linux-docker
|
||||
@@ -2027,76 +2007,6 @@ jobs:
|
||||
checkout: true
|
||||
build-type: 'Linux ARM64'
|
||||
|
||||
osx-testing-x64:
|
||||
executor:
|
||||
name: macos
|
||||
size: macos.x86.medium.gen2
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
<<: *env-testing-build
|
||||
<<: *env-ninja-status
|
||||
<<: *env-macos-build
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac'
|
||||
steps:
|
||||
- electron-build:
|
||||
persist: true
|
||||
checkout: false
|
||||
checkout-and-assume-cache: true
|
||||
attach: true
|
||||
artifact-key: 'darwin-x64'
|
||||
build-type: 'Darwin'
|
||||
after-build-and-save:
|
||||
- run:
|
||||
name: Configuring MAS build
|
||||
command: |
|
||||
echo 'export GN_EXTRA_ARGS="is_mas_build = true $GN_EXTRA_ARGS"' >> $BASH_ENV
|
||||
echo 'export MAS_BUILD="true"' >> $BASH_ENV
|
||||
rm -rf "src/out/Default/Electron Framework.framework"
|
||||
rm -rf src/out/Default/Electron*.app
|
||||
- build_and_save_artifacts:
|
||||
artifact-key: 'mas-x64'
|
||||
build-type: 'MAS'
|
||||
after-persist:
|
||||
- persist_to_workspace:
|
||||
root: .
|
||||
paths:
|
||||
- generated_artifacts_mas-x64
|
||||
could-be-aks: false
|
||||
|
||||
osx-testing-x64-gn-check:
|
||||
executor:
|
||||
name: macos
|
||||
size: macos.x86.medium.gen2
|
||||
environment:
|
||||
<<: *env-machine-mac
|
||||
<<: *env-testing-build
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac'
|
||||
steps:
|
||||
- run-gn-check:
|
||||
could-be-aks: false
|
||||
|
||||
osx-publish-x64:
|
||||
executor:
|
||||
name: macos
|
||||
size: macos.x86.medium.gen2
|
||||
environment:
|
||||
<<: *env-mac-large-release
|
||||
<<: *env-release-build
|
||||
UPLOAD_TO_STORAGE: << pipeline.parameters.upload-to-storage >>
|
||||
<<: *env-ninja-status
|
||||
steps:
|
||||
- run: echo running
|
||||
- when:
|
||||
condition:
|
||||
or:
|
||||
- equal: ["all", << pipeline.parameters.macos-publish-arch-limit >>]
|
||||
- equal: ["osx-x64", << pipeline.parameters.macos-publish-arch-limit >>]
|
||||
steps:
|
||||
- electron-publish:
|
||||
attach: true
|
||||
checkout: false
|
||||
build-type: 'Darwin'
|
||||
|
||||
osx-publish-arm64:
|
||||
executor:
|
||||
name: macos
|
||||
@@ -2157,28 +2067,6 @@ jobs:
|
||||
- generated_artifacts_mas-arm64
|
||||
could-be-aks: false
|
||||
|
||||
mas-publish-x64:
|
||||
executor:
|
||||
name: macos
|
||||
size: macos.x86.medium.gen2
|
||||
environment:
|
||||
<<: *env-mac-large-release
|
||||
<<: *env-mas
|
||||
<<: *env-release-build
|
||||
UPLOAD_TO_STORAGE: << pipeline.parameters.upload-to-storage >>
|
||||
steps:
|
||||
- run: echo running
|
||||
- when:
|
||||
condition:
|
||||
or:
|
||||
- equal: ["all", << pipeline.parameters.macos-publish-arch-limit >>]
|
||||
- equal: ["mas-x64", << pipeline.parameters.macos-publish-arch-limit >>]
|
||||
steps:
|
||||
- electron-publish:
|
||||
attach: true
|
||||
checkout: false
|
||||
build-type: 'MAS'
|
||||
|
||||
mas-publish-arm64:
|
||||
executor:
|
||||
name: macos
|
||||
@@ -2279,19 +2167,6 @@ jobs:
|
||||
- electron-tests:
|
||||
artifact-key: linux-arm64
|
||||
|
||||
darwin-testing-x64-tests:
|
||||
executor:
|
||||
name: macos
|
||||
size: macos.x86.medium.gen2
|
||||
version: 14.0.0
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
<<: *env-stack-dumping
|
||||
parallelism: 2
|
||||
steps:
|
||||
- electron-tests:
|
||||
artifact-key: darwin-x64
|
||||
|
||||
darwin-testing-arm64-tests:
|
||||
executor:
|
||||
name: macos
|
||||
@@ -2305,19 +2180,6 @@ jobs:
|
||||
- electron-tests:
|
||||
artifact-key: darwin-arm64
|
||||
|
||||
mas-testing-x64-tests:
|
||||
executor:
|
||||
name: macos
|
||||
size: macos.x86.medium.gen2
|
||||
version: 14.0.0
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
<<: *env-stack-dumping
|
||||
parallelism: 2
|
||||
steps:
|
||||
- electron-tests:
|
||||
artifact-key: mas-x64
|
||||
|
||||
mas-testing-arm64-tests:
|
||||
executor:
|
||||
name: macos
|
||||
@@ -2352,27 +2214,6 @@ workflows:
|
||||
- linux-arm64-publish:
|
||||
context: release-env
|
||||
|
||||
publish-macos:
|
||||
when: << pipeline.parameters.run-macos-publish >>
|
||||
jobs:
|
||||
- mac-checkout
|
||||
- osx-publish-x64:
|
||||
requires:
|
||||
- mac-checkout
|
||||
context: release-env
|
||||
- mas-publish-x64:
|
||||
requires:
|
||||
- mac-checkout
|
||||
context: release-env
|
||||
- osx-publish-arm64:
|
||||
requires:
|
||||
- mac-checkout
|
||||
context: release-env
|
||||
- mas-publish-arm64:
|
||||
requires:
|
||||
- mac-checkout
|
||||
context: release-env
|
||||
|
||||
build-linux:
|
||||
when:
|
||||
and:
|
||||
@@ -2433,17 +2274,7 @@ workflows:
|
||||
- equal: [false, << pipeline.parameters.run-linux-publish >>]
|
||||
- equal: [true, << pipeline.parameters.run-build-mac >>]
|
||||
jobs:
|
||||
- mac-make-src-cache-x64
|
||||
- mac-make-src-cache-arm64
|
||||
- osx-testing-x64:
|
||||
requires:
|
||||
- mac-make-src-cache-x64
|
||||
- osx-testing-x64-gn-check:
|
||||
requires:
|
||||
- mac-make-src-cache-x64
|
||||
- darwin-testing-x64-tests:
|
||||
requires:
|
||||
- osx-testing-x64
|
||||
- osx-testing-arm64:
|
||||
requires:
|
||||
- mac-make-src-cache-arm64
|
||||
@@ -2454,9 +2285,6 @@ workflows:
|
||||
ignore: /pull\/[0-9]+/
|
||||
requires:
|
||||
- osx-testing-arm64
|
||||
- mas-testing-x64-tests:
|
||||
requires:
|
||||
- osx-testing-x64
|
||||
- mas-testing-arm64-tests:
|
||||
filters:
|
||||
branches:
|
||||
|
||||
220
.github/actions/build-electron/action.yml
vendored
Normal file
220
.github/actions/build-electron/action.yml
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
name: 'Build Electron'
|
||||
description: 'Builds Electron & Friends'
|
||||
inputs:
|
||||
target-arch:
|
||||
description: 'Target arch'
|
||||
required: true
|
||||
target-platform:
|
||||
description: 'Target platform'
|
||||
required: true
|
||||
artifact-platform:
|
||||
description: 'Artifact platform, should be linux, darwin or mas'
|
||||
required: true
|
||||
step-suffix:
|
||||
description: 'Suffix for build steps'
|
||||
required: false
|
||||
default: ''
|
||||
is-release:
|
||||
description: 'Is release build'
|
||||
required: true
|
||||
strip-binaries:
|
||||
description: 'Strip binaries (Linux only)'
|
||||
required: false
|
||||
generate-symbols:
|
||||
description: 'Generate symbols'
|
||||
required: true
|
||||
upload-to-storage:
|
||||
description: 'Upload to storage'
|
||||
required: true
|
||||
is-asan:
|
||||
description: 'The ASan Linux build'
|
||||
required: false
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Set GN_EXTRA_ARGS for MacOS x64 Builds
|
||||
shell: bash
|
||||
if: ${{ inputs.target-arch == 'x64' && inputs.target-platform == 'macos' }}
|
||||
run: |
|
||||
GN_APPENDED_ARGS="$GN_EXTRA_ARGS v8_snapshot_toolchain=\"//build/toolchain/mac:clang_x64\""
|
||||
echo "GN_EXTRA_ARGS=$GN_APPENDED_ARGS" >> $GITHUB_ENV
|
||||
- name: Build Electron ${{ inputs.step-suffix }}
|
||||
shell: bash
|
||||
run: |
|
||||
rm -rf "src/out/Default/Electron Framework.framework"
|
||||
rm -rf src/out/Default/Electron*.app
|
||||
|
||||
cd src/electron
|
||||
# TODO(codebytere): remove this once we figure out why .git/packed-refs is initially missing
|
||||
git pack-refs
|
||||
cd ..
|
||||
|
||||
if [ "`uname`" = "Darwin" ]; then
|
||||
ulimit -n 10000
|
||||
sudo launchctl limit maxfiles 65536 200000
|
||||
fi
|
||||
|
||||
NINJA_SUMMARIZE_BUILD=1 e build -j $NUMBER_OF_NINJA_PROCESSES
|
||||
cp out/Default/.ninja_log out/electron_ninja_log
|
||||
node electron/script/check-symlinks.js
|
||||
- name: Strip Electron Binaries ${{ inputs.step-suffix }}
|
||||
shell: bash
|
||||
if: ${{ inputs.strip-binaries == 'true' }}
|
||||
run: |
|
||||
cd src
|
||||
electron/script/copy-debug-symbols.py --target-cpu="${{ inputs.target-arch }}" --out-dir=out/Default/debug --compress
|
||||
electron/script/strip-binaries.py --target-cpu="${{ inputs.target-arch }}"
|
||||
electron/script/add-debug-link.py --target-cpu="${{ inputs.target-arch }}" --debug-dir=out/Default/debug
|
||||
- name: Build Electron dist.zip ${{ inputs.step-suffix }}
|
||||
shell: bash
|
||||
run: |
|
||||
cd src
|
||||
e build electron:electron_dist_zip -j $NUMBER_OF_NINJA_PROCESSES
|
||||
if [ "${{ inputs.is-asan }}" != "true" ]; then
|
||||
target_os=${{ inputs.target-platform == 'linux' && 'linux' || 'mac'}}
|
||||
if [ "${{ inputs.artifact-platform }}" = "mas" ]; then
|
||||
target_os="${target_os}_mas"
|
||||
fi
|
||||
electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.$target_os.${{ inputs.target-arch }}.manifest
|
||||
fi
|
||||
- name: Build Mksnapshot ${{ inputs.step-suffix }}
|
||||
shell: bash
|
||||
run: |
|
||||
cd src
|
||||
e build electron:electron_mksnapshot -j $NUMBER_OF_NINJA_PROCESSES
|
||||
gn desc out/Default v8:run_mksnapshot_default args > out/Default/mksnapshot_args
|
||||
# Remove unused args from mksnapshot_args
|
||||
SEDOPTION="-i"
|
||||
if [ "`uname`" = "Darwin" ]; then
|
||||
SEDOPTION="-i ''"
|
||||
fi
|
||||
sed $SEDOPTION '/.*builtins-pgo/d' out/Default/mksnapshot_args
|
||||
sed $SEDOPTION '/--turbo-profiling-input/d' out/Default/mksnapshot_args
|
||||
sed $SEDOPTION '/The gn arg use_goma=true .*/d' out/Default/mksnapshot_args
|
||||
|
||||
if [ "`uname`" = "Linux" ]; then
|
||||
if [ "${{ inputs.target-arch }}" = "arm" ]; then
|
||||
electron/script/strip-binaries.py --file $PWD/out/Default/clang_x86_v8_arm/mksnapshot
|
||||
electron/script/strip-binaries.py --file $PWD/out/Default/clang_x86_v8_arm/v8_context_snapshot_generator
|
||||
elif [ "${{ inputs.target-arch }}" = "arm64" ]; then
|
||||
electron/script/strip-binaries.py --file $PWD/out/Default/clang_x64_v8_arm64/mksnapshot
|
||||
electron/script/strip-binaries.py --file $PWD/out/Default/clang_x64_v8_arm64/v8_context_snapshot_generator
|
||||
else
|
||||
electron/script/strip-binaries.py --file $PWD/out/Default/mksnapshot
|
||||
electron/script/strip-binaries.py --file $PWD/out/Default/v8_context_snapshot_generator
|
||||
fi
|
||||
fi
|
||||
|
||||
e build electron:electron_mksnapshot_zip -j $NUMBER_OF_NINJA_PROCESSES
|
||||
(cd out/Default; zip mksnapshot.zip mksnapshot_args gen/v8/embedded.S)
|
||||
- name: Generate Cross-Arch Snapshot (arm/arm64) ${{ inputs.step-suffix }}
|
||||
shell: bash
|
||||
if: ${{ (inputs.target-arch == 'arm' || inputs.target-arch == 'arm64') && inputs.target-platform == 'linux' }}
|
||||
run: |
|
||||
cd src
|
||||
if [ "${{ inputs.target-arch }}" = "arm" ]; then
|
||||
MKSNAPSHOT_PATH="clang_x86_v8_arm"
|
||||
elif [ "${{ inputs.target-arch }}" = "arm64" ]; then
|
||||
MKSNAPSHOT_PATH="clang_x64_v8_arm64"
|
||||
fi
|
||||
|
||||
cp "out/Default/$MKSNAPSHOT_PATH/mksnapshot" out/Default
|
||||
cp "out/Default/$MKSNAPSHOT_PATH/v8_context_snapshot_generator" out/Default
|
||||
cp "out/Default/$MKSNAPSHOT_PATH/libffmpeg.so" out/Default
|
||||
|
||||
python3 electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default --create-snapshot-only
|
||||
mkdir cross-arch-snapshots
|
||||
cp out/Default-mksnapshot-test/*.bin cross-arch-snapshots
|
||||
# Clean up so that ninja does not get confused
|
||||
rm -f out/Default/libffmpeg.so
|
||||
- name: Build Chromedriver ${{ inputs.step-suffix }}
|
||||
shell: bash
|
||||
run: |
|
||||
cd src
|
||||
e build electron:electron_chromedriver -j $NUMBER_OF_NINJA_PROCESSES
|
||||
e build electron:electron_chromedriver_zip
|
||||
- name: Build Node.js headers ${{ inputs.step-suffix }}
|
||||
shell: bash
|
||||
run: |
|
||||
cd src
|
||||
e build electron:node_headers
|
||||
- name: Generate & Zip Symbols ${{ inputs.step-suffix }}
|
||||
shell: bash
|
||||
run: |
|
||||
# Generate breakpad symbols on release builds
|
||||
if [ "${{ inputs.generate-symbols }}" = "true" ]; then
|
||||
e build electron:electron_symbols
|
||||
fi
|
||||
cd src
|
||||
export BUILD_PATH="$(pwd)/out/Default"
|
||||
e build electron:licenses
|
||||
e build electron:electron_version_file
|
||||
if [ "${{ inputs.is-release }}" = "true" ]; then
|
||||
DELETE_DSYMS_AFTER_ZIP=1 electron/script/zip-symbols.py -b $BUILD_PATH
|
||||
else
|
||||
electron/script/zip-symbols.py -b $BUILD_PATH
|
||||
fi
|
||||
- name: Generate FFMpeg ${{ inputs.step-suffix }}
|
||||
shell: bash
|
||||
if: ${{ inputs.is-release == 'true' }}
|
||||
run: |
|
||||
cd src
|
||||
gn gen out/ffmpeg --args="import(\"//electron/build/args/ffmpeg.gn\") use_remoteexec=true $GN_EXTRA_ARGS"
|
||||
autoninja -C out/ffmpeg electron:electron_ffmpeg_zip -j $NUMBER_OF_NINJA_PROCESSES
|
||||
- name: Generate Hunspell Dictionaries ${{ inputs.step-suffix }}
|
||||
shell: bash
|
||||
if: ${{ inputs.is-release == 'true' && inputs.target-platform == 'linux' }}
|
||||
run: |
|
||||
cd src
|
||||
autoninja -C out/Default electron:hunspell_dictionaries_zip -j $NUMBER_OF_NINJA_PROCESSES
|
||||
- name: Generate Libcxx ${{ inputs.step-suffix }}
|
||||
shell: bash
|
||||
if: ${{ inputs.is-release == 'true' && inputs.target-platform == 'linux' }}
|
||||
run: |
|
||||
cd src
|
||||
autoninja -C out/Default electron:libcxx_headers_zip -j $NUMBER_OF_NINJA_PROCESSES
|
||||
autoninja -C out/Default electron:libcxxabi_headers_zip -j $NUMBER_OF_NINJA_PROCESSES
|
||||
autoninja -C out/Default electron:libcxx_objects_zip -j $NUMBER_OF_NINJA_PROCESSES
|
||||
- name: Generate TypeScript Definitions ${{ inputs.step-suffix }}
|
||||
if: ${{ inputs.is-release == 'true' }}
|
||||
shell: bash
|
||||
run: |
|
||||
cd src/electron
|
||||
node script/yarn create-typescript-definitions
|
||||
- name: Publish Electron Dist ${{ inputs.step-suffix }}
|
||||
if: ${{ inputs.is-release == 'true' }}
|
||||
shell: bash
|
||||
run: |
|
||||
rm -rf src/out/Default/obj
|
||||
cd src/electron
|
||||
if [ "${{ inputs.upload-to-storage }}" = "1" ]; then
|
||||
echo 'Uploading Electron release distribution to Azure'
|
||||
script/release/uploaders/upload.py --verbose --upload_to_storage
|
||||
else
|
||||
echo 'Uploading Electron release distribution to GitHub releases'
|
||||
script/release/uploaders/upload.py --verbose
|
||||
fi
|
||||
- name: Generate Artifact Key
|
||||
shell: bash
|
||||
run: |
|
||||
if [ "${{ inputs.is-asan }}" = "true" ]; then
|
||||
ARTIFACT_KEY=${{ inputs.artifact-platform }}_${{ inputs.target-arch }}_asan
|
||||
else
|
||||
ARTIFACT_KEY=${{ inputs.artifact-platform }}_${{ inputs.target-arch }}
|
||||
fi
|
||||
echo "ARTIFACT_KEY=$ARTIFACT_KEY" >> $GITHUB_ENV
|
||||
# The current generated_artifacts_<< artifact.key >> name was taken from CircleCI
|
||||
# to ensure we don't break anything, but we may be able to improve that.
|
||||
- name: Move all Generated Artifacts to Upload Folder ${{ inputs.step-suffix }}
|
||||
shell: bash
|
||||
run: ./src/electron/script/actions/move-artifacts.sh
|
||||
- name: Upload Generated Artifacts ${{ inputs.step-suffix }}
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808
|
||||
with:
|
||||
name: generated_artifacts_${{ env.ARTIFACT_KEY }}
|
||||
path: ./generated_artifacts_${{ inputs.artifact-platform }}_${{ inputs.target-arch }}
|
||||
- name: Upload Src Artifacts ${{ inputs.step-suffix }}
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808
|
||||
with:
|
||||
name: src_artifacts_${{ env.ARTIFACT_KEY }}
|
||||
path: ./src_artifacts_${{ inputs.artifact-platform }}_${{ inputs.target-arch }}
|
||||
154
.github/actions/checkout/action.yml
vendored
Normal file
154
.github/actions/checkout/action.yml
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
name: 'Checkout'
|
||||
description: 'Checks out Electron and stores it in the AKS Cache'
|
||||
inputs:
|
||||
generate-sas-token:
|
||||
description: 'Whether to generate and persist a SAS token for the item in the cache'
|
||||
required: false
|
||||
default: 'false'
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Set GIT_CACHE_PATH to make gclient to use the cache
|
||||
shell: bash
|
||||
run: |
|
||||
echo "GIT_CACHE_PATH=$(pwd)/git-cache" >> $GITHUB_ENV
|
||||
- name: Install Dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
cd src/electron
|
||||
node script/yarn install --frozen-lockfile
|
||||
- name: Get Depot Tools
|
||||
shell: bash
|
||||
run: |
|
||||
git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
|
||||
sed -i '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
|
||||
# Remove swift-format dep from cipd on macOS until we send a patch upstream.
|
||||
cd depot_tools
|
||||
git apply --3way ../src/electron/.github/workflows/config/gclient.diff
|
||||
|
||||
# Ensure depot_tools does not update.
|
||||
test -d depot_tools && cd depot_tools
|
||||
touch .disable_auto_update
|
||||
- name: Add Depot Tools to PATH
|
||||
shell: bash
|
||||
run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH
|
||||
- name: Generate DEPS Hash
|
||||
shell: bash
|
||||
run: |
|
||||
node src/electron/script/generate-deps-hash.js && cat src/electron/.depshash-target
|
||||
echo "DEPSHASH=v1-src-cache-$(shasum src/electron/.depshash | cut -f1 -d' ')" >> $GITHUB_ENV
|
||||
- name: Generate SAS Key
|
||||
if: ${{ inputs.generate-sas-token == 'true' }}
|
||||
shell: bash
|
||||
run: |
|
||||
curl --unix-socket /var/run/sas/sas.sock --fail "http://foo/$DEPSHASH.tar" > sas-token
|
||||
- name: Save SAS Key
|
||||
if: ${{ inputs.generate-sas-token == 'true' }}
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
path: |
|
||||
sas-token
|
||||
key: sas-key-${{ github.run_number }}-${{ github.run_attempt }}
|
||||
- name: Check If Cache Exists
|
||||
id: check-cache
|
||||
shell: bash
|
||||
run: |
|
||||
cache_path=/mnt/cross-instance-cache/$DEPSHASH.tar
|
||||
echo "Using cache key: $DEPSHASH"
|
||||
echo "Checking for cache in: $cache_path"
|
||||
if [ ! -f "$cache_path" ]; then
|
||||
echo "cache_exists=false" >> $GITHUB_OUTPUT
|
||||
echo "Cache Does Not Exist for $DEPSHASH"
|
||||
else
|
||||
echo "cache_exists=false" >> $GITHUB_OUTPUT
|
||||
echo "Cache Already Exists for $DEPSHASH, Busting Cache.."
|
||||
fi
|
||||
- name: Gclient Sync
|
||||
if: steps.check-cache.outputs.cache_exists == 'false'
|
||||
shell: bash
|
||||
run: |
|
||||
gclient config \
|
||||
--name "src/electron" \
|
||||
--unmanaged \
|
||||
${GCLIENT_EXTRA_ARGS} \
|
||||
"$GITHUB_SERVER_URL/$GITHUB_REPOSITORY"
|
||||
|
||||
ELECTRON_USE_THREE_WAY_MERGE_FOR_PATCHES=1 gclient sync --with_branch_heads --with_tags -vvvvv
|
||||
if [ "${{ inputs.is-release }}" != "true" ]; then
|
||||
# Re-export all the patches to check if there were changes.
|
||||
python3 src/electron/script/export_all_patches.py src/electron/patches/config.json
|
||||
cd src/electron
|
||||
git update-index --refresh || true
|
||||
if ! git diff-index --quiet HEAD --; then
|
||||
# There are changes to the patches. Make a git commit with the updated patches
|
||||
git add patches
|
||||
GIT_COMMITTER_NAME="PatchUp" GIT_COMMITTER_EMAIL="73610968+patchup[bot]@users.noreply.github.com" git commit -m "chore: update patches" --author="PatchUp <73610968+patchup[bot]@users.noreply.github.com>"
|
||||
# Export it
|
||||
mkdir -p ../../patches
|
||||
git format-patch -1 --stdout --keep-subject --no-stat --full-index > ../../patches/update-patches.patch
|
||||
if (node ./script/push-patch.js 2> /dev/null > /dev/null); then
|
||||
echo
|
||||
echo "======================================================================"
|
||||
echo "Changes to the patches when applying, we have auto-pushed the diff to the current branch"
|
||||
echo "A new CI job will kick off shortly"
|
||||
echo "======================================================================"
|
||||
exit 1
|
||||
else
|
||||
echo
|
||||
echo "======================================================================"
|
||||
echo "There were changes to the patches when applying."
|
||||
echo "Check the CI artifacts for a patch you can apply to fix it."
|
||||
echo "======================================================================"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# delete all .git directories under src/ except for
|
||||
# third_party/angle/ and third_party/dawn/ because of build time generation of files
|
||||
# gen/angle/commit.h depends on third_party/angle/.git/HEAD
|
||||
# https://chromium-review.googlesource.com/c/angle/angle/+/2074924
|
||||
# and dawn/common/Version_autogen.h depends on third_party/dawn/.git/HEAD
|
||||
# https://dawn-review.googlesource.com/c/dawn/+/83901
|
||||
# TODO: maybe better to always leave out */.git/HEAD file for all targets ?
|
||||
- name: Delete .git directories under src to free space
|
||||
if: steps.check-cache.outputs.cache_exists == 'false'
|
||||
shell: bash
|
||||
run: |
|
||||
cd src
|
||||
( find . -type d -name ".git" -not -path "./third_party/angle/*" -not -path "./third_party/dawn/*" -not -path "./electron/*" ) | xargs rm -rf
|
||||
- name: Minimize Cache Size for Upload
|
||||
if: steps.check-cache.outputs.cache_exists == 'false'
|
||||
shell: bash
|
||||
run: |
|
||||
rm -rf src/android_webview
|
||||
rm -rf src/ios/chrome
|
||||
rm -rf src/third_party/blink/web_tests
|
||||
rm -rf src/third_party/blink/perf_tests
|
||||
rm -rf src/chrome/test/data/xr/webvr_info
|
||||
rm -rf src/third_party/angle/third_party/VK-GL-CTS/src
|
||||
rm -rf src/third_party/swift-toolchain
|
||||
rm -rf src/third_party/swiftshader/tests/regres/testlists
|
||||
rm -rf src/electron
|
||||
- name: Compress Src Directory
|
||||
if: steps.check-cache.outputs.cache_exists == 'false'
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Uncompressed src size: $(du -sh src | cut -f1 -d' ')"
|
||||
tar -cf $DEPSHASH.tar src
|
||||
echo "Compressed src to $(du -sh $DEPSHASH.tar | cut -f1 -d' ')"
|
||||
cp ./$DEPSHASH.tar /mnt/cross-instance-cache/
|
||||
- name: Persist Src Cache
|
||||
if: steps.check-cache.outputs.cache_exists == 'false'
|
||||
shell: bash
|
||||
run: |
|
||||
final_cache_path=/mnt/cross-instance-cache/$DEPSHASH.tar
|
||||
echo "Using cache key: $DEPSHASH"
|
||||
echo "Checking path: $final_cache_path"
|
||||
if [ ! -f "$final_cache_path" ]; then
|
||||
echo "Cache key not found"
|
||||
exit 1
|
||||
else
|
||||
echo "Cache key persisted in $final_cache_path"
|
||||
fi
|
||||
71
.github/actions/fix-sync/action.yml
vendored
Normal file
71
.github/actions/fix-sync/action.yml
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
name: 'Fix Sync'
|
||||
description: 'Checks out Electron and stores it in the AKS Cache'
|
||||
inputs:
|
||||
target-arch:
|
||||
description: 'Target arch'
|
||||
required: true
|
||||
target-platform:
|
||||
description: 'Target platform'
|
||||
required: true
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Fix Sync
|
||||
shell: bash
|
||||
# This step is required to correct for differences between "gclient sync"
|
||||
# on Linux and the expected state. This requires:
|
||||
# 1. Fixing Clang Install (wrong binary)
|
||||
# 2. Fixing esbuild (wrong binary)
|
||||
# 3. Fixing rustc (wrong binary)
|
||||
# 4. Fixing gn (wrong binary)
|
||||
# 5. Fix reclient (wrong binary)
|
||||
# 6. Fixing dsymutil (wrong binary)
|
||||
# 7. Ensuring we are using the correct ninja and adding it to PATH
|
||||
# 8. Fixing angle (wrong remote)
|
||||
run : |
|
||||
SEDOPTION="-i"
|
||||
if [ "${{ inputs.target-platform }}" = "macos" ]; then
|
||||
SEDOPTION="-i ''"
|
||||
rm -rf src/third_party/llvm-build
|
||||
python3 src/tools/clang/scripts/update.py
|
||||
|
||||
echo 'infra/3pp/tools/esbuild/${platform}' `gclient getdep --deps-file=src/third_party/devtools-frontend/src/DEPS -r 'third_party/esbuild:infra/3pp/tools/esbuild/${platform}'` > esbuild_ensure_file
|
||||
# Remove extra output from calling gclient getdep which always calls update_depot_tools
|
||||
sed -i '' "s/Updating depot_tools... //g" esbuild_ensure_file
|
||||
cipd ensure --root src/third_party/devtools-frontend/src/third_party/esbuild -ensure-file esbuild_ensure_file
|
||||
|
||||
rm -rf src/third_party/rust-toolchain
|
||||
python3 src/tools/rust/update_rust.py
|
||||
|
||||
# Prevent calling gclient getdep which always calls update_depot_tools
|
||||
echo 'gn/gn/mac-${arch}' `gclient getdep --deps-file=src/DEPS -r 'src/buildtools/mac:gn/gn/mac-${arch}'` > gn_ensure_file
|
||||
sed -i '' "s/Updating depot_tools... //g" gn_ensure_file
|
||||
cipd ensure --root src/buildtools/mac -ensure-file gn_ensure_file
|
||||
|
||||
# Prevent calling gclient getdep which always calls update_depot_tools
|
||||
echo 'infra/rbe/client/${platform}' `gclient getdep --deps-file=src/DEPS -r 'src/buildtools/reclient:infra/rbe/client/${platform}'` > gn_ensure_file
|
||||
sed -i '' "s/Updating depot_tools... //g" gn_ensure_file
|
||||
cipd ensure --root src/buildtools/reclient -ensure-file gn_ensure_file
|
||||
python3 src/buildtools/reclient_cfgs/configure_reclient_cfgs.py --rbe_instance "projects/rbe-chrome-untrusted/instances/default_instance" --reproxy_cfg_template reproxy.cfg.template --rewrapper_cfg_project "" --skip_remoteexec_cfg_fetch
|
||||
|
||||
if [ "${{ inputs.target-arch }}" == "arm64" ]; then
|
||||
DSYM_SHA_FILE=src/tools/clang/dsymutil/bin/dsymutil.arm64.sha1
|
||||
else
|
||||
DSYM_SHA_FILE=src/tools/clang/dsymutil/bin/dsymutil.x64.sha1
|
||||
fi
|
||||
python3 src/third_party/depot_tools/download_from_google_storage.py --no_resume --no_auth --bucket chromium-browser-clang -s $DSYM_SHA_FILE -o src/tools/clang/dsymutil/bin/dsymutil
|
||||
fi
|
||||
|
||||
echo 'infra/3pp/tools/ninja/${platform}' `gclient getdep --deps-file=src/DEPS -r 'src/third_party/ninja:infra/3pp/tools/ninja/${platform}'` > ninja_ensure_file
|
||||
sed $SEDOPTION "s/Updating depot_tools... //g" ninja_ensure_file
|
||||
cipd ensure --root src/third_party/ninja -ensure-file ninja_ensure_file
|
||||
|
||||
echo "$(pwd)/src/third_party/ninja" >> $GITHUB_PATH
|
||||
|
||||
cd src/third_party/angle
|
||||
rm -f .git/objects/info/alternates
|
||||
git remote set-url origin https://chromium.googlesource.com/angle/angle.git
|
||||
cp .git/config .git/config.backup
|
||||
git remote remove origin
|
||||
mv .git/config.backup .git/config
|
||||
git fetch
|
||||
65
.github/actions/free-space-macos/action.yml
vendored
Normal file
65
.github/actions/free-space-macos/action.yml
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
name: 'Free Space macOS'
|
||||
description: 'Checks out Electron and stores it in the AKS Cache'
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Free Space on MacOS
|
||||
shell: bash
|
||||
run: |
|
||||
sudo mkdir -p $TMPDIR/del-target
|
||||
|
||||
tmpify() {
|
||||
if [ -d "$1" ]; then
|
||||
sudo mv "$1" $TMPDIR/del-target/$(echo $1|shasum -a 256|head -n1|cut -d " " -f1)
|
||||
fi
|
||||
}
|
||||
|
||||
strip_universal_deep() {
|
||||
opwd=$(pwd)
|
||||
cd $1
|
||||
f=$(find . -perm +111 -type f)
|
||||
for fp in $f
|
||||
do
|
||||
if [[ $(file "$fp") == *"universal binary"* ]]; then
|
||||
if [ "`arch`" == "arm64" ]; then
|
||||
if [[ $(file "$fp") == *"x86_64"* ]]; then
|
||||
sudo lipo -remove x86_64 "$fp" -o "$fp" || true
|
||||
fi
|
||||
else
|
||||
if [[ $(file "$fp") == *"arm64e)"* ]]; then
|
||||
sudo lipo -remove arm64e "$fp" -o "$fp" || true
|
||||
fi
|
||||
if [[ $(file "$fp") == *"arm64)"* ]]; then
|
||||
sudo lipo -remove arm64 "$fp" -o "$fp" || true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
cd $opwd
|
||||
}
|
||||
|
||||
tmpify /Library/Developer/CoreSimulator
|
||||
tmpify ~/Library/Developer/CoreSimulator
|
||||
tmpify $(xcode-select -p)/Platforms/AppleTVOS.platform
|
||||
tmpify $(xcode-select -p)/Platforms/iPhoneOS.platform
|
||||
tmpify $(xcode-select -p)/Platforms/WatchOS.platform
|
||||
tmpify $(xcode-select -p)/Platforms/WatchSimulator.platform
|
||||
tmpify $(xcode-select -p)/Platforms/AppleTVSimulator.platform
|
||||
tmpify $(xcode-select -p)/Platforms/iPhoneSimulator.platform
|
||||
tmpify $(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/metal/ios
|
||||
tmpify $(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift
|
||||
tmpify $(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift-5.0
|
||||
tmpify ~/.rubies
|
||||
tmpify ~/Library/Caches/Homebrew
|
||||
tmpify /usr/local/Homebrew
|
||||
|
||||
sudo rm -rf $TMPDIR/del-target
|
||||
|
||||
sudo rm -rf /Applications/Safari.app
|
||||
sudo rm -rf ~/project/src/third_party/catapult/tracing/test_data
|
||||
sudo rm -rf ~/project/src/third_party/angle/third_party/VK-GL-CTS
|
||||
|
||||
# lipo off some huge binaries arm64 versions to save space
|
||||
strip_universal_deep $(xcode-select -p)/../SharedFrameworks
|
||||
# strip_arm_deep /System/Volumes/Data/Library/Developer/CommandLineTools/usr
|
||||
11
.github/actions/install-build-tools/action.yml
vendored
Normal file
11
.github/actions/install-build-tools/action.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
name: 'Install Build Tools'
|
||||
description: 'Installs an exact SHA of build tools'
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Install Build Tools
|
||||
shell: bash
|
||||
run: |
|
||||
export BUILD_TOOLS_SHA=d5b87591842be19058e8d75d2c5b7f1fabe9f450
|
||||
npm i -g @electron/build-tools
|
||||
e auto-update disable
|
||||
36
.github/actions/restore-cache-aks/action.yml
vendored
Normal file
36
.github/actions/restore-cache-aks/action.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
name: 'Restore Cache AKS'
|
||||
description: 'Restores Electron src cache via AKS'
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Restore and Ensure Src Cache
|
||||
shell: bash
|
||||
run: |
|
||||
cache_path=/mnt/cross-instance-cache/$DEPSHASH.tar
|
||||
echo "Using cache key: $DEPSHASH"
|
||||
echo "Checking for cache in: $cache_path"
|
||||
if [ ! -f "$cache_path" ]; then
|
||||
echo "Cache Does Not Exist for $DEPSHASH - exiting"
|
||||
exit 1
|
||||
else
|
||||
echo "Found Cache for $DEPSHASH at $cache_path"
|
||||
fi
|
||||
|
||||
echo "Persisted cache is $(du -sh $cache_path | cut -f1)"
|
||||
mkdir temp-cache
|
||||
tar -xf $cache_path -C temp-cache
|
||||
echo "Unzipped cache is $(du -sh temp-cache/src | cut -f1)"
|
||||
|
||||
if [ -d "temp-cache/src" ]; then
|
||||
echo "Relocating Cache"
|
||||
rm -rf src
|
||||
mv temp-cache/src src
|
||||
fi
|
||||
|
||||
if [ ! -d "src/third_party/blink" ]; then
|
||||
echo "Cache was not correctly restored - exiting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Wiping Electron Directory"
|
||||
rm -rf src/electron
|
||||
66
.github/actions/restore-cache-azcopy/action.yml
vendored
Normal file
66
.github/actions/restore-cache-azcopy/action.yml
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
name: 'Restore Cache AZCopy'
|
||||
description: 'Restores Electron src cache via AZCopy'
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Obtain SAS Key
|
||||
continue-on-error: true
|
||||
uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9
|
||||
with:
|
||||
path: |
|
||||
sas-token
|
||||
key: sas-key-${{ github.run_number }}-1
|
||||
- name: Obtain SAS Key
|
||||
continue-on-error: true
|
||||
uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9
|
||||
with:
|
||||
path: |
|
||||
sas-token
|
||||
key: sas-key-${{ github.run_number }}-${{ github.run_attempt }}
|
||||
- name: Download Src Cache from AKS
|
||||
# The cache will always exist here as a result of the checkout job
|
||||
# Either it was uploaded to Azure in the checkout job for this commit
|
||||
# or it was uploaded in the checkout job for a previous commit.
|
||||
uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e # v3.0.0
|
||||
with:
|
||||
timeout_minutes: 20
|
||||
max_attempts: 3
|
||||
retry_on: error
|
||||
command: |
|
||||
sas_token=$(cat sas-token)
|
||||
if [ -z $sas-token ]; then
|
||||
echo "SAS Token not found; exiting src cache download early..."
|
||||
exit 1
|
||||
fi
|
||||
azcopy copy \
|
||||
"https://${{ env.AZURE_AKS_CACHE_STORAGE_ACCOUNT }}.file.core.windows.net/${{ env.AZURE_AKS_CACHE_SHARE_NAME }}/${{ env.CACHE_PATH }}?$sas_token" $DEPSHASH.tar
|
||||
env:
|
||||
AZURE_AKS_CACHE_STORAGE_ACCOUNT: f723719aa87a34622b5f7f3
|
||||
AZURE_AKS_CACHE_SHARE_NAME: pvc-f6a4089f-b082-4bee-a3f9-c3e1c0c02d8f
|
||||
- name: Clean SAS Key
|
||||
shell: bash
|
||||
run: rm -f sas-token
|
||||
- name: Unzip and Ensure Src Cache
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Downloaded cache is $(du -sh $DEPSHASH.tar | cut -f1)"
|
||||
mkdir temp-cache
|
||||
tar -xf $DEPSHASH.tar -C temp-cache
|
||||
echo "Unzipped cache is $(du -sh temp-cache/src | cut -f1)"
|
||||
|
||||
if [ -d "temp-cache/src" ]; then
|
||||
echo "Relocating Cache"
|
||||
rm -rf src
|
||||
mv temp-cache/src src
|
||||
|
||||
echo "Deleting zip file"
|
||||
rm -rf $DEPSHASH.tar
|
||||
fi
|
||||
|
||||
if [ ! -d "src/third_party/blink" ]; then
|
||||
echo "Cache was not correctly restored - exiting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Wiping Electron Directory"
|
||||
rm -rf src/electron
|
||||
245
.github/workflows/build.yml
vendored
Normal file
245
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,245 @@
|
||||
name: Build
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
build-image-sha:
|
||||
type: string
|
||||
description: 'SHA for electron/build image'
|
||||
default: 'cf814a4d2501e8e843caea071a6b70a48e78b855'
|
||||
required: true
|
||||
skip-macos:
|
||||
type: boolean
|
||||
description: 'Skip macOS builds'
|
||||
default: false
|
||||
required: false
|
||||
skip-linux:
|
||||
type: boolean
|
||||
description: 'Skip Linux builds'
|
||||
default: false
|
||||
required: false
|
||||
skip-lint:
|
||||
type: boolean
|
||||
description: 'Skip lint check'
|
||||
default: false
|
||||
required: false
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- '[1-9][0-9]-x-y'
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
setup:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: read
|
||||
outputs:
|
||||
docs: ${{ steps.filter.outputs.docs }}
|
||||
src: ${{ steps.filter.outputs.src }}
|
||||
build-image-sha: ${{ steps.set-output.outputs.build-image-sha }}
|
||||
docs-only: ${{ steps.set-output.outputs.docs-only }}
|
||||
steps:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 #v4.0.2
|
||||
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
docs:
|
||||
- 'docs/**'
|
||||
src:
|
||||
- '!docs/**'
|
||||
- name: Set Outputs for Build Image SHA & Docs Only
|
||||
id: set-output
|
||||
run: |
|
||||
if [ -z "${{ inputs.build-image-sha }}" ]; then
|
||||
echo "build-image-sha=cf814a4d2501e8e843caea071a6b70a48e78b855" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "build-image-sha=${{ inputs.build-image-sha }}" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
echo "docs-only=${{ steps.filter.outputs.docs == 'true' && steps.filter.outputs.src == 'false' }}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# Lint Jobs
|
||||
lint:
|
||||
needs: setup
|
||||
if: ${{ !inputs.skip-lint }}
|
||||
uses: ./.github/workflows/pipeline-electron-lint.yml
|
||||
with:
|
||||
container: '{"image":"ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }}","options":"--user root"}'
|
||||
secrets: inherit
|
||||
|
||||
# Docs Only Jobs
|
||||
docs-only:
|
||||
needs: setup
|
||||
if: ${{ needs.setup.outputs.docs-only == 'true' }}
|
||||
uses: ./.github/workflows/pipeline-electron-docs-only.yml
|
||||
with:
|
||||
container: '{"image":"ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }}","options":"--user root"}'
|
||||
secrets: inherit
|
||||
|
||||
# Checkout Jobs
|
||||
checkout-macos:
|
||||
needs: setup
|
||||
if: ${{ needs.setup.outputs.src == 'true' && !inputs.skip-macos}}
|
||||
runs-on: electron-arc-linux-amd64-32core
|
||||
container:
|
||||
image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }}
|
||||
options: --user root
|
||||
volumes:
|
||||
- /mnt/cross-instance-cache:/mnt/cross-instance-cache
|
||||
- /var/run/sas:/var/run/sas
|
||||
env:
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac'
|
||||
outputs:
|
||||
build-image-sha: ${{ needs.setup.outputs.build-image-sha }}
|
||||
steps:
|
||||
- name: Checkout Electron
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
|
||||
with:
|
||||
path: src/electron
|
||||
fetch-depth: 0
|
||||
- name: Checkout & Sync & Save
|
||||
uses: ./src/electron/.github/actions/checkout
|
||||
with:
|
||||
generate-sas-token: 'true'
|
||||
|
||||
checkout-linux:
|
||||
needs: setup
|
||||
if: ${{ needs.setup.outputs.src == 'true' && !inputs.skip-linux}}
|
||||
runs-on: electron-arc-linux-amd64-32core
|
||||
container:
|
||||
image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }}
|
||||
options: --user root
|
||||
volumes:
|
||||
- /mnt/cross-instance-cache:/mnt/cross-instance-cache
|
||||
- /var/run/sas:/var/run/sas
|
||||
env:
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True'
|
||||
outputs:
|
||||
build-image-sha: ${{ needs.setup.outputs.build-image-sha}}
|
||||
steps:
|
||||
- name: Checkout Electron
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
|
||||
with:
|
||||
path: src/electron
|
||||
fetch-depth: 0
|
||||
- name: Checkout & Sync & Save
|
||||
uses: ./src/electron/.github/actions/checkout
|
||||
|
||||
# Build Jobs - These cascade into testing jobs
|
||||
macos-x64:
|
||||
permissions:
|
||||
contents: read
|
||||
issues: read
|
||||
pull-requests: read
|
||||
uses: ./.github/workflows/pipeline-electron-build-and-test.yml
|
||||
needs: checkout-macos
|
||||
with:
|
||||
build-runs-on: macos-14-xlarge
|
||||
test-runs-on: macos-13
|
||||
target-platform: macos
|
||||
target-arch: x64
|
||||
is-release: false
|
||||
gn-build-type: testing
|
||||
generate-symbols: false
|
||||
upload-to-storage: '0'
|
||||
secrets: inherit
|
||||
|
||||
macos-arm64:
|
||||
permissions:
|
||||
contents: read
|
||||
issues: read
|
||||
pull-requests: read
|
||||
uses: ./.github/workflows/pipeline-electron-build-and-test.yml
|
||||
needs: checkout-macos
|
||||
with:
|
||||
build-runs-on: macos-14-xlarge
|
||||
test-runs-on: macos-14
|
||||
target-platform: macos
|
||||
target-arch: arm64
|
||||
is-release: false
|
||||
gn-build-type: testing
|
||||
generate-symbols: false
|
||||
upload-to-storage: '0'
|
||||
secrets: inherit
|
||||
|
||||
linux-x64:
|
||||
permissions:
|
||||
contents: read
|
||||
issues: read
|
||||
pull-requests: read
|
||||
uses: ./.github/workflows/pipeline-electron-build-and-test-and-nan.yml
|
||||
needs: checkout-linux
|
||||
with:
|
||||
build-runs-on: electron-arc-linux-amd64-32core
|
||||
test-runs-on: electron-arc-linux-amd64-4core
|
||||
build-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
|
||||
test-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root --privileged --init"}'
|
||||
target-platform: linux
|
||||
target-arch: x64
|
||||
is-release: false
|
||||
gn-build-type: testing
|
||||
generate-symbols: false
|
||||
upload-to-storage: '0'
|
||||
secrets: inherit
|
||||
|
||||
linux-x64-asan:
|
||||
permissions:
|
||||
contents: read
|
||||
issues: read
|
||||
pull-requests: read
|
||||
uses: ./.github/workflows/pipeline-electron-build-and-test.yml
|
||||
needs: checkout-linux
|
||||
with:
|
||||
build-runs-on: electron-arc-linux-amd64-32core
|
||||
test-runs-on: electron-arc-linux-amd64-4core
|
||||
build-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
|
||||
test-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root --privileged --init"}'
|
||||
target-platform: linux
|
||||
target-arch: x64
|
||||
is-release: false
|
||||
gn-build-type: testing
|
||||
generate-symbols: false
|
||||
upload-to-storage: '0'
|
||||
is-asan: true
|
||||
secrets: inherit
|
||||
|
||||
linux-arm:
|
||||
permissions:
|
||||
contents: read
|
||||
issues: read
|
||||
pull-requests: read
|
||||
uses: ./.github/workflows/pipeline-electron-build-and-test.yml
|
||||
needs: checkout-linux
|
||||
with:
|
||||
build-runs-on: electron-arc-linux-amd64-32core
|
||||
test-runs-on: electron-arc-linux-arm64-4core
|
||||
build-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
|
||||
test-container: '{"image":"ghcr.io/electron/test:arm32v7-${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root --privileged --init","volumes":["/home/runner/externals:/mnt/runner-externals"]}'
|
||||
target-platform: linux
|
||||
target-arch: arm
|
||||
is-release: false
|
||||
gn-build-type: testing
|
||||
generate-symbols: false
|
||||
upload-to-storage: '0'
|
||||
secrets: inherit
|
||||
|
||||
linux-arm64:
|
||||
permissions:
|
||||
contents: read
|
||||
issues: read
|
||||
pull-requests: read
|
||||
uses: ./.github/workflows/pipeline-electron-build-and-test.yml
|
||||
needs: checkout-linux
|
||||
with:
|
||||
build-runs-on: electron-arc-linux-amd64-32core
|
||||
test-runs-on: electron-arc-linux-arm64-4core
|
||||
build-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
|
||||
test-container: '{"image":"ghcr.io/electron/test:arm64v8-${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root --privileged --init"}'
|
||||
target-platform: linux
|
||||
target-arch: arm64
|
||||
is-release: false
|
||||
gn-build-type: testing
|
||||
generate-symbols: false
|
||||
upload-to-storage: '0'
|
||||
secrets: inherit
|
||||
14
.github/workflows/config/gclient.diff
vendored
Normal file
14
.github/workflows/config/gclient.diff
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
diff --git a/gclient.py b/gclient.py
|
||||
index 59e2b4c5197928bdba1ef69bdbe637d7dfe471c1..b4bae5e48c83c84bd867187afaf40eed16e69851 100755
|
||||
--- a/gclient.py
|
||||
+++ b/gclient.py
|
||||
@@ -783,7 +783,8 @@ class Dependency(gclient_utils.WorkItem, DependencySettings):
|
||||
not condition or "non_git_source" not in condition):
|
||||
continue
|
||||
cipd_root = self.GetCipdRoot()
|
||||
- for package in dep_value.get('packages', []):
|
||||
+ packages = dep_value.get('packages', [])
|
||||
+ for package in (x for x in packages if "infra/3pp/tools/swift-format" not in x.get('package')):
|
||||
deps_to_add.append(
|
||||
CipdDependency(parent=self,
|
||||
name=name,
|
||||
86
.github/workflows/linux-publish.yml
vendored
Normal file
86
.github/workflows/linux-publish.yml
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
name: Publish Linux
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
build-image-sha:
|
||||
type: string
|
||||
description: 'SHA for electron/build image'
|
||||
default: 'cf814a4d2501e8e843caea071a6b70a48e78b855'
|
||||
upload-to-storage:
|
||||
description: 'Uploads to Azure storage'
|
||||
required: false
|
||||
default: '1'
|
||||
type: string
|
||||
run-linux-publish:
|
||||
description: 'Run the publish jobs vs just the build jobs'
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
checkout-linux:
|
||||
runs-on: electron-arc-linux-amd64-32core
|
||||
container:
|
||||
image: ghcr.io/electron/build:${{ inputs.build-image-sha }}
|
||||
options: --user root
|
||||
volumes:
|
||||
- /mnt/cross-instance-cache:/mnt/cross-instance-cache
|
||||
- /var/run/sas:/var/run/sas
|
||||
env:
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True'
|
||||
steps:
|
||||
- name: Checkout Electron
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
|
||||
with:
|
||||
path: src/electron
|
||||
fetch-depth: 0
|
||||
- name: Checkout & Sync & Save
|
||||
uses: ./src/electron/.github/actions/checkout
|
||||
|
||||
publish-x64:
|
||||
uses: ./.github/workflows/pipeline-segment-electron-build.yml
|
||||
needs: checkout-linux
|
||||
with:
|
||||
environment: production-release
|
||||
build-runs-on: electron-arc-linux-amd64-32core
|
||||
build-container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
|
||||
target-platform: linux
|
||||
target-arch: x64
|
||||
is-release: true
|
||||
gn-build-type: release
|
||||
generate-symbols: true
|
||||
strip-binaries: true
|
||||
upload-to-storage: ${{ inputs.upload-to-storage }}
|
||||
secrets: inherit
|
||||
|
||||
publish-arm:
|
||||
uses: ./.github/workflows/pipeline-segment-electron-build.yml
|
||||
needs: checkout-linux
|
||||
with:
|
||||
environment: production-release
|
||||
build-runs-on: electron-arc-linux-amd64-32core
|
||||
build-container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
|
||||
target-platform: linux
|
||||
target-arch: arm
|
||||
is-release: true
|
||||
gn-build-type: release
|
||||
generate-symbols: true
|
||||
strip-binaries: true
|
||||
upload-to-storage: ${{ inputs.upload-to-storage }}
|
||||
secrets: inherit
|
||||
|
||||
publish-arm64:
|
||||
uses: ./.github/workflows/pipeline-segment-electron-build.yml
|
||||
needs: checkout-linux
|
||||
with:
|
||||
environment: production-release
|
||||
build-runs-on: electron-arc-linux-amd64-32core
|
||||
build-container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
|
||||
target-platform: linux
|
||||
target-arch: arm64
|
||||
is-release: true
|
||||
gn-build-type: release
|
||||
generate-symbols: true
|
||||
strip-binaries: true
|
||||
upload-to-storage: ${{ inputs.upload-to-storage }}
|
||||
secrets: inherit
|
||||
69
.github/workflows/macos-publish.yml
vendored
Normal file
69
.github/workflows/macos-publish.yml
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
name: Publish MacOS
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
build-image-sha:
|
||||
type: string
|
||||
description: 'SHA for electron/build image'
|
||||
default: 'cf814a4d2501e8e843caea071a6b70a48e78b855'
|
||||
required: true
|
||||
upload-to-storage:
|
||||
description: 'Uploads to Azure storage'
|
||||
required: false
|
||||
default: '1'
|
||||
type: string
|
||||
run-macos-publish:
|
||||
description: 'Run the publish jobs vs just the build jobs'
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
checkout-macos:
|
||||
runs-on: electron-arc-linux-amd64-32core
|
||||
container:
|
||||
image: ghcr.io/electron/build:${{ inputs.build-image-sha }}
|
||||
options: --user root
|
||||
volumes:
|
||||
- /mnt/cross-instance-cache:/mnt/cross-instance-cache
|
||||
- /var/run/sas:/var/run/sas
|
||||
env:
|
||||
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac'
|
||||
steps:
|
||||
- name: Checkout Electron
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
|
||||
with:
|
||||
path: src/electron
|
||||
fetch-depth: 0
|
||||
- name: Checkout & Sync & Save
|
||||
uses: ./src/electron/.github/actions/checkout
|
||||
with:
|
||||
generate-sas-token: 'true'
|
||||
|
||||
publish-x64:
|
||||
uses: ./.github/workflows/pipeline-segment-electron-build.yml
|
||||
needs: checkout-macos
|
||||
with:
|
||||
environment: production-release
|
||||
build-runs-on: macos-14-xlarge
|
||||
target-platform: macos
|
||||
target-arch: x64
|
||||
is-release: true
|
||||
gn-build-type: release
|
||||
generate-symbols: true
|
||||
upload-to-storage: ${{ inputs.upload-to-storage }}
|
||||
secrets: inherit
|
||||
|
||||
publish-arm64:
|
||||
uses: ./.github/workflows/pipeline-segment-electron-build.yml
|
||||
needs: checkout-macos
|
||||
with:
|
||||
environment: production-release
|
||||
build-runs-on: macos-14-xlarge
|
||||
target-platform: macos
|
||||
target-arch: arm64
|
||||
is-release: true
|
||||
gn-build-type: release
|
||||
generate-symbols: true
|
||||
upload-to-storage: ${{ inputs.upload-to-storage }}
|
||||
secrets: inherit
|
||||
103
.github/workflows/pipeline-electron-build-and-test-and-nan.yml
vendored
Normal file
103
.github/workflows/pipeline-electron-build-and-test-and-nan.yml
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
name: Electron Build & Test (+ Node + NaN) Pipeline
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
target-platform:
|
||||
type: string
|
||||
description: 'Platform to run on, can be macos or linux'
|
||||
required: true
|
||||
target-arch:
|
||||
type: string
|
||||
description: 'Arch to build for, can be x64, arm64 or arm'
|
||||
required: true
|
||||
build-runs-on:
|
||||
type: string
|
||||
description: 'What host to run the build'
|
||||
required: true
|
||||
test-runs-on:
|
||||
type: string
|
||||
description: 'What host to run the tests on'
|
||||
required: true
|
||||
build-container:
|
||||
type: string
|
||||
description: 'JSON container information for aks runs-on'
|
||||
required: false
|
||||
default: '{"image":null}'
|
||||
test-container:
|
||||
type: string
|
||||
description: 'JSON container information for testing'
|
||||
required: false
|
||||
default: '{"image":null}'
|
||||
is-release:
|
||||
description: 'Whether this build job is a release job'
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
gn-build-type:
|
||||
description: 'The gn build type - testing or release'
|
||||
required: true
|
||||
type: string
|
||||
default: testing
|
||||
generate-symbols:
|
||||
description: 'Whether or not to generate symbols'
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
upload-to-storage:
|
||||
description: 'Whether or not to upload build artifacts to external storage'
|
||||
required: true
|
||||
type: string
|
||||
default: '0'
|
||||
is-asan:
|
||||
description: 'Building the Address Sanitizer (ASan) Linux build'
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
concurrency:
|
||||
group: electron-build-and-test-and-nan-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
uses: ./.github/workflows/pipeline-segment-electron-build.yml
|
||||
with:
|
||||
build-runs-on: ${{ inputs.build-runs-on }}
|
||||
build-container: ${{ inputs.build-container }}
|
||||
target-platform: ${{ inputs.target-platform }}
|
||||
target-arch: ${{ inputs.target-arch }}
|
||||
is-release: ${{ inputs.is-release }}
|
||||
gn-build-type: ${{ inputs.gn-build-type }}
|
||||
generate-symbols: ${{ inputs.generate-symbols }}
|
||||
upload-to-storage: ${{ inputs.upload-to-storage }}
|
||||
secrets: inherit
|
||||
gn-check:
|
||||
uses: ./.github/workflows/pipeline-segment-electron-gn-check.yml
|
||||
with:
|
||||
target-platform: ${{ inputs.target-platform }}
|
||||
target-arch: ${{ inputs.target-arch }}
|
||||
check-runs-on: ${{ inputs.build-runs-on }}
|
||||
check-container: ${{ inputs.build-container }}
|
||||
gn-build-type: ${{ inputs.gn-build-type }}
|
||||
is-asan: ${{ inputs.is-asan }}
|
||||
secrets: inherit
|
||||
test:
|
||||
uses: ./.github/workflows/pipeline-segment-electron-test.yml
|
||||
needs: build
|
||||
with:
|
||||
target-arch: ${{ inputs.target-arch }}
|
||||
target-platform: ${{ inputs.target-platform }}
|
||||
test-runs-on: ${{ inputs.test-runs-on }}
|
||||
test-container: ${{ inputs.test-container }}
|
||||
secrets: inherit
|
||||
nn-test:
|
||||
uses: ./.github/workflows/pipeline-segment-node-nan-test.yml
|
||||
needs: build
|
||||
with:
|
||||
target-arch: ${{ inputs.target-arch }}
|
||||
target-platform: ${{ inputs.target-platform }}
|
||||
test-runs-on: ${{ inputs.test-runs-on }}
|
||||
test-container: ${{ inputs.test-container }}
|
||||
gn-build-type: ${{ inputs.gn-build-type }}
|
||||
secrets: inherit
|
||||
100
.github/workflows/pipeline-electron-build-and-test.yml
vendored
Normal file
100
.github/workflows/pipeline-electron-build-and-test.yml
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
name: Electron Build & Test Pipeline
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
target-platform:
|
||||
type: string
|
||||
description: 'Platform to run on, can be macos or linux'
|
||||
required: true
|
||||
target-arch:
|
||||
type: string
|
||||
description: 'Arch to build for, can be x64, arm64 or arm'
|
||||
required: true
|
||||
build-runs-on:
|
||||
type: string
|
||||
description: 'What host to run the build'
|
||||
required: true
|
||||
test-runs-on:
|
||||
type: string
|
||||
description: 'What host to run the tests on'
|
||||
required: true
|
||||
build-container:
|
||||
type: string
|
||||
description: 'JSON container information for aks runs-on'
|
||||
required: false
|
||||
default: '{"image":null}'
|
||||
test-container:
|
||||
type: string
|
||||
description: 'JSON container information for testing'
|
||||
required: false
|
||||
default: '{"image":null}'
|
||||
is-release:
|
||||
description: 'Whether this build job is a release job'
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
gn-build-type:
|
||||
description: 'The gn build type - testing or release'
|
||||
required: true
|
||||
type: string
|
||||
default: testing
|
||||
generate-symbols:
|
||||
description: 'Whether or not to generate symbols'
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
upload-to-storage:
|
||||
description: 'Whether or not to upload build artifacts to external storage'
|
||||
required: true
|
||||
type: string
|
||||
default: '0'
|
||||
is-asan:
|
||||
description: 'Building the Address Sanitizer (ASan) Linux build'
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
concurrency:
|
||||
group: electron-build-and-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: read
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
uses: ./.github/workflows/pipeline-segment-electron-build.yml
|
||||
with:
|
||||
build-runs-on: ${{ inputs.build-runs-on }}
|
||||
build-container: ${{ inputs.build-container }}
|
||||
target-platform: ${{ inputs.target-platform }}
|
||||
target-arch: ${{ inputs.target-arch }}
|
||||
is-release: ${{ inputs.is-release }}
|
||||
gn-build-type: ${{ inputs.gn-build-type }}
|
||||
generate-symbols: ${{ inputs.generate-symbols }}
|
||||
upload-to-storage: ${{ inputs.upload-to-storage }}
|
||||
is-asan: ${{ inputs.is-asan}}
|
||||
secrets: inherit
|
||||
gn-check:
|
||||
uses: ./.github/workflows/pipeline-segment-electron-gn-check.yml
|
||||
with:
|
||||
target-platform: ${{ inputs.target-platform }}
|
||||
target-arch: ${{ inputs.target-arch }}
|
||||
check-runs-on: ${{ inputs.build-runs-on }}
|
||||
check-container: ${{ inputs.build-container }}
|
||||
gn-build-type: ${{ inputs.gn-build-type }}
|
||||
is-asan: ${{ inputs.is-asan }}
|
||||
secrets: inherit
|
||||
test:
|
||||
uses: ./.github/workflows/pipeline-segment-electron-test.yml
|
||||
needs: build
|
||||
with:
|
||||
target-arch: ${{ inputs.target-arch }}
|
||||
target-platform: ${{ inputs.target-platform }}
|
||||
test-runs-on: ${{ inputs.test-runs-on }}
|
||||
test-container: ${{ inputs.test-container }}
|
||||
is-asan: ${{ inputs.is-asan}}
|
||||
secrets: inherit
|
||||
43
.github/workflows/pipeline-electron-docs-only.yml
vendored
Normal file
43
.github/workflows/pipeline-electron-docs-only.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
name: Electron Docs Compile
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
container:
|
||||
required: true
|
||||
description: 'Container to run the docs-only ts compile in'
|
||||
type: string
|
||||
|
||||
concurrency:
|
||||
group: electron-docs-only-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
docs-only:
|
||||
name: Docs Only Compile
|
||||
runs-on: electron-arc-linux-amd64-4core
|
||||
timeout-minutes: 20
|
||||
container: ${{ fromJSON(inputs.container) }}
|
||||
steps:
|
||||
- name: Checkout Electron
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
|
||||
with:
|
||||
path: src/electron
|
||||
fetch-depth: 0
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
cd src/electron
|
||||
node script/yarn install --frozen-lockfile
|
||||
- name: Run TS/JS compile
|
||||
shell: bash
|
||||
run: |
|
||||
cd src/electron
|
||||
node script/yarn create-typescript-definitions
|
||||
node script/yarn tsc -p tsconfig.default_app.json --noEmit
|
||||
for f in build/webpack/*.js
|
||||
do
|
||||
out="${f:29}"
|
||||
if [ "$out" != "base.js" ]; then
|
||||
node script/yarn webpack --config $f --output-filename=$out --output-path=./.tmp --env mode=development
|
||||
fi
|
||||
done
|
||||
77
.github/workflows/pipeline-electron-lint.yml
vendored
Normal file
77
.github/workflows/pipeline-electron-lint.yml
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
name: Electron Lint
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
container:
|
||||
required: true
|
||||
description: 'Container to run lint in'
|
||||
type: string
|
||||
|
||||
concurrency:
|
||||
group: electron-lint-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }}
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint
|
||||
runs-on: electron-arc-linux-amd64-4core
|
||||
timeout-minutes: 20
|
||||
container: ${{ fromJSON(inputs.container) }}
|
||||
steps:
|
||||
- name: Checkout Electron
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
|
||||
with:
|
||||
path: src/electron
|
||||
fetch-depth: 0
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
cd src/electron
|
||||
node script/yarn install --frozen-lockfile
|
||||
- name: Setup third_party Depot Tools
|
||||
shell: bash
|
||||
run: |
|
||||
# "depot_tools" has to be checkout into "//third_party/depot_tools" so pylint.py can a "pylintrc" file.
|
||||
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git src/third_party/depot_tools
|
||||
echo "$(pwd)/src/third_party/depot_tools" >> $GITHUB_PATH
|
||||
- name: Download GN Binary
|
||||
shell: bash
|
||||
run: |
|
||||
chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)"
|
||||
gn_version="$(curl -sL "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/DEPS?format=TEXT" | base64 -d | grep gn_version | head -n1 | cut -d\' -f4)"
|
||||
|
||||
cipd ensure -ensure-file - -root . <<-CIPD
|
||||
\$ServiceURL https://chrome-infra-packages.appspot.com/
|
||||
@Subdir src/buildtools/linux64
|
||||
gn/gn/linux-amd64 $gn_version
|
||||
CIPD
|
||||
|
||||
buildtools_path="$(pwd)/src/buildtools"
|
||||
echo "CHROMIUM_BUILDTOOLS_PATH=$buildtools_path" >> $GITHUB_ENV
|
||||
- name: Download clang-format Binary
|
||||
shell: bash
|
||||
run: |
|
||||
chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)"
|
||||
|
||||
sha1_path='buildtools/linux64/clang-format.sha1'
|
||||
curl -sL "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/${sha1_path}?format=TEXT" | base64 -d > "src/${sha1_path}"
|
||||
|
||||
download_from_google_storage.py --no_resume --no_auth --bucket chromium-clang-format -s "src/${sha1_path}"
|
||||
- name: Run Lint
|
||||
shell: bash
|
||||
run: |
|
||||
# gn.py tries to find a gclient root folder starting from the current dir.
|
||||
# When it fails and returns "None" path, the whole script fails. Let's "fix" it.
|
||||
touch .gclient
|
||||
# Another option would be to checkout "buildtools" inside the Electron checkout,
|
||||
# but then we would lint its contents (at least gn format), and it doesn't pass it.
|
||||
|
||||
cd src/electron
|
||||
node script/yarn install --frozen-lockfile
|
||||
node script/yarn lint
|
||||
- name: Run Script Typechecker
|
||||
shell: bash
|
||||
run: |
|
||||
cd src/electron
|
||||
node script/yarn tsc -p tsconfig.script.json
|
||||
|
||||
216
.github/workflows/pipeline-segment-electron-build.yml
vendored
Normal file
216
.github/workflows/pipeline-segment-electron-build.yml
vendored
Normal file
@@ -0,0 +1,216 @@
|
||||
name: Pipeline Segment - Electron Build
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
environment:
|
||||
description: using the production or testing environment
|
||||
required: false
|
||||
type: string
|
||||
target-platform:
|
||||
type: string
|
||||
description: 'Platform to run on, can be macos or linux'
|
||||
required: true
|
||||
target-arch:
|
||||
type: string
|
||||
description: 'Arch to build for, can be x64, arm64 or arm'
|
||||
required: true
|
||||
build-runs-on:
|
||||
type: string
|
||||
description: 'What host to run the build'
|
||||
required: true
|
||||
build-container:
|
||||
type: string
|
||||
description: 'JSON container information for aks runs-on'
|
||||
required: false
|
||||
default: '{"image":null}'
|
||||
is-release:
|
||||
description: 'Whether this build job is a release job'
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
gn-build-type:
|
||||
description: 'The gn build type - testing or release'
|
||||
required: true
|
||||
type: string
|
||||
default: testing
|
||||
generate-symbols:
|
||||
description: 'Whether or not to generate symbols'
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
upload-to-storage:
|
||||
description: 'Whether or not to upload build artifacts to external storage'
|
||||
required: true
|
||||
type: string
|
||||
default: '0'
|
||||
strip-binaries:
|
||||
description: 'Strip the binaries before release (Linux only)'
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
is-asan:
|
||||
description: 'Building the Address Sanitizer (ASan) Linux build'
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
|
||||
concurrency:
|
||||
group: electron-build-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ inputs.is-asan }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }}
|
||||
|
||||
env:
|
||||
ELECTRON_ARTIFACTS_BLOB_STORAGE: ${{ secrets.ELECTRON_ARTIFACTS_BLOB_STORAGE }}
|
||||
ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }}
|
||||
ELECTRON_GITHUB_TOKEN: ${{ secrets.ELECTRON_GITHUB_TOKEN }}
|
||||
GCLIENT_EXTRA_ARGS: ${{ inputs.target-platform == 'macos' && '--custom-var=checkout_mac=True --custom-var=host_os=mac' || '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' }}
|
||||
ELECTRON_OUT_DIR: Default
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ inputs.build-runs-on }}
|
||||
container: ${{ fromJSON(inputs.build-container) }}
|
||||
environment: ${{ inputs.environment }}
|
||||
env:
|
||||
TARGET_ARCH: ${{ inputs.target-arch }}
|
||||
steps:
|
||||
- name: Create src dir
|
||||
run: mkdir src
|
||||
- name: Checkout Electron
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
|
||||
with:
|
||||
path: src/electron
|
||||
fetch-depth: 0
|
||||
- name: Setup Node.js/npm
|
||||
if: ${{ inputs.target-platform == 'macos' }}
|
||||
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8
|
||||
with:
|
||||
node-version: 20.11.x
|
||||
cache: yarn
|
||||
cache-dependency-path: src/electron/yarn.lock
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
cd src/electron
|
||||
node script/yarn install --frozen-lockfile
|
||||
- name: Install Python Tools (Mac)
|
||||
if: ${{ inputs.target-platform == 'macos' }}
|
||||
run: brew install python-setuptools
|
||||
- name: Install AZCopy
|
||||
if: ${{ inputs.target-platform == 'macos' }}
|
||||
run: brew install azcopy
|
||||
- name: Set GN_EXTRA_ARGS for Linux
|
||||
if: ${{ inputs.target-platform == 'linux' }}
|
||||
run: |
|
||||
if [ "${{ inputs.target-arch }}" = "arm" ]; then
|
||||
if [ "${{ inputs.is-release }}" = true ]; then
|
||||
GN_EXTRA_ARGS='target_cpu="arm" build_tflite_with_xnnpack=false symbol_level=1'
|
||||
else
|
||||
GN_EXTRA_ARGS='target_cpu="arm" build_tflite_with_xnnpack=false'
|
||||
fi
|
||||
elif [ "${{ inputs.target-arch }}" = "arm64" ]; then
|
||||
GN_EXTRA_ARGS='target_cpu="arm64" fatal_linker_warnings=false enable_linux_installer=false'
|
||||
elif [ "${{ inputs.is-asan }}" = true ]; then
|
||||
GN_EXTRA_ARGS='is_asan=true'
|
||||
fi
|
||||
echo "GN_EXTRA_ARGS=$GN_EXTRA_ARGS" >> $GITHUB_ENV
|
||||
- name: Get Depot Tools
|
||||
timeout-minutes: 5
|
||||
run: |
|
||||
git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
|
||||
SEDOPTION="-i"
|
||||
if [ "`uname`" = "Darwin" ]; then
|
||||
SEDOPTION="-i ''"
|
||||
fi
|
||||
|
||||
# remove ninjalog_uploader_wrapper.py from autoninja since we don't use it and it causes problems
|
||||
sed $SEDOPTION '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
|
||||
|
||||
# Ensure depot_tools does not update.
|
||||
test -d depot_tools && cd depot_tools
|
||||
if [ "`uname`" = "Linux" ]; then
|
||||
git apply --3way ../src/electron/.github/workflows/config/gclient.diff
|
||||
fi
|
||||
touch .disable_auto_update
|
||||
- name: Add Depot Tools to PATH
|
||||
run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH
|
||||
- name: Generate DEPS Hash
|
||||
run: |
|
||||
node src/electron/script/generate-deps-hash.js && cat src/electron/.depshash-target
|
||||
DEPSHASH=v1-src-cache-$(shasum src/electron/.depshash | cut -f1 -d' ')
|
||||
echo "DEPSHASH=$DEPSHASH" >> $GITHUB_ENV
|
||||
echo "CACHE_PATH=$DEPSHASH.tar" >> $GITHUB_ENV
|
||||
- name: Restore src cache via AZCopy
|
||||
if: ${{ inputs.target-platform == 'macos' }}
|
||||
uses: ./src/electron/.github/actions/restore-cache-azcopy
|
||||
- name: Restore src cache via AKS
|
||||
if: ${{ inputs.target-platform == 'linux' }}
|
||||
uses: ./src/electron/.github/actions/restore-cache-aks
|
||||
- name: Checkout Electron
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
|
||||
with:
|
||||
path: src/electron
|
||||
fetch-depth: 0
|
||||
- name: Install Build Tools
|
||||
uses: ./src/electron/.github/actions/install-build-tools
|
||||
- name: Init Build Tools
|
||||
run: |
|
||||
e init -f --root=$(pwd) --out=Default ${{ inputs.gn-build-type }} --import ${{ inputs.gn-build-type }} --target-cpu ${{ inputs.target-arch }} --only-sdk
|
||||
- name: Run Electron Only Hooks
|
||||
run: |
|
||||
gclient runhooks --spec="solutions=[{'name':'src/electron','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':False},'managed':False}]"
|
||||
- name: Regenerate DEPS Hash
|
||||
run: |
|
||||
(cd src/electron && git checkout .) && node src/electron/script/generate-deps-hash.js && cat src/electron/.depshash-target
|
||||
echo "DEPSHASH=$(shasum src/electron/.depshash | cut -f1 -d' ')" >> $GITHUB_ENV
|
||||
- name: Add CHROMIUM_BUILDTOOLS_PATH to env
|
||||
run: echo "CHROMIUM_BUILDTOOLS_PATH=$(pwd)/src/buildtools" >> $GITHUB_ENV
|
||||
- name: Fix Sync
|
||||
uses: ./src/electron/.github/actions/fix-sync
|
||||
with:
|
||||
target-arch: ${{ inputs.target-arch }}
|
||||
target-platform: ${{ inputs.target-platform }}
|
||||
- name: Install build-tools & Setup RBE
|
||||
run: |
|
||||
echo "NUMBER_OF_NINJA_PROCESSES=${{ inputs.target-platform == 'linux' && '300' || '200' }}" >> $GITHUB_ENV
|
||||
cd ~/.electron_build_tools
|
||||
npx yarn --ignore-engines
|
||||
# Pull down credential helper and print status
|
||||
node -e "require('./src/utils/reclient.js').downloadAndPrepare({})"
|
||||
HELPER=$(node -p "require('./src/utils/reclient.js').helperPath({})")
|
||||
$HELPER login
|
||||
echo 'RBE_service='`node -e "console.log(require('./src/utils/reclient.js').serviceAddress)"` >> $GITHUB_ENV
|
||||
echo 'RBE_experimental_credentials_helper='`node -e "console.log(require('./src/utils/reclient.js').helperPath({}))"` >> $GITHUB_ENV
|
||||
echo 'RBE_experimental_credentials_helper_args=print' >> $GITHUB_ENV
|
||||
- name: Free up space (macOS)
|
||||
if: ${{ inputs.target-platform == 'macos' }}
|
||||
uses: ./src/electron/.github/actions/free-space-macos
|
||||
- name: Build Electron
|
||||
uses: ./src/electron/.github/actions/build-electron
|
||||
with:
|
||||
target-arch: ${{ inputs.target-arch }}
|
||||
target-platform: ${{ inputs.target-platform }}
|
||||
artifact-platform: ${{ inputs.target-platform == 'linux' && 'linux' || 'darwin' }}
|
||||
is-release: '${{ inputs.is-release }}'
|
||||
generate-symbols: '${{ inputs.generate-symbols }}'
|
||||
strip-binaries: '${{ inputs.strip-binaries }}'
|
||||
upload-to-storage: '${{ inputs.upload-to-storage }}'
|
||||
is-asan: '${{ inputs.is-asan }}'
|
||||
- name: Set GN_EXTRA_ARGS for MAS Build
|
||||
if: ${{ inputs.target-platform == 'macos' }}
|
||||
run: |
|
||||
echo "MAS_BUILD=true" >> $GITHUB_ENV
|
||||
GN_EXTRA_ARGS='is_mas_build=true'
|
||||
echo "GN_EXTRA_ARGS=$GN_EXTRA_ARGS" >> $GITHUB_ENV
|
||||
- name: Build Electron (MAS)
|
||||
if: ${{ inputs.target-platform == 'macos' }}
|
||||
uses: ./src/electron/.github/actions/build-electron
|
||||
with:
|
||||
target-arch: ${{ inputs.target-arch }}
|
||||
target-platform: ${{ inputs.target-platform }}
|
||||
artifact-platform: 'mas'
|
||||
is-release: '${{ inputs.is-release }}'
|
||||
generate-symbols: '${{ inputs.generate-symbols }}'
|
||||
upload-to-storage: '${{ inputs.upload-to-storage }}'
|
||||
step-suffix: '(mas)'
|
||||
141
.github/workflows/pipeline-segment-electron-gn-check.yml
vendored
Normal file
141
.github/workflows/pipeline-segment-electron-gn-check.yml
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
name: Pipeline Segment - Electron GN Check
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
target-platform:
|
||||
type: string
|
||||
description: 'Platform to run on, can be macos or linux'
|
||||
required: true
|
||||
target-arch:
|
||||
type: string
|
||||
description: 'Arch to build for, can be x64, arm64 or arm'
|
||||
required: true
|
||||
check-runs-on:
|
||||
type: string
|
||||
description: 'What host to run the tests on'
|
||||
required: true
|
||||
check-container:
|
||||
type: string
|
||||
description: 'JSON container information for aks runs-on'
|
||||
required: false
|
||||
default: '{"image":null}'
|
||||
gn-build-type:
|
||||
description: 'The gn build type - testing or release'
|
||||
required: true
|
||||
type: string
|
||||
default: testing
|
||||
is-asan:
|
||||
description: 'Building the Address Sanitizer (ASan) Linux build'
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
concurrency:
|
||||
group: electron-gn-check-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ inputs.is-asan }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }}
|
||||
GCLIENT_EXTRA_ARGS: ${{ inputs.target-platform == 'macos' && '--custom-var=checkout_mac=True --custom-var=host_os=mac' || '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' }}
|
||||
ELECTRON_OUT_DIR: Default
|
||||
TARGET_ARCH: ${{ inputs.target-arch }}
|
||||
|
||||
jobs:
|
||||
gn-check:
|
||||
# TODO(codebytere): Change this to medium VM
|
||||
runs-on: ${{ inputs.check-runs-on }}
|
||||
container: ${{ fromJSON(inputs.check-container) }}
|
||||
env:
|
||||
TARGET_ARCH: ${{ inputs.target-arch }}
|
||||
steps:
|
||||
- name: Checkout Electron
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
|
||||
with:
|
||||
path: src/electron
|
||||
fetch-depth: 0
|
||||
- name: Install Build Tools
|
||||
uses: ./src/electron/.github/actions/install-build-tools
|
||||
- name: Init Build Tools
|
||||
run: |
|
||||
e init -f --root=$(pwd) --out=Default ${{ inputs.gn-build-type }} --import ${{ inputs.gn-build-type }} --target-cpu ${{ inputs.target-arch }} --only-sdk
|
||||
- name: Get Depot Tools
|
||||
timeout-minutes: 5
|
||||
run: |
|
||||
git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
|
||||
SEDOPTION="-i"
|
||||
if [ "`uname`" = "Darwin" ]; then
|
||||
SEDOPTION="-i ''"
|
||||
fi
|
||||
|
||||
# remove ninjalog_uploader_wrapper.py from autoninja since we don't use it and it causes problems
|
||||
sed $SEDOPTION '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
|
||||
|
||||
# Ensure depot_tools does not update.
|
||||
test -d depot_tools && cd depot_tools
|
||||
if [ "`uname`" = "Linux" ]; then
|
||||
git apply --3way ../src/electron/.github/workflows/config/gclient.diff
|
||||
fi
|
||||
touch .disable_auto_update
|
||||
- name: Add Depot Tools to PATH
|
||||
run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH
|
||||
- name: Set GN_EXTRA_ARGS for Linux
|
||||
if: ${{ inputs.target-platform == 'linux' }}
|
||||
run: |
|
||||
if [ "${{ inputs.target-arch }}" = "arm" ]; then
|
||||
GN_EXTRA_ARGS='build_tflite_with_xnnpack=false'
|
||||
elif [ "${{ inputs.target-arch }}" = "arm64" ]; then
|
||||
GN_EXTRA_ARGS='fatal_linker_warnings=false enable_linux_installer=false'
|
||||
fi
|
||||
echo "GN_EXTRA_ARGS=$GN_EXTRA_ARGS" >> $GITHUB_ENV
|
||||
- name: Generate DEPS Hash
|
||||
run: |
|
||||
node src/electron/script/generate-deps-hash.js && cat src/electron/.depshash-target
|
||||
DEPSHASH=v1-src-cache-$(shasum src/electron/.depshash | cut -f1 -d' ')
|
||||
echo "DEPSHASH=$DEPSHASH" >> $GITHUB_ENV
|
||||
echo "CACHE_PATH=$DEPSHASH.tar" >> $GITHUB_ENV
|
||||
- name: Restore src cache via AZCopy
|
||||
if: ${{ inputs.target-platform == 'macos' }}
|
||||
uses: ./src/electron/.github/actions/restore-cache-azcopy
|
||||
- name: Restore src cache via AKS
|
||||
if: ${{ inputs.target-platform == 'linux' }}
|
||||
uses: ./src/electron/.github/actions/restore-cache-aks
|
||||
- name: Run Electron Only Hooks
|
||||
run: |
|
||||
gclient runhooks --spec="solutions=[{'name':'src/electron','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':False},'managed':False}]"
|
||||
- name: Regenerate DEPS Hash
|
||||
run: |
|
||||
(cd src/electron && git checkout .) && node src/electron/script/generate-deps-hash.js && cat src/electron/.depshash-target
|
||||
echo "DEPSHASH=$(shasum src/electron/.depshash | cut -f1 -d' ')" >> $GITHUB_ENV
|
||||
- name: Add CHROMIUM_BUILDTOOLS_PATH to env
|
||||
run: echo "CHROMIUM_BUILDTOOLS_PATH=$(pwd)/src/buildtools" >> $GITHUB_ENV
|
||||
- name: Checkout Electron
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
|
||||
with:
|
||||
path: src/electron
|
||||
fetch-depth: 0
|
||||
- name: Default GN gen
|
||||
run: |
|
||||
cd src/electron
|
||||
git pack-refs
|
||||
cd ..
|
||||
|
||||
e build --only-gen
|
||||
- name: Run GN Check
|
||||
run: |
|
||||
cd src
|
||||
gn check out/Default //electron:electron_lib
|
||||
gn check out/Default //electron:electron_app
|
||||
gn check out/Default //electron/shell/common/api:mojo
|
||||
|
||||
# Check the hunspell filenames
|
||||
node electron/script/gen-hunspell-filenames.js --check
|
||||
node electron/script/gen-libc++-filenames.js --check
|
||||
- name: Wait for active SSH sessions
|
||||
if: always() && !cancelled()
|
||||
run: |
|
||||
while [ -f /var/.ssh-lock ]
|
||||
do
|
||||
sleep 60
|
||||
done
|
||||
196
.github/workflows/pipeline-segment-electron-test.yml
vendored
Normal file
196
.github/workflows/pipeline-segment-electron-test.yml
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
name: Pipeline Segment - Electron Test
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
target-platform:
|
||||
type: string
|
||||
description: 'Platform to run on, can be macos or linux'
|
||||
required: true
|
||||
target-arch:
|
||||
type: string
|
||||
description: 'Arch to build for, can be x64, arm64 or arm'
|
||||
required: true
|
||||
test-runs-on:
|
||||
type: string
|
||||
description: 'What host to run the tests on'
|
||||
required: true
|
||||
test-container:
|
||||
type: string
|
||||
description: 'JSON container information for aks runs-on'
|
||||
required: false
|
||||
default: '{"image":null}'
|
||||
is-asan:
|
||||
description: 'Building the Address Sanitizer (ASan) Linux build'
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
concurrency:
|
||||
group: electron-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ inputs.is-asan }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: read
|
||||
pull-requests: read
|
||||
|
||||
env:
|
||||
ELECTRON_OUT_DIR: Default
|
||||
ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }}
|
||||
ELECTRON_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ${{ inputs.test-runs-on }}
|
||||
container: ${{ fromJSON(inputs.test-container) }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
build-type: ${{ inputs.target-platform == 'macos' && fromJSON('["darwin","mas"]') || fromJSON('["linux"]') }}
|
||||
shard: ${{ inputs.target-platform == 'macos' && fromJSON('[1, 2]') || fromJSON('[1, 2, 3]') }}
|
||||
env:
|
||||
BUILD_TYPE: ${{ matrix.build-type }}
|
||||
TARGET_ARCH: ${{ inputs.target-arch }}
|
||||
ARTIFACT_KEY: ${{ matrix.build-type }}_${{ inputs.target-arch }}
|
||||
steps:
|
||||
- name: Fix node20 on arm32 runners
|
||||
if: ${{ inputs.target-arch == 'arm' }}
|
||||
run: |
|
||||
cp $(which node) /mnt/runner-externals/node20/bin/
|
||||
- name: Add TCC permissions on macOS
|
||||
if: ${{ inputs.target-platform == 'macos' }}
|
||||
run: |
|
||||
configure_user_tccdb () {
|
||||
local values=$1
|
||||
local dbPath="$HOME/Library/Application Support/com.apple.TCC/TCC.db"
|
||||
local sqlQuery="INSERT OR REPLACE INTO access VALUES($values);"
|
||||
sqlite3 "$dbPath" "$sqlQuery"
|
||||
}
|
||||
|
||||
configure_sys_tccdb () {
|
||||
local values=$1
|
||||
local dbPath="/Library/Application Support/com.apple.TCC/TCC.db"
|
||||
local sqlQuery="INSERT OR REPLACE INTO access VALUES($values);"
|
||||
sudo sqlite3 "$dbPath" "$sqlQuery"
|
||||
}
|
||||
|
||||
userValuesArray=(
|
||||
"'kTCCServiceMicrophone','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159"
|
||||
"'kTCCServiceCamera','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159"
|
||||
"'kTCCServiceBluetoothAlways','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159"
|
||||
)
|
||||
for values in "${userValuesArray[@]}"; do
|
||||
# Sonoma and higher have a few extra values
|
||||
# Ref: https://github.com/actions/runner-images/blob/main/images/macos/scripts/build/configure-tccdb-macos.sh
|
||||
if [ "$OSTYPE" = "darwin23" ]; then
|
||||
configure_user_tccdb "$values,NULL,NULL,'UNUSED',${values##*,}"
|
||||
configure_sys_tccdb "$values,NULL,NULL,'UNUSED',${values##*,}"
|
||||
else
|
||||
configure_user_tccdb "$values"
|
||||
configure_sys_tccdb "$values"
|
||||
fi
|
||||
done
|
||||
- name: Checkout Electron
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
|
||||
with:
|
||||
path: src/electron
|
||||
fetch-depth: 0
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
cd src/electron
|
||||
node script/yarn install --frozen-lockfile
|
||||
- name: Get Depot Tools
|
||||
timeout-minutes: 5
|
||||
run: |
|
||||
git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
if [ "`uname`" = "Darwin" ]; then
|
||||
# remove ninjalog_uploader_wrapper.py from autoninja since we don't use it and it causes problems
|
||||
sed -i '' '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
|
||||
else
|
||||
sed -i '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
|
||||
# Remove swift-format dep from cipd on macOS until we send a patch upstream.
|
||||
cd depot_tools
|
||||
git apply --3way ../src/electron/.github/workflows/config/gclient.diff
|
||||
fi
|
||||
# Ensure depot_tools does not update.
|
||||
test -d depot_tools && cd depot_tools
|
||||
touch .disable_auto_update
|
||||
- name: Add Depot Tools to PATH
|
||||
run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH
|
||||
- name: Load ASan specific environment variables
|
||||
if: ${{ inputs.is-asan == true }}
|
||||
run: |
|
||||
echo "ARTIFACT_KEY=${{ matrix.build-type }}_${{ inputs.target-arch }}_asan" >> $GITHUB_ENV
|
||||
echo "DISABLE_CRASH_REPORTER_TESTS=true" >> $GITHUB_ENV
|
||||
echo "IS_ASAN=true" >> $GITHUB_ENV
|
||||
- name: Download Generated Artifacts
|
||||
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e
|
||||
with:
|
||||
name: generated_artifacts_${{ env.ARTIFACT_KEY }}
|
||||
path: ./generated_artifacts_${{ matrix.build-type }}_${{ inputs.target-arch }}
|
||||
- name: Download Src Artifacts
|
||||
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e
|
||||
with:
|
||||
name: src_artifacts_${{ env.ARTIFACT_KEY }}
|
||||
path: ./src_artifacts_${{ matrix.build-type }}_${{ inputs.target-arch }}
|
||||
- name: Restore Generated Artifacts
|
||||
run: ./src/electron/script/actions/restore-artifacts.sh
|
||||
- name: Unzip Dist, Mksnapshot & Chromedriver
|
||||
run: |
|
||||
cd src/out/Default
|
||||
unzip -:o dist.zip
|
||||
unzip -:o chromedriver.zip
|
||||
unzip -:o mksnapshot.zip
|
||||
- name: Import & Trust Self-Signed Codesigning Cert on MacOS
|
||||
if: ${{ inputs.target-platform == 'macos' && inputs.target-arch == 'x64' }}
|
||||
run: |
|
||||
sudo security authorizationdb write com.apple.trust-settings.admin allow
|
||||
cd src/electron
|
||||
./script/codesign/generate-identity.sh
|
||||
- name: Run Electron Tests
|
||||
shell: bash
|
||||
env:
|
||||
MOCHA_REPORTER: mocha-multi-reporters
|
||||
ELECTRON_TEST_RESULTS_DIR: junit
|
||||
MOCHA_MULTI_REPORTERS: mocha-junit-reporter, tap
|
||||
ELECTRON_DISABLE_SECURITY_WARNINGS: 1
|
||||
ELECTRON_SKIP_NATIVE_MODULE_TESTS: true
|
||||
DISPLAY: ':99.0'
|
||||
run: |
|
||||
cd src/electron
|
||||
# Get which tests are on this shard
|
||||
tests_files=$(node script/split-tests ${{ matrix.shard }} ${{ inputs.target-platform == 'macos' && 2 || 3 }})
|
||||
|
||||
# Run tests
|
||||
if [ "`uname`" = "Darwin" ]; then
|
||||
echo "About to start tests"
|
||||
node script/yarn test --runners=main --trace-uncaught --enable-logging --files $tests_files
|
||||
else
|
||||
chown :builduser .. && chmod g+w ..
|
||||
chown -R :builduser . && chmod -R g+w .
|
||||
chmod 4755 ../out/Default/chrome-sandbox
|
||||
runuser -u builduser -- git config --global --add safe.directory $(pwd)
|
||||
if [ "${{ inputs.is-asan }}" == "true" ]; then
|
||||
cd ..
|
||||
ASAN_SYMBOLIZE="$PWD/tools/valgrind/asan/asan_symbolize.py --executable-path=$PWD/out/Default/electron"
|
||||
export ASAN_OPTIONS="symbolize=0 handle_abort=1"
|
||||
export G_SLICE=always-malloc
|
||||
export NSS_DISABLE_ARENA_FREE_LIST=1
|
||||
export NSS_DISABLE_UNLOAD=1
|
||||
export LLVM_SYMBOLIZER_PATH=$PWD/third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer
|
||||
export MOCHA_TIMEOUT=180000
|
||||
echo "Piping output to ASAN_SYMBOLIZE ($ASAN_SYMBOLIZE)"
|
||||
cd electron
|
||||
runuser -u builduser -- xvfb-run script/actions/run-tests.sh script/yarn test --runners=main --trace-uncaught --enable-logging --files $tests_files | $ASAN_SYMBOLIZE
|
||||
else
|
||||
runuser -u builduser -- xvfb-run script/actions/run-tests.sh script/yarn test --runners=main --trace-uncaught --enable-logging --files $tests_files
|
||||
fi
|
||||
fi
|
||||
- name: Wait for active SSH sessions
|
||||
if: always() && !cancelled()
|
||||
run: |
|
||||
while [ -f /var/.ssh-lock ]
|
||||
do
|
||||
sleep 60
|
||||
done
|
||||
165
.github/workflows/pipeline-segment-node-nan-test.yml
vendored
Normal file
165
.github/workflows/pipeline-segment-node-nan-test.yml
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
name: Pipeline Segment - Node/Nan Test
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
target-platform:
|
||||
type: string
|
||||
description: 'Platform to run on, can be macos or linux'
|
||||
required: true
|
||||
target-arch:
|
||||
type: string
|
||||
description: 'Arch to build for, can be x64, arm64 or arm'
|
||||
required: true
|
||||
test-runs-on:
|
||||
type: string
|
||||
description: 'What host to run the tests on'
|
||||
required: true
|
||||
test-container:
|
||||
type: string
|
||||
description: 'JSON container information for aks runs-on'
|
||||
required: false
|
||||
default: '{"image":null}'
|
||||
gn-build-type:
|
||||
description: 'The gn build type - testing or release'
|
||||
required: true
|
||||
type: string
|
||||
default: testing
|
||||
|
||||
concurrency:
|
||||
group: electron-node-nan-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }}
|
||||
|
||||
env:
|
||||
ELECTRON_OUT_DIR: Default
|
||||
ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }}
|
||||
|
||||
jobs:
|
||||
node-tests:
|
||||
name: Run Node.js Tests
|
||||
runs-on: electron-arc-linux-amd64-8core
|
||||
timeout-minutes: 20
|
||||
env:
|
||||
TARGET_ARCH: ${{ inputs.target-arch }}
|
||||
BUILD_TYPE: linux
|
||||
container: ${{ fromJSON(inputs.test-container) }}
|
||||
steps:
|
||||
- name: Checkout Electron
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
|
||||
with:
|
||||
path: src/electron
|
||||
fetch-depth: 0
|
||||
- name: Install Build Tools
|
||||
uses: ./src/electron/.github/actions/install-build-tools
|
||||
- name: Init Build Tools
|
||||
run: |
|
||||
e init -f --root=$(pwd) --out=Default ${{ inputs.gn-build-type }} --import ${{ inputs.gn-build-type }} --target-cpu ${{ inputs.target-arch }}
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
cd src/electron
|
||||
node script/yarn install --frozen-lockfile
|
||||
- name: Get Depot Tools
|
||||
timeout-minutes: 5
|
||||
run: |
|
||||
git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
sed -i '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
|
||||
cd depot_tools
|
||||
git apply --3way ../src/electron/.github/workflows/config/gclient.diff
|
||||
# Ensure depot_tools does not update.
|
||||
test -d depot_tools && cd depot_tools
|
||||
touch .disable_auto_update
|
||||
- name: Add Depot Tools to PATH
|
||||
run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH
|
||||
- name: Download Generated Artifacts
|
||||
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e
|
||||
with:
|
||||
name: generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }}
|
||||
path: ./generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }}
|
||||
- name: Download Src Artifacts
|
||||
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e
|
||||
with:
|
||||
name: src_artifacts_linux_${{ env.TARGET_ARCH }}
|
||||
path: ./src_artifacts_linux_${{ env.TARGET_ARCH }}
|
||||
- name: Restore Generated Artifacts
|
||||
run: ./src/electron/script/actions/restore-artifacts.sh
|
||||
- name: Unzip Dist
|
||||
run: |
|
||||
cd src/out/Default
|
||||
unzip -:o dist.zip
|
||||
- name: Setup Linux for Headless Testing
|
||||
run: sh -e /etc/init.d/xvfb start
|
||||
- name: Run Node.js Tests
|
||||
run: |
|
||||
cd src
|
||||
node electron/script/node-spec-runner.js --default --jUnitDir=junit
|
||||
- name: Wait for active SSH sessions
|
||||
if: always() && !cancelled()
|
||||
run: |
|
||||
while [ -f /var/.ssh-lock ]
|
||||
do
|
||||
sleep 60
|
||||
done
|
||||
nan-tests:
|
||||
name: Run Nan Tests
|
||||
runs-on: electron-arc-linux-amd64-4core
|
||||
timeout-minutes: 20
|
||||
env:
|
||||
TARGET_ARCH: ${{ inputs.target-arch }}
|
||||
BUILD_TYPE: linux
|
||||
container: ${{ fromJSON(inputs.test-container) }}
|
||||
steps:
|
||||
- name: Checkout Electron
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
|
||||
with:
|
||||
path: src/electron
|
||||
fetch-depth: 0
|
||||
- name: Install Build Tools
|
||||
uses: ./src/electron/.github/actions/install-build-tools
|
||||
- name: Init Build Tools
|
||||
run: |
|
||||
e init -f --root=$(pwd) --out=Default ${{ inputs.gn-build-type }}
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
cd src/electron
|
||||
node script/yarn install --frozen-lockfile
|
||||
- name: Get Depot Tools
|
||||
timeout-minutes: 5
|
||||
run: |
|
||||
git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
sed -i '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
|
||||
cd depot_tools
|
||||
git apply --3way ../src/electron/.github/workflows/config/gclient.diff
|
||||
# Ensure depot_tools does not update.
|
||||
test -d depot_tools && cd depot_tools
|
||||
touch .disable_auto_update
|
||||
- name: Add Depot Tools to PATH
|
||||
run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH
|
||||
- name: Download Generated Artifacts
|
||||
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e
|
||||
with:
|
||||
name: generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }}
|
||||
path: ./generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }}
|
||||
- name: Download Src Artifacts
|
||||
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e
|
||||
with:
|
||||
name: src_artifacts_linux_${{ env.TARGET_ARCH }}
|
||||
path: ./src_artifacts_linux_${{ env.TARGET_ARCH }}
|
||||
- name: Restore Generated Artifacts
|
||||
run: ./src/electron/script/actions/restore-artifacts.sh
|
||||
- name: Unzip Dist
|
||||
run: |
|
||||
cd src/out/Default
|
||||
unzip -:o dist.zip
|
||||
- name: Setup Linux for Headless Testing
|
||||
run: sh -e /etc/init.d/xvfb start
|
||||
- name: Run Node.js Tests
|
||||
run: |
|
||||
cd src
|
||||
node electron/script/nan-spec-runner.js
|
||||
- name: Wait for active SSH sessions
|
||||
if: always() && !cancelled()
|
||||
run: |
|
||||
while [ -f /var/.ssh-lock ]
|
||||
do
|
||||
sleep 60
|
||||
done
|
||||
15
BUILD.gn
15
BUILD.gn
@@ -81,18 +81,11 @@ if (is_linux) {
|
||||
]
|
||||
}
|
||||
|
||||
# Generates electron_gtk_stubs.h header which contains
|
||||
# stubs for extracting function ptrs from the gtk library.
|
||||
# Function signatures for which stubs are required should be
|
||||
# declared in electron_gtk.sigs, currently this file contains
|
||||
# signatures for the functions used with native file chooser
|
||||
# implementation. In future, this file can be extended to contain
|
||||
# gtk4 stubs to switch gtk version in runtime.
|
||||
# Generates headers which contain stubs for extracting function ptrs
|
||||
# from the gtk library. Function signatures for which stubs are
|
||||
# required should be declared in the sig files.
|
||||
generate_stubs("electron_gtk_stubs") {
|
||||
sigs = [
|
||||
"shell/browser/ui/electron_gdk_pixbuf.sigs",
|
||||
"shell/browser/ui/electron_gtk.sigs",
|
||||
]
|
||||
sigs = [ "shell/browser/ui/electron_gdk_pixbuf.sigs" ]
|
||||
extra_header = "shell/browser/ui/electron_gtk.fragment"
|
||||
output_name = "electron_gtk_stubs"
|
||||
public_deps = [ "//ui/gtk:gtk_config" ]
|
||||
|
||||
@@ -1261,7 +1261,7 @@ Returns `Object`:
|
||||
|
||||
* `openAtLogin` boolean - `true` if the app is set to open at login.
|
||||
* `openAsHidden` boolean _macOS_ _Deprecated_ - `true` if the app is set to open as hidden at login. This does not work on macOS 13 and up.
|
||||
* `wasOpenedAtLogin` boolean _macOS_ _Deprecated_ - `true` if the app was opened at login automatically. This setting is not available on [MAS builds][mas-builds] or on macOS 13 and up.
|
||||
* `wasOpenedAtLogin` boolean _macOS_ - `true` if the app was opened at login automatically.
|
||||
* `wasOpenedAsHidden` boolean _macOS_ _Deprecated_ - `true` if the app was opened as a hidden login item. This indicates that the app should not open any windows at startup. This setting is not available on [MAS builds][mas-builds] or on macOS 13 and up.
|
||||
* `restoreState` boolean _macOS_ _Deprecated_ - `true` if the app was opened as a login item that should restore the state from the previous session. This indicates that the app should restore the windows that were open the last time the app was closed. This setting is not available on [MAS builds][mas-builds] or on macOS 13 and up.
|
||||
* `status` string _macOS_ - can be one of `not-registered`, `enabled`, `requires-approval`, or `not-found`.
|
||||
|
||||
@@ -34,7 +34,7 @@ filenames = {
|
||||
"shell/browser/notifications/linux/notification_presenter_linux.h",
|
||||
"shell/browser/relauncher_linux.cc",
|
||||
"shell/browser/ui/electron_desktop_window_tree_host_linux.cc",
|
||||
"shell/browser/ui/file_dialog_gtk.cc",
|
||||
"shell/browser/ui/file_dialog_linux.cc",
|
||||
"shell/browser/ui/gtk/menu_gtk.cc",
|
||||
"shell/browser/ui/gtk/menu_gtk.h",
|
||||
"shell/browser/ui/gtk/menu_util.cc",
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
cherry-pick-a65e511a14b4.patch
|
||||
cherry-pick-bc18aec94c82.patch
|
||||
cherry-pick-bd7aa9779873.patch
|
||||
cherry-pick-2a434fd0af6b.patch
|
||||
cherry-pick-867c1001637e.patch
|
||||
cherry-pick-0b785e88fefa.patch
|
||||
cherry-pick-511cfef8e050.patch
|
||||
cherry-pick-93c3cf1c787f.patch
|
||||
cherry-pick-33051b084850.patch
|
||||
cherry-pick-b845fed99111.patch
|
||||
cherry-pick-771e74ab497d.patch
|
||||
cherry-pick-8f07d39227f6.patch
|
||||
cherry-pick-b3c64851765c.patch
|
||||
|
||||
523
patches/DirectXShaderCompiler/cherry-pick-0b785e88fefa.patch
Normal file
523
patches/DirectXShaderCompiler/cherry-pick-0b785e88fefa.patch
Normal file
@@ -0,0 +1,523 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Antonio Maiorano <amaiorano@google.com>
|
||||
Date: Fri, 24 May 2024 15:51:26 -0400
|
||||
Subject: Fix dxil-remove-dead-blocks removing switch with multiple same
|
||||
successor (#6610)
|
||||
|
||||
Given a switch with a constant condition and all cases the same
|
||||
(branching to the same successor), dxil-remove-dead-blocks would
|
||||
incorrectly remove the switch when replacing it with a branch, by
|
||||
forgetting to remove the N-1 incoming values to the PHIs in the
|
||||
successor block.
|
||||
|
||||
Bug: chromium:338071106
|
||||
Change-Id: Iaa2c42642f3e370afd19d88c96c81056c16349b6
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5570270
|
||||
Reviewed-by: Ben Clayton <bclayton@chromium.org>
|
||||
Reviewed-by: James Price <jrprice@google.com>
|
||||
|
||||
diff --git a/lib/Transforms/Scalar/DxilRemoveDeadBlocks.cpp b/lib/Transforms/Scalar/DxilRemoveDeadBlocks.cpp
|
||||
index 54308eed2e018903e518be4a5ff809e080be78c0..9a87f4e6740c8da0522c6bf00f2a365f838cb3c0 100644
|
||||
--- a/lib/Transforms/Scalar/DxilRemoveDeadBlocks.cpp
|
||||
+++ b/lib/Transforms/Scalar/DxilRemoveDeadBlocks.cpp
|
||||
@@ -35,6 +35,7 @@
|
||||
using namespace llvm;
|
||||
using namespace hlsl;
|
||||
|
||||
+// Removes BB from PHI nodes in SuccBB, deleting the PHI nodes if empty.
|
||||
static void RemoveIncomingValueFrom(BasicBlock *SuccBB, BasicBlock *BB) {
|
||||
for (auto inst_it = SuccBB->begin(); inst_it != SuccBB->end();) {
|
||||
Instruction *I = &*(inst_it++);
|
||||
@@ -105,6 +106,8 @@ bool DeadBlockDeleter::Run(Function &F, DxilValueCache *DVC) {
|
||||
} else if (SwitchInst *Switch = dyn_cast<SwitchInst>(BB->getTerminator())) {
|
||||
Value *Cond = Switch->getCondition();
|
||||
BasicBlock *Succ = nullptr;
|
||||
+ // If the condition to Switch is constant, replace Switch with a branch
|
||||
+ // to the current case successor.
|
||||
if (ConstantInt *ConstCond = DVC->GetConstInt(Cond)) {
|
||||
Succ = hlsl::dxilutil::GetSwitchSuccessorForCond(Switch, ConstCond);
|
||||
}
|
||||
@@ -112,16 +115,32 @@ bool DeadBlockDeleter::Run(Function &F, DxilValueCache *DVC) {
|
||||
if (Succ) {
|
||||
Add(Succ);
|
||||
|
||||
+ // Create branch from BB to Succ that will replace Switch.
|
||||
+ // This adds BB to preds of Succ.
|
||||
BranchInst *NewBr = BranchInst::Create(Succ, BB);
|
||||
hlsl::DxilMDHelper::CopyMetadata(*NewBr, *Switch);
|
||||
|
||||
+ // For any successors we're not going to, remove incoming block BB from
|
||||
+ // PHI nodes in those successors.
|
||||
+ unsigned numSucc = 0;
|
||||
for (unsigned i = 0; i < Switch->getNumSuccessors(); i++) {
|
||||
BasicBlock *NotSucc = Switch->getSuccessor(i);
|
||||
- if (NotSucc != Succ) {
|
||||
+ if (NotSucc != Succ)
|
||||
RemoveIncomingValueFrom(NotSucc, BB);
|
||||
- }
|
||||
+ else
|
||||
+ ++numSucc;
|
||||
+ }
|
||||
+
|
||||
+ // We're replacing Switch with a single unconditional branch. If Switch
|
||||
+ // has N cases with the same Succ, we need to remove N-1 incoming values
|
||||
+ // of BB from the PHI nodes in Succ. This ensures that the preds of Succ
|
||||
+ // match the ones in its PHIs.
|
||||
+ for (unsigned i = 1; i < numSucc; i++) {
|
||||
+ RemoveIncomingValueFrom(Succ, BB);
|
||||
}
|
||||
|
||||
+ // Finally, erase Switch, which will remove BB as pred from all
|
||||
+ // successors.
|
||||
Switch->eraseFromParent();
|
||||
Switch = nullptr;
|
||||
Changed = true;
|
||||
diff --git a/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.hlsl b/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.hlsl
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..43c3510b2ce18b15ff74a0db4697898da807f49f
|
||||
--- /dev/null
|
||||
+++ b/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.hlsl
|
||||
@@ -0,0 +1,68 @@
|
||||
+// Test switch with multiple same successors
|
||||
+// RUN: %dxc -T ps_6_6 %s | FileCheck %s
|
||||
+
|
||||
+// This test used to fail with validation errors:
|
||||
+//
|
||||
+// error: validation errors
|
||||
+// error: Module bitcode is invalid.
|
||||
+// error: PHINode should have one entry for each predecessor of its parent basic block!
|
||||
+// %22 = phi i32 [ 1, %20 ], [ 1, %20 ], [ 1, %20 ], [ 1, %20 ], [ %11, %13 ]
|
||||
+// PHINode should have one entry for each predecessor of its parent basic block!
|
||||
+// %28 = phi i32 [ 1, %26 ], [ 1, %26 ], [ 1, %26 ], [ 1, %26 ], [ %22, %24 ]
|
||||
+// PHINode should have one entry for each predecessor of its parent basic block!
|
||||
+// %34 = phi i32 [ 1, %32 ], [ 1, %32 ], [ 1, %32 ], [ 1, %32 ], [ %28, %30 ]
|
||||
+// PHINode should have one entry for each predecessor of its parent basic block!
|
||||
+// %47 = phi i32 [ 1, %45 ], [ 1, %45 ], [ 1, %45 ], [ 1, %45 ], [ %41, %43 ]
|
||||
+//
|
||||
+// This was fixed in dxil-remove-dead-blocks. See switch-with-multiple-same-successor.ll
|
||||
+// for the pass-specific checks. Here, we just want to make sure dxc compiles this without error.
|
||||
+
|
||||
+// CHECK: @main
|
||||
+
|
||||
+ByteAddressBuffer g_buff : register(t0);
|
||||
+
|
||||
+struct retval {
|
||||
+ float4 value : SV_Target0;
|
||||
+};
|
||||
+
|
||||
+retval main() {
|
||||
+ float4 g = asfloat(g_buff.Load4(0u));
|
||||
+ bool do_discard = false;
|
||||
+
|
||||
+ for (int i = 0; i < 10; ++i) {
|
||||
+ if (g.x != 0.0f)
|
||||
+ continue;
|
||||
+
|
||||
+ // Switch with the same successor in all cases
|
||||
+ switch(i) {
|
||||
+ case 1: {
|
||||
+ g.x = g.x;
|
||||
+ break;
|
||||
+ }
|
||||
+ case 2: {
|
||||
+ g.x = g.x;
|
||||
+ break;
|
||||
+ }
|
||||
+ case 3: {
|
||||
+ g.x = g.x;
|
||||
+ break;
|
||||
+ }
|
||||
+ // Skip 'case 4' to avoid case range combining
|
||||
+ case 5: {
|
||||
+ g.x = g.x;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ if (i == 6) {
|
||||
+ break;
|
||||
+ }
|
||||
+ g.x = atan2(1.0f, g.x);
|
||||
+ do_discard = true;
|
||||
+ }
|
||||
+
|
||||
+ if (do_discard) {
|
||||
+ discard;
|
||||
+ }
|
||||
+
|
||||
+ return (retval)0;
|
||||
+}
|
||||
diff --git a/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.ll b/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.ll
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..d3e7e2f1e40c816c4ed28bfc45a1569e130f472c
|
||||
--- /dev/null
|
||||
+++ b/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.ll
|
||||
@@ -0,0 +1,369 @@
|
||||
+; RUN: %dxopt %s -hlsl-passes-resume -dxil-remove-dead-blocks -S | FileCheck %s
|
||||
+
|
||||
+; Validate that a switch with a constant condition and multiple of the same successor
|
||||
+; is correctly removed, ensuring that PHIs in the successor are properly updated.
|
||||
+; For instance, in:
|
||||
+;
|
||||
+;
|
||||
+; if.end.1: ; preds = %for.inc
|
||||
+; switch i32 1, label %sw.epilog.1 [
|
||||
+; i32 1, label %dx.struct_exit.new_exiting.1
|
||||
+; i32 2, label %dx.struct_exit.new_exiting.1
|
||||
+; i32 3, label %dx.struct_exit.new_exiting.1
|
||||
+; i32 5, label %dx.struct_exit.new_exiting.1
|
||||
+; ], !dbg !31 ; line:23 col:5
|
||||
+;
|
||||
+; sw.epilog.1: ; preds = %if.end.1
|
||||
+; br label %dx.struct_exit.new_exiting.1
|
||||
+;
|
||||
+; dx.struct_exit.new_exiting.1: ; preds = %sw.epilog.1, %if.end.1, %if.end.1, %if.end.1, %if.end.1, %for.inc
|
||||
+; %dx.struct_exit.prop.1 = phi i32 [ %do_discard.2, %sw.epilog.1 ], [ 0, %if.end.1 ], [ 0, %if.end.1 ], [ 0, %if.end.1 ], [ 0, %if.end.1 ], [ 0, %for.inc ]
|
||||
+; %do_discard.2.1 = phi i32 [ 1, %sw.epilog.1 ], [ 1, %if.end.1 ], [ 1, %if.end.1 ], [ 1, %if.end.1 ], [ 1, %if.end.1 ], [ %do_discard.2, %for.inc ]
|
||||
+; %g.2.i0.1 = phi float [ 0x3FF921FB60000000, %sw.epilog.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ %g.2.i0, %for.inc ]
|
||||
+; br i1 false, label %cleanup, label %for.inc.1
|
||||
+;
|
||||
+;
|
||||
+; After dxil-remove-dead-blocks, the multiple `%if.end.1` in preds and in the two phi instructions should be removed,
|
||||
+; and only one instance should be left.
|
||||
+
|
||||
+; CHECK: if.end.1: ; preds = %for.inc
|
||||
+; CHECK-NEXT: br label %dx.struct_exit.new_exiting.1
|
||||
+
|
||||
+; CHECK: dx.struct_exit.new_exiting.1: ; preds = %if.end.1, %for.inc
|
||||
+; CHECK-NEXT: %do_discard.2.1 = phi i32 [ 1, %if.end.1 ], [ %do_discard.2, %for.inc ]
|
||||
+; CHECK-NEXT: %g.2.i0.1 = phi float [ 0x3FF921FB60000000, %if.end.1 ], [ %g.2.i0, %for.inc ]
|
||||
+
|
||||
+;
|
||||
+; Output signature:
|
||||
+;
|
||||
+; Name Index InterpMode DynIdx
|
||||
+; -------------------- ----- ---------------------- ------
|
||||
+; SV_Target 0
|
||||
+;
|
||||
+; Buffer Definitions:
|
||||
+;
|
||||
+;
|
||||
+; Resource Bindings:
|
||||
+;
|
||||
+; Name Type Format Dim ID HLSL Bind Count
|
||||
+; ------------------------------ ---------- ------- ----------- ------- -------------- ------
|
||||
+; g_buff texture byte r/o T0 t0 1
|
||||
+;
|
||||
+target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
|
||||
+target triple = "dxil-ms-dx"
|
||||
+
|
||||
+%struct.ByteAddressBuffer = type { i32 }
|
||||
+%dx.types.Handle = type { i8* }
|
||||
+%dx.types.ResourceProperties = type { i32, i32 }
|
||||
+%dx.types.ResRet.i32 = type { i32, i32, i32, i32, i32 }
|
||||
+%struct.retval = type { <4 x float> }
|
||||
+
|
||||
+@"\01?g_buff@@3UByteAddressBuffer@@A" = external global %struct.ByteAddressBuffer, align 4
|
||||
+@llvm.used = appending global [1 x i8*] [i8* bitcast (%struct.ByteAddressBuffer* @"\01?g_buff@@3UByteAddressBuffer@@A" to i8*)], section "llvm.metadata"
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+define void @main(<4 x float>* noalias nocapture readnone) #0 {
|
||||
+for.body.lr.ph:
|
||||
+ %1 = load %struct.ByteAddressBuffer, %struct.ByteAddressBuffer* @"\01?g_buff@@3UByteAddressBuffer@@A", align 4, !dbg !23 ; line:15 col:22
|
||||
+ %2 = call %dx.types.Handle @dx.op.createHandleForLib.struct.ByteAddressBuffer(i32 160, %struct.ByteAddressBuffer %1), !dbg !23 ; line:15 col:22 ; CreateHandleForLib(Resource)
|
||||
+ %3 = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle %2, %dx.types.ResourceProperties { i32 11, i32 0 }), !dbg !23 ; line:15 col:22 ; AnnotateHandle(res,props) resource: ByteAddressBuffer
|
||||
+ %RawBufferLoad = call %dx.types.ResRet.i32 @dx.op.rawBufferLoad.i32(i32 139, %dx.types.Handle %3, i32 0, i32 undef, i8 15, i32 4), !dbg !23 ; line:15 col:22 ; RawBufferLoad(srv,index,elementOffset,mask,alignment)
|
||||
+ %4 = extractvalue %dx.types.ResRet.i32 %RawBufferLoad, 0, !dbg !23 ; line:15 col:22
|
||||
+ %.i0 = bitcast i32 %4 to float, !dbg !27 ; line:15 col:14
|
||||
+ br label %for.body, !dbg !28 ; line:18 col:3
|
||||
+
|
||||
+for.body: ; preds = %for.body.lr.ph
|
||||
+ %cmp3 = fcmp fast une float %.i0, 0.000000e+00, !dbg !29 ; line:19 col:13
|
||||
+ br i1 %cmp3, label %dx.struct_exit.new_exiting, label %if.end, !dbg !30 ; line:19 col:9
|
||||
+
|
||||
+if.end: ; preds = %for.body
|
||||
+ switch i32 0, label %sw.epilog [
|
||||
+ i32 1, label %dx.struct_exit.new_exiting
|
||||
+ i32 2, label %dx.struct_exit.new_exiting
|
||||
+ i32 3, label %dx.struct_exit.new_exiting
|
||||
+ i32 5, label %dx.struct_exit.new_exiting
|
||||
+ ], !dbg !31 ; line:23 col:5
|
||||
+
|
||||
+sw.epilog: ; preds = %if.end
|
||||
+ br label %dx.struct_exit.new_exiting
|
||||
+
|
||||
+dx.struct_exit.new_exiting: ; preds = %sw.epilog, %if.end, %if.end, %if.end, %if.end, %for.body
|
||||
+ %do_discard.2 = phi i32 [ 0, %for.body ], [ 1, %if.end ], [ 1, %if.end ], [ 1, %if.end ], [ 1, %if.end ], [ 1, %sw.epilog ]
|
||||
+ %g.2.i0 = phi float [ %.i0, %for.body ], [ 0x3FF921FB60000000, %if.end ], [ 0x3FF921FB60000000, %if.end ], [ 0x3FF921FB60000000, %if.end ], [ 0x3FF921FB60000000, %if.end ], [ 0x3FF921FB60000000, %sw.epilog ]
|
||||
+ br i1 false, label %cleanup, label %for.inc
|
||||
+
|
||||
+for.inc: ; preds = %dx.struct_exit.new_exiting
|
||||
+ %cmp3.1 = fcmp fast une float %g.2.i0, 0.000000e+00, !dbg !29 ; line:19 col:13
|
||||
+ br i1 %cmp3.1, label %dx.struct_exit.new_exiting.1, label %if.end.1, !dbg !30 ; line:19 col:9
|
||||
+
|
||||
+cleanup: ; preds = %for.inc.9, %dx.struct_exit.new_exiting.9, %dx.struct_exit.new_exiting.8, %dx.struct_exit.new_exiting.7, %dx.struct_exit.new_exiting.6, %dx.struct_exit.new_exiting.5, %dx.struct_exit.new_exiting.4, %dx.struct_exit.new_exiting.3, %dx.struct_exit.new_exiting.2, %dx.struct_exit.new_exiting.1, %dx.struct_exit.new_exiting
|
||||
+ %do_discard.3 = phi i32 [ 0, %dx.struct_exit.new_exiting ], [ %dx.struct_exit.prop.1, %dx.struct_exit.new_exiting.1 ], [ %dx.struct_exit.prop.2, %dx.struct_exit.new_exiting.2 ], [ %dx.struct_exit.prop.3, %dx.struct_exit.new_exiting.3 ], [ %dx.struct_exit.prop.4, %dx.struct_exit.new_exiting.4 ], [ %dx.struct_exit.prop.5, %dx.struct_exit.new_exiting.5 ], [ %dx.struct_exit.prop.6, %dx.struct_exit.new_exiting.6 ], [ %dx.struct_exit.prop.7, %dx.struct_exit.new_exiting.7 ], [ %dx.struct_exit.prop.8, %dx.struct_exit.new_exiting.8 ], [ %dx.struct_exit.prop.9, %dx.struct_exit.new_exiting.9 ], [ %do_discard.2.9, %for.inc.9 ]
|
||||
+ %tobool15 = icmp eq i32 %do_discard.3, 0, !dbg !32 ; line:49 col:7
|
||||
+ br i1 %tobool15, label %if.end.17, label %if.then.16, !dbg !32 ; line:49 col:7
|
||||
+
|
||||
+if.then.16: ; preds = %cleanup
|
||||
+ call void @dx.op.discard(i32 82, i1 true), !dbg !33 ; line:49 col:19 ; Discard(condition)
|
||||
+ br label %if.end.17, !dbg !34 ; line:51 col:3
|
||||
+
|
||||
+if.end.17: ; preds = %cleanup, %if.then.16
|
||||
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float 0.000000e+00), !dbg !35 ; line:53 col:18 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
|
||||
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float 0.000000e+00), !dbg !35 ; line:53 col:18 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
|
||||
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float 0.000000e+00), !dbg !35 ; line:53 col:18 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
|
||||
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3, float 0.000000e+00), !dbg !35 ; line:53 col:18 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
|
||||
+ ret void, !dbg !36 ; line:54 col:1
|
||||
+
|
||||
+if.end.1: ; preds = %for.inc
|
||||
+ switch i32 1, label %sw.epilog.1 [
|
||||
+ i32 1, label %dx.struct_exit.new_exiting.1
|
||||
+ i32 2, label %dx.struct_exit.new_exiting.1
|
||||
+ i32 3, label %dx.struct_exit.new_exiting.1
|
||||
+ i32 5, label %dx.struct_exit.new_exiting.1
|
||||
+ ], !dbg !31 ; line:23 col:5
|
||||
+
|
||||
+sw.epilog.1: ; preds = %if.end.1
|
||||
+ br label %dx.struct_exit.new_exiting.1
|
||||
+
|
||||
+dx.struct_exit.new_exiting.1: ; preds = %sw.epilog.1, %if.end.1, %if.end.1, %if.end.1, %if.end.1, %for.inc
|
||||
+ %dx.struct_exit.prop.1 = phi i32 [ %do_discard.2, %sw.epilog.1 ], [ 0, %if.end.1 ], [ 0, %if.end.1 ], [ 0, %if.end.1 ], [ 0, %if.end.1 ], [ 0, %for.inc ]
|
||||
+ %do_discard.2.1 = phi i32 [ 1, %sw.epilog.1 ], [ 1, %if.end.1 ], [ 1, %if.end.1 ], [ 1, %if.end.1 ], [ 1, %if.end.1 ], [ %do_discard.2, %for.inc ]
|
||||
+ %g.2.i0.1 = phi float [ 0x3FF921FB60000000, %sw.epilog.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ %g.2.i0, %for.inc ]
|
||||
+ br i1 false, label %cleanup, label %for.inc.1
|
||||
+
|
||||
+for.inc.1: ; preds = %dx.struct_exit.new_exiting.1
|
||||
+ %cmp3.2 = fcmp fast une float %g.2.i0.1, 0.000000e+00, !dbg !29 ; line:19 col:13
|
||||
+ br i1 %cmp3.2, label %dx.struct_exit.new_exiting.2, label %if.end.2, !dbg !30 ; line:19 col:9
|
||||
+
|
||||
+if.end.2: ; preds = %for.inc.1
|
||||
+ switch i32 2, label %sw.epilog.2 [
|
||||
+ i32 1, label %dx.struct_exit.new_exiting.2
|
||||
+ i32 2, label %dx.struct_exit.new_exiting.2
|
||||
+ i32 3, label %dx.struct_exit.new_exiting.2
|
||||
+ i32 5, label %dx.struct_exit.new_exiting.2
|
||||
+ ], !dbg !31 ; line:23 col:5
|
||||
+
|
||||
+sw.epilog.2: ; preds = %if.end.2
|
||||
+ br label %dx.struct_exit.new_exiting.2
|
||||
+
|
||||
+dx.struct_exit.new_exiting.2: ; preds = %sw.epilog.2, %if.end.2, %if.end.2, %if.end.2, %if.end.2, %for.inc.1
|
||||
+ %dx.struct_exit.prop.2 = phi i32 [ %do_discard.2.1, %sw.epilog.2 ], [ 0, %if.end.2 ], [ 0, %if.end.2 ], [ 0, %if.end.2 ], [ 0, %if.end.2 ], [ 0, %for.inc.1 ]
|
||||
+ %do_discard.2.2 = phi i32 [ 1, %sw.epilog.2 ], [ 1, %if.end.2 ], [ 1, %if.end.2 ], [ 1, %if.end.2 ], [ 1, %if.end.2 ], [ %do_discard.2.1, %for.inc.1 ]
|
||||
+ %g.2.i0.2 = phi float [ 0x3FF921FB60000000, %sw.epilog.2 ], [ 0x3FF921FB60000000, %if.end.2 ], [ 0x3FF921FB60000000, %if.end.2 ], [ 0x3FF921FB60000000, %if.end.2 ], [ 0x3FF921FB60000000, %if.end.2 ], [ %g.2.i0.1, %for.inc.1 ]
|
||||
+ br i1 false, label %cleanup, label %for.inc.2
|
||||
+
|
||||
+for.inc.2: ; preds = %dx.struct_exit.new_exiting.2
|
||||
+ %cmp3.3 = fcmp fast une float %g.2.i0.2, 0.000000e+00, !dbg !29 ; line:19 col:13
|
||||
+ br i1 %cmp3.3, label %dx.struct_exit.new_exiting.3, label %if.end.3, !dbg !30 ; line:19 col:9
|
||||
+
|
||||
+if.end.3: ; preds = %for.inc.2
|
||||
+ switch i32 3, label %sw.epilog.3 [
|
||||
+ i32 1, label %dx.struct_exit.new_exiting.3
|
||||
+ i32 2, label %dx.struct_exit.new_exiting.3
|
||||
+ i32 3, label %dx.struct_exit.new_exiting.3
|
||||
+ i32 5, label %dx.struct_exit.new_exiting.3
|
||||
+ ], !dbg !31 ; line:23 col:5
|
||||
+
|
||||
+sw.epilog.3: ; preds = %if.end.3
|
||||
+ br label %dx.struct_exit.new_exiting.3
|
||||
+
|
||||
+dx.struct_exit.new_exiting.3: ; preds = %sw.epilog.3, %if.end.3, %if.end.3, %if.end.3, %if.end.3, %for.inc.2
|
||||
+ %dx.struct_exit.prop.3 = phi i32 [ %do_discard.2.2, %sw.epilog.3 ], [ 0, %if.end.3 ], [ 0, %if.end.3 ], [ 0, %if.end.3 ], [ 0, %if.end.3 ], [ 0, %for.inc.2 ]
|
||||
+ %do_discard.2.3 = phi i32 [ 1, %sw.epilog.3 ], [ 1, %if.end.3 ], [ 1, %if.end.3 ], [ 1, %if.end.3 ], [ 1, %if.end.3 ], [ %do_discard.2.2, %for.inc.2 ]
|
||||
+ %g.2.i0.3 = phi float [ 0x3FF921FB60000000, %sw.epilog.3 ], [ 0x3FF921FB60000000, %if.end.3 ], [ 0x3FF921FB60000000, %if.end.3 ], [ 0x3FF921FB60000000, %if.end.3 ], [ 0x3FF921FB60000000, %if.end.3 ], [ %g.2.i0.2, %for.inc.2 ]
|
||||
+ br i1 false, label %cleanup, label %for.inc.3
|
||||
+
|
||||
+for.inc.3: ; preds = %dx.struct_exit.new_exiting.3
|
||||
+ %cmp3.4 = fcmp fast une float %g.2.i0.3, 0.000000e+00, !dbg !29 ; line:19 col:13
|
||||
+ br i1 %cmp3.4, label %dx.struct_exit.new_exiting.4, label %if.end.4, !dbg !30 ; line:19 col:9
|
||||
+
|
||||
+if.end.4: ; preds = %for.inc.3
|
||||
+ switch i32 4, label %sw.epilog.4 [
|
||||
+ i32 1, label %dx.struct_exit.new_exiting.4
|
||||
+ i32 2, label %dx.struct_exit.new_exiting.4
|
||||
+ i32 3, label %dx.struct_exit.new_exiting.4
|
||||
+ i32 5, label %dx.struct_exit.new_exiting.4
|
||||
+ ], !dbg !31 ; line:23 col:5
|
||||
+
|
||||
+sw.epilog.4: ; preds = %if.end.4
|
||||
+ br label %dx.struct_exit.new_exiting.4
|
||||
+
|
||||
+dx.struct_exit.new_exiting.4: ; preds = %sw.epilog.4, %if.end.4, %if.end.4, %if.end.4, %if.end.4, %for.inc.3
|
||||
+ %dx.struct_exit.prop.4 = phi i32 [ %do_discard.2.3, %sw.epilog.4 ], [ 0, %if.end.4 ], [ 0, %if.end.4 ], [ 0, %if.end.4 ], [ 0, %if.end.4 ], [ 0, %for.inc.3 ]
|
||||
+ %do_discard.2.4 = phi i32 [ 1, %sw.epilog.4 ], [ 1, %if.end.4 ], [ 1, %if.end.4 ], [ 1, %if.end.4 ], [ 1, %if.end.4 ], [ %do_discard.2.3, %for.inc.3 ]
|
||||
+ %g.2.i0.4 = phi float [ 0x3FF921FB60000000, %sw.epilog.4 ], [ 0x3FF921FB60000000, %if.end.4 ], [ 0x3FF921FB60000000, %if.end.4 ], [ 0x3FF921FB60000000, %if.end.4 ], [ 0x3FF921FB60000000, %if.end.4 ], [ %g.2.i0.3, %for.inc.3 ]
|
||||
+ br i1 false, label %cleanup, label %for.inc.4
|
||||
+
|
||||
+for.inc.4: ; preds = %dx.struct_exit.new_exiting.4
|
||||
+ %cmp3.5 = fcmp fast une float %g.2.i0.4, 0.000000e+00, !dbg !29 ; line:19 col:13
|
||||
+ br i1 %cmp3.5, label %dx.struct_exit.new_exiting.5, label %if.end.5, !dbg !30 ; line:19 col:9
|
||||
+
|
||||
+if.end.5: ; preds = %for.inc.4
|
||||
+ switch i32 5, label %sw.epilog.5 [
|
||||
+ i32 1, label %dx.struct_exit.new_exiting.5
|
||||
+ i32 2, label %dx.struct_exit.new_exiting.5
|
||||
+ i32 3, label %dx.struct_exit.new_exiting.5
|
||||
+ i32 5, label %dx.struct_exit.new_exiting.5
|
||||
+ ], !dbg !31 ; line:23 col:5
|
||||
+
|
||||
+sw.epilog.5: ; preds = %if.end.5
|
||||
+ br label %dx.struct_exit.new_exiting.5
|
||||
+
|
||||
+dx.struct_exit.new_exiting.5: ; preds = %sw.epilog.5, %if.end.5, %if.end.5, %if.end.5, %if.end.5, %for.inc.4
|
||||
+ %dx.struct_exit.prop.5 = phi i32 [ %do_discard.2.4, %sw.epilog.5 ], [ 0, %if.end.5 ], [ 0, %if.end.5 ], [ 0, %if.end.5 ], [ 0, %if.end.5 ], [ 0, %for.inc.4 ]
|
||||
+ %do_discard.2.5 = phi i32 [ 1, %sw.epilog.5 ], [ 1, %if.end.5 ], [ 1, %if.end.5 ], [ 1, %if.end.5 ], [ 1, %if.end.5 ], [ %do_discard.2.4, %for.inc.4 ]
|
||||
+ %g.2.i0.5 = phi float [ 0x3FF921FB60000000, %sw.epilog.5 ], [ 0x3FF921FB60000000, %if.end.5 ], [ 0x3FF921FB60000000, %if.end.5 ], [ 0x3FF921FB60000000, %if.end.5 ], [ 0x3FF921FB60000000, %if.end.5 ], [ %g.2.i0.4, %for.inc.4 ]
|
||||
+ br i1 false, label %cleanup, label %for.inc.5
|
||||
+
|
||||
+for.inc.5: ; preds = %dx.struct_exit.new_exiting.5
|
||||
+ %cmp3.6 = fcmp fast une float %g.2.i0.5, 0.000000e+00, !dbg !29 ; line:19 col:13
|
||||
+ br i1 %cmp3.6, label %dx.struct_exit.new_exiting.6, label %if.end.6, !dbg !30 ; line:19 col:9
|
||||
+
|
||||
+if.end.6: ; preds = %for.inc.5
|
||||
+ switch i32 6, label %sw.epilog.6 [
|
||||
+ i32 1, label %dx.struct_exit.new_exiting.6
|
||||
+ i32 2, label %dx.struct_exit.new_exiting.6
|
||||
+ i32 3, label %dx.struct_exit.new_exiting.6
|
||||
+ i32 5, label %dx.struct_exit.new_exiting.6
|
||||
+ ], !dbg !31 ; line:23 col:5
|
||||
+
|
||||
+sw.epilog.6: ; preds = %if.end.6
|
||||
+ br label %dx.struct_exit.new_exiting.6
|
||||
+
|
||||
+dx.struct_exit.new_exiting.6: ; preds = %sw.epilog.6, %if.end.6, %if.end.6, %if.end.6, %if.end.6, %for.inc.5
|
||||
+ %dx.struct_exit.prop23.6 = phi i1 [ true, %sw.epilog.6 ], [ false, %if.end.6 ], [ false, %if.end.6 ], [ false, %if.end.6 ], [ false, %if.end.6 ], [ false, %for.inc.5 ]
|
||||
+ %dx.struct_exit.prop.6 = phi i32 [ %do_discard.2.5, %sw.epilog.6 ], [ 0, %if.end.6 ], [ 0, %if.end.6 ], [ 0, %if.end.6 ], [ 0, %if.end.6 ], [ 0, %for.inc.5 ]
|
||||
+ %do_discard.2.6 = phi i32 [ 1, %sw.epilog.6 ], [ 1, %if.end.6 ], [ 1, %if.end.6 ], [ 1, %if.end.6 ], [ 1, %if.end.6 ], [ %do_discard.2.5, %for.inc.5 ]
|
||||
+ %g.2.i0.6 = phi float [ 0x3FF921FB60000000, %sw.epilog.6 ], [ 0x3FF921FB60000000, %if.end.6 ], [ 0x3FF921FB60000000, %if.end.6 ], [ 0x3FF921FB60000000, %if.end.6 ], [ 0x3FF921FB60000000, %if.end.6 ], [ %g.2.i0.5, %for.inc.5 ]
|
||||
+ br i1 %dx.struct_exit.prop23.6, label %cleanup, label %for.inc.6
|
||||
+
|
||||
+for.inc.6: ; preds = %dx.struct_exit.new_exiting.6
|
||||
+ %cmp3.7 = fcmp fast une float %g.2.i0.6, 0.000000e+00, !dbg !29 ; line:19 col:13
|
||||
+ br i1 %cmp3.7, label %dx.struct_exit.new_exiting.7, label %if.end.7, !dbg !30 ; line:19 col:9
|
||||
+
|
||||
+if.end.7: ; preds = %for.inc.6
|
||||
+ switch i32 7, label %sw.epilog.7 [
|
||||
+ i32 1, label %dx.struct_exit.new_exiting.7
|
||||
+ i32 2, label %dx.struct_exit.new_exiting.7
|
||||
+ i32 3, label %dx.struct_exit.new_exiting.7
|
||||
+ i32 5, label %dx.struct_exit.new_exiting.7
|
||||
+ ], !dbg !31 ; line:23 col:5
|
||||
+
|
||||
+sw.epilog.7: ; preds = %if.end.7
|
||||
+ br label %dx.struct_exit.new_exiting.7
|
||||
+
|
||||
+dx.struct_exit.new_exiting.7: ; preds = %sw.epilog.7, %if.end.7, %if.end.7, %if.end.7, %if.end.7, %for.inc.6
|
||||
+ %dx.struct_exit.prop.7 = phi i32 [ %do_discard.2.6, %sw.epilog.7 ], [ 0, %if.end.7 ], [ 0, %if.end.7 ], [ 0, %if.end.7 ], [ 0, %if.end.7 ], [ 0, %for.inc.6 ]
|
||||
+ %do_discard.2.7 = phi i32 [ 1, %sw.epilog.7 ], [ 1, %if.end.7 ], [ 1, %if.end.7 ], [ 1, %if.end.7 ], [ 1, %if.end.7 ], [ %do_discard.2.6, %for.inc.6 ]
|
||||
+ %g.2.i0.7 = phi float [ 0x3FF921FB60000000, %sw.epilog.7 ], [ 0x3FF921FB60000000, %if.end.7 ], [ 0x3FF921FB60000000, %if.end.7 ], [ 0x3FF921FB60000000, %if.end.7 ], [ 0x3FF921FB60000000, %if.end.7 ], [ %g.2.i0.6, %for.inc.6 ]
|
||||
+ br i1 false, label %cleanup, label %for.inc.7
|
||||
+
|
||||
+for.inc.7: ; preds = %dx.struct_exit.new_exiting.7
|
||||
+ %cmp3.8 = fcmp fast une float %g.2.i0.7, 0.000000e+00, !dbg !29 ; line:19 col:13
|
||||
+ br i1 %cmp3.8, label %dx.struct_exit.new_exiting.8, label %if.end.8, !dbg !30 ; line:19 col:9
|
||||
+
|
||||
+if.end.8: ; preds = %for.inc.7
|
||||
+ switch i32 8, label %sw.epilog.8 [
|
||||
+ i32 1, label %dx.struct_exit.new_exiting.8
|
||||
+ i32 2, label %dx.struct_exit.new_exiting.8
|
||||
+ i32 3, label %dx.struct_exit.new_exiting.8
|
||||
+ i32 5, label %dx.struct_exit.new_exiting.8
|
||||
+ ], !dbg !31 ; line:23 col:5
|
||||
+
|
||||
+sw.epilog.8: ; preds = %if.end.8
|
||||
+ br label %dx.struct_exit.new_exiting.8
|
||||
+
|
||||
+dx.struct_exit.new_exiting.8: ; preds = %sw.epilog.8, %if.end.8, %if.end.8, %if.end.8, %if.end.8, %for.inc.7
|
||||
+ %dx.struct_exit.prop.8 = phi i32 [ %do_discard.2.7, %sw.epilog.8 ], [ 0, %if.end.8 ], [ 0, %if.end.8 ], [ 0, %if.end.8 ], [ 0, %if.end.8 ], [ 0, %for.inc.7 ]
|
||||
+ %do_discard.2.8 = phi i32 [ 1, %sw.epilog.8 ], [ 1, %if.end.8 ], [ 1, %if.end.8 ], [ 1, %if.end.8 ], [ 1, %if.end.8 ], [ %do_discard.2.7, %for.inc.7 ]
|
||||
+ %g.2.i0.8 = phi float [ 0x3FF921FB60000000, %sw.epilog.8 ], [ 0x3FF921FB60000000, %if.end.8 ], [ 0x3FF921FB60000000, %if.end.8 ], [ 0x3FF921FB60000000, %if.end.8 ], [ 0x3FF921FB60000000, %if.end.8 ], [ %g.2.i0.7, %for.inc.7 ]
|
||||
+ br i1 false, label %cleanup, label %for.inc.8
|
||||
+
|
||||
+for.inc.8: ; preds = %dx.struct_exit.new_exiting.8
|
||||
+ %cmp3.9 = fcmp fast une float %g.2.i0.8, 0.000000e+00, !dbg !29 ; line:19 col:13
|
||||
+ br i1 %cmp3.9, label %dx.struct_exit.new_exiting.9, label %if.end.9, !dbg !30 ; line:19 col:9
|
||||
+
|
||||
+if.end.9: ; preds = %for.inc.8
|
||||
+ switch i32 9, label %sw.epilog.9 [
|
||||
+ i32 1, label %dx.struct_exit.new_exiting.9
|
||||
+ i32 2, label %dx.struct_exit.new_exiting.9
|
||||
+ i32 3, label %dx.struct_exit.new_exiting.9
|
||||
+ i32 5, label %dx.struct_exit.new_exiting.9
|
||||
+ ], !dbg !31 ; line:23 col:5
|
||||
+
|
||||
+sw.epilog.9: ; preds = %if.end.9
|
||||
+ br label %dx.struct_exit.new_exiting.9
|
||||
+
|
||||
+dx.struct_exit.new_exiting.9: ; preds = %sw.epilog.9, %if.end.9, %if.end.9, %if.end.9, %if.end.9, %for.inc.8
|
||||
+ %dx.struct_exit.prop.9 = phi i32 [ %do_discard.2.8, %sw.epilog.9 ], [ 0, %if.end.9 ], [ 0, %if.end.9 ], [ 0, %if.end.9 ], [ 0, %if.end.9 ], [ 0, %for.inc.8 ]
|
||||
+ %do_discard.2.9 = phi i32 [ 1, %sw.epilog.9 ], [ 1, %if.end.9 ], [ 1, %if.end.9 ], [ 1, %if.end.9 ], [ 1, %if.end.9 ], [ %do_discard.2.8, %for.inc.8 ]
|
||||
+ br i1 false, label %cleanup, label %for.inc.9
|
||||
+
|
||||
+for.inc.9: ; preds = %dx.struct_exit.new_exiting.9
|
||||
+ br label %cleanup
|
||||
+}
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+declare void @dx.op.storeOutput.f32(i32, i32, i32, i8, float) #0
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+declare void @dx.op.discard(i32, i1) #0
|
||||
+
|
||||
+; Function Attrs: nounwind readonly
|
||||
+declare %dx.types.ResRet.i32 @dx.op.rawBufferLoad.i32(i32, %dx.types.Handle, i32, i32, i8, i32) #1
|
||||
+
|
||||
+; Function Attrs: nounwind readonly
|
||||
+declare %dx.types.Handle @dx.op.createHandleForLib.struct.ByteAddressBuffer(i32, %struct.ByteAddressBuffer) #1
|
||||
+
|
||||
+; Function Attrs: nounwind readnone
|
||||
+declare %dx.types.Handle @dx.op.annotateHandle(i32, %dx.types.Handle, %dx.types.ResourceProperties) #2
|
||||
+
|
||||
+attributes #0 = { nounwind }
|
||||
+attributes #1 = { nounwind readonly }
|
||||
+attributes #2 = { nounwind readnone }
|
||||
+
|
||||
+!llvm.module.flags = !{!0}
|
||||
+!pauseresume = !{!1}
|
||||
+!llvm.ident = !{!2}
|
||||
+!dx.version = !{!3}
|
||||
+!dx.valver = !{!4}
|
||||
+!dx.shaderModel = !{!5}
|
||||
+!dx.resources = !{!6}
|
||||
+!dx.typeAnnotations = !{!9, !12}
|
||||
+!dx.entryPoints = !{!19}
|
||||
+
|
||||
+!0 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
+!1 = !{!"hlsl-dxilemit", !"hlsl-dxilload"}
|
||||
+!2 = !{!"dxc(private) 1.8.0.4514 (d9bd2a706-dirty)"}
|
||||
+!3 = !{i32 1, i32 6}
|
||||
+!4 = !{i32 1, i32 8}
|
||||
+!5 = !{!"ps", i32 6, i32 6}
|
||||
+!6 = !{!7, null, null, null}
|
||||
+!7 = !{!8}
|
||||
+!8 = !{i32 0, %struct.ByteAddressBuffer* @"\01?g_buff@@3UByteAddressBuffer@@A", !"g_buff", i32 0, i32 0, i32 1, i32 11, i32 0, null}
|
||||
+!9 = !{i32 0, %struct.retval undef, !10}
|
||||
+!10 = !{i32 16, !11}
|
||||
+!11 = !{i32 6, !"value", i32 3, i32 0, i32 4, !"SV_Target0", i32 7, i32 9}
|
||||
+!12 = !{i32 1, void (<4 x float>*)* @main, !13}
|
||||
+!13 = !{!14, !16}
|
||||
+!14 = !{i32 0, !15, !15}
|
||||
+!15 = !{}
|
||||
+!16 = !{i32 1, !17, !18}
|
||||
+!17 = !{i32 4, !"SV_Target0", i32 7, i32 9}
|
||||
+!18 = !{i32 0}
|
||||
+!19 = !{void (<4 x float>*)* @main, !"main", !20, !6, null}
|
||||
+!20 = !{null, !21, null}
|
||||
+!21 = !{!22}
|
||||
+!22 = !{i32 0, !"SV_Target", i8 9, i8 16, !18, i8 0, i32 1, i8 4, i32 0, i8 0, null}
|
||||
+!23 = !DILocation(line: 15, column: 22, scope: !24)
|
||||
+!24 = !DISubprogram(name: "main", scope: !25, file: !25, line: 14, type: !26, isLocal: false, isDefinition: true, scopeLine: 14, flags: DIFlagPrototyped, isOptimized: false, function: void (<4 x float>*)* @main)
|
||||
+!25 = !DIFile(filename: "/home/amaiorano/src/external/DirectXShaderCompiler/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.hlsl", directory: "")
|
||||
+!26 = !DISubroutineType(types: !15)
|
||||
+!27 = !DILocation(line: 15, column: 14, scope: !24)
|
||||
+!28 = !DILocation(line: 18, column: 3, scope: !24)
|
||||
+!29 = !DILocation(line: 19, column: 13, scope: !24)
|
||||
+!30 = !DILocation(line: 19, column: 9, scope: !24)
|
||||
+!31 = !DILocation(line: 23, column: 5, scope: !24)
|
||||
+!32 = !DILocation(line: 49, column: 7, scope: !24)
|
||||
+!33 = !DILocation(line: 49, column: 19, scope: !24)
|
||||
+!34 = !DILocation(line: 51, column: 3, scope: !24)
|
||||
+!35 = !DILocation(line: 53, column: 18, scope: !24)
|
||||
+!36 = !DILocation(line: 54, column: 1, scope: !24)
|
||||
419
patches/DirectXShaderCompiler/cherry-pick-2a434fd0af6b.patch
Normal file
419
patches/DirectXShaderCompiler/cherry-pick-2a434fd0af6b.patch
Normal file
@@ -0,0 +1,419 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Antonio Maiorano <amaiorano@google.com>
|
||||
Date: Wed, 8 May 2024 13:38:38 -0400
|
||||
Subject: Fix invalid IR from scalarrepl-param-hlsl in ReplaceConstantWithInst
|
||||
(#6556)
|
||||
|
||||
ReplaceConstantWithInst(C, V) replaces uses of C in the current function
|
||||
with V. If such a use C is an instruction I, the it replaces uses of C
|
||||
in I with V. However, this function did not make sure to only perform
|
||||
this replacement if V dominates I. As a result, it may end up replacing
|
||||
uses of C in instructions before the definition of V.
|
||||
|
||||
The fix is to lazily compute the dominator tree in
|
||||
ReplaceConstantWithInst so that we can guard the replacement with that
|
||||
dominance check.
|
||||
|
||||
Bug: chromium:333414294
|
||||
Change-Id: I2a8bf64094298b49a1887cc7c1334e91a745c396
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5525429
|
||||
Reviewed-by: James Price <jrprice@google.com>
|
||||
Reviewed-by: dan sinclair <dsinclair@google.com>
|
||||
|
||||
diff --git a/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp b/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp
|
||||
index 3f8ffdbcfa09a96899295fd85291cedb879a248b..9b843ef0e49e554001b827e30eb6256853d90f5b 100644
|
||||
--- a/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp
|
||||
+++ b/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp
|
||||
@@ -3271,15 +3271,34 @@ bool SROA_Helper::DoScalarReplacement(GlobalVariable *GV,
|
||||
return true;
|
||||
}
|
||||
|
||||
-static void ReplaceConstantWithInst(Constant *C, Value *V,
|
||||
+// Replaces uses of constant C in the current function
|
||||
+// with V, when those uses are dominated by V.
|
||||
+// Returns true if it was completely replaced.
|
||||
+static bool ReplaceConstantWithInst(Constant *C, Value *V,
|
||||
IRBuilder<> &Builder) {
|
||||
+ bool bReplacedAll = true;
|
||||
Function *F = Builder.GetInsertBlock()->getParent();
|
||||
+ Instruction *VInst = dyn_cast<Instruction>(V);
|
||||
+ // Lazily calculate dominance
|
||||
+ DominatorTree DT;
|
||||
+ bool Calculated = false;
|
||||
+ auto Dominates = [&](llvm::Instruction *Def, llvm::Instruction *User) {
|
||||
+ if (!Calculated) {
|
||||
+ DT.recalculate(*F);
|
||||
+ Calculated = true;
|
||||
+ }
|
||||
+ return DT.dominates(Def, User);
|
||||
+ };
|
||||
+
|
||||
for (auto it = C->user_begin(); it != C->user_end();) {
|
||||
User *U = *(it++);
|
||||
if (Instruction *I = dyn_cast<Instruction>(U)) {
|
||||
if (I->getParent()->getParent() != F)
|
||||
continue;
|
||||
- I->replaceUsesOfWith(C, V);
|
||||
+ if (VInst && Dominates(VInst, I))
|
||||
+ I->replaceUsesOfWith(C, V);
|
||||
+ else
|
||||
+ bReplacedAll = false;
|
||||
} else {
|
||||
// Skip unused ConstantExpr.
|
||||
if (U->user_empty())
|
||||
@@ -3288,10 +3307,12 @@ static void ReplaceConstantWithInst(Constant *C, Value *V,
|
||||
Instruction *Inst = CE->getAsInstruction();
|
||||
Builder.Insert(Inst);
|
||||
Inst->replaceUsesOfWith(C, V);
|
||||
- ReplaceConstantWithInst(CE, Inst, Builder);
|
||||
+ if (!ReplaceConstantWithInst(CE, Inst, Builder))
|
||||
+ bReplacedAll = false;
|
||||
}
|
||||
}
|
||||
C->removeDeadConstantUsers();
|
||||
+ return bReplacedAll;
|
||||
}
|
||||
|
||||
static void ReplaceUnboundedArrayUses(Value *V, Value *Src) {
|
||||
@@ -3531,7 +3552,8 @@ static bool ReplaceMemcpy(Value *V, Value *Src, MemCpyInst *MC,
|
||||
} else {
|
||||
// Replace Constant with a non-Constant.
|
||||
IRBuilder<> Builder(MC);
|
||||
- ReplaceConstantWithInst(C, Src, Builder);
|
||||
+ if (!ReplaceConstantWithInst(C, Src, Builder))
|
||||
+ return false;
|
||||
}
|
||||
} else {
|
||||
// Try convert special pattern for cbuffer which copy array of float4 to
|
||||
@@ -3539,7 +3561,8 @@ static bool ReplaceMemcpy(Value *V, Value *Src, MemCpyInst *MC,
|
||||
if (!tryToReplaceCBVec4ArrayToScalarArray(V, TyV, Src, TySrc, MC, DL)) {
|
||||
IRBuilder<> Builder(MC);
|
||||
Src = Builder.CreateBitCast(Src, V->getType());
|
||||
- ReplaceConstantWithInst(C, Src, Builder);
|
||||
+ if (!ReplaceConstantWithInst(C, Src, Builder))
|
||||
+ return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -5447,9 +5470,9 @@ void SROA_Parameter_HLSL::flattenArgument(
|
||||
if (Ty->isPointerTy())
|
||||
Ty = Ty->getPointerElementType();
|
||||
unsigned size = DL.getTypeAllocSize(Ty);
|
||||
-#if 0 // HLSL Change
|
||||
+#if 0 // HLSL Change
|
||||
DIExpression *DDIExp = DIB.createBitPieceExpression(debugOffset, size);
|
||||
-#else // HLSL Change
|
||||
+#else // HLSL Change
|
||||
Type *argTy = Arg->getType();
|
||||
if (argTy->isPointerTy())
|
||||
argTy = argTy->getPointerElementType();
|
||||
diff --git a/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-const-to-local-and-back.hlsl b/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-const-to-local-and-back.hlsl
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0f30050e69decaf7da3f2ae645611c1a49a4a719
|
||||
--- /dev/null
|
||||
+++ b/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-const-to-local-and-back.hlsl
|
||||
@@ -0,0 +1,45 @@
|
||||
+// RUN: not %dxc -T ps_6_2 %s 2>&1 | FileCheck %s
|
||||
+
|
||||
+// Validate that copying from static array to local, then back to static
|
||||
+// array does not crash the compiler. This was resulting in an invalid
|
||||
+// ReplaceConstantWithInst from ScalarReplAggregatesHLSL, which would
|
||||
+// result in referenced deleted instruction in a later pass.
|
||||
+
|
||||
+// CHECK: error: Loop must have break.
|
||||
+
|
||||
+static int arr1[10] = (int[10])0;
|
||||
+static int arr2[10] = (int[10])0;
|
||||
+static float result = 0;
|
||||
+ByteAddressBuffer buff : register(t0);
|
||||
+
|
||||
+void foo() {
|
||||
+ int i = 0;
|
||||
+ if (buff.Load(0u)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ arr2[i] = arr1[i];
|
||||
+ result = float(arr1[0]);
|
||||
+}
|
||||
+
|
||||
+struct tint_symbol {
|
||||
+ float4 value : SV_Target0;
|
||||
+};
|
||||
+
|
||||
+float main_inner() {
|
||||
+ foo();
|
||||
+ bool cond = false;
|
||||
+ while (true) {
|
||||
+ if (cond) { break; }
|
||||
+ }
|
||||
+ int arr1_copy[10] = arr1; // constant to local
|
||||
+ arr1 = arr1_copy; // local to constant
|
||||
+ foo();
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
+tint_symbol main() {
|
||||
+ float inner_result = main_inner();
|
||||
+ tint_symbol wrapper_result = (tint_symbol)0;
|
||||
+ wrapper_result.value.x = inner_result;
|
||||
+ return wrapper_result;
|
||||
+}
|
||||
diff --git a/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-const-to-local-and-back.ll b/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-const-to-local-and-back.ll
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..6ca08ab3a9c500cacb715f63ee407c7add4fc51c
|
||||
--- /dev/null
|
||||
+++ b/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-const-to-local-and-back.ll
|
||||
@@ -0,0 +1,253 @@
|
||||
+; RUN: %dxopt %s -hlsl-passes-resume -scalarrepl-param-hlsl -S | FileCheck %s
|
||||
+
|
||||
+; The first memcpy, from arr1 to arr1_copy.i, should be replaced by a series of 10 loads and stores,
|
||||
+; while the second memcpy, from arr1_copy.i back to arr1, should be removed:
|
||||
+; %19 = bitcast [10 x i32]* %arr1_copy.i to i8*, !dbg !33 ; line:25 col:23
|
||||
+; call void @llvm.memcpy.p0i8.p0i8.i64(i8* %19, i8* bitcast ([10 x i32]* @arr1 to i8*), i64 40, i32 1, i1 false) #0, !dbg !33 ; line:25 col:23
|
||||
+; %20 = bitcast [10 x i32]* %arr1_copy.i to i8*, !dbg !34 ; line:26 col:10
|
||||
+; call void @llvm.memcpy.p0i8.p0i8.i64(i8* bitcast ([10 x i32]* @arr1 to i8*), i8* %20, i64 40, i32 1, i1 false) #0, !dbg !34 ; line:26 col:10
|
||||
+; store i32 0, i32* %i.i.1.i, align 4, !dbg !35, !tbaa !12 ; line:7 col:7
|
||||
+
|
||||
+; CHECK: [[DEST0:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 0
|
||||
+; CHECK-NEXT: [[SRC0:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 0)
|
||||
+; CHECK-NEXT: store i32 [[SRC0:%[a-z0-9\.]+]], i32* [[DEST0:%[a-z0-9\.]+]]
|
||||
+; CHECK-NEXT: [[DEST1:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 1
|
||||
+; CHECK-NEXT: [[SRC1:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 1)
|
||||
+; CHECK-NEXT: store i32 [[SRC1:%[a-z0-9\.]+]], i32* [[DEST1:%[a-z0-9\.]+]]
|
||||
+; CHECK-NEXT: [[DEST2:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 2
|
||||
+; CHECK-NEXT: [[SRC2:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 2)
|
||||
+; CHECK-NEXT: store i32 [[SRC2:%[a-z0-9\.]+]], i32* [[DEST2:%[a-z0-9\.]+]]
|
||||
+; CHECK-NEXT: [[DEST3:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 3
|
||||
+; CHECK-NEXT: [[SRC3:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 3)
|
||||
+; CHECK-NEXT: store i32 [[SRC3:%[a-z0-9\.]+]], i32* [[DEST3:%[a-z0-9\.]+]]
|
||||
+; CHECK-NEXT: [[DEST4:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 4
|
||||
+; CHECK-NEXT: [[SRC4:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 4)
|
||||
+; CHECK-NEXT: store i32 [[SRC4:%[a-z0-9\.]+]], i32* [[DEST4:%[a-z0-9\.]+]]
|
||||
+; CHECK-NEXT: [[DEST5:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 5
|
||||
+; CHECK-NEXT: [[SRC5:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 5)
|
||||
+; CHECK-NEXT: store i32 [[SRC5:%[a-z0-9\.]+]], i32* [[DEST5:%[a-z0-9\.]+]]
|
||||
+; CHECK-NEXT: [[DEST6:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 6
|
||||
+; CHECK-NEXT: [[SRC6:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 6)
|
||||
+; CHECK-NEXT: store i32 [[SRC6:%[a-z0-9\.]+]], i32* [[DEST6:%[a-z0-9\.]+]]
|
||||
+; CHECK-NEXT: [[DEST7:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 7
|
||||
+; CHECK-NEXT: [[SRC7:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 7)
|
||||
+; CHECK-NEXT: store i32 [[SRC7:%[a-z0-9\.]+]], i32* [[DEST7:%[a-z0-9\.]+]]
|
||||
+; CHECK-NEXT: [[DEST8:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 8
|
||||
+; CHECK-NEXT: [[SRC8:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 8)
|
||||
+; CHECK-NEXT: store i32 [[SRC8:%[a-z0-9\.]+]], i32* [[DEST8:%[a-z0-9\.]+]]
|
||||
+; CHECK-NEXT: [[DEST9:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 9
|
||||
+; CHECK-NEXT: [[SRC9:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 9)
|
||||
+; CHECK-NEXT: store i32 [[SRC9:%[a-z0-9\.]+]], i32* [[DEST9:%[a-z0-9\.]+]]
|
||||
+
|
||||
+;
|
||||
+; Buffer Definitions:
|
||||
+;
|
||||
+; cbuffer $Globals
|
||||
+; {
|
||||
+;
|
||||
+; [0 x i8] (type annotation not present)
|
||||
+;
|
||||
+; }
|
||||
+;
|
||||
+;
|
||||
+; Resource Bindings:
|
||||
+;
|
||||
+; Name Type Format Dim ID HLSL Bind Count
|
||||
+; ------------------------------ ---------- ------- ----------- ------- -------------- ------
|
||||
+; $Globals cbuffer NA NA CB0 cb4294967295 1
|
||||
+; buff texture byte r/o T0 t0 1
|
||||
+;
|
||||
+target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
|
||||
+target triple = "dxil-ms-dx"
|
||||
+
|
||||
+%struct.ByteAddressBuffer = type { i32 }
|
||||
+%ConstantBuffer = type opaque
|
||||
+%struct.tint_symbol = type { <4 x float> }
|
||||
+%dx.types.Handle = type { i8* }
|
||||
+%dx.types.ResourceProperties = type { i32, i32 }
|
||||
+
|
||||
+@"\01?buff@@3UByteAddressBuffer@@A" = external global %struct.ByteAddressBuffer, align 4
|
||||
+@arr1 = internal global [10 x i32] zeroinitializer, align 4
|
||||
+@arr2 = internal global [10 x i32] zeroinitializer, align 4
|
||||
+@"$Globals" = external constant %ConstantBuffer
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+define void @main(%struct.tint_symbol* noalias sret %agg.result) #0 {
|
||||
+ %1 = alloca float
|
||||
+ store float 0.000000e+00, float* %1
|
||||
+ %i.i.1.i = alloca i32, align 4
|
||||
+ %i.i.i = alloca i32, align 4
|
||||
+ %cond.i = alloca i32, align 4
|
||||
+ %arr1_copy.i = alloca [10 x i32], align 4
|
||||
+ %inner_result = alloca float, align 4
|
||||
+ %wrapper_result = alloca %struct.tint_symbol, align 4
|
||||
+ store i32 0, i32* %i.i.i, align 4, !dbg !23, !tbaa !31 ; line:7 col:7
|
||||
+ %2 = load %struct.ByteAddressBuffer, %struct.ByteAddressBuffer* @"\01?buff@@3UByteAddressBuffer@@A", !dbg !35 ; line:8 col:7
|
||||
+ %3 = call %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %struct.ByteAddressBuffer)"(i32 0, %struct.ByteAddressBuffer %2) #0, !dbg !35 ; line:8 col:7
|
||||
+ %4 = call %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer)"(i32 14, %dx.types.Handle %3, %dx.types.ResourceProperties { i32 11, i32 0 }, %struct.ByteAddressBuffer undef) #0, !dbg !35 ; line:8 col:7
|
||||
+ %5 = call i32 @"dx.hl.op.ro.i32 (i32, %dx.types.Handle, i32)"(i32 231, %dx.types.Handle %4, i32 0) #0, !dbg !35 ; line:8 col:7
|
||||
+ %6 = icmp ne i32 %5, 0, !dbg !35 ; line:8 col:7
|
||||
+ br i1 %6, label %"\01?foo@@YAXXZ.exit.i", label %7, !dbg !35 ; line:8 col:7
|
||||
+
|
||||
+; <label>:7 ; preds = %0
|
||||
+ %8 = load i32, i32* %i.i.i, align 4, !dbg !36, !tbaa !31 ; line:11 col:18
|
||||
+ %9 = getelementptr inbounds [10 x i32], [10 x i32]* @arr1, i32 0, i32 %8, !dbg !37 ; line:11 col:13
|
||||
+ %10 = load i32, i32* %9, align 4, !dbg !37, !tbaa !31 ; line:11 col:13
|
||||
+ %11 = load i32, i32* %i.i.i, align 4, !dbg !38, !tbaa !31 ; line:11 col:8
|
||||
+ %12 = getelementptr inbounds [10 x i32], [10 x i32]* @arr2, i32 0, i32 %11, !dbg !39 ; line:11 col:3
|
||||
+ store i32 %10, i32* %12, align 4, !dbg !40, !tbaa !31 ; line:11 col:11
|
||||
+ %13 = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 0), align 4, !dbg !41, !tbaa !31 ; line:12 col:18
|
||||
+ %14 = sitofp i32 %13 to float, !dbg !41 ; line:12 col:18
|
||||
+ store float %14, float* %1, align 4, !dbg !42, !tbaa !43 ; line:12 col:10
|
||||
+ br label %"\01?foo@@YAXXZ.exit.i", !dbg !45 ; line:13 col:1
|
||||
+
|
||||
+"\01?foo@@YAXXZ.exit.i": ; preds = %7, %0
|
||||
+ store i32 0, i32* %cond.i, align 4, !dbg !46, !tbaa !47 ; line:21 col:8
|
||||
+ br label %15, !dbg !49 ; line:22 col:3
|
||||
+
|
||||
+; <label>:15 ; preds = %15, %"\01?foo@@YAXXZ.exit.i"
|
||||
+ %16 = load i32, i32* %cond.i, align 4, !dbg !50, !tbaa !47, !range !51 ; line:23 col:9
|
||||
+ %17 = icmp ne i32 %16, 0, !dbg !50 ; line:23 col:9
|
||||
+ br i1 %17, label %18, label %15, !dbg !50 ; line:23 col:9
|
||||
+
|
||||
+; <label>:18 ; preds = %15
|
||||
+ %19 = bitcast [10 x i32]* %arr1_copy.i to i8*, !dbg !52 ; line:25 col:23
|
||||
+ call void @llvm.memcpy.p0i8.p0i8.i64(i8* %19, i8* bitcast ([10 x i32]* @arr1 to i8*), i64 40, i32 1, i1 false) #0, !dbg !52 ; line:25 col:23
|
||||
+ %20 = bitcast [10 x i32]* %arr1_copy.i to i8*, !dbg !53 ; line:26 col:10
|
||||
+ call void @llvm.memcpy.p0i8.p0i8.i64(i8* bitcast ([10 x i32]* @arr1 to i8*), i8* %20, i64 40, i32 1, i1 false) #0, !dbg !53 ; line:26 col:10
|
||||
+ store i32 0, i32* %i.i.1.i, align 4, !dbg !54, !tbaa !31 ; line:7 col:7
|
||||
+ %21 = load %struct.ByteAddressBuffer, %struct.ByteAddressBuffer* @"\01?buff@@3UByteAddressBuffer@@A", !dbg !56 ; line:8 col:7
|
||||
+ %22 = call %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %struct.ByteAddressBuffer)"(i32 0, %struct.ByteAddressBuffer %21) #0, !dbg !56 ; line:8 col:7
|
||||
+ %23 = call %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer)"(i32 14, %dx.types.Handle %22, %dx.types.ResourceProperties { i32 11, i32 0 }, %struct.ByteAddressBuffer undef) #0, !dbg !56 ; line:8 col:7
|
||||
+ %24 = call i32 @"dx.hl.op.ro.i32 (i32, %dx.types.Handle, i32)"(i32 231, %dx.types.Handle %23, i32 0) #0, !dbg !56 ; line:8 col:7
|
||||
+ %25 = icmp ne i32 %24, 0, !dbg !56 ; line:8 col:7
|
||||
+ br i1 %25, label %"\01?main_inner@@YAMXZ.exit", label %26, !dbg !56 ; line:8 col:7
|
||||
+
|
||||
+; <label>:26 ; preds = %18
|
||||
+ %27 = load i32, i32* %i.i.1.i, align 4, !dbg !57, !tbaa !31 ; line:11 col:18
|
||||
+ %28 = getelementptr inbounds [10 x i32], [10 x i32]* @arr1, i32 0, i32 %27, !dbg !58 ; line:11 col:13
|
||||
+ %29 = load i32, i32* %28, align 4, !dbg !58, !tbaa !31 ; line:11 col:13
|
||||
+ %30 = load i32, i32* %i.i.1.i, align 4, !dbg !59, !tbaa !31 ; line:11 col:8
|
||||
+ %31 = getelementptr inbounds [10 x i32], [10 x i32]* @arr2, i32 0, i32 %30, !dbg !60 ; line:11 col:3
|
||||
+ store i32 %29, i32* %31, align 4, !dbg !61, !tbaa !31 ; line:11 col:11
|
||||
+ %32 = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 0), align 4, !dbg !62, !tbaa !31 ; line:12 col:18
|
||||
+ %33 = sitofp i32 %32 to float, !dbg !62 ; line:12 col:18
|
||||
+ store float %33, float* %1, align 4, !dbg !63, !tbaa !43 ; line:12 col:10
|
||||
+ br label %"\01?main_inner@@YAMXZ.exit", !dbg !64 ; line:13 col:1
|
||||
+
|
||||
+"\01?main_inner@@YAMXZ.exit": ; preds = %18, %26
|
||||
+ %34 = load float, float* %1, align 4, !dbg !65, !tbaa !43 ; line:28 col:10
|
||||
+ store float %34, float* %inner_result, align 4, !dbg !66, !tbaa !43 ; line:32 col:9
|
||||
+ %35 = getelementptr inbounds %struct.tint_symbol, %struct.tint_symbol* %wrapper_result, i32 0, i32 0, !dbg !67 ; line:33 col:45
|
||||
+ store <4 x float> zeroinitializer, <4 x float>* %35, !dbg !67 ; line:33 col:45
|
||||
+ %36 = load float, float* %inner_result, align 4, !dbg !68, !tbaa !43 ; line:34 col:28
|
||||
+ %37 = getelementptr inbounds %struct.tint_symbol, %struct.tint_symbol* %wrapper_result, i32 0, i32 0, !dbg !69 ; line:34 col:18
|
||||
+ %38 = load <4 x float>, <4 x float>* %37, align 4, !dbg !70 ; line:34 col:26
|
||||
+ %39 = getelementptr <4 x float>, <4 x float>* %37, i32 0, i32 0, !dbg !70 ; line:34 col:26
|
||||
+ store float %36, float* %39, !dbg !70 ; line:34 col:26
|
||||
+ %40 = bitcast %struct.tint_symbol* %agg.result to i8*, !dbg !71 ; line:35 col:10
|
||||
+ %41 = bitcast %struct.tint_symbol* %wrapper_result to i8*, !dbg !71 ; line:35 col:10
|
||||
+ call void @llvm.memcpy.p0i8.p0i8.i64(i8* %40, i8* %41, i64 16, i32 1, i1 false), !dbg !71 ; line:35 col:10
|
||||
+ ret void, !dbg !72 ; line:35 col:3
|
||||
+}
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1) #0
|
||||
+
|
||||
+; Function Attrs: nounwind readonly
|
||||
+declare i32 @"dx.hl.op.ro.i32 (i32, %dx.types.Handle, i32)"(i32, %dx.types.Handle, i32) #1
|
||||
+
|
||||
+; Function Attrs: nounwind readnone
|
||||
+declare %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %struct.ByteAddressBuffer)"(i32, %struct.ByteAddressBuffer) #2
|
||||
+
|
||||
+; Function Attrs: nounwind readnone
|
||||
+declare %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer)"(i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer) #2
|
||||
+
|
||||
+attributes #0 = { nounwind }
|
||||
+attributes #1 = { nounwind readonly }
|
||||
+attributes #2 = { nounwind readnone }
|
||||
+
|
||||
+!llvm.module.flags = !{!0}
|
||||
+!pauseresume = !{!1}
|
||||
+!llvm.ident = !{!2}
|
||||
+!dx.version = !{!3}
|
||||
+!dx.valver = !{!4}
|
||||
+!dx.shaderModel = !{!5}
|
||||
+!dx.typeAnnotations = !{!6, !9}
|
||||
+!dx.entryPoints = !{!14}
|
||||
+!dx.fnprops = !{!20}
|
||||
+!dx.options = !{!21, !22}
|
||||
+
|
||||
+!0 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
+!1 = !{!"hlsl-hlemit", !"hlsl-hlensure"}
|
||||
+!2 = !{!"dxc(private) 1.8.0.4547 (14ec4b49d)"}
|
||||
+!3 = !{i32 1, i32 2}
|
||||
+!4 = !{i32 1, i32 8}
|
||||
+!5 = !{!"ps", i32 6, i32 2}
|
||||
+!6 = !{i32 0, %struct.tint_symbol undef, !7}
|
||||
+!7 = !{i32 16, !8}
|
||||
+!8 = !{i32 6, !"value", i32 3, i32 0, i32 4, !"SV_Target0", i32 7, i32 9}
|
||||
+!9 = !{i32 1, void (%struct.tint_symbol*)* @main, !10}
|
||||
+!10 = !{!11, !13}
|
||||
+!11 = !{i32 0, !12, !12}
|
||||
+!12 = !{}
|
||||
+!13 = !{i32 1, !12, !12}
|
||||
+!14 = !{void (%struct.tint_symbol*)* @main, !"main", null, !15, null}
|
||||
+!15 = !{!16, null, !18, null}
|
||||
+!16 = !{!17}
|
||||
+!17 = !{i32 0, %struct.ByteAddressBuffer* @"\01?buff@@3UByteAddressBuffer@@A", !"buff", i32 0, i32 0, i32 1, i32 11, i32 0, null}
|
||||
+!18 = !{!19}
|
||||
+!19 = !{i32 0, %ConstantBuffer* @"$Globals", !"$Globals", i32 0, i32 -1, i32 1, i32 0, null}
|
||||
+!20 = !{void (%struct.tint_symbol*)* @main, i32 0, i1 false}
|
||||
+!21 = !{i32 144}
|
||||
+!22 = !{i32 -1}
|
||||
+!23 = !DILocation(line: 7, column: 7, scope: !24, inlinedAt: !27)
|
||||
+!24 = !DISubprogram(name: "foo", scope: !25, file: !25, line: 6, type: !26, isLocal: false, isDefinition: true, scopeLine: 6, flags: DIFlagPrototyped, isOptimized: false)
|
||||
+!25 = !DIFile(filename: "333414294_simplifed.hlsl", directory: "")
|
||||
+!26 = !DISubroutineType(types: !12)
|
||||
+!27 = distinct !DILocation(line: 20, column: 3, scope: !28, inlinedAt: !29)
|
||||
+!28 = !DISubprogram(name: "main_inner", scope: !25, file: !25, line: 19, type: !26, isLocal: false, isDefinition: true, scopeLine: 19, flags: DIFlagPrototyped, isOptimized: false)
|
||||
+!29 = distinct !DILocation(line: 32, column: 24, scope: !30)
|
||||
+!30 = !DISubprogram(name: "main", scope: !25, file: !25, line: 31, type: !26, isLocal: false, isDefinition: true, scopeLine: 31, flags: DIFlagPrototyped, isOptimized: false, function: void (%struct.tint_symbol*)* @main)
|
||||
+!31 = !{!32, !32, i64 0}
|
||||
+!32 = !{!"int", !33, i64 0}
|
||||
+!33 = !{!"omnipotent char", !34, i64 0}
|
||||
+!34 = !{!"Simple C/C++ TBAA"}
|
||||
+!35 = !DILocation(line: 8, column: 7, scope: !24, inlinedAt: !27)
|
||||
+!36 = !DILocation(line: 11, column: 18, scope: !24, inlinedAt: !27)
|
||||
+!37 = !DILocation(line: 11, column: 13, scope: !24, inlinedAt: !27)
|
||||
+!38 = !DILocation(line: 11, column: 8, scope: !24, inlinedAt: !27)
|
||||
+!39 = !DILocation(line: 11, column: 3, scope: !24, inlinedAt: !27)
|
||||
+!40 = !DILocation(line: 11, column: 11, scope: !24, inlinedAt: !27)
|
||||
+!41 = !DILocation(line: 12, column: 18, scope: !24, inlinedAt: !27)
|
||||
+!42 = !DILocation(line: 12, column: 10, scope: !24, inlinedAt: !27)
|
||||
+!43 = !{!44, !44, i64 0}
|
||||
+!44 = !{!"float", !33, i64 0}
|
||||
+!45 = !DILocation(line: 13, column: 1, scope: !24, inlinedAt: !27)
|
||||
+!46 = !DILocation(line: 21, column: 8, scope: !28, inlinedAt: !29)
|
||||
+!47 = !{!48, !48, i64 0}
|
||||
+!48 = !{!"bool", !33, i64 0}
|
||||
+!49 = !DILocation(line: 22, column: 3, scope: !28, inlinedAt: !29)
|
||||
+!50 = !DILocation(line: 23, column: 9, scope: !28, inlinedAt: !29)
|
||||
+!51 = !{i32 0, i32 2}
|
||||
+!52 = !DILocation(line: 25, column: 23, scope: !28, inlinedAt: !29)
|
||||
+!53 = !DILocation(line: 26, column: 10, scope: !28, inlinedAt: !29)
|
||||
+!54 = !DILocation(line: 7, column: 7, scope: !24, inlinedAt: !55)
|
||||
+!55 = distinct !DILocation(line: 27, column: 3, scope: !28, inlinedAt: !29)
|
||||
+!56 = !DILocation(line: 8, column: 7, scope: !24, inlinedAt: !55)
|
||||
+!57 = !DILocation(line: 11, column: 18, scope: !24, inlinedAt: !55)
|
||||
+!58 = !DILocation(line: 11, column: 13, scope: !24, inlinedAt: !55)
|
||||
+!59 = !DILocation(line: 11, column: 8, scope: !24, inlinedAt: !55)
|
||||
+!60 = !DILocation(line: 11, column: 3, scope: !24, inlinedAt: !55)
|
||||
+!61 = !DILocation(line: 11, column: 11, scope: !24, inlinedAt: !55)
|
||||
+!62 = !DILocation(line: 12, column: 18, scope: !24, inlinedAt: !55)
|
||||
+!63 = !DILocation(line: 12, column: 10, scope: !24, inlinedAt: !55)
|
||||
+!64 = !DILocation(line: 13, column: 1, scope: !24, inlinedAt: !55)
|
||||
+!65 = !DILocation(line: 28, column: 10, scope: !28, inlinedAt: !29)
|
||||
+!66 = !DILocation(line: 32, column: 9, scope: !30)
|
||||
+!67 = !DILocation(line: 33, column: 45, scope: !30)
|
||||
+!68 = !DILocation(line: 34, column: 28, scope: !30)
|
||||
+!69 = !DILocation(line: 34, column: 18, scope: !30)
|
||||
+!70 = !DILocation(line: 34, column: 26, scope: !30)
|
||||
+!71 = !DILocation(line: 35, column: 10, scope: !30)
|
||||
+!72 = !DILocation(line: 35, column: 3, scope: !30)
|
||||
332
patches/DirectXShaderCompiler/cherry-pick-33051b084850.patch
Normal file
332
patches/DirectXShaderCompiler/cherry-pick-33051b084850.patch
Normal file
@@ -0,0 +1,332 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Antonio Maiorano <amaiorano@google.com>
|
||||
Date: Mon, 10 Jun 2024 10:52:30 -0400
|
||||
Subject: Loop exit restructurizer: don't iterate over uses while mutating them
|
||||
(#6644)
|
||||
|
||||
The SkipBlockWithBranch function does the following:
|
||||
- Splits the block into three blocks with an if-then-endif structure.
|
||||
- Moves most instructions from the original block into the "then" block
|
||||
- If any of those values are used outside the original block, they are
|
||||
propagated through newly-constructed phis in the 'endif' block.
|
||||
|
||||
This algorithm had a bug where the uses of a value were being scanned
|
||||
while the uses were also being updated. In some cases a downstream
|
||||
out-of-block use could be skipped. That results in an invalid module
|
||||
because now the original definition is now in the 'then' block, which
|
||||
does not dominate the downstream out-of-block use.
|
||||
|
||||
Add a test that demonstrates the problem.
|
||||
|
||||
Bug: chromium:339171223
|
||||
Change-Id: Ia34fd7a2fe84de635289f7499772d11866a28e24
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5615350
|
||||
Reviewed-by: James Price <jrprice@google.com>
|
||||
Reviewed-by: dan sinclair <dsinclair@google.com>
|
||||
|
||||
diff --git a/lib/Transforms/Scalar/DxilRemoveUnstructuredLoopExits.cpp b/lib/Transforms/Scalar/DxilRemoveUnstructuredLoopExits.cpp
|
||||
index ef6718f0f22ee33e3f16f9801a64c1a6fb6c653a..70e6ccd8ddbaeabdb469710ad8529933f0286abd 100644
|
||||
--- a/lib/Transforms/Scalar/DxilRemoveUnstructuredLoopExits.cpp
|
||||
+++ b/lib/Transforms/Scalar/DxilRemoveUnstructuredLoopExits.cpp
|
||||
@@ -322,24 +322,26 @@ static void SkipBlockWithBranch(BasicBlock *bb, Value *cond, Loop *L,
|
||||
BranchInst::Create(end, body, cond, bb);
|
||||
|
||||
for (Instruction &inst : *body) {
|
||||
- PHINode *phi = nullptr;
|
||||
|
||||
// For each user that's outside of 'body', replace its use of 'inst' with a
|
||||
// phi created in 'end'
|
||||
- for (auto it = inst.user_begin(); it != inst.user_end();) {
|
||||
- Instruction *user_inst = cast<Instruction>(*(it++));
|
||||
- if (user_inst == phi)
|
||||
- continue;
|
||||
+ SmallPtrSet<Instruction *, 8> users_in_other_blocks;
|
||||
+ for (auto *user : inst.users()) {
|
||||
+ Instruction *user_inst = cast<Instruction>(user);
|
||||
if (user_inst->getParent() != body) {
|
||||
- if (!phi) {
|
||||
- phi = PHINode::Create(inst.getType(), 2, "", &*end->begin());
|
||||
- phi->addIncoming(GetDefaultValue(inst.getType()), bb);
|
||||
- phi->addIncoming(&inst, body);
|
||||
- }
|
||||
+ users_in_other_blocks.insert(user_inst);
|
||||
+ }
|
||||
+ }
|
||||
+ if (users_in_other_blocks.size() > 0) {
|
||||
+ auto *phi = PHINode::Create(inst.getType(), 2, "", &*end->begin());
|
||||
+ phi->addIncoming(GetDefaultValue(inst.getType()), bb);
|
||||
+ phi->addIncoming(&inst, body);
|
||||
+
|
||||
+ for (auto *user_inst : users_in_other_blocks) {
|
||||
user_inst->replaceUsesOfWith(&inst, phi);
|
||||
}
|
||||
- } // For each user of inst of body
|
||||
- } // For each inst in body
|
||||
+ }
|
||||
+ } // For each inst in body
|
||||
|
||||
L->addBasicBlockToLoop(body, *LI);
|
||||
L->addBasicBlockToLoop(end, *LI);
|
||||
diff --git a/tools/clang/test/DXC/Passes/DxilRemoveUnstructuredLoopExits/struct_exit_wrap_value_iteration_bug.ll b/tools/clang/test/DXC/Passes/DxilRemoveUnstructuredLoopExits/struct_exit_wrap_value_iteration_bug.ll
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..ee912c929bdc0424959a29d16c3d5c64f885f809
|
||||
--- /dev/null
|
||||
+++ b/tools/clang/test/DXC/Passes/DxilRemoveUnstructuredLoopExits/struct_exit_wrap_value_iteration_bug.ll
|
||||
@@ -0,0 +1,257 @@
|
||||
+; RUN: %dxopt %s -hlsl-passes-resume -loop-unroll,StructurizeLoopExits=1 -S | FileCheck %s
|
||||
+
|
||||
+; The Loop exit structurizer will wrap the definition of %DerivFineX3 in a conditional block.
|
||||
+; Its value will later be propagated into a phi, and that phi replaces all further uses
|
||||
+; of %DerivFineX3.
|
||||
+;
|
||||
+; Tests that a bug is fixed where the code used to iterate through the uses of a value
|
||||
+; while also updating those uses. The old code would fail to update the definition
|
||||
+; of %g.i.2.i3 and the result would be an invalid module: %DerivFineX3 would not dominate
|
||||
+; all its uses.
|
||||
+
|
||||
+
|
||||
+; CHECK: define void @main
|
||||
+; CHECK-NOT: %DerivFineX3
|
||||
+; CHECK: "\01?f@@YAXXZ.exit.i":
|
||||
+; CHECK-NEXT: br i1 true, label %dx.struct_exit.cond_end, label %dx.struct_exit.cond_body
|
||||
+
|
||||
+; CHECK: dx.struct_exit.cond_body:
|
||||
+; CHECK: %DerivFineX3 = call
|
||||
+; CHECK: br label %dx.struct_exit.cond_end
|
||||
+
|
||||
+; CHECK: dx.struct_exit.cond_end:
|
||||
+; CHECK: = phi {{.*}} %DerivFineX3
|
||||
+; CHECK: br
|
||||
+; CHECK-NOT: %DerivFineX3
|
||||
+; CHECK: ret void
|
||||
+
|
||||
+
|
||||
+;
|
||||
+;
|
||||
+; void f() {
|
||||
+; int l_1 = 10;
|
||||
+; for (int l = 0, l_2 = 0; l < 5 && l_2 < 1; l++, l_2++) {
|
||||
+; while (1 < l_1) { }
|
||||
+; }
|
||||
+; }
|
||||
+;
|
||||
+;
|
||||
+; struct tint_symbol {
|
||||
+; float4 value : SV_Target0;
|
||||
+; };
|
||||
+;
|
||||
+; float4 main_inner() {
|
||||
+; float4 g = float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
+; bool2 true2 = (true).xx;
|
||||
+; uint2 _e8 = (0u).xx;
|
||||
+; do {
|
||||
+; if (_e8.x != 2u) {
|
||||
+; f();
|
||||
+; float4 _e15 = ddx_fine(g);
|
||||
+; if (_e8[_e8.x] == 2u) {
|
||||
+; g = _e15;
|
||||
+; } else {
|
||||
+; f();
|
||||
+; }
|
||||
+; switch(_e8.x) {
|
||||
+; case 3u: {
|
||||
+; break;
|
||||
+; }
|
||||
+; case 2u: {
|
||||
+; g = _e15;
|
||||
+; break;
|
||||
+; }
|
||||
+; default: {
|
||||
+; g = _e15;
|
||||
+; }
|
||||
+; }
|
||||
+; f();
|
||||
+; }
|
||||
+; } while(!all(true2));
|
||||
+; return g;
|
||||
+;}
|
||||
+;
|
||||
+;tint_symbol main() {
|
||||
+; float4 inner_result = main_inner();
|
||||
+; tint_symbol wrapper_result = (tint_symbol)0;
|
||||
+; wrapper_result.value = inner_result;
|
||||
+; return wrapper_result;
|
||||
+;}
|
||||
+
|
||||
+target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
|
||||
+target triple = "dxil-ms-dx"
|
||||
+
|
||||
+%struct.tint_symbol = type { <4 x float> }
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+define void @main(<4 x float>* noalias) #0 {
|
||||
+entry:
|
||||
+ %1 = alloca [2 x i32], align 4
|
||||
+ %2 = getelementptr inbounds [2 x i32], [2 x i32]* %1, i32 0, i32 0, !dbg !20 ; line:17 col:9
|
||||
+ store i32 0, i32* %2, align 4, !dbg !20 ; line:17 col:9
|
||||
+ %3 = getelementptr inbounds [2 x i32], [2 x i32]* %1, i32 0, i32 1, !dbg !20 ; line:17 col:9
|
||||
+ store i32 0, i32* %3, align 4, !dbg !20 ; line:17 col:9
|
||||
+ br label %do.body.i, !dbg !26 ; line:18 col:3
|
||||
+
|
||||
+do.body.i: ; preds = %do.cond.i, %entry
|
||||
+ %g.i.0.i0 = phi float [ 0.000000e+00, %entry ], [ %g.i.3.i0, %do.cond.i ]
|
||||
+ %g.i.0.i1 = phi float [ 0.000000e+00, %entry ], [ %g.i.3.i1, %do.cond.i ]
|
||||
+ %g.i.0.i2 = phi float [ 0.000000e+00, %entry ], [ %g.i.3.i2, %do.cond.i ]
|
||||
+ %g.i.0.i3 = phi float [ 0.000000e+00, %entry ], [ %g.i.3.i3, %do.cond.i ]
|
||||
+ %4 = getelementptr inbounds [2 x i32], [2 x i32]* %1, i32 0, i32 0, !dbg !27 ; line:19 col:9
|
||||
+ %5 = load i32, i32* %4, align 4, !dbg !27 ; line:19 col:9
|
||||
+ %cmp.i = icmp ne i32 %5, 2, !dbg !28 ; line:19 col:15
|
||||
+ br i1 %cmp.i, label %for.cond.i.i, label %do.cond.i, !dbg !27 ; line:19 col:9
|
||||
+
|
||||
+for.cond.i.i: ; preds = %do.body.i
|
||||
+ br i1 true, label %while.cond.i.i.preheader, label %"\01?f@@YAXXZ.exit.i", !dbg !29 ; line:4 col:3
|
||||
+
|
||||
+while.cond.i.i.preheader: ; preds = %for.cond.i.i
|
||||
+ br label %while.cond.i.i, !dbg !32 ; line:5 col:5
|
||||
+
|
||||
+while.cond.i.i: ; preds = %while.cond.i.i.preheader, %while.cond.i.i
|
||||
+ br label %while.cond.i.i, !dbg !32 ; line:5 col:5
|
||||
+
|
||||
+"\01?f@@YAXXZ.exit.i": ; preds = %for.cond.i.i
|
||||
+ %DerivFineX = call float @dx.op.unary.f32(i32 85, float %g.i.0.i0), !dbg !33 ; line:21 col:21 ; DerivFineX(value)
|
||||
+ %DerivFineX1 = call float @dx.op.unary.f32(i32 85, float %g.i.0.i1), !dbg !33 ; line:21 col:21 ; DerivFineX(value)
|
||||
+ %DerivFineX2 = call float @dx.op.unary.f32(i32 85, float %g.i.0.i2), !dbg !33 ; line:21 col:21 ; DerivFineX(value)
|
||||
+ %DerivFineX3 = call float @dx.op.unary.f32(i32 85, float %g.i.0.i3), !dbg !33 ; line:21 col:21 ; DerivFineX(value)
|
||||
+ %6 = getelementptr inbounds [2 x i32], [2 x i32]* %1, i32 0, i32 0, !dbg !34 ; line:22 col:15
|
||||
+ %7 = load i32, i32* %6, align 4, !dbg !34 ; line:22 col:15
|
||||
+ %8 = getelementptr [2 x i32], [2 x i32]* %1, i32 0, i32 %7, !dbg !35 ; line:22 col:11
|
||||
+ %9 = load i32, i32* %8, !dbg !35, !tbaa !36 ; line:22 col:11
|
||||
+ %cmp6.i = icmp eq i32 %9, 2, !dbg !40 ; line:22 col:22
|
||||
+ br i1 %cmp6.i, label %if.end.i, label %for.cond.i.19.i, !dbg !35 ; line:22 col:11
|
||||
+
|
||||
+for.cond.i.19.i: ; preds = %"\01?f@@YAXXZ.exit.i"
|
||||
+ br i1 true, label %while.cond.i.24.i.preheader, label %if.end.i, !dbg !41 ; line:4 col:3
|
||||
+
|
||||
+while.cond.i.24.i.preheader: ; preds = %for.cond.i.19.i
|
||||
+ br label %while.cond.i.24.i, !dbg !43 ; line:5 col:5
|
||||
+
|
||||
+while.cond.i.24.i: ; preds = %while.cond.i.24.i.preheader, %while.cond.i.24.i
|
||||
+ br label %while.cond.i.24.i, !dbg !43 ; line:5 col:5
|
||||
+
|
||||
+if.end.i: ; preds = %for.cond.i.19.i, %"\01?f@@YAXXZ.exit.i"
|
||||
+ %g.i.1.i0 = phi float [ %DerivFineX, %"\01?f@@YAXXZ.exit.i" ], [ %g.i.0.i0, %for.cond.i.19.i ]
|
||||
+ %g.i.1.i1 = phi float [ %DerivFineX1, %"\01?f@@YAXXZ.exit.i" ], [ %g.i.0.i1, %for.cond.i.19.i ]
|
||||
+ %g.i.1.i2 = phi float [ %DerivFineX2, %"\01?f@@YAXXZ.exit.i" ], [ %g.i.0.i2, %for.cond.i.19.i ]
|
||||
+ %g.i.1.i3 = phi float [ %DerivFineX3, %"\01?f@@YAXXZ.exit.i" ], [ %g.i.0.i3, %for.cond.i.19.i ]
|
||||
+ %10 = getelementptr inbounds [2 x i32], [2 x i32]* %1, i32 0, i32 0, !dbg !44 ; line:27 col:14
|
||||
+ %11 = load i32, i32* %10, align 4, !dbg !44 ; line:27 col:14
|
||||
+ switch i32 %11, label %sw.default.i [
|
||||
+ i32 3, label %for.cond.i.5.i
|
||||
+ i32 2, label %sw.bb.10.i
|
||||
+ ], !dbg !45 ; line:27 col:7
|
||||
+
|
||||
+sw.bb.10.i: ; preds = %if.end.i
|
||||
+ br label %for.cond.i.5.i, !dbg !46 ; line:33 col:11
|
||||
+
|
||||
+sw.default.i: ; preds = %if.end.i
|
||||
+ br label %for.cond.i.5.i, !dbg !47 ; line:38 col:7
|
||||
+
|
||||
+for.cond.i.5.i: ; preds = %if.end.i, %sw.bb.10.i, %sw.default.i
|
||||
+ %g.i.2.i0 = phi float [ %DerivFineX, %sw.default.i ], [ %DerivFineX, %sw.bb.10.i ], [ %g.i.1.i0, %if.end.i ]
|
||||
+ %g.i.2.i1 = phi float [ %DerivFineX1, %sw.default.i ], [ %DerivFineX1, %sw.bb.10.i ], [ %g.i.1.i1, %if.end.i ]
|
||||
+ %g.i.2.i2 = phi float [ %DerivFineX2, %sw.default.i ], [ %DerivFineX2, %sw.bb.10.i ], [ %g.i.1.i2, %if.end.i ]
|
||||
+ %g.i.2.i3 = phi float [ %DerivFineX3, %sw.default.i ], [ %DerivFineX3, %sw.bb.10.i ], [ %g.i.1.i3, %if.end.i ]
|
||||
+ br i1 true, label %while.cond.i.10.i.preheader, label %do.cond.i, !dbg !48 ; line:4 col:3
|
||||
+
|
||||
+while.cond.i.10.i.preheader: ; preds = %for.cond.i.5.i
|
||||
+ br label %while.cond.i.10.i, !dbg !50 ; line:5 col:5
|
||||
+
|
||||
+while.cond.i.10.i: ; preds = %while.cond.i.10.i.preheader, %while.cond.i.10.i
|
||||
+ br label %while.cond.i.10.i, !dbg !50 ; line:5 col:5
|
||||
+
|
||||
+do.cond.i: ; preds = %for.cond.i.5.i, %do.body.i
|
||||
+ %g.i.3.i0 = phi float [ %g.i.0.i0, %do.body.i ], [ %g.i.2.i0, %for.cond.i.5.i ]
|
||||
+ %g.i.3.i1 = phi float [ %g.i.0.i1, %do.body.i ], [ %g.i.2.i1, %for.cond.i.5.i ]
|
||||
+ %g.i.3.i2 = phi float [ %g.i.0.i2, %do.body.i ], [ %g.i.2.i2, %for.cond.i.5.i ]
|
||||
+ %g.i.3.i3 = phi float [ %g.i.0.i3, %do.body.i ], [ %g.i.2.i3, %for.cond.i.5.i ]
|
||||
+ br i1 false, label %do.body.i, label %"\01?main_inner@@YA?AV?$vector@M$03@@XZ.exit", !dbg !51 ; line:41 col:3
|
||||
+
|
||||
+"\01?main_inner@@YA?AV?$vector@M$03@@XZ.exit": ; preds = %do.cond.i
|
||||
+ %g.i.3.i3.lcssa = phi float [ %g.i.3.i3, %do.cond.i ]
|
||||
+ %g.i.3.i2.lcssa = phi float [ %g.i.3.i2, %do.cond.i ]
|
||||
+ %g.i.3.i1.lcssa = phi float [ %g.i.3.i1, %do.cond.i ]
|
||||
+ %g.i.3.i0.lcssa = phi float [ %g.i.3.i0, %do.cond.i ]
|
||||
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float %g.i.3.i0.lcssa), !dbg !52 ; line:49 col:10 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
|
||||
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float %g.i.3.i1.lcssa), !dbg !52 ; line:49 col:10 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
|
||||
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float %g.i.3.i2.lcssa), !dbg !52 ; line:49 col:10 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
|
||||
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3, float %g.i.3.i3.lcssa), !dbg !52 ; line:49 col:10 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
|
||||
+ ret void, !dbg !53 ; line:49 col:3
|
||||
+}
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+declare void @dx.op.storeOutput.f32(i32, i32, i32, i8, float) #0
|
||||
+
|
||||
+; Function Attrs: nounwind readnone
|
||||
+declare float @dx.op.unary.f32(i32, float) #1
|
||||
+
|
||||
+attributes #0 = { nounwind }
|
||||
+attributes #1 = { nounwind readnone }
|
||||
+
|
||||
+!llvm.module.flags = !{!0}
|
||||
+!pauseresume = !{!1}
|
||||
+!llvm.ident = !{!2}
|
||||
+!dx.version = !{!3}
|
||||
+!dx.valver = !{!4}
|
||||
+!dx.shaderModel = !{!5}
|
||||
+!dx.typeAnnotations = !{!6, !9}
|
||||
+!dx.entryPoints = !{!16}
|
||||
+
|
||||
+!0 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
+!1 = !{!"hlsl-dxilemit", !"hlsl-dxilload"}
|
||||
+!2 = !{!"dxc(private) 1.8.0.14549 (main, 0781ded87-dirty)"}
|
||||
+!3 = !{i32 1, i32 0}
|
||||
+!4 = !{i32 1, i32 8}
|
||||
+!5 = !{!"ps", i32 6, i32 0}
|
||||
+!6 = !{i32 0, %struct.tint_symbol undef, !7}
|
||||
+!7 = !{i32 16, !8}
|
||||
+!8 = !{i32 6, !"value", i32 3, i32 0, i32 4, !"SV_Target0", i32 7, i32 9}
|
||||
+!9 = !{i32 1, void (<4 x float>*)* @main, !10}
|
||||
+!10 = !{!11, !13}
|
||||
+!11 = !{i32 0, !12, !12}
|
||||
+!12 = !{}
|
||||
+!13 = !{i32 1, !14, !15}
|
||||
+!14 = !{i32 4, !"SV_Target0", i32 7, i32 9}
|
||||
+!15 = !{i32 0}
|
||||
+!16 = !{void (<4 x float>*)* @main, !"main", !17, null, null}
|
||||
+!17 = !{null, !18, null}
|
||||
+!18 = !{!19}
|
||||
+!19 = !{i32 0, !"SV_Target", i8 9, i8 16, !15, i8 0, i32 1, i8 4, i32 0, i8 0, null}
|
||||
+!20 = !DILocation(line: 17, column: 9, scope: !21, inlinedAt: !24)
|
||||
+!21 = !DISubprogram(name: "main_inner", scope: !22, file: !22, line: 14, type: !23, isLocal: false, isDefinition: true, scopeLine: 14, flags: DIFlagPrototyped, isOptimized: false)
|
||||
+!22 = !DIFile(filename: "s2.hlsl", directory: "")
|
||||
+!23 = !DISubroutineType(types: !12)
|
||||
+!24 = distinct !DILocation(line: 46, column: 25, scope: !25)
|
||||
+!25 = !DISubprogram(name: "main", scope: !22, file: !22, line: 45, type: !23, isLocal: false, isDefinition: true, scopeLine: 45, flags: DIFlagPrototyped, isOptimized: false, function: void (<4 x float>*)* @main)
|
||||
+!26 = !DILocation(line: 18, column: 3, scope: !21, inlinedAt: !24)
|
||||
+!27 = !DILocation(line: 19, column: 9, scope: !21, inlinedAt: !24)
|
||||
+!28 = !DILocation(line: 19, column: 15, scope: !21, inlinedAt: !24)
|
||||
+!29 = !DILocation(line: 4, column: 3, scope: !30, inlinedAt: !31)
|
||||
+!30 = !DISubprogram(name: "f", scope: !22, file: !22, line: 2, type: !23, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false)
|
||||
+!31 = distinct !DILocation(line: 20, column: 7, scope: !21, inlinedAt: !24)
|
||||
+!32 = !DILocation(line: 5, column: 5, scope: !30, inlinedAt: !31)
|
||||
+!33 = !DILocation(line: 21, column: 21, scope: !21, inlinedAt: !24)
|
||||
+!34 = !DILocation(line: 22, column: 15, scope: !21, inlinedAt: !24)
|
||||
+!35 = !DILocation(line: 22, column: 11, scope: !21, inlinedAt: !24)
|
||||
+!36 = !{!37, !37, i64 0}
|
||||
+!37 = !{!"int", !38, i64 0}
|
||||
+!38 = !{!"omnipotent char", !39, i64 0}
|
||||
+!39 = !{!"Simple C/C++ TBAA"}
|
||||
+!40 = !DILocation(line: 22, column: 22, scope: !21, inlinedAt: !24)
|
||||
+!41 = !DILocation(line: 4, column: 3, scope: !30, inlinedAt: !42)
|
||||
+!42 = distinct !DILocation(line: 25, column: 9, scope: !21, inlinedAt: !24)
|
||||
+!43 = !DILocation(line: 5, column: 5, scope: !30, inlinedAt: !42)
|
||||
+!44 = !DILocation(line: 27, column: 14, scope: !21, inlinedAt: !24)
|
||||
+!45 = !DILocation(line: 27, column: 7, scope: !21, inlinedAt: !24)
|
||||
+!46 = !DILocation(line: 33, column: 11, scope: !21, inlinedAt: !24)
|
||||
+!47 = !DILocation(line: 38, column: 7, scope: !21, inlinedAt: !24)
|
||||
+!48 = !DILocation(line: 4, column: 3, scope: !30, inlinedAt: !49)
|
||||
+!49 = distinct !DILocation(line: 39, column: 7, scope: !21, inlinedAt: !24)
|
||||
+!50 = !DILocation(line: 5, column: 5, scope: !30, inlinedAt: !49)
|
||||
+!51 = !DILocation(line: 41, column: 3, scope: !21, inlinedAt: !24)
|
||||
+!52 = !DILocation(line: 49, column: 10, scope: !25)
|
||||
+!53 = !DILocation(line: 49, column: 3, scope: !25)
|
||||
243
patches/DirectXShaderCompiler/cherry-pick-511cfef8e050.patch
Normal file
243
patches/DirectXShaderCompiler/cherry-pick-511cfef8e050.patch
Normal file
@@ -0,0 +1,243 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Antonio Maiorano <amaiorano@google.com>
|
||||
Date: Mon, 27 May 2024 15:41:40 -0400
|
||||
Subject: Fix use-after-free in SimplifyCFG (#6628)
|
||||
|
||||
When SimplifySwitchOnSelect calls SimplifyTerminatorOnSelect, it holds
|
||||
onto the select's condition value to use for the conditional branch it
|
||||
replaces the switch with. When removing the switch's unused
|
||||
predecessors, it must make sure not to delete PHIs in case one of them
|
||||
is used by the condition value, otherwise the condition value itself may
|
||||
get deleted, resulting in an use-after-free.
|
||||
|
||||
Note that this was fixed in LLVM as well:
|
||||
|
||||
https://github.com/llvm/llvm-project/commit/dc3b67b4cad5c18a687edfabd50779c3c656c620
|
||||
|
||||
Bug: chromium:338103465
|
||||
Change-Id: Iff5d5f2e3ecf38a3fb22bbc65e7c33ad0de659fb
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5570018
|
||||
Reviewed-by: James Price <jrprice@google.com>
|
||||
Reviewed-by: Natalie Chouinard <chouinard@chromium.org>
|
||||
|
||||
diff --git a/lib/Transforms/Utils/SimplifyCFG.cpp b/lib/Transforms/Utils/SimplifyCFG.cpp
|
||||
index b45caa2929a5cc3aa064fdbd9c06c20ad9e1e155..0d3ba1e00719060c1e71fa238726f0c63bd5b32f 100644
|
||||
--- a/lib/Transforms/Utils/SimplifyCFG.cpp
|
||||
+++ b/lib/Transforms/Utils/SimplifyCFG.cpp
|
||||
@@ -2619,7 +2619,10 @@ static bool SimplifyTerminatorOnSelect(TerminatorInst *OldTerm, Value *Cond,
|
||||
else if (Succ == KeepEdge2)
|
||||
KeepEdge2 = nullptr;
|
||||
else
|
||||
- Succ->removePredecessor(OldTerm->getParent());
|
||||
+ Succ->removePredecessor(
|
||||
+ OldTerm->getParent(),
|
||||
+ /*DontDeleteUselessPHIs=*/true // HLSL Change: foward port LLVM fix
|
||||
+ );
|
||||
}
|
||||
|
||||
IRBuilder<> Builder(OldTerm);
|
||||
diff --git a/tools/clang/test/DXC/Passes/SimplifyCFG/simplifycfg-uaf-select-condition.ll b/tools/clang/test/DXC/Passes/SimplifyCFG/simplifycfg-uaf-select-condition.ll
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..149906c11285ed99a19c0fe1743801a795827792
|
||||
--- /dev/null
|
||||
+++ b/tools/clang/test/DXC/Passes/SimplifyCFG/simplifycfg-uaf-select-condition.ll
|
||||
@@ -0,0 +1,199 @@
|
||||
+; RUN: %dxopt %s -hlsl-passes-resume -simplifycfg -S | FileCheck %s
|
||||
+
|
||||
+; The IR below comes from the following HLSL.
|
||||
+; Compiling this HLSL with dxc was resulting in an ASAN
|
||||
+; use-after-free in SimplifyCFG during
|
||||
+; SimplifyTerminatorOnSelect because it was deleting
|
||||
+; a PHI node with an input value that the pass later
|
||||
+; emits (the select condition value).
|
||||
+
|
||||
+; ByteAddressBuffer buff : register(t0);
|
||||
+;
|
||||
+; [numthreads(1, 1, 1)]
|
||||
+; void main() {
|
||||
+; if (buff.Load(0u)) {
|
||||
+; return;
|
||||
+; }
|
||||
+;
|
||||
+; int i = 0;
|
||||
+; int j = 0;
|
||||
+; while (true) {
|
||||
+; bool a = (i < 2);
|
||||
+; switch(i) {
|
||||
+; case 0: {
|
||||
+; while (true) {
|
||||
+; bool b = (j < 2);
|
||||
+; if (b) {
|
||||
+; } else {
|
||||
+; break;
|
||||
+; }
|
||||
+; while (true) {
|
||||
+; int unused = 0;
|
||||
+; while (true) {
|
||||
+; if (a) break;
|
||||
+; }
|
||||
+; while (true) {
|
||||
+; while (true) {
|
||||
+; if (b) {
|
||||
+; if (b) return;
|
||||
+; } else {
|
||||
+; break;
|
||||
+; }
|
||||
+; while (true) {
|
||||
+; i = 0;
|
||||
+; if (b) break;
|
||||
+; }
|
||||
+; if (a) break;
|
||||
+; }
|
||||
+; if (a) break;
|
||||
+; }
|
||||
+; if (a) break;
|
||||
+; }
|
||||
+; j = (j + 2);
|
||||
+; }
|
||||
+; }
|
||||
+; }
|
||||
+; }
|
||||
+; }
|
||||
+
|
||||
+; Make sure the phi node did not get deleted by simplifycfg
|
||||
+; CHECK: cleanup:
|
||||
+; CHECK-NEXT: %cleanup.dest.slot.0 = phi i32 [ 1, %while.body.20 ], [ %.mux, %while.end.37 ]
|
||||
+; CHECK-NEXT: switch i32 %cleanup.dest.slot.0, label %cleanup.46 [
|
||||
+
|
||||
+;
|
||||
+; Buffer Definitions:
|
||||
+;
|
||||
+;
|
||||
+; Resource Bindings:
|
||||
+;
|
||||
+; Name Type Format Dim ID HLSL Bind Count
|
||||
+; ------------------------------ ---------- ------- ----------- ------- -------------- ------
|
||||
+; buff texture byte r/o T0 t0 1
|
||||
+;
|
||||
+target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
|
||||
+target triple = "dxil-ms-dx"
|
||||
+
|
||||
+%struct.ByteAddressBuffer = type { i32 }
|
||||
+%dx.types.Handle = type { i8* }
|
||||
+%dx.types.ResourceProperties = type { i32, i32 }
|
||||
+
|
||||
+@"\01?buff@@3UByteAddressBuffer@@A" = external global %struct.ByteAddressBuffer, align 4
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+define void @main() #0 {
|
||||
+entry:
|
||||
+ %0 = load %struct.ByteAddressBuffer, %struct.ByteAddressBuffer* @"\01?buff@@3UByteAddressBuffer@@A", !dbg !17 ; line:5 col:7
|
||||
+ %1 = call %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %struct.ByteAddressBuffer)"(i32 0, %struct.ByteAddressBuffer %0), !dbg !17 ; line:5 col:7
|
||||
+ %2 = call %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer)"(i32 14, %dx.types.Handle %1, %dx.types.ResourceProperties { i32 11, i32 0 }, %struct.ByteAddressBuffer undef), !dbg !17 ; line:5 col:7
|
||||
+ %3 = call i32 @"dx.hl.op.ro.i32 (i32, %dx.types.Handle, i32)"(i32 231, %dx.types.Handle %2, i32 0), !dbg !17 ; line:5 col:7
|
||||
+ %tobool = icmp ne i32 %3, 0, !dbg !17 ; line:5 col:7
|
||||
+ br i1 %tobool, label %return, label %while.body, !dbg !17 ; line:5 col:7
|
||||
+
|
||||
+while.body: ; preds = %while.body.3, %while.body, %cleanup.46, %entry
|
||||
+ %j.0 = phi i32 [ 0, %entry ], [ %j.1, %cleanup.46 ], [ %j.0, %while.body ], [ %j.1, %while.body.3 ]
|
||||
+ %i.0 = phi i32 [ 0, %entry ], [ %i.1, %cleanup.46 ], [ %i.0, %while.body ], [ %i.1, %while.body.3 ]
|
||||
+ %cmp = icmp slt i32 %i.0, 2, !dbg !21 ; line:12 col:17
|
||||
+ %cond = icmp eq i32 %i.0, 0, !dbg !22 ; line:13 col:5
|
||||
+ br i1 %cond, label %while.body.3, label %while.body, !dbg !22 ; line:13 col:5
|
||||
+
|
||||
+while.body.3: ; preds = %cleanup.46.thread, %while.body, %cleanup.46
|
||||
+ %j.1 = phi i32 [ %j.1, %cleanup.46 ], [ %j.0, %while.body ], [ %add, %cleanup.46.thread ]
|
||||
+ %i.1 = phi i32 [ %i.1, %cleanup.46 ], [ %i.0, %while.body ], [ %i.1, %cleanup.46.thread ]
|
||||
+ %cmp4 = icmp slt i32 %j.1, 2, !dbg !23 ; line:16 col:23
|
||||
+ br i1 %cmp4, label %while.body.11, label %while.body, !dbg !24 ; line:17 col:15
|
||||
+
|
||||
+while.body.11: ; preds = %while.body.3, %cleanup
|
||||
+ br label %while.body.13, !dbg !25 ; line:23 col:13
|
||||
+
|
||||
+while.body.13: ; preds = %while.body.13, %while.body.11
|
||||
+ br i1 %cmp, label %while.body.20, label %while.body.13, !dbg !26 ; line:24 col:19
|
||||
+
|
||||
+while.body.20: ; preds = %while.body.13, %while.end.37
|
||||
+ br i1 %cmp4, label %cleanup, label %while.end.37, !dbg !27 ; line:28 col:21
|
||||
+
|
||||
+while.end.37: ; preds = %while.body.20
|
||||
+ br i1 %cmp, label %cleanup, label %while.body.20, !dbg !28 ; line:39 col:19
|
||||
+
|
||||
+cleanup: ; preds = %while.end.37, %while.body.20
|
||||
+ %cleanup.dest.slot.0 = phi i32 [ 1, %while.body.20 ], [ 8, %while.end.37 ]
|
||||
+ switch i32 %cleanup.dest.slot.0, label %cleanup.46 [
|
||||
+ i32 0, label %while.body.11
|
||||
+ i32 8, label %cleanup.46.thread
|
||||
+ ]
|
||||
+
|
||||
+cleanup.46.thread: ; preds = %cleanup
|
||||
+ %add = add nsw i32 %j.1, 2, !dbg !29 ; line:43 col:18
|
||||
+ br label %while.body.3
|
||||
+
|
||||
+cleanup.46: ; preds = %cleanup
|
||||
+ switch i32 %cleanup.dest.slot.0, label %return [
|
||||
+ i32 0, label %while.body.3
|
||||
+ i32 6, label %while.body
|
||||
+ ]
|
||||
+
|
||||
+return: ; preds = %cleanup.46, %entry
|
||||
+ ret void, !dbg !30 ; line:48 col:1
|
||||
+}
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+declare void @llvm.lifetime.start(i64, i8* nocapture) #0
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+declare void @llvm.lifetime.end(i64, i8* nocapture) #0
|
||||
+
|
||||
+; Function Attrs: nounwind readonly
|
||||
+declare i32 @"dx.hl.op.ro.i32 (i32, %dx.types.Handle, i32)"(i32, %dx.types.Handle, i32) #1
|
||||
+
|
||||
+; Function Attrs: nounwind readnone
|
||||
+declare %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %struct.ByteAddressBuffer)"(i32, %struct.ByteAddressBuffer) #2
|
||||
+
|
||||
+; Function Attrs: nounwind readnone
|
||||
+declare %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer)"(i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer) #2
|
||||
+
|
||||
+attributes #0 = { nounwind }
|
||||
+attributes #1 = { nounwind readonly }
|
||||
+attributes #2 = { nounwind readnone }
|
||||
+
|
||||
+!llvm.module.flags = !{!0}
|
||||
+!pauseresume = !{!1}
|
||||
+!llvm.ident = !{!2}
|
||||
+!dx.version = !{!3}
|
||||
+!dx.valver = !{!4}
|
||||
+!dx.shaderModel = !{!5}
|
||||
+!dx.typeAnnotations = !{!6}
|
||||
+!dx.entryPoints = !{!10}
|
||||
+!dx.fnprops = !{!14}
|
||||
+!dx.options = !{!15, !16}
|
||||
+
|
||||
+!0 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
+!1 = !{!"hlsl-hlemit", !"hlsl-hlensure"}
|
||||
+!2 = !{!"dxc(private) 1.8.0.4514 (d9bd2a706-dirty)"}
|
||||
+!3 = !{i32 1, i32 6}
|
||||
+!4 = !{i32 1, i32 8}
|
||||
+!5 = !{!"cs", i32 6, i32 6}
|
||||
+!6 = !{i32 1, void ()* @main, !7}
|
||||
+!7 = !{!8}
|
||||
+!8 = !{i32 1, !9, !9}
|
||||
+!9 = !{}
|
||||
+!10 = !{void ()* @main, !"main", null, !11, null}
|
||||
+!11 = !{!12, null, null, null}
|
||||
+!12 = !{!13}
|
||||
+!13 = !{i32 0, %struct.ByteAddressBuffer* @"\01?buff@@3UByteAddressBuffer@@A", !"buff", i32 0, i32 0, i32 1, i32 11, i32 0, null}
|
||||
+!14 = !{void ()* @main, i32 5, i32 1, i32 1, i32 1}
|
||||
+!15 = !{i32 64}
|
||||
+!16 = !{i32 -1}
|
||||
+!17 = !DILocation(line: 5, column: 7, scope: !18)
|
||||
+!18 = !DISubprogram(name: "main", scope: !19, file: !19, line: 4, type: !20, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false, function: void ()* @main)
|
||||
+!19 = !DIFile(filename: "/mnt/c/Users/amaiorano/Downloads/338103465/standalone_reduced.hlsl", directory: "")
|
||||
+!20 = !DISubroutineType(types: !9)
|
||||
+!21 = !DILocation(line: 12, column: 17, scope: !18)
|
||||
+!22 = !DILocation(line: 13, column: 5, scope: !18)
|
||||
+!23 = !DILocation(line: 16, column: 23, scope: !18)
|
||||
+!24 = !DILocation(line: 17, column: 15, scope: !18)
|
||||
+!25 = !DILocation(line: 23, column: 13, scope: !18)
|
||||
+!26 = !DILocation(line: 24, column: 19, scope: !18)
|
||||
+!27 = !DILocation(line: 28, column: 21, scope: !18)
|
||||
+!28 = !DILocation(line: 39, column: 19, scope: !18)
|
||||
+!29 = !DILocation(line: 43, column: 18, scope: !18)
|
||||
+!30 = !DILocation(line: 48, column: 1, scope: !18)
|
||||
116
patches/DirectXShaderCompiler/cherry-pick-771e74ab497d.patch
Normal file
116
patches/DirectXShaderCompiler/cherry-pick-771e74ab497d.patch
Normal file
@@ -0,0 +1,116 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Antonio Maiorano <amaiorano@google.com>
|
||||
Date: Thu, 20 Jun 2024 14:02:42 -0400
|
||||
Subject: indvars: don't replace a phi when that breaks LCSSA (#6695)
|
||||
|
||||
Induction variable simplification (indvars) tries to rewrite exit
|
||||
values; these appear as phi nodes in loop exit blocks. If the
|
||||
replacement for the phi is still in the loop, then that would break the
|
||||
LCSSA property. Don't do that.
|
||||
|
||||
Add a test for this.
|
||||
|
||||
Bug: chromium:345993680
|
||||
Change-Id: Ib2330afa3c6f47373cb4336cfd00e851044fea3a
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5645925
|
||||
Reviewed-by: dan sinclair <dsinclair@chromium.org>
|
||||
Reviewed-by: James Price <jrprice@google.com>
|
||||
|
||||
diff --git a/lib/Transforms/Scalar/IndVarSimplify.cpp b/lib/Transforms/Scalar/IndVarSimplify.cpp
|
||||
index f5b1455d5932b63dfef699991c5eeab38e447a7d..e6ff7b3ab4d81bbb782f0bd0a7b5185a30fd1285 100644
|
||||
--- a/lib/Transforms/Scalar/IndVarSimplify.cpp
|
||||
+++ b/lib/Transforms/Scalar/IndVarSimplify.cpp
|
||||
@@ -24,7 +24,6 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
-#include "llvm/Transforms/Scalar.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
@@ -41,11 +40,13 @@
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/IntrinsicInst.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
+#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/PatternMatch.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
+#include "llvm/Transforms/Scalar.h"
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Transforms/Utils/Local.h"
|
||||
#include "llvm/Transforms/Utils/SimplifyIndVar.h"
|
||||
@@ -698,6 +699,16 @@ void IndVarSimplify::RewriteLoopExitValues(Loop *L, SCEVExpander &Rewriter) {
|
||||
continue;
|
||||
}
|
||||
|
||||
+ // HLSL Change Begin
|
||||
+ // Avoid breaking LCSSA: Don't replace the PHI if its replacement
|
||||
+ // is defined inside the loop.
|
||||
+ if (auto *ExitValInst = dyn_cast<Instruction>(ExitVal)) {
|
||||
+ if (L->contains(ExitValInst)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+ // HLSL Change End
|
||||
+
|
||||
// Collect all the candidate PHINodes to be rewritten.
|
||||
RewritePhiSet.push_back(
|
||||
RewritePhi(PN, i, ExitVal, HighCost, LCSSASafePhiForRAUW));
|
||||
diff --git a/test/HLSL/passes/indvars/preserve-phi-when-replacement-is-in-loop.ll b/test/HLSL/passes/indvars/preserve-phi-when-replacement-is-in-loop.ll
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..b550ce993837814229f8223a47b2af328cc7c87c
|
||||
--- /dev/null
|
||||
+++ b/test/HLSL/passes/indvars/preserve-phi-when-replacement-is-in-loop.ll
|
||||
@@ -0,0 +1,49 @@
|
||||
+; RUN: opt < %s -indvars -S | FileCheck %s
|
||||
+
|
||||
+; The inner loop (%header1) has a fixed trip count.
|
||||
+; The indvars pass is tempted to delete the phi instruction %hexit,
|
||||
+; and replace its uses with %add3.
|
||||
+; But %hexit is used in %latch0, which is outside the inner loop and
|
||||
+; its exit block. Deleting the phi %hexit would break LCSSA form.
|
||||
+
|
||||
+; CHECK: @main
|
||||
+; CHECK: exit1:
|
||||
+; CHECK-NEXT: %hexit = phi i32 [ %hnext, %header1 ]
|
||||
+; CHECK-NEXT: br label %latch0
|
||||
+
|
||||
+; CHECK: latch0:
|
||||
+
|
||||
+target triple = "dxil-ms-dx"
|
||||
+
|
||||
+define void @main(i32 %arg) {
|
||||
+entry:
|
||||
+ br label %header0
|
||||
+
|
||||
+header0:
|
||||
+ %isgt0 = icmp sgt i32 %arg, 0
|
||||
+ %smax = select i1 %isgt0, i32 %arg, i32 0
|
||||
+ %h0 = add i32 %smax, 1
|
||||
+ %j0 = add i32 %smax, 2
|
||||
+ %doinner = icmp slt i32 %j0, 1
|
||||
+ br i1 %doinner, label %header1.pre, label %latch0
|
||||
+
|
||||
+header1.pre:
|
||||
+ br label %header1
|
||||
+
|
||||
+header1:
|
||||
+ %hi = phi i32 [ %hnext, %header1 ], [ %h0, %header1.pre ]
|
||||
+ %ji = phi i32 [ %jnext, %header1 ], [ %j0, %header1.pre ]
|
||||
+ %add3 = add i32 %smax, 3
|
||||
+ %hnext = add i32 %hi, 1
|
||||
+ %jnext = add nsw i32 %ji, 1 ; the nsw here is essential
|
||||
+ %do1again = icmp slt i32 %ji, %add3
|
||||
+ br i1 %do1again, label %header1, label %exit1
|
||||
+
|
||||
+exit1:
|
||||
+ %hexit = phi i32 [ %hnext, %header1 ]
|
||||
+ br label %latch0
|
||||
+
|
||||
+latch0:
|
||||
+ %useh = phi i32 [ %h0, %header0 ], [ %hexit, %exit1 ]
|
||||
+ br label %header0
|
||||
+}
|
||||
108
patches/DirectXShaderCompiler/cherry-pick-867c1001637e.patch
Normal file
108
patches/DirectXShaderCompiler/cherry-pick-867c1001637e.patch
Normal file
@@ -0,0 +1,108 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Antonio Maiorano <amaiorano@google.com>
|
||||
Date: Thu, 16 May 2024 14:24:27 -0400
|
||||
Subject: Fix invalid module bitcode when indexing a swizzled bool vector
|
||||
(#6582)
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
When indexing a swizzled bool vector, some HLSL-specific code in
|
||||
EmitCXXMemberOrOperatorMemberCallExpr kicks in to handle the
|
||||
HLSLVecType. In this case, we’re dealing with an ExtVectorElt because of
|
||||
the swizzle, so this function creates a GEP, Load, and Store on the
|
||||
vector. However, boolean scalars are returned as type i11 while the
|
||||
store is storing to a bool, which is an i32, so we need to insert a cast
|
||||
before the store.
|
||||
|
||||
Bug: chromium:338161969
|
||||
Change-Id: I45f8ec383be49210a10f725d8266b66fd30c34be
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5545820
|
||||
Reviewed-by: James Price <jrprice@google.com>
|
||||
Reviewed-by: dan sinclair <dsinclair@google.com>
|
||||
|
||||
diff --git a/tools/clang/lib/CodeGen/CGExpr.cpp b/tools/clang/lib/CodeGen/CGExpr.cpp
|
||||
index cc46d067e617f1032bd7bc3ea6f65276984df130..efef0593b334103e511d43e3986fed3c304d28a3 100644
|
||||
--- a/tools/clang/lib/CodeGen/CGExpr.cpp
|
||||
+++ b/tools/clang/lib/CodeGen/CGExpr.cpp
|
||||
@@ -1137,6 +1137,12 @@ llvm::MDNode *CodeGenFunction::getRangeForLoadFromType(QualType Ty) {
|
||||
return MDHelper.createRange(Min, End);
|
||||
}
|
||||
|
||||
+static bool ShouldEmitRangeMD(llvm::Value *Value, QualType Ty) {
|
||||
+ if (hasBooleanRepresentation(Ty))
|
||||
+ return cast<llvm::IntegerType>(Value->getType())->getBitWidth() != 1;
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
|
||||
unsigned Alignment, QualType Ty,
|
||||
SourceLocation Loc,
|
||||
@@ -1236,7 +1242,8 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
|
||||
EmitCheck(std::make_pair(Check, Kind), "load_invalid_value", StaticArgs,
|
||||
EmitCheckValue(Load));
|
||||
}
|
||||
- } else if (CGM.getCodeGenOpts().OptimizationLevel > 0)
|
||||
+ } else if (CGM.getCodeGenOpts().OptimizationLevel > 0 &&
|
||||
+ ShouldEmitRangeMD(Load, Ty))
|
||||
if (llvm::MDNode *RangeInfo = getRangeForLoadFromType(Ty))
|
||||
Load->setMetadata(llvm::LLVMContext::MD_range, RangeInfo);
|
||||
|
||||
diff --git a/tools/clang/lib/CodeGen/CGExprCXX.cpp b/tools/clang/lib/CodeGen/CGExprCXX.cpp
|
||||
index 2efde7c30f7f25fed5b36fe7de062b31e6cd74a2..924a0f806e7a8acf310005a212bb3c50a3c519b9 100644
|
||||
--- a/tools/clang/lib/CodeGen/CGExprCXX.cpp
|
||||
+++ b/tools/clang/lib/CodeGen/CGExprCXX.cpp
|
||||
@@ -235,12 +235,17 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
|
||||
|
||||
llvm::Constant *zero = Builder.getInt32(0);
|
||||
llvm::Value *TmpThis = CreateTempAlloca(Ty);
|
||||
+ QualType ElTy = hlsl::GetElementTypeOrType(Base->getType());
|
||||
+ bool IsBool = ElTy->isSpecificBuiltinType(BuiltinType::Bool);
|
||||
for (unsigned i = 0; i < Ty->getVectorNumElements(); i++) {
|
||||
llvm::Value *EltIdx = Elts->getAggregateElement(i);
|
||||
llvm::Value *EltGEP = Builder.CreateGEP(This, {zero, EltIdx});
|
||||
llvm::Value *TmpEltGEP =
|
||||
Builder.CreateGEP(TmpThis, {zero, Builder.getInt32(i)});
|
||||
llvm::Value *Elt = Builder.CreateLoad(EltGEP);
|
||||
+ if (IsBool)
|
||||
+ Elt = Builder.CreateTrunc(
|
||||
+ Elt, llvm::Type::getInt1Ty(getLLVMContext()));
|
||||
Builder.CreateStore(Elt, TmpEltGEP);
|
||||
}
|
||||
This = TmpThis;
|
||||
diff --git a/tools/clang/test/CodeGenDXIL/operators/swizzle/indexSwizzledBoolVec.hlsl b/tools/clang/test/CodeGenDXIL/operators/swizzle/indexSwizzledBoolVec.hlsl
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..a47482d204547d01b8f237bdde0765e61e6b7ab0
|
||||
--- /dev/null
|
||||
+++ b/tools/clang/test/CodeGenDXIL/operators/swizzle/indexSwizzledBoolVec.hlsl
|
||||
@@ -0,0 +1,30 @@
|
||||
+// Test indexing a swizzled bool vector
|
||||
+// RUN: %dxc -fcgl -T cs_6_0 %s | FileCheck %s
|
||||
+
|
||||
+// This was asserting in Instructions.cpp with:
|
||||
+// void llvm::StoreInst::AssertOK(): Assertion `getOperand(0)->getType() == cast<PointerType>(getOperand(1)->getType())->getElementType() && "Ptr must be a pointer to Val type!"' failed.
|
||||
+
|
||||
+// Make sure load of i32 gets truncated to i1 when indexing bool vectors
|
||||
+// CHECK: [[TMP:%[a-z0-9\.]+]] = alloca <2 x i1>
|
||||
+// CHECK: [[VA0:%[a-z0-9\.]+]] = getelementptr <2 x i1>, <2 x i1>* [[TMP]], i32 0, i32 0,
|
||||
+// CHECK-NEXT: [[VA1:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds (<4 x i32>, <4 x i32>* @"\01?v_bool4@?1??main@@YAXXZ@3V?$vector@_N$03@@B", i32 0, i32 2),
|
||||
+// CHECK-NEXT: [[VA2:%[a-z0-9\.]+]] = trunc i32 [[VA1]] to i1,
|
||||
+// CHECK-NEXT: store i1 [[VA2]], i1* [[VA0]],
|
||||
+// CHECK-NEXT: [[VB0:%[a-z0-9\.]+]] = getelementptr <2 x i1>, <2 x i1>* [[TMP]], i32 0, i32 1,
|
||||
+// CHECK-NEXT: [[VB1:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds (<4 x i32>, <4 x i32>* @"\01?v_bool4@?1??main@@YAXXZ@3V?$vector@_N$03@@B", i32 0, i32 3),
|
||||
+// CHECK-NEXT: [[VB2:%[a-z0-9\.]+]] = trunc i32 [[VB1]] to i1,
|
||||
+// CHECK-NEXT: store i1 [[VB2]], i1* [[VB0]],
|
||||
+
|
||||
+
|
||||
+cbuffer cbuffer_tint_symbol_3 : register(b0) {
|
||||
+ uint4 global_uint4[1];
|
||||
+};
|
||||
+
|
||||
+[numthreads(1, 1, 1)]
|
||||
+void main() {
|
||||
+ const bool4 v_bool4 = bool4(true, true, true, true);
|
||||
+ const uint gx = global_uint4[0].x;
|
||||
+ if (v_bool4.zw[gx] == 0) {
|
||||
+ GroupMemoryBarrierWithGroupSync();
|
||||
+ }
|
||||
+}
|
||||
151
patches/DirectXShaderCompiler/cherry-pick-8f07d39227f6.patch
Normal file
151
patches/DirectXShaderCompiler/cherry-pick-8f07d39227f6.patch
Normal file
@@ -0,0 +1,151 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Antonio Maiorano <amaiorano@google.com>
|
||||
Date: Thu, 20 Jun 2024 14:49:58 -0400
|
||||
Subject: Fix crash in scalarrepl-param-hlsl when dynamically indexing a GEP of
|
||||
a constant indexed GEP (#6670)
|
||||
|
||||
When processing global values to determine when to flatten vectors, this
|
||||
pass was only checking the immdiate users of the value for non-dynamic
|
||||
indexing of the vector. But this would fail in the case of a dynamic
|
||||
indexed GEP of a constant indexed GEP (e.g. h[0][a]) because the first
|
||||
level GEP was constant indexed, but not the second. We fix this by
|
||||
checking the full User tree of the value in `hasDynamicVectorIndexing`.
|
||||
|
||||
Bug: chromium:342428008
|
||||
Change-Id: Ibf2ae3a6528cfc9b50634058385c5a45aa1d3b75
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5645927
|
||||
Reviewed-by: James Price <jrprice@google.com>
|
||||
Reviewed-by: dan sinclair <dsinclair@chromium.org>
|
||||
|
||||
diff --git a/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp b/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp
|
||||
index 9b843ef0e49e554001b827e30eb6256853d90f5b..b1b38c0ee038dedb2064f5726663992a5bec736b 100644
|
||||
--- a/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp
|
||||
+++ b/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp
|
||||
@@ -1645,6 +1645,10 @@ bool hasDynamicVectorIndexing(Value *V) {
|
||||
}
|
||||
}
|
||||
}
|
||||
+ // Also recursively check the uses of this User to find a possible
|
||||
+ // dynamically indexed GEP of this GEP.
|
||||
+ if (hasDynamicVectorIndexing(U))
|
||||
+ return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
diff --git a/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-dyn-idx-gep-of-const-idx-gep.ll b/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-dyn-idx-gep-of-const-idx-gep.ll
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..04fdea1500e75266a59705a1c2da98a4aef7391c
|
||||
--- /dev/null
|
||||
+++ b/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-dyn-idx-gep-of-const-idx-gep.ll
|
||||
@@ -0,0 +1,111 @@
|
||||
+; RUN: %dxopt %s -hlsl-passes-resume -scalarrepl-param-hlsl -S | FileCheck %s
|
||||
+
|
||||
+; Produced from the following HLSL:
|
||||
+; static int4 g[4] = (int4[4])0;
|
||||
+; static int4 h[4] = (int4[4])0;
|
||||
+;
|
||||
+; [numthreads(1, 1, 1)]
|
||||
+; void main() {
|
||||
+; int a = 0;
|
||||
+; int b = h[0][a];
|
||||
+; h = g;
|
||||
+; }
|
||||
+;
|
||||
+; This was crashing in scalarrepl-param-hlsl because it was attempting to flatten
|
||||
+; global variable 'h' even though it is dynamically indexed. This was not detected
|
||||
+; because the resulting IR was a dynamically indexed GEP of a constant-indexed GEP,
|
||||
+; and the code was only checking the immediate users of 'h':
|
||||
+;
|
||||
+; %1 = getelementptr <4 x i32>, <4 x i32>* getelementptr inbounds ([4 x <4 x i32>], [4 x <4 x i32>]* @h, i32 0, i32 0), i32 0, i32 %0, !dbg !26 ; line:7 col:11
|
||||
+;
|
||||
+; Verify that it does not get flattened
|
||||
+; CHECK: %1 = getelementptr <4 x i32>, <4 x i32>* getelementptr inbounds ([4 x <4 x i32>], [4 x <4 x i32>]* @g, i32 0, i32 0), i32 0, i32 %0
|
||||
+
|
||||
+;
|
||||
+; Buffer Definitions:
|
||||
+;
|
||||
+; cbuffer $Globals
|
||||
+; {
|
||||
+;
|
||||
+; [0 x i8] (type annotation not present)
|
||||
+;
|
||||
+; }
|
||||
+;
|
||||
+;
|
||||
+; Resource Bindings:
|
||||
+;
|
||||
+; Name Type Format Dim ID HLSL Bind Count
|
||||
+; ------------------------------ ---------- ------- ----------- ------- -------------- ------
|
||||
+; $Globals cbuffer NA NA CB0 cb4294967295 1
|
||||
+;
|
||||
+target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
|
||||
+target triple = "dxil-ms-dx"
|
||||
+
|
||||
+%ConstantBuffer = type opaque
|
||||
+
|
||||
+@h = internal global [4 x <4 x i32>] zeroinitializer, align 4
|
||||
+@g = internal global [4 x <4 x i32>] zeroinitializer, align 4
|
||||
+@"$Globals" = external constant %ConstantBuffer
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+define void @main() #0 {
|
||||
+entry:
|
||||
+ %a = alloca i32, align 4
|
||||
+ %b = alloca i32, align 4
|
||||
+ store i32 0, i32* %a, align 4, !dbg !17, !tbaa !21 ; line:6 col:7
|
||||
+ %0 = load i32, i32* %a, align 4, !dbg !25, !tbaa !21 ; line:7 col:16
|
||||
+ %1 = getelementptr <4 x i32>, <4 x i32>* getelementptr inbounds ([4 x <4 x i32>], [4 x <4 x i32>]* @h, i32 0, i32 0), i32 0, i32 %0, !dbg !26 ; line:7 col:11
|
||||
+ %2 = load i32, i32* %1, !dbg !26, !tbaa !21 ; line:7 col:11
|
||||
+ store i32 %2, i32* %b, align 4, !dbg !27, !tbaa !21 ; line:7 col:7
|
||||
+ %3 = bitcast [4 x <4 x i32>]* @h to i8*, !dbg !28 ; line:8 col:7
|
||||
+ %4 = bitcast [4 x <4 x i32>]* @g to i8*, !dbg !28 ; line:8 col:7
|
||||
+ call void @llvm.memcpy.p0i8.p0i8.i64(i8* %3, i8* %4, i64 64, i32 1, i1 false), !dbg !28 ; line:8 col:7
|
||||
+ ret void, !dbg !29 ; line:9 col:1
|
||||
+}
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1) #0
|
||||
+
|
||||
+attributes #0 = { nounwind }
|
||||
+
|
||||
+!llvm.module.flags = !{!0}
|
||||
+!pauseresume = !{!1}
|
||||
+!llvm.ident = !{!2}
|
||||
+!dx.version = !{!3}
|
||||
+!dx.valver = !{!4}
|
||||
+!dx.shaderModel = !{!5}
|
||||
+!dx.typeAnnotations = !{!6}
|
||||
+!dx.entryPoints = !{!10}
|
||||
+!dx.fnprops = !{!14}
|
||||
+!dx.options = !{!15, !16}
|
||||
+
|
||||
+!0 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
+!1 = !{!"hlsl-hlemit", !"hlsl-hlensure"}
|
||||
+!2 = !{!"dxc(private) 1.8.0.4514 (d9bd2a706-dirty)"}
|
||||
+!3 = !{i32 1, i32 0}
|
||||
+!4 = !{i32 1, i32 8}
|
||||
+!5 = !{!"cs", i32 6, i32 0}
|
||||
+!6 = !{i32 1, void ()* @main, !7}
|
||||
+!7 = !{!8}
|
||||
+!8 = !{i32 1, !9, !9}
|
||||
+!9 = !{}
|
||||
+!10 = !{void ()* @main, !"main", null, !11, null}
|
||||
+!11 = !{null, null, !12, null}
|
||||
+!12 = !{!13}
|
||||
+!13 = !{i32 0, %ConstantBuffer* @"$Globals", !"$Globals", i32 0, i32 -1, i32 1, i32 0, null}
|
||||
+!14 = !{void ()* @main, i32 5, i32 1, i32 1, i32 1}
|
||||
+!15 = !{i32 64}
|
||||
+!16 = !{i32 -1}
|
||||
+!17 = !DILocation(line: 6, column: 7, scope: !18)
|
||||
+!18 = !DISubprogram(name: "main", scope: !19, file: !19, line: 5, type: !20, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false, function: void ()* @main)
|
||||
+!19 = !DIFile(filename: "/mnt/c/Users/amaiorano/Downloads/342428008/standalone_reduced.hlsl", directory: "")
|
||||
+!20 = !DISubroutineType(types: !9)
|
||||
+!21 = !{!22, !22, i64 0}
|
||||
+!22 = !{!"int", !23, i64 0}
|
||||
+!23 = !{!"omnipotent char", !24, i64 0}
|
||||
+!24 = !{!"Simple C/C++ TBAA"}
|
||||
+!25 = !DILocation(line: 7, column: 16, scope: !18)
|
||||
+!26 = !DILocation(line: 7, column: 11, scope: !18)
|
||||
+!27 = !DILocation(line: 7, column: 7, scope: !18)
|
||||
+!28 = !DILocation(line: 8, column: 7, scope: !18)
|
||||
+!29 = !DILocation(line: 9, column: 1, scope: !18)
|
||||
312
patches/DirectXShaderCompiler/cherry-pick-93c3cf1c787f.patch
Normal file
312
patches/DirectXShaderCompiler/cherry-pick-93c3cf1c787f.patch
Normal file
@@ -0,0 +1,312 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Natalie Chouinard <chouinard@google.com>
|
||||
Date: Fri, 14 Jun 2024 13:29:19 +0000
|
||||
Subject: Fix another UAF in SimplifyCFG (#6680)
|
||||
|
||||
In certain cases of unreachable code, SimplifyCFG could try to replace a
|
||||
phi node with a select where the phi node itself was the select's
|
||||
condition. This resulted in an ASAN use-after-free during SimplifyCFG.
|
||||
|
||||
The test case added isn't quite ideal because by the end of the
|
||||
SimplifyCFG pass, the phi node is restored to its original state both
|
||||
before and after this fix. However, an ASAN build of `dxopt` or
|
||||
`check-clang-dxc` will identify a heap-use-after-free failure in the
|
||||
intermediary steps of this test without this patch and succeeds with it.
|
||||
|
||||
This was also fixed in upstream LLVM:
|
||||
https://github.com/llvm/llvm-project/commit/602ab248335e1540e82667e74fea44b7f042e112
|
||||
|
||||
Bug: 344639860
|
||||
Change-Id: I743e96fb172de867c89cad51805edf96387c04ec
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5631796
|
||||
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
|
||||
Reviewed-by: James Price <jrprice@google.com>
|
||||
|
||||
diff --git a/lib/Transforms/Utils/SimplifyCFG.cpp b/lib/Transforms/Utils/SimplifyCFG.cpp
|
||||
index 0d3ba1e00719060c1e71fa238726f0c63bd5b32f..5b364856928af6aab007e958b24f1daea32cd733 100644
|
||||
--- a/lib/Transforms/Utils/SimplifyCFG.cpp
|
||||
+++ b/lib/Transforms/Utils/SimplifyCFG.cpp
|
||||
@@ -1830,6 +1830,14 @@ static bool FoldTwoEntryPHINode(PHINode *PN, const TargetTransformInfo &TTI,
|
||||
isa<ConstantInt>(IfCond))
|
||||
return false;
|
||||
|
||||
+ // HLSL Change Begins: Patching in llvm/llvm-project@602ab24
|
||||
+ // Don't try to fold an unreachable block. For example, the phi node itself
|
||||
+ // can't be the candidate if-condition for a select that we want to form.
|
||||
+ if (auto *IfCondPhiInst = dyn_cast<PHINode>(IfCond))
|
||||
+ if (IfCondPhiInst->getParent() == BB)
|
||||
+ return false;
|
||||
+ // HLSL Change Ends.
|
||||
+
|
||||
// Okay, we found that we can merge this two-entry phi node into a select.
|
||||
// Doing so would require us to fold *all* two entry phi nodes in this block.
|
||||
// At some point this becomes non-profitable (particularly if the target
|
||||
diff --git a/tools/clang/test/DXC/Passes/SimplifyCFG/simplifycfg-uaf-phi-condition.ll b/tools/clang/test/DXC/Passes/SimplifyCFG/simplifycfg-uaf-phi-condition.ll
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..573745a819fd1b51e3163d644088738d5128d30c
|
||||
--- /dev/null
|
||||
+++ b/tools/clang/test/DXC/Passes/SimplifyCFG/simplifycfg-uaf-phi-condition.ll
|
||||
@@ -0,0 +1,263 @@
|
||||
+; RUN: %dxopt %s -hlsl-passes-resume -simplifycfg -S | FileCheck %s
|
||||
+
|
||||
+; The IR below comes from the following HLSL.
|
||||
+; Compiling this HLSL with dxc was resulting in an ASAN use-after-free in
|
||||
+; SimplifyCFG during FoldTwoEntryPHINode because it was deleting a PHI node
|
||||
+; which was itself used as the condition for the select that replaced it.
|
||||
+
|
||||
+; struct a {
|
||||
+; int b[2];
|
||||
+; };
|
||||
+;
|
||||
+; cbuffer cbuffer_c : register(b0) {
|
||||
+; uint4 c[1];
|
||||
+; };
|
||||
+;
|
||||
+; void d(inout a e, inout int f) {
|
||||
+; int n = f;
|
||||
+; int g = asint(c[0].x);
|
||||
+; int s = f;
|
||||
+; bool i = (s >= 0);
|
||||
+; int j = (s * n);
|
||||
+; bool k = (6 > g);
|
||||
+; int l = 0;
|
||||
+; bool q = (s > j);
|
||||
+; while (true) {
|
||||
+; while (true) {
|
||||
+; while (true) {
|
||||
+; if (k) {
|
||||
+; {
|
||||
+; int t[2] = e.b;
|
||||
+; t[g] = n;
|
||||
+; e.b = t;
|
||||
+; }
|
||||
+; }
|
||||
+; e.b[1] = g;
|
||||
+; e.b[0] = s;
|
||||
+; if (q) {
|
||||
+; break;
|
||||
+; }
|
||||
+; }
|
||||
+; switch(j) {
|
||||
+; case 0: {
|
||||
+; break;
|
||||
+; }
|
||||
+; case 9: {
|
||||
+; break;
|
||||
+; }
|
||||
+; default: {
|
||||
+; {
|
||||
+; int u[2] = e.b;
|
||||
+; u[g] = l;
|
||||
+; e.b = u;
|
||||
+; }
|
||||
+; break;
|
||||
+; }
|
||||
+; }
|
||||
+; {
|
||||
+; if (q) { break; }
|
||||
+; }
|
||||
+; }
|
||||
+; {
|
||||
+; int v[2] = e.b;
|
||||
+; v[g] = j;
|
||||
+; e.b = v;
|
||||
+; }
|
||||
+; if (!(i)) {
|
||||
+; break;
|
||||
+; }
|
||||
+; }
|
||||
+; }
|
||||
+;
|
||||
+; [numthreads(1, 1, 1)]
|
||||
+; void main() {
|
||||
+; int o = 0;
|
||||
+; a p = (a)0;
|
||||
+; while (true) {
|
||||
+; bool i = (o < asint(c[0].x));
|
||||
+; if (i) {
|
||||
+; bool r = !(i);
|
||||
+; if (!(r)) {
|
||||
+; return;
|
||||
+; }
|
||||
+; d(p, o);
|
||||
+; }
|
||||
+; o = (o + 1);
|
||||
+; }
|
||||
+; return;
|
||||
+; }
|
||||
+
|
||||
+; Make sure the phi node did not get deleted by simplifycfg
|
||||
+; CHECK: while.body:
|
||||
+; CHECK-NEXT: %o.0 = phi i32 [ 0, %entry ], [ %add, %if.end.6 ]
|
||||
+
|
||||
+;
|
||||
+; Buffer Definitions:
|
||||
+;
|
||||
+; cbuffer cbuffer_c
|
||||
+; {
|
||||
+;
|
||||
+; struct cbuffer_c
|
||||
+; {
|
||||
+;
|
||||
+; uint4 c[1]; ; Offset: 0
|
||||
+;
|
||||
+; } cbuffer_c; ; Offset: 0 Size: 16
|
||||
+;
|
||||
+; }
|
||||
+;
|
||||
+;
|
||||
+; Resource Bindings:
|
||||
+;
|
||||
+; Name Type Format Dim ID HLSL Bind Count
|
||||
+; ------------------------------ ---------- ------- ----------- ------- -------------- ------
|
||||
+; cbuffer_c cbuffer NA NA CB0 cb0 1
|
||||
+;
|
||||
+target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
|
||||
+target triple = "dxil-ms-dx"
|
||||
+
|
||||
+%cbuffer_c = type { [1 x <4 x i32>] }
|
||||
+%dx.types.Handle = type { i8* }
|
||||
+%dx.types.ResourceProperties = type { i32, i32 }
|
||||
+%dx.types.CBufRet.i32 = type { i32, i32, i32, i32 }
|
||||
+%struct.a = type { [2 x i32] }
|
||||
+
|
||||
+@cbuffer_c = external constant %cbuffer_c
|
||||
+@llvm.used = appending global [1 x i8*] [i8* bitcast (%cbuffer_c* @cbuffer_c to i8*)], section "llvm.metadata"
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+define void @main() #0 {
|
||||
+entry:
|
||||
+ %0 = load %cbuffer_c, %cbuffer_c* @cbuffer_c, align 4
|
||||
+ %cbuffer_c8 = call %dx.types.Handle @dx.op.createHandleForLib.cbuffer_c(i32 160, %cbuffer_c %0) ; CreateHandleForLib(Resource)
|
||||
+ %1 = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle %cbuffer_c8, %dx.types.ResourceProperties { i32 13, i32 16 }) ; AnnotateHandle(res,props) resource: CBuffer
|
||||
+ %cbuffer_c = call %dx.types.Handle @dx.op.createHandleForLib.cbuffer_c(i32 160, %cbuffer_c %0) ; CreateHandleForLib(Resource)
|
||||
+ %2 = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle %cbuffer_c, %dx.types.ResourceProperties { i32 13, i32 16 }) ; AnnotateHandle(res,props) resource: CBuffer
|
||||
+ br label %while.body, !dbg !21 ; line:69 col:3
|
||||
+
|
||||
+while.body: ; preds = %if.end.6, %entry
|
||||
+ %o.0 = phi i32 [ 0, %entry ], [ %add, %if.end.6 ]
|
||||
+ %3 = call %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32(i32 59, %dx.types.Handle %1, i32 0), !dbg !25 ; line:70 col:25 ; CBufferLoadLegacy(handle,regIndex)
|
||||
+ %4 = extractvalue %dx.types.CBufRet.i32 %3, 0, !dbg !25 ; line:70 col:25
|
||||
+ %cmp = icmp slt i32 %o.0, %4, !dbg !26 ; line:70 col:17
|
||||
+ br i1 %cmp, label %if.then, label %if.end.6, !dbg !27 ; line:71 col:9
|
||||
+
|
||||
+if.then: ; preds = %while.body
|
||||
+ br i1 %cmp, label %if.then.5, label %if.end, !dbg !28 ; line:73 col:11
|
||||
+
|
||||
+if.then.5: ; preds = %if.then
|
||||
+ ret void, !dbg !29 ; line:74 col:9
|
||||
+
|
||||
+if.end: ; preds = %if.then
|
||||
+ %5 = call %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32(i32 59, %dx.types.Handle %2, i32 0), !dbg !30 ; line:11 col:17 ; CBufferLoadLegacy(handle,regIndex)
|
||||
+ %6 = extractvalue %dx.types.CBufRet.i32 %5, 0, !dbg !30 ; line:11 col:17
|
||||
+ %cmp.i = icmp sgt i32 %o.0, -1, !dbg !33 ; line:13 col:15
|
||||
+ %mul.i = mul nsw i32 %o.0, %o.0, !dbg !34 ; line:14 col:14
|
||||
+ %cmp1.i = icmp slt i32 %6, 6, !dbg !35 ; line:15 col:15
|
||||
+ %cmp4.i = icmp sgt i32 %o.0, %mul.i, !dbg !36 ; line:17 col:15
|
||||
+ br label %while.body.10.i, !dbg !37 ; line:18 col:3
|
||||
+
|
||||
+while.body.10.i: ; preds = %while.end.27.i, %sw.epilog.i, %if.end.i, %if.end
|
||||
+ br i1 %cmp1.i, label %if.then.i, label %if.end.i, !dbg !38 ; line:21 col:13
|
||||
+
|
||||
+if.then.i: ; preds = %while.body.10.i
|
||||
+ br label %if.end.i, !dbg !39 ; line:27 col:9
|
||||
+
|
||||
+if.end.i: ; preds = %if.then.i, %while.body.10.i
|
||||
+ br i1 %cmp4.i, label %while.end.i, label %while.body.10.i, !dbg !40 ; line:30 col:13
|
||||
+
|
||||
+while.end.i: ; preds = %if.end.i
|
||||
+ switch i32 %mul.i, label %sw.default.i [
|
||||
+ i32 0, label %sw.epilog.i
|
||||
+ i32 9, label %sw.epilog.i
|
||||
+ ], !dbg !41 ; line:34 col:7
|
||||
+
|
||||
+sw.default.i: ; preds = %while.end.i
|
||||
+ br label %sw.epilog.i, !dbg !42 ; line:47 col:11
|
||||
+
|
||||
+sw.epilog.i: ; preds = %sw.default.i, %while.end.i, %while.end.i
|
||||
+ br i1 %cmp4.i, label %while.end.27.i, label %while.body.10.i, !dbg !43 ; line:51 col:13
|
||||
+
|
||||
+while.end.27.i: ; preds = %sw.epilog.i
|
||||
+ br i1 %cmp.i, label %while.body.10.i, label %if.end.6, !dbg !44 ; line:59 col:9
|
||||
+
|
||||
+if.end.6: ; preds = %while.end.27.i, %while.body
|
||||
+ %add = add nsw i32 %o.0, 1, !dbg !45 ; line:78 col:12
|
||||
+ br label %while.body, !dbg !21 ; line:69 col:3
|
||||
+}
|
||||
+
|
||||
+; Function Attrs: nounwind readnone
|
||||
+declare %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %cbuffer_c*, i32)"(i32, %cbuffer_c*, i32) #1
|
||||
+
|
||||
+; Function Attrs: nounwind readnone
|
||||
+declare %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %cbuffer_c)"(i32, %dx.types.Handle, %dx.types.ResourceProperties, %cbuffer_c) #1
|
||||
+
|
||||
+; Function Attrs: nounwind readonly
|
||||
+declare %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32(i32, %dx.types.Handle, i32) #2
|
||||
+
|
||||
+; Function Attrs: nounwind readonly
|
||||
+declare %dx.types.Handle @dx.op.createHandleForLib.cbuffer_c(i32, %cbuffer_c) #2
|
||||
+
|
||||
+; Function Attrs: nounwind readnone
|
||||
+declare %dx.types.Handle @dx.op.annotateHandle(i32, %dx.types.Handle, %dx.types.ResourceProperties) #1
|
||||
+
|
||||
+attributes #0 = { nounwind }
|
||||
+attributes #1 = { nounwind readnone }
|
||||
+attributes #2 = { nounwind readonly }
|
||||
+
|
||||
+!llvm.module.flags = !{!0}
|
||||
+!pauseresume = !{!1}
|
||||
+!llvm.ident = !{!2}
|
||||
+!dx.version = !{!3}
|
||||
+!dx.valver = !{!4}
|
||||
+!dx.shaderModel = !{!5}
|
||||
+!dx.resources = !{!6}
|
||||
+!dx.typeAnnotations = !{!9, !14}
|
||||
+!dx.entryPoints = !{!18}
|
||||
+
|
||||
+!0 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
+!1 = !{!"hlsl-dxilemit", !"hlsl-dxilload"}
|
||||
+!2 = !{!"dxc(private) 1.8.0.14620 (main, 8408ae882)"}
|
||||
+!3 = !{i32 1, i32 2}
|
||||
+!4 = !{i32 1, i32 8}
|
||||
+!5 = !{!"cs", i32 6, i32 2}
|
||||
+!6 = !{null, null, !7, null}
|
||||
+!7 = !{!8}
|
||||
+!8 = !{i32 0, %cbuffer_c* @cbuffer_c, !"cbuffer_c", i32 0, i32 0, i32 1, i32 16, null}
|
||||
+!9 = !{i32 0, %struct.a undef, !10, %cbuffer_c undef, !12}
|
||||
+!10 = !{i32 20, !11}
|
||||
+!11 = !{i32 6, !"b", i32 3, i32 0, i32 7, i32 4}
|
||||
+!12 = !{i32 16, !13}
|
||||
+!13 = !{i32 6, !"c", i32 3, i32 0, i32 7, i32 5}
|
||||
+!14 = !{i32 1, void ()* @main, !15}
|
||||
+!15 = !{!16}
|
||||
+!16 = !{i32 1, !17, !17}
|
||||
+!17 = !{}
|
||||
+!18 = !{void ()* @main, !"main", null, !6, !19}
|
||||
+!19 = !{i32 4, !20}
|
||||
+!20 = !{i32 1, i32 1, i32 1}
|
||||
+!21 = !DILocation(line: 69, column: 3, scope: !22)
|
||||
+!22 = !DISubprogram(name: "main", scope: !23, file: !23, line: 66, type: !24, isLocal: false, isDefinition: true, scopeLine: 66, flags: DIFlagPrototyped, isOptimized: false, function: void ()* @main)
|
||||
+!23 = !DIFile(filename: "/usr/local/google/home/chouinard/Downloads/standalone.hlsl", directory: "")
|
||||
+!24 = !DISubroutineType(types: !17)
|
||||
+!25 = !DILocation(line: 70, column: 25, scope: !22)
|
||||
+!26 = !DILocation(line: 70, column: 17, scope: !22)
|
||||
+!27 = !DILocation(line: 71, column: 9, scope: !22)
|
||||
+!28 = !DILocation(line: 73, column: 11, scope: !22)
|
||||
+!29 = !DILocation(line: 74, column: 9, scope: !22)
|
||||
+!30 = !DILocation(line: 11, column: 17, scope: !31, inlinedAt: !32)
|
||||
+!31 = !DISubprogram(name: "d", scope: !23, file: !23, line: 9, type: !24, isLocal: false, isDefinition: true, scopeLine: 9, flags: DIFlagPrototyped, isOptimized: false)
|
||||
+!32 = distinct !DILocation(line: 76, column: 7, scope: !22)
|
||||
+!33 = !DILocation(line: 13, column: 15, scope: !31, inlinedAt: !32)
|
||||
+!34 = !DILocation(line: 14, column: 14, scope: !31, inlinedAt: !32)
|
||||
+!35 = !DILocation(line: 15, column: 15, scope: !31, inlinedAt: !32)
|
||||
+!36 = !DILocation(line: 17, column: 15, scope: !31, inlinedAt: !32)
|
||||
+!37 = !DILocation(line: 18, column: 3, scope: !31, inlinedAt: !32)
|
||||
+!38 = !DILocation(line: 21, column: 13, scope: !31, inlinedAt: !32)
|
||||
+!39 = !DILocation(line: 27, column: 9, scope: !31, inlinedAt: !32)
|
||||
+!40 = !DILocation(line: 30, column: 13, scope: !31, inlinedAt: !32)
|
||||
+!41 = !DILocation(line: 34, column: 7, scope: !31, inlinedAt: !32)
|
||||
+!42 = !DILocation(line: 47, column: 11, scope: !31, inlinedAt: !32)
|
||||
+!43 = !DILocation(line: 51, column: 13, scope: !31, inlinedAt: !32)
|
||||
+!44 = !DILocation(line: 59, column: 9, scope: !31, inlinedAt: !32)
|
||||
+!45 = !DILocation(line: 78, column: 12, scope: !22)
|
||||
231
patches/DirectXShaderCompiler/cherry-pick-b3c64851765c.patch
Normal file
231
patches/DirectXShaderCompiler/cherry-pick-b3c64851765c.patch
Normal file
@@ -0,0 +1,231 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Antonio Maiorano <amaiorano@google.com>
|
||||
Date: Thu, 20 Jun 2024 15:39:00 -0400
|
||||
Subject: Fix instcombine overflow check inserting inst at wrong place (#6679)
|
||||
|
||||
When optimizing an overflow check of an add followed by a compare, the
|
||||
new instruction was being inserted at the compare, and the add removed.
|
||||
This produced invalid IR in cases where there were other uses of the
|
||||
former add between it and the compare. This fix makes sure to insert the
|
||||
new instruction at the old add location, rather than at the compare.
|
||||
|
||||
Note that this was also fixed in LLVM:
|
||||
|
||||
https://github.com/llvm/llvm-project/commit/6f5dca70ed1c030957a45ad91bd295921f17b18d
|
||||
|
||||
Bug: chromium:342545100
|
||||
Change-Id: Iecf758e4465b32371266bbe9879790328f363322
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5644335
|
||||
Reviewed-by: dan sinclair <dsinclair@google.com>
|
||||
Reviewed-by: Ryan Harrison <rharrison@chromium.org>
|
||||
|
||||
diff --git a/lib/Transforms/InstCombine/InstCombineCompares.cpp b/lib/Transforms/InstCombine/InstCombineCompares.cpp
|
||||
index 7274304b3de7b110a4fa3a5123ea7215d99935ef..82e7e49003e65846c84e3df2801453fb463aa23e 100644
|
||||
--- a/lib/Transforms/InstCombine/InstCombineCompares.cpp
|
||||
+++ b/lib/Transforms/InstCombine/InstCombineCompares.cpp
|
||||
@@ -2145,6 +2145,12 @@ bool InstCombiner::OptimizeOverflowCheck(OverflowCheckFlavor OCF, Value *LHS,
|
||||
return true;
|
||||
};
|
||||
|
||||
+ // If the overflow check was an add followed by a compare, the insertion point
|
||||
+ // may be pointing to the compare. We want to insert the new instructions
|
||||
+ // before the add in case there are uses of the add between the add and the
|
||||
+ // compare.
|
||||
+ Builder->SetInsertPoint(&OrigI);
|
||||
+
|
||||
switch (OCF) {
|
||||
case OCF_INVALID:
|
||||
llvm_unreachable("bad overflow check kind!");
|
||||
diff --git a/tools/clang/test/DXC/Passes/InstructionCombining/instcombine-opt-overflow-check-inserts-at-add.ll b/tools/clang/test/DXC/Passes/InstructionCombining/instcombine-opt-overflow-check-inserts-at-add.ll
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..70efa00c91c6523867980de0fb9f69c7fcfb318c
|
||||
--- /dev/null
|
||||
+++ b/tools/clang/test/DXC/Passes/InstructionCombining/instcombine-opt-overflow-check-inserts-at-add.ll
|
||||
@@ -0,0 +1,187 @@
|
||||
+; RUN: %dxopt %s -hlsl-passes-resume -instcombine,NoSink=0 -S | FileCheck %s
|
||||
+
|
||||
+; Generated from the following HLSL:
|
||||
+; cbuffer cbuffer_g : register(b0) {
|
||||
+; uint4 g[1];
|
||||
+; };
|
||||
+;
|
||||
+; [numthreads(1, 1, 1)]
|
||||
+; void main() {
|
||||
+; uint a = 2147483648u;
|
||||
+; uint b = (g[0].x | 2651317025u);
|
||||
+; uint c = (b + 2651317025u);
|
||||
+; while (true) {
|
||||
+; bool d = (a > c);
|
||||
+; if (d) {
|
||||
+; break;
|
||||
+; } else {
|
||||
+; while (true) {
|
||||
+; if (!d) {
|
||||
+; return;
|
||||
+; }
|
||||
+; a = b;
|
||||
+; bool e = (d ? d : d);
|
||||
+; if (e) {
|
||||
+; break;
|
||||
+; }
|
||||
+; }
|
||||
+; }
|
||||
+; }
|
||||
+; }
|
||||
+;
|
||||
+; Compiling this was resulting in invalid IR being produced from instcombine.
|
||||
+; Specifically, when optimizing an overflow check of an add followed by a compare,
|
||||
+; the new instruction was being inserted at the compare, and the add removed. This
|
||||
+; broke in cases like this one, where there were other uses of the former add between
|
||||
+; it and the compare. The fix was to make sure to insert the new instruction
|
||||
+; (another add in this case) at the old add rather than at the compare.
|
||||
+
|
||||
+; Make sure the new %add is still in the entry block before its uses.
|
||||
+; CHECK-LABEL: entry
|
||||
+; CHECK: %add = add i32 %or, -1643650271
|
||||
+; CHECK-NEXT: %cmp.2 = icmp sgt i32 %add, -1,
|
||||
+;
|
||||
+; Make sure the new %add is NOT in the loopexit where %cmp was optimized.
|
||||
+; CHECK-LABEL: while.body.loopexit
|
||||
+; CHECK-NEXT: br i1 false, label %if.end.preheader, label %while.end.14
|
||||
+
|
||||
+;
|
||||
+; Buffer Definitions:
|
||||
+;
|
||||
+; cbuffer cbuffer_g
|
||||
+; {
|
||||
+;
|
||||
+; struct cbuffer_g
|
||||
+; {
|
||||
+;
|
||||
+; uint4 g[1]; ; Offset: 0
|
||||
+;
|
||||
+; } cbuffer_g; ; Offset: 0 Size: 16
|
||||
+;
|
||||
+; }
|
||||
+;
|
||||
+;
|
||||
+; Resource Bindings:
|
||||
+;
|
||||
+; Name Type Format Dim ID HLSL Bind Count
|
||||
+; ------------------------------ ---------- ------- ----------- ------- -------------- ------
|
||||
+; cbuffer_g cbuffer NA NA CB0 cb0 1
|
||||
+;
|
||||
+target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
|
||||
+target triple = "dxil-ms-dx"
|
||||
+
|
||||
+%cbuffer_g = type { [1 x <4 x i32>] }
|
||||
+%dx.types.Handle = type { i8* }
|
||||
+%dx.types.ResourceProperties = type { i32, i32 }
|
||||
+%dx.types.CBufRet.i32 = type { i32, i32, i32, i32 }
|
||||
+
|
||||
+@cbuffer_g = external constant %cbuffer_g
|
||||
+@llvm.used = appending global [1 x i8*] [i8* bitcast (%cbuffer_g* @cbuffer_g to i8*)], section "llvm.metadata"
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+define void @main() #0 {
|
||||
+entry:
|
||||
+ %0 = load %cbuffer_g, %cbuffer_g* @cbuffer_g
|
||||
+ %cbuffer_g = call %dx.types.Handle @dx.op.createHandleForLib.cbuffer_g(i32 160, %cbuffer_g %0) ; CreateHandleForLib(Resource)
|
||||
+ %1 = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle %cbuffer_g, %dx.types.ResourceProperties { i32 13, i32 16 }) ; AnnotateHandle(res,props) resource: CBuffer
|
||||
+ %2 = call %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32(i32 59, %dx.types.Handle %1, i32 0), !dbg !19 ; line:8 col:13 ; CBufferLoadLegacy(handle,regIndex)
|
||||
+ %3 = extractvalue %dx.types.CBufRet.i32 %2, 0, !dbg !19 ; line:8 col:13
|
||||
+ %or = or i32 %3, -1643650271, !dbg !23 ; line:8 col:20
|
||||
+ %add = add i32 %or, -1643650271, !dbg !24 ; line:9 col:15
|
||||
+ %cmp.2 = icmp ugt i32 -2147483648, %add, !dbg !25 ; line:11 col:17
|
||||
+ %frombool.3 = zext i1 %cmp.2 to i32, !dbg !26 ; line:11 col:10
|
||||
+ %tobool1.4 = icmp eq i32 %frombool.3, 0, !dbg !27 ; line:12 col:9
|
||||
+ %or.cond.6 = and i1 %tobool1.4, %cmp.2, !dbg !27 ; line:12 col:9
|
||||
+ br i1 %or.cond.6, label %if.end.preheader, label %while.end.14, !dbg !27 ; line:12 col:9
|
||||
+
|
||||
+while.body.loopexit: ; preds = %if.end
|
||||
+ %cmp = icmp ugt i32 %or, %add, !dbg !25 ; line:11 col:17
|
||||
+ %frombool = zext i1 %cmp to i32, !dbg !26 ; line:11 col:10
|
||||
+ %tobool1 = icmp eq i32 %frombool, 0, !dbg !27 ; line:12 col:9
|
||||
+ %or.cond = and i1 %tobool1, %cmp, !dbg !27 ; line:12 col:9
|
||||
+ br i1 %or.cond, label %if.end.preheader, label %while.end.14, !dbg !27 ; line:12 col:9
|
||||
+
|
||||
+if.end.preheader: ; preds = %entry, %while.body.loopexit
|
||||
+ %d.0 = phi i32 [ %frombool, %while.body.loopexit ], [ %frombool.3, %entry ]
|
||||
+ br label %if.end, !dbg !28 ; line:19 col:13
|
||||
+
|
||||
+while.body.3: ; preds = %if.end
|
||||
+ %tobool4.old = icmp ne i32 %d.0, 0, !dbg !29 ; line:16 col:14
|
||||
+ br i1 %tobool4.old, label %if.end, label %while.end.14, !dbg !30 ; line:16 col:13
|
||||
+
|
||||
+if.end: ; preds = %if.end.preheader, %while.body.3
|
||||
+ %tobool6 = icmp ne i32 %d.0, 0, !dbg !31 ; line:20 col:19
|
||||
+ %tobool7 = icmp ne i32 %d.0, 0, !dbg !32 ; line:20 col:23
|
||||
+ %tobool8 = icmp ne i32 %d.0, 0, !dbg !33 ; line:20 col:27
|
||||
+ %4 = select i1 %tobool6, i1 %tobool7, i1 %tobool8, !dbg !31 ; line:20 col:19
|
||||
+ br i1 %4, label %while.body.loopexit, label %while.body.3, !dbg !34 ; line:21 col:13
|
||||
+
|
||||
+while.end.14: ; preds = %while.body.loopexit, %while.body.3, %entry
|
||||
+ ret void, !dbg !35 ; line:27 col:1
|
||||
+}
|
||||
+
|
||||
+; Function Attrs: nounwind readnone
|
||||
+declare %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %cbuffer_g*, i32)"(i32, %cbuffer_g*, i32) #1
|
||||
+
|
||||
+; Function Attrs: nounwind readnone
|
||||
+declare %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %cbuffer_g)"(i32, %dx.types.Handle, %dx.types.ResourceProperties, %cbuffer_g) #1
|
||||
+
|
||||
+; Function Attrs: nounwind readonly
|
||||
+declare %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32(i32, %dx.types.Handle, i32) #2
|
||||
+
|
||||
+; Function Attrs: nounwind readonly
|
||||
+declare %dx.types.Handle @dx.op.createHandleForLib.cbuffer_g(i32, %cbuffer_g) #2
|
||||
+
|
||||
+; Function Attrs: nounwind readnone
|
||||
+declare %dx.types.Handle @dx.op.annotateHandle(i32, %dx.types.Handle, %dx.types.ResourceProperties) #1
|
||||
+
|
||||
+attributes #0 = { nounwind }
|
||||
+attributes #1 = { nounwind readnone }
|
||||
+attributes #2 = { nounwind readonly }
|
||||
+
|
||||
+!llvm.module.flags = !{!0}
|
||||
+!pauseresume = !{!1}
|
||||
+!llvm.ident = !{!2}
|
||||
+!dx.version = !{!3}
|
||||
+!dx.valver = !{!4}
|
||||
+!dx.shaderModel = !{!5}
|
||||
+!dx.resources = !{!6}
|
||||
+!dx.typeAnnotations = !{!9, !12}
|
||||
+!dx.entryPoints = !{!16}
|
||||
+
|
||||
+!0 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
+!1 = !{!"hlsl-dxilemit", !"hlsl-dxilload"}
|
||||
+!2 = !{!"dxc(private) 1.8.0.4514 (d9bd2a706-dirty)"}
|
||||
+!3 = !{i32 1, i32 0}
|
||||
+!4 = !{i32 1, i32 8}
|
||||
+!5 = !{!"cs", i32 6, i32 0}
|
||||
+!6 = !{null, null, !7, null}
|
||||
+!7 = !{!8}
|
||||
+!8 = !{i32 0, %cbuffer_g* @cbuffer_g, !"cbuffer_g", i32 0, i32 0, i32 1, i32 16, null}
|
||||
+!9 = !{i32 0, %cbuffer_g undef, !10}
|
||||
+!10 = !{i32 16, !11}
|
||||
+!11 = !{i32 6, !"g", i32 3, i32 0, i32 7, i32 5}
|
||||
+!12 = !{i32 1, void ()* @main, !13}
|
||||
+!13 = !{!14}
|
||||
+!14 = !{i32 1, !15, !15}
|
||||
+!15 = !{}
|
||||
+!16 = !{void ()* @main, !"main", null, !6, !17}
|
||||
+!17 = !{i32 4, !18}
|
||||
+!18 = !{i32 1, i32 1, i32 1}
|
||||
+!19 = !DILocation(line: 8, column: 13, scope: !20)
|
||||
+!20 = !DISubprogram(name: "main", scope: !21, file: !21, line: 6, type: !22, isLocal: false, isDefinition: true, scopeLine: 6, flags: DIFlagPrototyped, isOptimized: false, function: void ()* @main)
|
||||
+!21 = !DIFile(filename: "/mnt/c/Users/amaiorano/Downloads/342545100/standalone_reduced.hlsl", directory: "")
|
||||
+!22 = !DISubroutineType(types: !15)
|
||||
+!23 = !DILocation(line: 8, column: 20, scope: !20)
|
||||
+!24 = !DILocation(line: 9, column: 15, scope: !20)
|
||||
+!25 = !DILocation(line: 11, column: 17, scope: !20)
|
||||
+!26 = !DILocation(line: 11, column: 10, scope: !20)
|
||||
+!27 = !DILocation(line: 12, column: 9, scope: !20)
|
||||
+!28 = !DILocation(line: 19, column: 13, scope: !20)
|
||||
+!29 = !DILocation(line: 16, column: 14, scope: !20)
|
||||
+!30 = !DILocation(line: 16, column: 13, scope: !20)
|
||||
+!31 = !DILocation(line: 20, column: 19, scope: !20)
|
||||
+!32 = !DILocation(line: 20, column: 23, scope: !20)
|
||||
+!33 = !DILocation(line: 20, column: 27, scope: !20)
|
||||
+!34 = !DILocation(line: 21, column: 13, scope: !20)
|
||||
+!35 = !DILocation(line: 27, column: 1, scope: !20)
|
||||
294
patches/DirectXShaderCompiler/cherry-pick-b845fed99111.patch
Normal file
294
patches/DirectXShaderCompiler/cherry-pick-b845fed99111.patch
Normal file
@@ -0,0 +1,294 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Natalie Chouinard <chouinard@google.com>
|
||||
Date: Mon, 10 Jun 2024 18:21:40 +0000
|
||||
Subject: Fix LoopDeletion incorrectly updating PHI with multiple duplicate
|
||||
inputs (#6643)
|
||||
|
||||
LoopDeletion was incorrectly updating PHI nodes in the target block when
|
||||
it had duplicate input edges. This happens, for example, when deleting a
|
||||
loop that uses a switch with multiple cases that exit the same way.
|
||||
|
||||
After determining that this was the bug, I found this fix in LLVM:
|
||||
https://reviews.llvm.org/D34516 and applied it here.
|
||||
|
||||
Bug: 340196361
|
||||
Change-Id: I98b150bb9a164466eb84dd3d46f720d5d92ef909
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5616791
|
||||
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
|
||||
Reviewed-by: dan sinclair <dsinclair@chromium.org>
|
||||
|
||||
diff --git a/lib/Transforms/Scalar/LoopDeletion.cpp b/lib/Transforms/Scalar/LoopDeletion.cpp
|
||||
index 6c2c1d60548f5a8a7939fee70728e8a34572b648..6cd1fba7c085b6d61dcb23b073358fc4c798e099 100644
|
||||
--- a/lib/Transforms/Scalar/LoopDeletion.cpp
|
||||
+++ b/lib/Transforms/Scalar/LoopDeletion.cpp
|
||||
@@ -195,15 +195,29 @@ bool LoopDeletion::runOnLoop(Loop *L, LPPassManager &LPM) {
|
||||
|
||||
// Rewrite phis in the exit block to get their inputs from
|
||||
// the preheader instead of the exiting block.
|
||||
- BasicBlock *exitingBlock = exitingBlocks[0];
|
||||
BasicBlock::iterator BI = exitBlock->begin();
|
||||
while (PHINode *P = dyn_cast<PHINode>(BI)) {
|
||||
- int j = P->getBasicBlockIndex(exitingBlock);
|
||||
- assert(j >= 0 && "Can't find exiting block in exit block's phi node!");
|
||||
- P->setIncomingBlock(j, preheader);
|
||||
- for (unsigned i = 1; i < exitingBlocks.size(); ++i)
|
||||
- P->removeIncomingValue(exitingBlocks[i]);
|
||||
+ // HLSL Change begin - apply https://reviews.llvm.org/D34516
|
||||
+ // Set the zero'th element of Phi to be from the preheader and remove all
|
||||
+ // other incoming values. Given the loop has dedicated exits, all other
|
||||
+ // incoming values must be from the exiting blocks.
|
||||
+ int PredIndex = 0;
|
||||
+ P->setIncomingBlock(PredIndex, preheader);
|
||||
+ // Removes all incoming values from all other exiting blocks (including
|
||||
+ // duplicate values from an exiting block).
|
||||
+ // Nuke all entries except the zero'th entry which is the preheader entry.
|
||||
+ // NOTE! We need to remove Incoming Values in the reverse order as done
|
||||
+ // below, to keep the indices valid for deletion (removeIncomingValues
|
||||
+ // updates getNumIncomingValues and shifts all values down into the operand
|
||||
+ // being deleted).
|
||||
+ for (unsigned i = 0, e = P->getNumIncomingValues() - 1; i != e; ++i)
|
||||
+ P->removeIncomingValue(e - i, false);
|
||||
+
|
||||
+ assert((P->getNumIncomingValues() == 1 &&
|
||||
+ P->getIncomingBlock(PredIndex) == preheader) &&
|
||||
+ "Should have exactly one value and that's from the preheader!");
|
||||
++BI;
|
||||
+ // HLSL Change end
|
||||
}
|
||||
|
||||
// Update the dominator tree and remove the instructions and blocks that will
|
||||
diff --git a/tools/clang/test/DXC/Passes/DxilLoopDeletion/dxil-loop-deletion-phi-with-duplicate-preds.ll b/tools/clang/test/DXC/Passes/DxilLoopDeletion/dxil-loop-deletion-phi-with-duplicate-preds.ll
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..62736bf2934a5db67ee75386431498f49e101f49
|
||||
--- /dev/null
|
||||
+++ b/tools/clang/test/DXC/Passes/DxilLoopDeletion/dxil-loop-deletion-phi-with-duplicate-preds.ll
|
||||
@@ -0,0 +1,229 @@
|
||||
+; RUN: %dxopt %s -hlsl-passes-resume -dxil-loop-deletion,NoSink=0 -S | FileCheck %s
|
||||
+
|
||||
+; This test was generated from the following HLSL:
|
||||
+;
|
||||
+; cbuffer cbuffer_g : register(b0) {
|
||||
+; uint4 gu4[1];
|
||||
+; };
|
||||
+;
|
||||
+; float4 f() {
|
||||
+; float4 r = float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
+; int i = 0;
|
||||
+; int j = 0;
|
||||
+; while (true) {
|
||||
+; float a = asfloat(gu4[0].y);
|
||||
+; int ai = int(a);
|
||||
+; bool b = (j < ai);
|
||||
+; if (j >= ai) {
|
||||
+; break;
|
||||
+; }
|
||||
+; bool c = (i > 0);
|
||||
+; if (c) {
|
||||
+; break;
|
||||
+; } else {
|
||||
+; bool3 b3 = bool3(b.xxx);
|
||||
+; if (b3[i]) {
|
||||
+; switch(i) {
|
||||
+; case 0: return r;
|
||||
+; case -1: return r;
|
||||
+; }
|
||||
+; if (c) {
|
||||
+; break;
|
||||
+; }
|
||||
+; } else {
|
||||
+; r = float4(0.0f, 0.0f, 0.0f, a);
|
||||
+; }
|
||||
+; }
|
||||
+; i = j;
|
||||
+; j = (j + 1);
|
||||
+; }
|
||||
+; r = (0.0f).xxxx;
|
||||
+; return r;
|
||||
+; }
|
||||
+;
|
||||
+; struct return_val {
|
||||
+; float4 value : SV_Target0;
|
||||
+; };
|
||||
+;
|
||||
+; return_val main() {
|
||||
+; float4 inner_result = f();
|
||||
+; return_val wrapper_result = (return_val)0;
|
||||
+; wrapper_result.value = inner_result;
|
||||
+; return wrapper_result;
|
||||
+; }
|
||||
+;
|
||||
+; When compiling the above with dxc, ASAN reported a use-after-free in simplifycfg,
|
||||
+; which originated from a delete during the dxil-loop-deletion pass. This was due
|
||||
+; to a bug in LoopDeletion::runOnLoop that did not properly handle updated PHIs
|
||||
+; with duplicate input preds. After this test runs, the loop should be deleted,
|
||||
+; and the program optimized to simply write out 0s to the cbuffer.
|
||||
+
|
||||
+; CHECK: define void @main
|
||||
+; CHECK-NEXT: entry:
|
||||
+; CHECK-NEXT: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float 0.000000e+00)
|
||||
+; CHECK-NEXT: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float 0.000000e+00)
|
||||
+; CHECK-NEXT: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float 0.000000e+00)
|
||||
+; CHECK-NEXT: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3, float 0.000000e+00)
|
||||
+; CHECK-NEXT: ret void
|
||||
+
|
||||
+;
|
||||
+; Output signature:
|
||||
+;
|
||||
+; Name Index InterpMode DynIdx
|
||||
+; -------------------- ----- ---------------------- ------
|
||||
+; SV_Target 0
|
||||
+;
|
||||
+; Buffer Definitions:
|
||||
+;
|
||||
+; cbuffer cbuffer_g
|
||||
+; {
|
||||
+;
|
||||
+; struct cbuffer_g
|
||||
+; {
|
||||
+;
|
||||
+; uint4 gu4[1]; ; Offset: 0
|
||||
+;
|
||||
+; } cbuffer_g; ; Offset: 0 Size: 16
|
||||
+;
|
||||
+; }
|
||||
+;
|
||||
+;
|
||||
+; Resource Bindings:
|
||||
+;
|
||||
+; Name Type Format Dim ID HLSL Bind Count
|
||||
+; ------------------------------ ---------- ------- ----------- ------- -------------- ------
|
||||
+; cbuffer_g cbuffer NA NA CB0 cb0 1
|
||||
+;
|
||||
+target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
|
||||
+target triple = "dxil-ms-dx"
|
||||
+
|
||||
+%cbuffer_g = type { [1 x <4 x i32>] }
|
||||
+%dx.types.Handle = type { i8* }
|
||||
+%dx.types.ResourceProperties = type { i32, i32 }
|
||||
+%dx.types.CBufRet.i32 = type { i32, i32, i32, i32 }
|
||||
+%struct.return_val = type { <4 x float> }
|
||||
+
|
||||
+@cbuffer_g = external constant %cbuffer_g
|
||||
+@.hca = internal unnamed_addr constant [3 x i32] [i32 1, i32 1, i32 1]
|
||||
+@llvm.used = appending global [1 x i8*] [i8* bitcast (%cbuffer_g* @cbuffer_g to i8*)], section "llvm.metadata"
|
||||
+
|
||||
+; Function Attrs: nounwind readnone
|
||||
+declare %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %cbuffer_g*, i32)"(i32, %cbuffer_g*, i32) #0
|
||||
+
|
||||
+; Function Attrs: nounwind readnone
|
||||
+declare %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %cbuffer_g)"(i32, %dx.types.Handle, %dx.types.ResourceProperties, %cbuffer_g) #0
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+define void @main(<4 x float>* noalias nocapture readnone) #1 {
|
||||
+entry:
|
||||
+ %1 = load %cbuffer_g, %cbuffer_g* @cbuffer_g, align 4, !dbg !25 ; line:45 col:25
|
||||
+ %cbuffer_g = call %dx.types.Handle @dx.op.createHandleForLib.cbuffer_g(i32 160, %cbuffer_g %1), !dbg !25 ; line:45 col:25 ; CreateHandleForLib(Resource)
|
||||
+ %2 = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle %cbuffer_g, %dx.types.ResourceProperties { i32 13, i32 16 }), !dbg !25 ; line:45 col:25 ; AnnotateHandle(res,props) resource: CBuffer
|
||||
+ %3 = call %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32(i32 59, %dx.types.Handle %2, i32 0), !dbg !29 ; line:10 col:23 ; CBufferLoadLegacy(handle,regIndex)
|
||||
+ %4 = extractvalue %dx.types.CBufRet.i32 %3, 1, !dbg !29 ; line:10 col:23
|
||||
+ %5 = bitcast i32 %4 to float, !dbg !32 ; line:10 col:15
|
||||
+ %conv.i.6 = fptosi float %5 to i32, !dbg !33 ; line:11 col:18
|
||||
+ %cmp1.i.8 = icmp sgt i32 %conv.i.6, 0, !dbg !34 ; line:13 col:11
|
||||
+ br i1 %cmp1.i.8, label %if.end.i, label %"\01?f@@YA?AV?$vector@M$03@@XZ.exit", !dbg !35 ; line:13 col:9
|
||||
+
|
||||
+if.end.i: ; preds = %entry, %if.end.19.i
|
||||
+ %6 = phi float [ %9, %if.end.19.i ], [ %5, %entry ]
|
||||
+ %j.i.011 = phi i32 [ %add.i, %if.end.19.i ], [ 0, %entry ]
|
||||
+ %r.i.0.i310 = phi float [ %r.i.0.i310, %if.end.19.i ], [ 0.000000e+00, %entry ]
|
||||
+ %i.i.09 = phi i32 [ %j.i.011, %if.end.19.i ], [ 0, %entry ]
|
||||
+ %cmp4.i = icmp sgt i32 %i.i.09, 0, !dbg !36 ; line:16 col:17
|
||||
+ br i1 %cmp4.i, label %"\01?f@@YA?AV?$vector@M$03@@XZ.exit", label %if.then.12.i, !dbg !37 ; line:17 col:9
|
||||
+
|
||||
+if.then.12.i: ; preds = %if.end.i
|
||||
+ switch i32 %i.i.09, label %if.end.19.i [
|
||||
+ i32 0, label %"\01?f@@YA?AV?$vector@M$03@@XZ.exit"
|
||||
+ i32 -1, label %"\01?f@@YA?AV?$vector@M$03@@XZ.exit"
|
||||
+ ], !dbg !38 ; line:22 col:9
|
||||
+
|
||||
+if.end.19.i: ; preds = %if.then.12.i
|
||||
+ %add.i = add nuw nsw i32 %j.i.011, 1, !dbg !39 ; line:34 col:12
|
||||
+ %7 = call %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32(i32 59, %dx.types.Handle %2, i32 0), !dbg !29 ; line:10 col:23 ; CBufferLoadLegacy(handle,regIndex)
|
||||
+ %8 = extractvalue %dx.types.CBufRet.i32 %7, 1, !dbg !29 ; line:10 col:23
|
||||
+ %9 = bitcast i32 %8 to float, !dbg !32 ; line:10 col:15
|
||||
+ %conv.i = fptosi float %9 to i32, !dbg !33 ; line:11 col:18
|
||||
+ %cmp.i = icmp slt i32 %add.i, %conv.i, !dbg !40 ; line:12 col:17
|
||||
+ br i1 %cmp.i, label %if.end.i, label %"\01?f@@YA?AV?$vector@M$03@@XZ.exit", !dbg !35 ; line:13 col:9
|
||||
+
|
||||
+"\01?f@@YA?AV?$vector@M$03@@XZ.exit": ; preds = %if.then.12.i, %if.then.12.i, %if.end.i, %if.end.19.i, %entry
|
||||
+ %retval.i.0.i3 = phi float [ 0.000000e+00, %entry ], [ %r.i.0.i310, %if.then.12.i ], [ %r.i.0.i310, %if.then.12.i ], [ 0.000000e+00, %if.end.i ], [ 0.000000e+00, %if.end.19.i ]
|
||||
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float 0.000000e+00), !dbg !41 ; line:48 col:10 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
|
||||
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float 0.000000e+00), !dbg !41 ; line:48 col:10 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
|
||||
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float 0.000000e+00), !dbg !41 ; line:48 col:10 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
|
||||
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3, float %retval.i.0.i3), !dbg !41 ; line:48 col:10 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
|
||||
+ ret void, !dbg !42 ; line:48 col:3
|
||||
+}
|
||||
+
|
||||
+; Function Attrs: nounwind
|
||||
+declare void @dx.op.storeOutput.f32(i32, i32, i32, i8, float) #1
|
||||
+
|
||||
+; Function Attrs: nounwind readonly
|
||||
+declare %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32(i32, %dx.types.Handle, i32) #2
|
||||
+
|
||||
+; Function Attrs: nounwind readonly
|
||||
+declare %dx.types.Handle @dx.op.createHandleForLib.cbuffer_g(i32, %cbuffer_g) #2
|
||||
+
|
||||
+; Function Attrs: nounwind readnone
|
||||
+declare %dx.types.Handle @dx.op.annotateHandle(i32, %dx.types.Handle, %dx.types.ResourceProperties) #0
|
||||
+
|
||||
+attributes #0 = { nounwind readnone }
|
||||
+attributes #1 = { nounwind }
|
||||
+attributes #2 = { nounwind readonly }
|
||||
+
|
||||
+!llvm.module.flags = !{!0}
|
||||
+!pauseresume = !{!1}
|
||||
+!llvm.ident = !{!2}
|
||||
+!dx.version = !{!3}
|
||||
+!dx.valver = !{!4}
|
||||
+!dx.shaderModel = !{!5}
|
||||
+!dx.resources = !{!6}
|
||||
+!dx.typeAnnotations = !{!9, !14}
|
||||
+!dx.entryPoints = !{!21}
|
||||
+
|
||||
+!0 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
+!1 = !{!"hlsl-dxilemit", !"hlsl-dxilload"}
|
||||
+!2 = !{!"dxc(private) 1.8.0.4514 (d9bd2a706-dirty)"}
|
||||
+!3 = !{i32 1, i32 5}
|
||||
+!4 = !{i32 1, i32 8}
|
||||
+!5 = !{!"ps", i32 6, i32 5}
|
||||
+!6 = !{null, null, !7, null}
|
||||
+!7 = !{!8}
|
||||
+!8 = !{i32 0, %cbuffer_g* @cbuffer_g, !"cbuffer_g", i32 0, i32 0, i32 1, i32 16, null}
|
||||
+!9 = !{i32 0, %struct.return_val undef, !10, %cbuffer_g undef, !12}
|
||||
+!10 = !{i32 16, !11}
|
||||
+!11 = !{i32 6, !"value", i32 3, i32 0, i32 4, !"SV_Target0", i32 7, i32 9}
|
||||
+!12 = !{i32 16, !13}
|
||||
+!13 = !{i32 6, !"gu4", i32 3, i32 0, i32 7, i32 5}
|
||||
+!14 = !{i32 1, void (<4 x float>*)* @main, !15}
|
||||
+!15 = !{!16, !18}
|
||||
+!16 = !{i32 0, !17, !17}
|
||||
+!17 = !{}
|
||||
+!18 = !{i32 1, !19, !20}
|
||||
+!19 = !{i32 4, !"SV_Target0", i32 7, i32 9}
|
||||
+!20 = !{i32 0}
|
||||
+!21 = !{void (<4 x float>*)* @main, !"main", !22, !6, null}
|
||||
+!22 = !{null, !23, null}
|
||||
+!23 = !{!24}
|
||||
+!24 = !{i32 0, !"SV_Target", i8 9, i8 16, !20, i8 0, i32 1, i8 4, i32 0, i8 0, null}
|
||||
+!25 = !DILocation(line: 45, column: 25, scope: !26)
|
||||
+!26 = !DISubprogram(name: "main", scope: !27, file: !27, line: 44, type: !28, isLocal: false, isDefinition: true, scopeLine: 44, flags: DIFlagPrototyped, isOptimized: false, function: void (<4 x float>*)* @main)
|
||||
+!27 = !DIFile(filename: "/mnt/c/Users/amaiorano/Downloads/340196361/standalone_reduced.hlsl", directory: "")
|
||||
+!28 = !DISubroutineType(types: !17)
|
||||
+!29 = !DILocation(line: 10, column: 23, scope: !30, inlinedAt: !31)
|
||||
+!30 = !DISubprogram(name: "f", scope: !27, file: !27, line: 5, type: !28, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false)
|
||||
+!31 = distinct !DILocation(line: 45, column: 25, scope: !26)
|
||||
+!32 = !DILocation(line: 10, column: 15, scope: !30, inlinedAt: !31)
|
||||
+!33 = !DILocation(line: 11, column: 18, scope: !30, inlinedAt: !31)
|
||||
+!34 = !DILocation(line: 13, column: 11, scope: !30, inlinedAt: !31)
|
||||
+!35 = !DILocation(line: 13, column: 9, scope: !30, inlinedAt: !31)
|
||||
+!36 = !DILocation(line: 16, column: 17, scope: !30, inlinedAt: !31)
|
||||
+!37 = !DILocation(line: 17, column: 9, scope: !30, inlinedAt: !31)
|
||||
+!38 = !DILocation(line: 22, column: 9, scope: !30, inlinedAt: !31)
|
||||
+!39 = !DILocation(line: 34, column: 12, scope: !30, inlinedAt: !31)
|
||||
+!40 = !DILocation(line: 12, column: 17, scope: !30, inlinedAt: !31)
|
||||
+!41 = !DILocation(line: 48, column: 10, scope: !26)
|
||||
+!42 = !DILocation(line: 48, column: 3, scope: !26)
|
||||
@@ -2,3 +2,5 @@ m123_vulkan_fix_access_to_inactive_attributes.patch
|
||||
cherry-pick-f6672dbbe223.patch
|
||||
cherry-pick-ba3b4e239620.patch
|
||||
cherry-pick-c67f290ef0f0.patch
|
||||
cherry-pick-bda89e1f7c71.patch
|
||||
m126_vulkan_disable_vk_ext_shader_stencil_export_on_swiftshader.patch
|
||||
|
||||
74
patches/angle/cherry-pick-bda89e1f7c71.patch
Normal file
74
patches/angle/cherry-pick-bda89e1f7c71.patch
Normal file
@@ -0,0 +1,74 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
Date: Thu, 2 May 2024 11:17:33 -0400
|
||||
Subject: M124: Vulkan: Turn SPIR-V limitations to crash instead of security
|
||||
bug
|
||||
|
||||
The input shader can be made complex in a number of different ways,
|
||||
resulting in instructions with a length higher than what can fit in
|
||||
SPIR-V (i.e. 16 bits). Ideally, the translator would catch such complex
|
||||
usage early on and gracefully fail compilation. However, as a safety
|
||||
net, this change makes sure such a case is detected when the SPIR-V
|
||||
instruction is being generated and turned into a crash. This makes sure
|
||||
such bugs are no longer security bugs.
|
||||
|
||||
Bug: chromium:335613092
|
||||
Change-Id: Iab16b49ed80929fc343b4c7bffce306919de2e96
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5547611
|
||||
Reviewed-by: Roman Lavrov <romanl@google.com>
|
||||
|
||||
diff --git a/scripts/code_generation_hashes/SPIR-V_helpers.json b/scripts/code_generation_hashes/SPIR-V_helpers.json
|
||||
index cb1b596b6d02f35e2817cac53ace42d64e33bffd..944cf1a2cbd34a0e28e7cfad4b874344f662512b 100644
|
||||
--- a/scripts/code_generation_hashes/SPIR-V_helpers.json
|
||||
+++ b/scripts/code_generation_hashes/SPIR-V_helpers.json
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"src/common/spirv/gen_spirv_builder_and_parser.py":
|
||||
- "e95670a30a4eda80a146b61c986fb03c",
|
||||
+ "868a697edbc38c95e36be54cf5c71435",
|
||||
"src/common/spirv/spirv_instruction_builder_autogen.cpp":
|
||||
- "1b5f60a24d459e7a30c29cf7acfa2106",
|
||||
+ "c149de371bcd571bd31cc8eb1e517910",
|
||||
"src/common/spirv/spirv_instruction_builder_autogen.h":
|
||||
"56b1309d8afabb2b64d7e16f0c4a4898",
|
||||
"src/common/spirv/spirv_instruction_parser_autogen.cpp":
|
||||
diff --git a/src/common/spirv/gen_spirv_builder_and_parser.py b/src/common/spirv/gen_spirv_builder_and_parser.py
|
||||
index 5e8e9bc4e8914cf2173a8fa720446f6647dd065e..c7e1f401b380f3b4fe0bd6b9178b42ee5ac41250 100755
|
||||
--- a/src/common/spirv/gen_spirv_builder_and_parser.py
|
||||
+++ b/src/common/spirv/gen_spirv_builder_and_parser.py
|
||||
@@ -93,6 +93,15 @@ uint32_t MakeLengthOp(size_t length, spv::Op op)
|
||||
ASSERT(length <= 0xFFFFu);
|
||||
ASSERT(op <= 0xFFFFu);
|
||||
|
||||
+ // It's easy for a complex shader to be crafted to hit the length limit,
|
||||
+ // turn that into a crash instead of a security bug. Ideally, the compiler
|
||||
+ // would gracefully fail compilation, so this is more of a safety net.
|
||||
+ if (ANGLE_UNLIKELY(length > 0xFFFFu))
|
||||
+ {
|
||||
+ ERR() << "Complex shader not representible in SPIR-V";
|
||||
+ ANGLE_CRASH();
|
||||
+ }
|
||||
+
|
||||
return static_cast<uint32_t>(length) << 16 | op;
|
||||
}
|
||||
} // anonymous namespace
|
||||
diff --git a/src/common/spirv/spirv_instruction_builder_autogen.cpp b/src/common/spirv/spirv_instruction_builder_autogen.cpp
|
||||
index 3c73c58e3c0141f3e00a61eab784d3e3b96dff8e..6e6ad6f510cb76588f61dacee8dbcac5a544d8d1 100644
|
||||
--- a/src/common/spirv/spirv_instruction_builder_autogen.cpp
|
||||
+++ b/src/common/spirv/spirv_instruction_builder_autogen.cpp
|
||||
@@ -25,6 +25,15 @@ uint32_t MakeLengthOp(size_t length, spv::Op op)
|
||||
ASSERT(length <= 0xFFFFu);
|
||||
ASSERT(op <= 0xFFFFu);
|
||||
|
||||
+ // It's easy for a complex shader to be crafted to hit the length limit,
|
||||
+ // turn that into a crash instead of a security bug. Ideally, the compiler
|
||||
+ // would gracefully fail compilation, so this is more of a safety net.
|
||||
+ if (ANGLE_UNLIKELY(length > 0xFFFFu))
|
||||
+ {
|
||||
+ ERR() << "Complex shader not representible in SPIR-V";
|
||||
+ ANGLE_CRASH();
|
||||
+ }
|
||||
+
|
||||
return static_cast<uint32_t>(length) << 16 | op;
|
||||
}
|
||||
} // anonymous namespace
|
||||
@@ -0,0 +1,27 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
Date: Thu, 13 Jun 2024 16:54:03 -0400
|
||||
Subject: M126: Vulkan: Disable VK_EXT_shader_stencil_export on SwiftShader
|
||||
|
||||
Bug: chromium:40942995
|
||||
Change-Id: I5035d9b11997a1c7c839d7d62544fecca9fd1f73
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5634418
|
||||
Reviewed-by: Yuly Novikov <ynovikov@chromium.org>
|
||||
|
||||
diff --git a/src/libANGLE/renderer/vulkan/RendererVk.cpp b/src/libANGLE/renderer/vulkan/RendererVk.cpp
|
||||
index 25beb6a346798f117b8fe15de9858adcc32881cd..4827c61a166633d191e1f9b03a3dc47066ce9522 100644
|
||||
--- a/src/libANGLE/renderer/vulkan/RendererVk.cpp
|
||||
+++ b/src/libANGLE/renderer/vulkan/RendererVk.cpp
|
||||
@@ -4175,9 +4175,11 @@ void RendererVk::initFeatures(DisplayVk *displayVk,
|
||||
}
|
||||
#endif // defined(ANGLE_PLATFORM_ANDROID) || defined(ANGLE_PLATFORM_LINUX)
|
||||
|
||||
+ // Disabled on SwiftShader due to http://crbug.com/40942995
|
||||
ANGLE_FEATURE_CONDITION(
|
||||
&mFeatures, supportsShaderStencilExport,
|
||||
- ExtensionFound(VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME, deviceExtensionNames));
|
||||
+ ExtensionFound(VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME, deviceExtensionNames) &&
|
||||
+ !isSwiftShader);
|
||||
|
||||
ANGLE_FEATURE_CONDITION(
|
||||
&mFeatures, supportsRenderPassLoadStoreOpNone,
|
||||
@@ -141,3 +141,12 @@ cherry-pick-c1f25647c2fc.patch
|
||||
cherry-pick-013961609785.patch
|
||||
a11y_avoid_clearing_resetting_focus_on_an_already_focus_event.patch
|
||||
cherry-pick-b2cc7b7ac538.patch
|
||||
feat_add_support_for_missing_dialog_features_to_shell_dialogs.patch
|
||||
cherry-pick-03609e39be8c.patch
|
||||
x11_use_localized_display_label_only_for_browser_process.patch
|
||||
cherry-pick-b922fcb61e3b.patch
|
||||
cherry-pick-0d9598145069.patch
|
||||
cherry-pick-24329fe5c4d0.patch
|
||||
m120-lts_mediasession_use_a_mediasessionimpl_weakptr_in.patch
|
||||
x11_fix_crash_when_randr_getmonitors_fails.patch
|
||||
feat_enable_passing_exit_code_on_service_process_crash.patch
|
||||
|
||||
117
patches/chromium/cherry-pick-03609e39be8c.patch
Normal file
117
patches/chromium/cherry-pick-03609e39be8c.patch
Normal file
@@ -0,0 +1,117 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: David Benjamin <davidben@chromium.org>
|
||||
Date: Fri, 10 May 2024 15:10:48 +0000
|
||||
Subject: Fix size calculations in V8StringToUTF8
|
||||
|
||||
While I'm here, remove the unnecessary use of base::WriteInto, which is
|
||||
a remnant of C++03 copy-on-write strings. Also ask V8 not to write a
|
||||
NUL terminator because std::(u16)string already owns that byte.
|
||||
|
||||
(cherry picked from commit f414dc31032a453f4a6c88977d7894fcb3cba44e)
|
||||
|
||||
Bug: 338574384
|
||||
Change-Id: I5c6eaa99093925db799736f321eab92d35f5acbb
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5515743
|
||||
Reviewed-by: mmenke <mmenke@chromium.org>
|
||||
Commit-Queue: David Benjamin <davidben@chromium.org>
|
||||
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1297196}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5527764
|
||||
Auto-Submit: David Benjamin <davidben@chromium.org>
|
||||
Commit-Queue: mmenke <mmenke@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/6367@{#1148}
|
||||
Cr-Branched-From: d158c6dc6e3604e6f899041972edf26087a49740-refs/heads/main@{#1274542}
|
||||
|
||||
diff --git a/services/proxy_resolver/proxy_resolver_v8.cc b/services/proxy_resolver/proxy_resolver_v8.cc
|
||||
index eca8014359b60f54d47c46aa7e106da83ec8a85f..da8232b229f3c6387d5ec063b197650ea24ec292 100644
|
||||
--- a/services/proxy_resolver/proxy_resolver_v8.cc
|
||||
+++ b/services/proxy_resolver/proxy_resolver_v8.cc
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/memory/raw_ptr_exclusion.h"
|
||||
#include "base/notreached.h"
|
||||
+#include "base/numerics/safe_conversions.h"
|
||||
#include "base/strings/string_tokenizer.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
@@ -148,25 +149,22 @@ const size_t kMaxStringBytesForCopy = 256;
|
||||
|
||||
// Converts a V8 String to a UTF8 std::string.
|
||||
std::string V8StringToUTF8(v8::Isolate* isolate, v8::Local<v8::String> s) {
|
||||
- int len = s->Length();
|
||||
- std::string result;
|
||||
- if (len > 0)
|
||||
- s->WriteUtf8(isolate, base::WriteInto(&result, len + 1));
|
||||
- return result;
|
||||
+ int len = s->Utf8Length(isolate);
|
||||
+ std::string str(base::checked_cast<size_t>(len), '\0');
|
||||
+ s->WriteUtf8(isolate, str.data(), len, /*nchars_ref=*/nullptr,
|
||||
+ v8::String::NO_NULL_TERMINATION);
|
||||
+ return str;
|
||||
}
|
||||
|
||||
// Converts a V8 String to a UTF16 std::u16string.
|
||||
std::u16string V8StringToUTF16(v8::Isolate* isolate, v8::Local<v8::String> s) {
|
||||
int len = s->Length();
|
||||
- std::u16string result;
|
||||
- // Note that the reinterpret cast is because on Windows string16 is an alias
|
||||
- // to wstring, and hence has character type wchar_t not uint16_t.
|
||||
- if (len > 0) {
|
||||
- s->Write(isolate,
|
||||
- reinterpret_cast<uint16_t*>(base::WriteInto(&result, len + 1)), 0,
|
||||
- len);
|
||||
- }
|
||||
- return result;
|
||||
+ std::u16string str(base::checked_cast<size_t>(len), '\0');
|
||||
+ // `char16_t` and `uint16_t` are not the same type, but we build with strict
|
||||
+ // aliasing off. See https://crbug.com/42209752.
|
||||
+ s->Write(isolate, reinterpret_cast<uint16_t*>(str.data()), /*start=*/0, len,
|
||||
+ v8::String::NO_NULL_TERMINATION);
|
||||
+ return str;
|
||||
}
|
||||
|
||||
// Converts an ASCII std::string to a V8 string.
|
||||
diff --git a/services/proxy_resolver/test/data/proxy_resolver_v8_unittest/pac_library_unittest.js b/services/proxy_resolver/test/data/proxy_resolver_v8_unittest/pac_library_unittest.js
|
||||
index 3414dc0b4a33a64c8fe09b0d2a5cd48123a5d9ac..1b8bc17862f0c3cfa4fdc97121619afac8777a9d 100644
|
||||
--- a/services/proxy_resolver/test/data/proxy_resolver_v8_unittest/pac_library_unittest.js
|
||||
+++ b/services/proxy_resolver/test/data/proxy_resolver_v8_unittest/pac_library_unittest.js
|
||||
@@ -69,6 +69,11 @@ Tests.testIsPlainHostName = function(t) {
|
||||
t.expectFalse(isPlainHostName("."));
|
||||
t.expectFalse(isPlainHostName(".:"));
|
||||
|
||||
+ // These are not really hostnames, but `isPlainHostName` accepts any dotless,
|
||||
+ // non-IP string.
|
||||
+ t.expectTrue(isPlainHostName("\uffff".repeat(256)));
|
||||
+ t.expectTrue(isPlainHostName(""));
|
||||
+
|
||||
// Valid IPv6 address
|
||||
t.expectFalse(isPlainHostName("::1"));
|
||||
|
||||
@@ -178,6 +183,7 @@ Tests.testSortIpAddressList = function(t) {
|
||||
t.expectEquals(null, sortIpAddressList());
|
||||
t.expectEquals(null, sortIpAddressList(null));
|
||||
t.expectEquals(null, sortIpAddressList(null, null));
|
||||
+ t.expectEquals(null, sortIpAddressList("\uffff".repeat(256)));
|
||||
};
|
||||
|
||||
Tests.testIsInNetEx = function(t) {
|
||||
@@ -223,10 +229,14 @@ Tests.testIsInNetEx = function(t) {
|
||||
// Invalid IP address.
|
||||
t.expectFalse(isInNetEx("256.0.0.1", "198.95.249.79"));
|
||||
t.expectFalse(isInNetEx("127.0.0.1 ", "127.0.0.1/32")); // Extra space.
|
||||
+ t.expectFalse(isInNetEx("\uffff".repeat(256), "127.0.0.1/32"));
|
||||
+ t.expectFalse(isInNetEx("", "127.0.0.1/32"));
|
||||
|
||||
// Invalid prefix.
|
||||
t.expectFalse(isInNetEx("198.95.115.10", "198.95.0.0/34"));
|
||||
t.expectFalse(isInNetEx("127.0.0.1", "127.0.0.1")); // Missing '/' in prefix.
|
||||
+ t.expectFalse(isInNetEx("127.0.0.1", "\uffff".repeat(256)));
|
||||
+ t.expectFalse(isInNetEx("127.0.0.1", ""));
|
||||
};
|
||||
|
||||
Tests.testWeekdayRange = function(t) {
|
||||
@@ -465,4 +475,3 @@ MockDate.setCurrent = function(currentDateString) {
|
||||
|
||||
// Bind the methods to proxy requests to the wrapped Date().
|
||||
MockDate.init();
|
||||
-
|
||||
805
patches/chromium/cherry-pick-0d9598145069.patch
Normal file
805
patches/chromium/cherry-pick-0d9598145069.patch
Normal file
@@ -0,0 +1,805 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Brendon Tiszka <tiszka@chromium.org>
|
||||
Date: Mon, 20 May 2024 18:33:53 +0000
|
||||
Subject: Fix bugs in GLES* command handlers
|
||||
|
||||
If the command buffer is in an invalid state then we can't trust
|
||||
the contents of the get buffer.
|
||||
|
||||
(cherry picked from commit 374789ab8f5eeac24e2e335af825d34b8c3fde81)
|
||||
|
||||
Bug: 340822365,40947303
|
||||
Change-Id: I465d617e5056877fb464dd59df983a9e8d866b85
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5542488
|
||||
Commit-Queue: Brendon Tiszka <tiszka@chromium.org>
|
||||
Reviewed-by: Geoff Lang <geofflang@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1301529}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5550571
|
||||
Reviewed-by: Brendon Tiszka <tiszka@chromium.org>
|
||||
Owners-Override: Prudhvikumar Bommana <pbommana@google.com>
|
||||
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Cr-Commit-Position: refs/branch-heads/6367@{#1205}
|
||||
Cr-Branched-From: d158c6dc6e3604e6f899041972edf26087a49740-refs/heads/main@{#1274542}
|
||||
|
||||
diff --git a/gpu/command_buffer/build_cmd_buffer_lib.py b/gpu/command_buffer/build_cmd_buffer_lib.py
|
||||
index b8ca818edd2d225ea6309f202edbba6e957f1f35..4f1aa8efefd3ef8591aad3e90fc57f4b78347317 100644
|
||||
--- a/gpu/command_buffer/build_cmd_buffer_lib.py
|
||||
+++ b/gpu/command_buffer/build_cmd_buffer_lib.py
|
||||
@@ -2954,7 +2954,9 @@ class GETnHandler(TypeHandler):
|
||||
result->SetNumResults(0);
|
||||
helper_->%(func_name)s(%(arg_string)s,
|
||||
GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(%(last_arg_name)s);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -4456,7 +4458,9 @@ TEST_P(%(test_name)s, %(name)sInvalidArgsBadSharedMemoryId) {
|
||||
f.write(
|
||||
" helper_->%s(%s, GetResultShmId(), result.offset());\n" %
|
||||
(func.name, arg_string))
|
||||
- f.write(" WaitForCmd();\n")
|
||||
+ f.write(" if (!WaitForCmd()) {\n")
|
||||
+ f.write(" return %s; \n" % error_value)
|
||||
+ f.write(" }\n")
|
||||
f.write(" %s result_value = *result" % func.return_type)
|
||||
if func.return_type == "GLboolean":
|
||||
f.write(" != 0")
|
||||
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
|
||||
index e02399bcbdc6b2e642751038aa47ecfdf80e587c..ad9aa976ec776ff6be69c57c701bbcfc7cdfbd93 100644
|
||||
--- a/gpu/command_buffer/client/gles2_implementation.cc
|
||||
+++ b/gpu/command_buffer/client/gles2_implementation.cc
|
||||
@@ -595,7 +595,9 @@ GLenum GLES2Implementation::GetGLError() {
|
||||
}
|
||||
*result = GL_NO_ERROR;
|
||||
helper_->GetError(GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return GL_NO_ERROR;
|
||||
+ }
|
||||
GLenum error = *result;
|
||||
if (error == GL_NO_ERROR) {
|
||||
error = GetClientSideGLError();
|
||||
@@ -720,7 +722,9 @@ GLboolean GLES2Implementation::IsEnabled(GLenum cap) {
|
||||
}
|
||||
*result = 0;
|
||||
helper_->IsEnabled(cap, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return GL_FALSE;
|
||||
+ }
|
||||
state = (*result) != 0;
|
||||
}
|
||||
|
||||
@@ -741,7 +745,9 @@ GLboolean GLES2Implementation::IsEnablediOES(GLenum target, GLuint index) {
|
||||
auto result = GetResultAs<Result>();
|
||||
*result = 0;
|
||||
helper_->IsEnablediOES(target, index, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return GL_FALSE;
|
||||
+ }
|
||||
state = (*result) != 0;
|
||||
}
|
||||
|
||||
@@ -1360,7 +1366,9 @@ GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUMHelper(GLuint buffer_id,
|
||||
*result = 0;
|
||||
helper_->GetMaxValueInBufferCHROMIUM(buffer_id, count, type, offset,
|
||||
GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return 0;
|
||||
+ }
|
||||
return *result;
|
||||
}
|
||||
|
||||
@@ -1663,7 +1671,9 @@ void GLES2Implementation::GetVertexAttribPointerv(GLuint index,
|
||||
result->SetNumResults(0);
|
||||
helper_->GetVertexAttribPointerv(index, pname, GetResultShmId(),
|
||||
result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(ptr);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK(num_results = result->GetNumResults());
|
||||
}
|
||||
@@ -1738,7 +1748,9 @@ GLint GLES2Implementation::GetAttribLocationHelper(GLuint program,
|
||||
*result = -1;
|
||||
helper_->GetAttribLocation(program, kResultBucketId, GetResultShmId(),
|
||||
result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return -1;
|
||||
+ }
|
||||
helper_->SetBucketSize(kResultBucketId, 0);
|
||||
return *result;
|
||||
}
|
||||
@@ -1766,7 +1778,9 @@ GLint GLES2Implementation::GetUniformLocationHelper(GLuint program,
|
||||
*result = -1;
|
||||
helper_->GetUniformLocation(program, kResultBucketId, GetResultShmId(),
|
||||
result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return -1;
|
||||
+ }
|
||||
helper_->SetBucketSize(kResultBucketId, 0);
|
||||
return *result;
|
||||
}
|
||||
@@ -1799,7 +1813,9 @@ bool GLES2Implementation::GetUniformIndicesHelper(GLuint program,
|
||||
result->SetNumResults(0);
|
||||
helper_->GetUniformIndices(program, kResultBucketId, GetResultShmId(),
|
||||
result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return false;
|
||||
+ }
|
||||
if (result->GetNumResults() != count) {
|
||||
return false;
|
||||
}
|
||||
@@ -1859,7 +1875,9 @@ GLint GLES2Implementation::GetFragDataIndexEXTHelper(GLuint program,
|
||||
*result = -1;
|
||||
helper_->GetFragDataIndexEXT(program, kResultBucketId, GetResultShmId(),
|
||||
result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return -1;
|
||||
+ }
|
||||
helper_->SetBucketSize(kResultBucketId, 0);
|
||||
return *result;
|
||||
}
|
||||
@@ -1888,7 +1906,9 @@ GLint GLES2Implementation::GetFragDataLocationHelper(GLuint program,
|
||||
*result = -1;
|
||||
helper_->GetFragDataLocation(program, kResultBucketId, GetResultShmId(),
|
||||
result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return -1;
|
||||
+ }
|
||||
helper_->SetBucketSize(kResultBucketId, 0);
|
||||
return *result;
|
||||
}
|
||||
@@ -1917,7 +1937,9 @@ GLuint GLES2Implementation::GetUniformBlockIndexHelper(GLuint program,
|
||||
*result = GL_INVALID_INDEX;
|
||||
helper_->GetUniformBlockIndex(program, kResultBucketId, GetResultShmId(),
|
||||
result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return GL_INVALID_INDEX;
|
||||
+ }
|
||||
helper_->SetBucketSize(kResultBucketId, 0);
|
||||
return *result;
|
||||
}
|
||||
@@ -1962,7 +1984,9 @@ GLuint GLES2Implementation::GetProgramResourceIndexHelper(
|
||||
*result = GL_INVALID_INDEX;
|
||||
helper_->GetProgramResourceIndex(program, program_interface, kResultBucketId,
|
||||
GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return GL_INVALID_INDEX;
|
||||
+ }
|
||||
helper_->SetBucketSize(kResultBucketId, 0);
|
||||
return *result;
|
||||
}
|
||||
@@ -2007,7 +2031,9 @@ bool GLES2Implementation::GetProgramResourceNameHelper(GLuint program,
|
||||
helper_->GetProgramResourceName(program, program_interface, index,
|
||||
kResultBucketId, GetResultShmId(),
|
||||
result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return false;
|
||||
+ }
|
||||
success = !!*result;
|
||||
}
|
||||
if (success) {
|
||||
@@ -2066,7 +2092,9 @@ bool GLES2Implementation::GetProgramResourceivHelper(GLuint program,
|
||||
helper_->GetProgramResourceiv(program, program_interface, index,
|
||||
kResultBucketId, GetResultShmId(),
|
||||
result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return false;
|
||||
+ }
|
||||
if (length) {
|
||||
*length = result->GetNumResults();
|
||||
}
|
||||
@@ -2138,7 +2166,9 @@ GLint GLES2Implementation::GetProgramResourceLocationHelper(
|
||||
helper_->GetProgramResourceLocation(program, program_interface,
|
||||
kResultBucketId, GetResultShmId(),
|
||||
result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return -1;
|
||||
+ }
|
||||
helper_->SetBucketSize(kResultBucketId, 0);
|
||||
return *result;
|
||||
}
|
||||
@@ -4015,7 +4045,9 @@ bool GLES2Implementation::GetActiveAttribHelper(GLuint program,
|
||||
result->success = false;
|
||||
helper_->GetActiveAttrib(program, index, kResultBucketId, GetResultShmId(),
|
||||
result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return false;
|
||||
+ }
|
||||
bool success = !!result->success;
|
||||
if (success) {
|
||||
if (size) {
|
||||
@@ -4083,7 +4115,9 @@ bool GLES2Implementation::GetActiveUniformHelper(GLuint program,
|
||||
result->success = false;
|
||||
helper_->GetActiveUniform(program, index, kResultBucketId, GetResultShmId(),
|
||||
result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return false;
|
||||
+ }
|
||||
bool success = !!result->success;
|
||||
if (success) {
|
||||
if (size) {
|
||||
@@ -4150,7 +4184,9 @@ bool GLES2Implementation::GetActiveUniformBlockNameHelper(GLuint program,
|
||||
*result = 0;
|
||||
helper_->GetActiveUniformBlockName(program, index, kResultBucketId,
|
||||
GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return false;
|
||||
+ }
|
||||
bool success = !!result;
|
||||
if (success) {
|
||||
// Note: this can invalidate |result|.
|
||||
@@ -4197,7 +4233,9 @@ bool GLES2Implementation::GetActiveUniformBlockivHelper(GLuint program,
|
||||
result->SetNumResults(0);
|
||||
helper_->GetActiveUniformBlockiv(program, index, pname, GetResultShmId(),
|
||||
result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return false;
|
||||
+ }
|
||||
if (result->GetNumResults() > 0) {
|
||||
if (params) {
|
||||
result->CopyResult(params);
|
||||
@@ -4254,7 +4292,9 @@ bool GLES2Implementation::GetActiveUniformsivHelper(GLuint program,
|
||||
result->SetNumResults(0);
|
||||
helper_->GetActiveUniformsiv(program, kResultBucketId, pname,
|
||||
GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return false;
|
||||
+ }
|
||||
bool success = result->GetNumResults() == count;
|
||||
if (success) {
|
||||
if (params) {
|
||||
@@ -4330,7 +4370,9 @@ void GLES2Implementation::GetAttachedShaders(GLuint program,
|
||||
transfer_buffer_->GetOffset(result),
|
||||
checked_size);
|
||||
int32_t token = helper_->InsertToken();
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
if (count) {
|
||||
*count = result->GetNumResults();
|
||||
}
|
||||
@@ -4372,7 +4414,9 @@ void GLES2Implementation::GetShaderPrecisionFormat(GLenum shadertype,
|
||||
result->success = false;
|
||||
helper_->GetShaderPrecisionFormat(shadertype, precisiontype,
|
||||
GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
if (result->success)
|
||||
static_state_.shader_precisions[key] = *result;
|
||||
}
|
||||
@@ -4485,7 +4529,9 @@ bool GLES2Implementation::GetTransformFeedbackVaryingHelper(GLuint program,
|
||||
result->success = false;
|
||||
helper_->GetTransformFeedbackVarying(program, index, kResultBucketId,
|
||||
GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return false;
|
||||
+ }
|
||||
if (result->success) {
|
||||
if (size) {
|
||||
*size = result->size;
|
||||
@@ -4553,7 +4599,9 @@ void GLES2Implementation::GetUniformfv(GLuint program,
|
||||
}
|
||||
result->SetNumResults(0);
|
||||
helper_->GetUniformfv(program, location, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(params);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -4581,7 +4629,9 @@ void GLES2Implementation::GetUniformiv(GLuint program,
|
||||
}
|
||||
result->SetNumResults(0);
|
||||
helper_->GetUniformiv(program, location, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(params);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -4610,7 +4660,9 @@ void GLES2Implementation::GetUniformuiv(GLuint program,
|
||||
result->SetNumResults(0);
|
||||
helper_->GetUniformuiv(program, location, GetResultShmId(),
|
||||
result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(params);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -4788,7 +4840,9 @@ void GLES2Implementation::ReadbackARGBImagePixelsINTERNAL(
|
||||
dst_sk_color_type, dst_sk_alpha_type, shm_id, shm_offset,
|
||||
color_space_offset, pixels_offset, mailbox_offset);
|
||||
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
if (!*readback_result) {
|
||||
return;
|
||||
}
|
||||
@@ -4936,7 +4990,9 @@ void GLES2Implementation::ReadPixels(GLint xoffset,
|
||||
helper_->ReadPixels(xoffset, y_index, width, num_rows, format, type,
|
||||
buffer.shm_id(), buffer.offset(), GetResultShmId(),
|
||||
result.offset(), false);
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ break;
|
||||
+ }
|
||||
// If it was not marked as successful exit.
|
||||
if (!result->success) {
|
||||
break;
|
||||
@@ -5645,7 +5701,9 @@ void GLES2Implementation::GetVertexAttribfv(GLuint index,
|
||||
}
|
||||
result->SetNumResults(0);
|
||||
helper_->GetVertexAttribfv(index, pname, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(params);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -5678,7 +5736,9 @@ void GLES2Implementation::GetVertexAttribiv(GLuint index,
|
||||
}
|
||||
result->SetNumResults(0);
|
||||
helper_->GetVertexAttribiv(index, pname, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(params);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -5712,7 +5772,9 @@ void GLES2Implementation::GetVertexAttribIiv(GLuint index,
|
||||
result->SetNumResults(0);
|
||||
helper_->GetVertexAttribIiv(index, pname, GetResultShmId(),
|
||||
result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(params);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -5746,7 +5808,9 @@ void GLES2Implementation::GetVertexAttribIuiv(GLuint index,
|
||||
result->SetNumResults(0);
|
||||
helper_->GetVertexAttribIuiv(index, pname, GetResultShmId(),
|
||||
result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(params);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -5781,7 +5845,9 @@ GLboolean GLES2Implementation::EnableFeatureCHROMIUM(const char* feature) {
|
||||
*result = 0;
|
||||
helper_->EnableFeatureCHROMIUM(kResultBucketId, GetResultShmId(),
|
||||
result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return false;
|
||||
+ }
|
||||
helper_->SetBucketSize(kResultBucketId, 0);
|
||||
GPU_CLIENT_LOG(" returned " << GLES2Util::GetStringBool(*result));
|
||||
return *result != 0;
|
||||
@@ -5936,7 +6002,9 @@ void* GLES2Implementation::MapBufferRange(GLenum target,
|
||||
GetResultShmId(), result.offset());
|
||||
// TODO(zmo): For write only mode with MAP_INVALID_*_BIT, we should
|
||||
// consider an early return without WaitForCmd(). crbug.com/465804.
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return nullptr;
|
||||
+ }
|
||||
if (*result) {
|
||||
const GLbitfield kInvalidateBits =
|
||||
GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_INVALIDATE_RANGE_BIT;
|
||||
@@ -7211,7 +7279,9 @@ GLenum GLES2Implementation::ClientWaitSync(GLsync sync,
|
||||
*result = GL_WAIT_FAILED;
|
||||
helper_->ClientWaitSync(ToGLuint(sync), flags, timeout, GetResultShmId(),
|
||||
result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return GL_WAIT_FAILED;
|
||||
+ }
|
||||
localResult = *result;
|
||||
GPU_CLIENT_LOG("returned " << localResult);
|
||||
}
|
||||
@@ -7289,7 +7359,9 @@ void GLES2Implementation::GetInternalformativ(GLenum target,
|
||||
result->SetNumResults(0);
|
||||
helper_->GetInternalformativ(target, format, pname, GetResultShmId(),
|
||||
result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
|
||||
diff --git a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
|
||||
index 5db0583dceea74aaa819979d2253bb0ae5b03413..9e578e3f4c69a16098250ff22e04b8b4e0391d1b 100644
|
||||
--- a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
|
||||
+++ b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
|
||||
@@ -207,7 +207,9 @@ GLenum GLES2Implementation::CheckFramebufferStatus(GLenum target) {
|
||||
}
|
||||
*result = 0;
|
||||
helper_->CheckFramebufferStatus(target, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return GL_FRAMEBUFFER_UNSUPPORTED;
|
||||
+ }
|
||||
GLenum result_value = *result;
|
||||
GPU_CLIENT_LOG("returned " << result_value);
|
||||
CheckGLError();
|
||||
@@ -882,7 +884,9 @@ void GLES2Implementation::GetBooleanv(GLenum pname, GLboolean* params) {
|
||||
}
|
||||
result->SetNumResults(0);
|
||||
helper_->GetBooleanv(pname, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(params);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -910,7 +914,9 @@ void GLES2Implementation::GetBooleani_v(GLenum pname,
|
||||
}
|
||||
result->SetNumResults(0);
|
||||
helper_->GetBooleani_v(pname, index, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(data);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -939,7 +945,9 @@ void GLES2Implementation::GetBufferParameteri64v(GLenum target,
|
||||
result->SetNumResults(0);
|
||||
helper_->GetBufferParameteri64v(target, pname, GetResultShmId(),
|
||||
result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(params);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -969,7 +977,9 @@ void GLES2Implementation::GetBufferParameteriv(GLenum target,
|
||||
result->SetNumResults(0);
|
||||
helper_->GetBufferParameteriv(target, pname, GetResultShmId(),
|
||||
result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(params);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -994,7 +1004,9 @@ void GLES2Implementation::GetFloatv(GLenum pname, GLfloat* params) {
|
||||
}
|
||||
result->SetNumResults(0);
|
||||
helper_->GetFloatv(pname, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(params);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -1029,7 +1041,9 @@ void GLES2Implementation::GetFramebufferAttachmentParameteriv(GLenum target,
|
||||
result->SetNumResults(0);
|
||||
helper_->GetFramebufferAttachmentParameteriv(
|
||||
target, attachment, pname, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(params);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -1054,7 +1068,9 @@ void GLES2Implementation::GetInteger64v(GLenum pname, GLint64* params) {
|
||||
}
|
||||
result->SetNumResults(0);
|
||||
helper_->GetInteger64v(pname, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(params);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -1082,7 +1098,9 @@ void GLES2Implementation::GetIntegeri_v(GLenum pname,
|
||||
}
|
||||
result->SetNumResults(0);
|
||||
helper_->GetIntegeri_v(pname, index, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(data);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -1109,7 +1127,9 @@ void GLES2Implementation::GetInteger64i_v(GLenum pname,
|
||||
}
|
||||
result->SetNumResults(0);
|
||||
helper_->GetInteger64i_v(pname, index, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(data);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -1135,7 +1155,9 @@ void GLES2Implementation::GetIntegerv(GLenum pname, GLint* params) {
|
||||
}
|
||||
result->SetNumResults(0);
|
||||
helper_->GetIntegerv(pname, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(params);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -1163,7 +1185,9 @@ void GLES2Implementation::GetProgramiv(GLuint program,
|
||||
}
|
||||
result->SetNumResults(0);
|
||||
helper_->GetProgramiv(program, pname, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(params);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -1220,7 +1244,9 @@ void GLES2Implementation::GetRenderbufferParameteriv(GLenum target,
|
||||
result->SetNumResults(0);
|
||||
helper_->GetRenderbufferParameteriv(target, pname, GetResultShmId(),
|
||||
result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(params);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -1249,7 +1275,9 @@ void GLES2Implementation::GetSamplerParameterfv(GLuint sampler,
|
||||
result->SetNumResults(0);
|
||||
helper_->GetSamplerParameterfv(sampler, pname, GetResultShmId(),
|
||||
result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(params);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -1279,7 +1307,9 @@ void GLES2Implementation::GetSamplerParameteriv(GLuint sampler,
|
||||
result->SetNumResults(0);
|
||||
helper_->GetSamplerParameteriv(sampler, pname, GetResultShmId(),
|
||||
result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(params);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -1307,7 +1337,9 @@ void GLES2Implementation::GetShaderiv(GLuint shader,
|
||||
}
|
||||
result->SetNumResults(0);
|
||||
helper_->GetShaderiv(shader, pname, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(params);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -1396,7 +1428,9 @@ void GLES2Implementation::GetSynciv(GLsync sync,
|
||||
}
|
||||
result->SetNumResults(0);
|
||||
helper_->GetSynciv(ToGLuint(sync), pname, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(values);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -1427,7 +1461,9 @@ void GLES2Implementation::GetTexParameterfv(GLenum target,
|
||||
}
|
||||
result->SetNumResults(0);
|
||||
helper_->GetTexParameterfv(target, pname, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(params);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -1456,7 +1492,9 @@ void GLES2Implementation::GetTexParameteriv(GLenum target,
|
||||
}
|
||||
result->SetNumResults(0);
|
||||
helper_->GetTexParameteriv(target, pname, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(params);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -1541,7 +1579,9 @@ GLboolean GLES2Implementation::IsBuffer(GLuint buffer) {
|
||||
}
|
||||
*result = 0;
|
||||
helper_->IsBuffer(buffer, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return GL_FALSE;
|
||||
+ }
|
||||
GLboolean result_value = *result != 0;
|
||||
GPU_CLIENT_LOG("returned " << result_value);
|
||||
CheckGLError();
|
||||
@@ -1560,7 +1600,9 @@ GLboolean GLES2Implementation::IsFramebuffer(GLuint framebuffer) {
|
||||
}
|
||||
*result = 0;
|
||||
helper_->IsFramebuffer(framebuffer, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return GL_FALSE;
|
||||
+ }
|
||||
GLboolean result_value = *result != 0;
|
||||
GPU_CLIENT_LOG("returned " << result_value);
|
||||
CheckGLError();
|
||||
@@ -1578,7 +1620,9 @@ GLboolean GLES2Implementation::IsProgram(GLuint program) {
|
||||
}
|
||||
*result = 0;
|
||||
helper_->IsProgram(program, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return GL_FALSE;
|
||||
+ }
|
||||
GLboolean result_value = *result != 0;
|
||||
GPU_CLIENT_LOG("returned " << result_value);
|
||||
CheckGLError();
|
||||
@@ -1597,7 +1641,9 @@ GLboolean GLES2Implementation::IsRenderbuffer(GLuint renderbuffer) {
|
||||
}
|
||||
*result = 0;
|
||||
helper_->IsRenderbuffer(renderbuffer, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return GL_FALSE;
|
||||
+ }
|
||||
GLboolean result_value = *result != 0;
|
||||
GPU_CLIENT_LOG("returned " << result_value);
|
||||
CheckGLError();
|
||||
@@ -1615,7 +1661,9 @@ GLboolean GLES2Implementation::IsSampler(GLuint sampler) {
|
||||
}
|
||||
*result = 0;
|
||||
helper_->IsSampler(sampler, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return GL_FALSE;
|
||||
+ }
|
||||
GLboolean result_value = *result != 0;
|
||||
GPU_CLIENT_LOG("returned " << result_value);
|
||||
CheckGLError();
|
||||
@@ -1633,7 +1681,9 @@ GLboolean GLES2Implementation::IsShader(GLuint shader) {
|
||||
}
|
||||
*result = 0;
|
||||
helper_->IsShader(shader, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return GL_FALSE;
|
||||
+ }
|
||||
GLboolean result_value = *result != 0;
|
||||
GPU_CLIENT_LOG("returned " << result_value);
|
||||
CheckGLError();
|
||||
@@ -1651,7 +1701,9 @@ GLboolean GLES2Implementation::IsSync(GLsync sync) {
|
||||
}
|
||||
*result = 0;
|
||||
helper_->IsSync(ToGLuint(sync), GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return GL_FALSE;
|
||||
+ }
|
||||
GLboolean result_value = *result != 0;
|
||||
GPU_CLIENT_LOG("returned " << result_value);
|
||||
CheckGLError();
|
||||
@@ -1669,7 +1721,9 @@ GLboolean GLES2Implementation::IsTexture(GLuint texture) {
|
||||
}
|
||||
*result = 0;
|
||||
helper_->IsTexture(texture, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return GL_FALSE;
|
||||
+ }
|
||||
GLboolean result_value = *result != 0;
|
||||
GPU_CLIENT_LOG("returned " << result_value);
|
||||
CheckGLError();
|
||||
@@ -1689,7 +1743,9 @@ GLboolean GLES2Implementation::IsTransformFeedback(GLuint transformfeedback) {
|
||||
*result = 0;
|
||||
helper_->IsTransformFeedback(transformfeedback, GetResultShmId(),
|
||||
result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return GL_FALSE;
|
||||
+ }
|
||||
GLboolean result_value = *result != 0;
|
||||
GPU_CLIENT_LOG("returned " << result_value);
|
||||
CheckGLError();
|
||||
@@ -3093,7 +3149,9 @@ GLboolean GLES2Implementation::IsVertexArrayOES(GLuint array) {
|
||||
}
|
||||
*result = 0;
|
||||
helper_->IsVertexArrayOES(array, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return GL_FALSE;
|
||||
+ }
|
||||
GLboolean result_value = *result != 0;
|
||||
GPU_CLIENT_LOG("returned " << result_value);
|
||||
CheckGLError();
|
||||
@@ -3187,7 +3245,9 @@ void GLES2Implementation::GetProgramInterfaceiv(GLuint program,
|
||||
result->SetNumResults(0);
|
||||
helper_->GetProgramInterfaceiv(program, program_interface, pname,
|
||||
GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(params);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -3905,7 +3965,9 @@ void GLES2Implementation::GetFramebufferPixelLocalStorageParameterfvANGLE(
|
||||
result->SetNumResults(0);
|
||||
helper_->GetFramebufferPixelLocalStorageParameterfvANGLE(
|
||||
plane, pname, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(params);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
@@ -3939,7 +4001,9 @@ void GLES2Implementation::GetFramebufferPixelLocalStorageParameterivANGLE(
|
||||
result->SetNumResults(0);
|
||||
helper_->GetFramebufferPixelLocalStorageParameterivANGLE(
|
||||
plane, pname, GetResultShmId(), result.offset());
|
||||
- WaitForCmd();
|
||||
+ if (!WaitForCmd()) {
|
||||
+ return;
|
||||
+ }
|
||||
result->CopyResult(params);
|
||||
GPU_CLIENT_LOG_CODE_BLOCK({
|
||||
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
|
||||
106
patches/chromium/cherry-pick-24329fe5c4d0.patch
Normal file
106
patches/chromium/cherry-pick-24329fe5c4d0.patch
Normal file
@@ -0,0 +1,106 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Nidhi Jaju <nidhijaju@chromium.org>
|
||||
Date: Fri, 24 May 2024 01:26:02 +0000
|
||||
Subject: Streams: Check if buffer is detached when filling pull-into
|
||||
descriptor
|
||||
|
||||
The pull-into descriptor can become out-of-sync with the array buffer
|
||||
when the buffer is detached. This CL adds a check to see if the buffer
|
||||
is detached before trying to fill it.
|
||||
|
||||
(cherry picked from commit cd405492789ec4bc6ecd598754154c527ff60e95)
|
||||
|
||||
Bug: 339877167
|
||||
Change-Id: Ibf46a75e36dc739910db07f2e88ff9998c21e8a8
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5553232
|
||||
Reviewed-by: Domenic Denicola <domenic@chromium.org>
|
||||
Commit-Queue: Nidhi Jaju <nidhijaju@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1303628}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5553411
|
||||
Cr-Commit-Position: refs/branch-heads/6367@{#1228}
|
||||
Cr-Branched-From: d158c6dc6e3604e6f899041972edf26087a49740-refs/heads/main@{#1274542}
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc
|
||||
index 85e2214ca95790f547819e2a14628d342f7913bb..a844d84d20e68172e285cefe3301c49f3edfbd3a 100644
|
||||
--- a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc
|
||||
+++ b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc
|
||||
@@ -494,7 +494,8 @@ void ReadableByteStreamController::ProcessPullIntoDescriptorsUsingQueue(
|
||||
controller->pending_pull_intos_[0];
|
||||
// c. If ! ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(
|
||||
// controller, pullIntoDescriptor) is true,
|
||||
- if (FillPullIntoDescriptorFromQueue(controller, pull_into_descriptor)) {
|
||||
+ if (FillPullIntoDescriptorFromQueue(controller, pull_into_descriptor,
|
||||
+ exception_state)) {
|
||||
// i. Perform !
|
||||
// ReadableByteStreamControllerShiftPendingPullInto(controller).
|
||||
ShiftPendingPullInto(controller);
|
||||
@@ -505,6 +506,15 @@ void ReadableByteStreamController::ProcessPullIntoDescriptorsUsingQueue(
|
||||
pull_into_descriptor, exception_state);
|
||||
DCHECK(!exception_state.HadException());
|
||||
}
|
||||
+ if (exception_state.HadException()) {
|
||||
+ // Instead of returning a rejection, which is inconvenient here,
|
||||
+ // call ControllerError(). The only difference this makes is that it
|
||||
+ // happens synchronously, but that should not be observable.
|
||||
+ ReadableByteStreamController::Error(script_state, controller,
|
||||
+ exception_state.GetException());
|
||||
+ exception_state.ClearException();
|
||||
+ return;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -989,7 +999,12 @@ void ReadableByteStreamController::FillHeadPullIntoDescriptor(
|
||||
|
||||
bool ReadableByteStreamController::FillPullIntoDescriptorFromQueue(
|
||||
ReadableByteStreamController* controller,
|
||||
- PullIntoDescriptor* pull_into_descriptor) {
|
||||
+ PullIntoDescriptor* pull_into_descriptor,
|
||||
+ ExceptionState& exception_state) {
|
||||
+ if (pull_into_descriptor->buffer->IsDetached()) {
|
||||
+ exception_state.ThrowTypeError("buffer is detached");
|
||||
+ return false;
|
||||
+ }
|
||||
// https://streams.spec.whatwg.org/#readable-byte-stream-controller-fill-pull-into-descriptor-from-queue
|
||||
// 1. Let elementSize be pullIntoDescriptor.[[elementSize]].
|
||||
const size_t element_size = pull_into_descriptor->element_size;
|
||||
@@ -1240,7 +1255,8 @@ void ReadableByteStreamController::PullInto(
|
||||
// a. If !
|
||||
// ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller,
|
||||
// pullIntoDescriptor) is true,
|
||||
- if (FillPullIntoDescriptorFromQueue(controller, pull_into_descriptor)) {
|
||||
+ if (FillPullIntoDescriptorFromQueue(controller, pull_into_descriptor,
|
||||
+ exception_state)) {
|
||||
// i. Let filledView be !
|
||||
// ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor).
|
||||
DOMArrayBufferView* filled_view = ConvertPullIntoDescriptor(
|
||||
@@ -1254,6 +1270,15 @@ void ReadableByteStreamController::PullInto(
|
||||
// iv. Return.
|
||||
return;
|
||||
}
|
||||
+ if (exception_state.HadException()) {
|
||||
+ // Instead of returning a rejection, which is inconvenient here,
|
||||
+ // call ControllerError(). The only difference this makes is that it
|
||||
+ // happens synchronously, but that should not be observable.
|
||||
+ ReadableByteStreamController::Error(script_state, controller,
|
||||
+ exception_state.GetException());
|
||||
+ exception_state.ClearException();
|
||||
+ return;
|
||||
+ }
|
||||
// b. If controller.[[closeRequested]] is true,
|
||||
if (controller->close_requested_) {
|
||||
// i. Let e be a TypeError exception.
|
||||
diff --git a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h
|
||||
index aff7d589cef5a32f43e1dc0b06aa0d2921e39169..f31f660fddbc01d95dff904ad9ac5b1cf3ee8d86 100644
|
||||
--- a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h
|
||||
+++ b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h
|
||||
@@ -218,7 +218,8 @@ class CORE_EXPORT ReadableByteStreamController
|
||||
|
||||
// https://streams.spec.whatwg.org/#readable-byte-stream-controller-fill-pull-into-descriptor-from-queue
|
||||
static bool FillPullIntoDescriptorFromQueue(ReadableByteStreamController*,
|
||||
- PullIntoDescriptor*);
|
||||
+ PullIntoDescriptor*,
|
||||
+ ExceptionState&);
|
||||
|
||||
// https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontrollerfillreadrequestfromqueue
|
||||
static void FillReadRequestFromQueue(ScriptState*,
|
||||
89
patches/chromium/cherry-pick-b922fcb61e3b.patch
Normal file
89
patches/chromium/cherry-pick-b922fcb61e3b.patch
Normal file
@@ -0,0 +1,89 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: rubberyuzu <yuzus@chromium.org>
|
||||
Date: Fri, 17 May 2024 02:53:09 +0000
|
||||
Subject: Use WeakPtr for delegate_
|
||||
|
||||
This CL starts using a WeakPtr for `delegate_`. This is because
|
||||
`ReportFeaturesToDelegate()` is posted and when it's executed,
|
||||
`delegate_` might be destroyed.
|
||||
|
||||
(cherry picked from commit da7a6845e589dc71da9898f7e181a7c88a62e2e1)
|
||||
|
||||
Bug: 336012573
|
||||
Change-Id: I9aa5ee7ae7d484d4208e6bdd8ea2853763d69a6b
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5493004
|
||||
Reviewed-by: Kentaro Hara <haraken@chromium.org>
|
||||
Commit-Queue: Yuzu Saijo <yuzus@chromium.org>
|
||||
Reviewed-by: Fergal Daly <fergal@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1297242}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5547038
|
||||
Auto-Submit: Yuzu Saijo <yuzus@chromium.org>
|
||||
Commit-Queue: Kentaro Hara <haraken@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/6367@{#1190}
|
||||
Cr-Branched-From: d158c6dc6e3604e6f899041972edf26087a49740-refs/heads/main@{#1274542}
|
||||
|
||||
diff --git a/third_party/blink/renderer/platform/scheduler/common/back_forward_cache_disabling_feature_tracker.cc b/third_party/blink/renderer/platform/scheduler/common/back_forward_cache_disabling_feature_tracker.cc
|
||||
index e2f7dc1ff4384fa2e0dcb07539b269cdbb3f0c89..6bb65c49603e8efd3a84cabc6bf77a8a0fb359be 100644
|
||||
--- a/third_party/blink/renderer/platform/scheduler/common/back_forward_cache_disabling_feature_tracker.cc
|
||||
+++ b/third_party/blink/renderer/platform/scheduler/common/back_forward_cache_disabling_feature_tracker.cc
|
||||
@@ -22,9 +22,13 @@ BackForwardCacheDisablingFeatureTracker::
|
||||
|
||||
void BackForwardCacheDisablingFeatureTracker::SetDelegate(
|
||||
FrameOrWorkerScheduler::Delegate* delegate) {
|
||||
+ // This function is only called when initializing. `delegate_` should be
|
||||
+ // nullptr at first.
|
||||
DCHECK(!delegate_);
|
||||
- delegate_ = delegate;
|
||||
- // `delegate` might be nullptr on tests.
|
||||
+ // `delegate` can be nullptr for tests.
|
||||
+ if (delegate) {
|
||||
+ delegate_ = (*delegate).AsWeakPtr();
|
||||
+ }
|
||||
}
|
||||
|
||||
void BackForwardCacheDisablingFeatureTracker::Reset() {
|
||||
@@ -162,7 +166,13 @@ void BackForwardCacheDisablingFeatureTracker::ReportFeaturesToDelegate() {
|
||||
last_reported_sticky_ = sticky_features_and_js_locations_;
|
||||
FrameOrWorkerScheduler::Delegate::BlockingDetails details(
|
||||
non_sticky_features_and_js_locations_, sticky_features_and_js_locations_);
|
||||
- delegate_->UpdateBackForwardCacheDisablingFeatures(details);
|
||||
+
|
||||
+ // Check if the delegate still exists. This check is necessary because
|
||||
+ // `FrameOrWorkerScheduler::Delegate` might be destroyed and thus `delegate_`
|
||||
+ // might be gone when `ReportFeaturesToDelegate() is executed.
|
||||
+ if (delegate_) {
|
||||
+ delegate_->UpdateBackForwardCacheDisablingFeatures(details);
|
||||
+ }
|
||||
}
|
||||
|
||||
} // namespace scheduler
|
||||
diff --git a/third_party/blink/renderer/platform/scheduler/common/back_forward_cache_disabling_feature_tracker.h b/third_party/blink/renderer/platform/scheduler/common/back_forward_cache_disabling_feature_tracker.h
|
||||
index c78d791aa7c40a6775e84f79fd1a5e357328581e..1ec5cc4627cc71a941df32ecd989a5897f796dce 100644
|
||||
--- a/third_party/blink/renderer/platform/scheduler/common/back_forward_cache_disabling_feature_tracker.h
|
||||
+++ b/third_party/blink/renderer/platform/scheduler/common/back_forward_cache_disabling_feature_tracker.h
|
||||
@@ -119,8 +119,7 @@ class PLATFORM_EXPORT BackForwardCacheDisablingFeatureTracker {
|
||||
BFCacheBlockingFeatureAndLocations non_sticky_features_and_js_locations_;
|
||||
BFCacheBlockingFeatureAndLocations sticky_features_and_js_locations_;
|
||||
|
||||
- raw_ptr<FrameOrWorkerScheduler::Delegate, DanglingUntriaged> delegate_ =
|
||||
- nullptr;
|
||||
+ base::WeakPtr<FrameOrWorkerScheduler::Delegate> delegate_ = nullptr;
|
||||
raw_ptr<ThreadSchedulerBase, DanglingUntriaged> scheduler_;
|
||||
|
||||
base::WeakPtrFactory<BackForwardCacheDisablingFeatureTracker> weak_factory_{
|
||||
diff --git a/third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h b/third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h
|
||||
index 82befdeabdce4904002d6b35aaef8a796b613209..7f95ec0339cc2baabbae05a1a9b332e4dbc23bf5 100644
|
||||
--- a/third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h
|
||||
+++ b/third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h
|
||||
@@ -149,6 +149,11 @@ class PLATFORM_EXPORT FrameOrWorkerScheduler {
|
||||
// changed when a blocking feature and its JS location are registered or
|
||||
// removed.
|
||||
virtual void UpdateBackForwardCacheDisablingFeatures(BlockingDetails) = 0;
|
||||
+
|
||||
+ base::WeakPtr<Delegate> AsWeakPtr() {
|
||||
+ return weak_ptr_factory_.GetWeakPtr();
|
||||
+ }
|
||||
+ base::WeakPtrFactory<Delegate> weak_ptr_factory_{this};
|
||||
};
|
||||
|
||||
virtual ~FrameOrWorkerScheduler();
|
||||
@@ -0,0 +1,402 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shelley Vohr <shelley.vohr@gmail.com>
|
||||
Date: Sun, 5 May 2024 09:17:17 +0000
|
||||
Subject: feat: add support for missing dialog features to //shell_dialogs
|
||||
|
||||
This CL adds support for the following features to //shell_dialogs:
|
||||
* buttonLabel - Custom label for the confirmation button.
|
||||
* showHiddenFiles - Show hidden files in dialog.
|
||||
* showOverwriteConfirmation - Whether the user will be presented a confirmation dialog if the user types a file name that already exists.
|
||||
|
||||
This may be partially upstreamed to Chromium in the future.
|
||||
|
||||
diff --git a/ui/gtk/select_file_dialog_linux_gtk.cc b/ui/gtk/select_file_dialog_linux_gtk.cc
|
||||
index 38f8b2fa5ef4a8c86b9efa93d34dfb5ab1099c76..c1b5bd6cc2f31eee1f84cc57da58eba48576f139 100644
|
||||
--- a/ui/gtk/select_file_dialog_linux_gtk.cc
|
||||
+++ b/ui/gtk/select_file_dialog_linux_gtk.cc
|
||||
@@ -244,6 +244,10 @@ void SelectFileDialogLinuxGtk::SelectFileImpl(
|
||||
|
||||
std::string title_string = base::UTF16ToUTF8(title);
|
||||
|
||||
+ ExtraSettings extra_settings;
|
||||
+ if (params)
|
||||
+ extra_settings = *(static_cast<ExtraSettings*>(params));
|
||||
+
|
||||
set_file_type_index(file_type_index);
|
||||
if (file_types)
|
||||
set_file_types(*file_types);
|
||||
@@ -262,23 +266,23 @@ void SelectFileDialogLinuxGtk::SelectFileImpl(
|
||||
case SELECT_UPLOAD_FOLDER:
|
||||
case SELECT_EXISTING_FOLDER:
|
||||
dialog = CreateSelectFolderDialog(type, title_string, default_path,
|
||||
- owning_window);
|
||||
+ owning_window, extra_settings);
|
||||
connect("response",
|
||||
&SelectFileDialogLinuxGtk::OnSelectSingleFolderDialogResponse);
|
||||
break;
|
||||
case SELECT_OPEN_FILE:
|
||||
- dialog = CreateFileOpenDialog(title_string, default_path, owning_window);
|
||||
+ dialog = CreateFileOpenDialog(title_string, default_path, owning_window, extra_settings);
|
||||
connect("response",
|
||||
&SelectFileDialogLinuxGtk::OnSelectSingleFileDialogResponse);
|
||||
break;
|
||||
case SELECT_OPEN_MULTI_FILE:
|
||||
dialog =
|
||||
- CreateMultiFileOpenDialog(title_string, default_path, owning_window);
|
||||
+ CreateMultiFileOpenDialog(title_string, default_path, owning_window, extra_settings);
|
||||
connect("response",
|
||||
&SelectFileDialogLinuxGtk::OnSelectMultiFileDialogResponse);
|
||||
break;
|
||||
case SELECT_SAVEAS_FILE:
|
||||
- dialog = CreateSaveAsDialog(title_string, default_path, owning_window);
|
||||
+ dialog = CreateSaveAsDialog(title_string, default_path, owning_window, extra_settings);
|
||||
connect("response",
|
||||
&SelectFileDialogLinuxGtk::OnSelectSingleFileDialogResponse);
|
||||
break;
|
||||
@@ -413,10 +417,14 @@ void SelectFileDialogLinuxGtk::FileNotSelected(GtkWidget* dialog) {
|
||||
GtkWidget* SelectFileDialogLinuxGtk::CreateFileOpenHelper(
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
- gfx::NativeWindow parent) {
|
||||
+ gfx::NativeWindow parent,
|
||||
+ const ExtraSettings& settings) {
|
||||
+ const char* button_label = settings.button_label.empty()
|
||||
+ ? GetOpenLabel()
|
||||
+ : settings.button_label.c_str();
|
||||
GtkWidget* dialog = GtkFileChooserDialogNew(
|
||||
title.c_str(), nullptr, GTK_FILE_CHOOSER_ACTION_OPEN, GetCancelLabel(),
|
||||
- GTK_RESPONSE_CANCEL, GetOpenLabel(), GTK_RESPONSE_ACCEPT);
|
||||
+ GTK_RESPONSE_CANCEL, button_label, GTK_RESPONSE_ACCEPT);
|
||||
SetGtkTransientForAura(dialog, parent);
|
||||
AddFilters(GTK_FILE_CHOOSER(dialog));
|
||||
|
||||
@@ -432,6 +440,8 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateFileOpenHelper(
|
||||
GtkFileChooserSetCurrentFolder(GTK_FILE_CHOOSER(dialog),
|
||||
*last_opened_path());
|
||||
}
|
||||
+ gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dialog),
|
||||
+ settings.show_hidden);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@@ -439,7 +449,8 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSelectFolderDialog(
|
||||
Type type,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
- gfx::NativeWindow parent) {
|
||||
+ gfx::NativeWindow parent,
|
||||
+ const ExtraSettings& settings) {
|
||||
std::string title_string = title;
|
||||
if (title_string.empty()) {
|
||||
title_string =
|
||||
@@ -447,11 +458,14 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSelectFolderDialog(
|
||||
? l10n_util::GetStringUTF8(IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE)
|
||||
: l10n_util::GetStringUTF8(IDS_SELECT_FOLDER_DIALOG_TITLE);
|
||||
}
|
||||
- std::string accept_button_label =
|
||||
- (type == SELECT_UPLOAD_FOLDER)
|
||||
- ? l10n_util::GetStringUTF8(
|
||||
- IDS_SELECT_UPLOAD_FOLDER_DIALOG_UPLOAD_BUTTON)
|
||||
- : GetOpenLabel();
|
||||
+
|
||||
+ std::string accept_button_label = settings.button_label;
|
||||
+ if (accept_button_label.empty()) {
|
||||
+ accept_button_label = (type == SELECT_UPLOAD_FOLDER)
|
||||
+ ? l10n_util::GetStringUTF8(
|
||||
+ IDS_SELECT_UPLOAD_FOLDER_DIALOG_UPLOAD_BUTTON)
|
||||
+ : GetOpenLabel();
|
||||
+ }
|
||||
|
||||
GtkWidget* dialog = GtkFileChooserDialogNew(
|
||||
title_string.c_str(), nullptr, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
|
||||
@@ -473,19 +487,21 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSelectFolderDialog(
|
||||
gtk_file_filter_add_mime_type(only_folders, "inode/directory");
|
||||
gtk_file_filter_add_mime_type(only_folders, "text/directory");
|
||||
gtk_file_chooser_add_filter(chooser, only_folders);
|
||||
- gtk_file_chooser_set_select_multiple(chooser, FALSE);
|
||||
+ gtk_file_chooser_set_select_multiple(chooser, settings.allow_multiple_selection);
|
||||
+ gtk_file_chooser_set_show_hidden(chooser, settings.show_hidden);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
GtkWidget* SelectFileDialogLinuxGtk::CreateFileOpenDialog(
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
- gfx::NativeWindow parent) {
|
||||
+ gfx::NativeWindow parent,
|
||||
+ const ExtraSettings& settings) {
|
||||
std::string title_string =
|
||||
!title.empty() ? title
|
||||
: l10n_util::GetStringUTF8(IDS_OPEN_FILE_DIALOG_TITLE);
|
||||
|
||||
- GtkWidget* dialog = CreateFileOpenHelper(title_string, default_path, parent);
|
||||
+ GtkWidget* dialog = CreateFileOpenHelper(title_string, default_path, parent, settings);
|
||||
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE);
|
||||
return dialog;
|
||||
}
|
||||
@@ -493,12 +509,14 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateFileOpenDialog(
|
||||
GtkWidget* SelectFileDialogLinuxGtk::CreateMultiFileOpenDialog(
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
- gfx::NativeWindow parent) {
|
||||
+ gfx::NativeWindow parent,
|
||||
+ const ExtraSettings& settings) {
|
||||
std::string title_string =
|
||||
!title.empty() ? title
|
||||
: l10n_util::GetStringUTF8(IDS_OPEN_FILES_DIALOG_TITLE);
|
||||
|
||||
- GtkWidget* dialog = CreateFileOpenHelper(title_string, default_path, parent);
|
||||
+ GtkWidget* dialog =
|
||||
+ CreateFileOpenHelper(title_string, default_path, parent, settings);
|
||||
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
|
||||
return dialog;
|
||||
}
|
||||
@@ -506,14 +524,17 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateMultiFileOpenDialog(
|
||||
GtkWidget* SelectFileDialogLinuxGtk::CreateSaveAsDialog(
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
- gfx::NativeWindow parent) {
|
||||
+ gfx::NativeWindow parent,
|
||||
+ const ExtraSettings& settings) {
|
||||
std::string title_string =
|
||||
!title.empty() ? title
|
||||
: l10n_util::GetStringUTF8(IDS_SAVE_AS_DIALOG_TITLE);
|
||||
-
|
||||
+ const char* button_label = settings.button_label.empty()
|
||||
+ ? GetSaveLabel()
|
||||
+ : settings.button_label.c_str();
|
||||
GtkWidget* dialog = GtkFileChooserDialogNew(
|
||||
title_string.c_str(), nullptr, GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||
- GetCancelLabel(), GTK_RESPONSE_CANCEL, GetSaveLabel(),
|
||||
+ GetCancelLabel(), GTK_RESPONSE_CANCEL, button_label,
|
||||
GTK_RESPONSE_ACCEPT);
|
||||
SetGtkTransientForAura(dialog, parent);
|
||||
|
||||
@@ -539,9 +560,10 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSaveAsDialog(
|
||||
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE);
|
||||
// Overwrite confirmation is always enabled in GTK4.
|
||||
if (!GtkCheckVersion(4)) {
|
||||
- gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog),
|
||||
- TRUE);
|
||||
+ gtk_file_chooser_set_do_overwrite_confirmation(
|
||||
+ GTK_FILE_CHOOSER(dialog), settings.show_overwrite_confirmation);
|
||||
}
|
||||
+ gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dialog), settings.show_hidden);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
diff --git a/ui/gtk/select_file_dialog_linux_gtk.h b/ui/gtk/select_file_dialog_linux_gtk.h
|
||||
index 53ae15f14c45ee72abdae172fc4555c9e4b3ff9a..ee19c3f399a1d060d5e9bd0dc5f1b3828381e8df 100644
|
||||
--- a/ui/gtk/select_file_dialog_linux_gtk.h
|
||||
+++ b/ui/gtk/select_file_dialog_linux_gtk.h
|
||||
@@ -90,19 +90,23 @@ class SelectFileDialogLinuxGtk : public ui::SelectFileDialogLinux,
|
||||
GtkWidget* CreateSelectFolderDialog(Type type,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
- gfx::NativeWindow parent);
|
||||
+ gfx::NativeWindow parent,
|
||||
+ const ExtraSettings& settings);
|
||||
|
||||
GtkWidget* CreateFileOpenDialog(const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
- gfx::NativeWindow parent);
|
||||
+ gfx::NativeWindow parent,
|
||||
+ const ExtraSettings& settings);
|
||||
|
||||
GtkWidget* CreateMultiFileOpenDialog(const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
- gfx::NativeWindow parent);
|
||||
+ gfx::NativeWindow parent,
|
||||
+ const ExtraSettings& settings);
|
||||
|
||||
GtkWidget* CreateSaveAsDialog(const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
- gfx::NativeWindow parent);
|
||||
+ gfx::NativeWindow parent,
|
||||
+ const ExtraSettings& settings);
|
||||
|
||||
// Removes and returns the |params| associated with |dialog| from
|
||||
// |params_map_|.
|
||||
@@ -121,7 +125,8 @@ class SelectFileDialogLinuxGtk : public ui::SelectFileDialogLinux,
|
||||
// Common function for CreateFileOpenDialog and CreateMultiFileOpenDialog.
|
||||
GtkWidget* CreateFileOpenHelper(const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
- gfx::NativeWindow parent);
|
||||
+ gfx::NativeWindow parent,
|
||||
+ const ExtraSettings& settings);
|
||||
|
||||
// Callback for when the user responds to a Save As or Open File dialog.
|
||||
void OnSelectSingleFileDialogResponse(GtkWidget* dialog, int response_id);
|
||||
diff --git a/ui/shell_dialogs/select_file_dialog_linux.h b/ui/shell_dialogs/select_file_dialog_linux.h
|
||||
index 20ad001988831afca73315c577f90c824a36e282..57a8d35ace583eaafb526f70935d21c0f8fd1078 100644
|
||||
--- a/ui/shell_dialogs/select_file_dialog_linux.h
|
||||
+++ b/ui/shell_dialogs/select_file_dialog_linux.h
|
||||
@@ -26,6 +26,13 @@ class SHELL_DIALOGS_EXPORT SelectFileDialogLinux : public SelectFileDialog {
|
||||
SelectFileDialogLinux(const SelectFileDialogLinux&) = delete;
|
||||
SelectFileDialogLinux& operator=(const SelectFileDialogLinux&) = delete;
|
||||
|
||||
+ struct ExtraSettings {
|
||||
+ std::string button_label;
|
||||
+ bool show_overwrite_confirmation = true;
|
||||
+ bool show_hidden = false;
|
||||
+ bool allow_multiple_selection = false;
|
||||
+ };
|
||||
+
|
||||
// Returns true if the SelectFileDialog class returned by
|
||||
// NewSelectFileDialogImplKDE will actually work.
|
||||
static bool CheckKDEDialogWorksOnUIThread(std::string& kdialog_version);
|
||||
diff --git a/ui/shell_dialogs/select_file_dialog_linux_kde.cc b/ui/shell_dialogs/select_file_dialog_linux_kde.cc
|
||||
index 796e98cd42a5c6087da6cdf1d7bff4248113aeab..bcf43ab96bcb426fde6362dd0da4421758854449 100644
|
||||
--- a/ui/shell_dialogs/select_file_dialog_linux_kde.cc
|
||||
+++ b/ui/shell_dialogs/select_file_dialog_linux_kde.cc
|
||||
@@ -479,6 +479,9 @@ void SelectFileDialogLinuxKde::CreateSelectFolderDialog(
|
||||
int title_message_id = (type == SELECT_UPLOAD_FOLDER)
|
||||
? IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE
|
||||
: IDS_SELECT_FOLDER_DIALOG_TITLE;
|
||||
+ ExtraSettings extra_settings;
|
||||
+ if (params)
|
||||
+ extra_settings = *(static_cast<ExtraSettings*>(params));
|
||||
pipe_task_runner_->PostTaskAndReplyWithResult(
|
||||
FROM_HERE,
|
||||
base::BindOnce(
|
||||
@@ -486,7 +489,7 @@ void SelectFileDialogLinuxKde::CreateSelectFolderDialog(
|
||||
KDialogParams(
|
||||
"--getexistingdirectory", GetTitle(title, title_message_id),
|
||||
default_path.empty() ? *last_opened_path() : default_path, parent,
|
||||
- false, false)),
|
||||
+ false, extra_settings.allow_multiple_selection)),
|
||||
base::BindOnce(
|
||||
&SelectFileDialogLinuxKde::OnSelectSingleFolderDialogResponse, this,
|
||||
parent, params));
|
||||
diff --git a/ui/shell_dialogs/select_file_dialog_linux_portal.cc b/ui/shell_dialogs/select_file_dialog_linux_portal.cc
|
||||
index decba61300c21f7f5d070b24c23ff2e08b06d161..ae6e76186b6db9d0d32d51baaaeafa6106225c0f 100644
|
||||
--- a/ui/shell_dialogs/select_file_dialog_linux_portal.cc
|
||||
+++ b/ui/shell_dialogs/select_file_dialog_linux_portal.cc
|
||||
@@ -218,6 +218,10 @@ void SelectFileDialogLinuxPortal::SelectFileImpl(
|
||||
info_->main_task_runner = base::SequencedTaskRunner::GetCurrentDefault();
|
||||
listener_params_ = params;
|
||||
|
||||
+ ExtraSettings extra_settings;
|
||||
+ if (params)
|
||||
+ extra_settings = *(static_cast<ExtraSettings*>(params));
|
||||
+
|
||||
if (owning_window) {
|
||||
if (auto* root = owning_window->GetRootWindow()) {
|
||||
if (auto* host = root->GetNativeWindowProperty(
|
||||
@@ -245,7 +249,7 @@ void SelectFileDialogLinuxPortal::SelectFileImpl(
|
||||
host_->GetAcceleratedWidget(),
|
||||
base::BindOnce(
|
||||
&SelectFileDialogLinuxPortal::SelectFileImplWithParentHandle,
|
||||
- this, title, default_path, filter_set, default_extension))) {
|
||||
+ this, title, default_path, filter_set, default_extension, extra_settings))) {
|
||||
// Return early to skip the fallback below.
|
||||
return;
|
||||
} else {
|
||||
@@ -255,7 +259,7 @@ void SelectFileDialogLinuxPortal::SelectFileImpl(
|
||||
|
||||
// No parent, so just use a blank parent handle.
|
||||
SelectFileImplWithParentHandle(title, default_path, filter_set,
|
||||
- default_extension, "");
|
||||
+ default_extension, extra_settings, "");
|
||||
}
|
||||
|
||||
bool SelectFileDialogLinuxPortal::HasMultipleFileTypeChoicesImpl() {
|
||||
@@ -452,6 +456,7 @@ void SelectFileDialogLinuxPortal::SelectFileImplWithParentHandle(
|
||||
base::FilePath default_path,
|
||||
PortalFilterSet filter_set,
|
||||
base::FilePath::StringType default_extension,
|
||||
+ const ExtraSettings& settings,
|
||||
std::string parent_handle) {
|
||||
bool default_path_exists = CallDirectoryExistsOnUIThread(default_path);
|
||||
dbus_thread_linux::GetTaskRunner()->PostTask(
|
||||
@@ -460,7 +465,7 @@ void SelectFileDialogLinuxPortal::SelectFileImplWithParentHandle(
|
||||
&SelectFileDialogLinuxPortal::DialogInfo::SelectFileImplOnBusThread,
|
||||
info_, std::move(title), std::move(default_path), default_path_exists,
|
||||
std::move(filter_set), std::move(default_extension),
|
||||
- std::move(parent_handle)));
|
||||
+ std::move(parent_handle), std::move(settings)));
|
||||
}
|
||||
|
||||
void SelectFileDialogLinuxPortal::DialogInfo::SelectFileImplOnBusThread(
|
||||
@@ -469,7 +474,8 @@ void SelectFileDialogLinuxPortal::DialogInfo::SelectFileImplOnBusThread(
|
||||
const bool default_path_exists,
|
||||
PortalFilterSet filter_set,
|
||||
base::FilePath::StringType default_extension,
|
||||
- std::string parent_handle) {
|
||||
+ std::string parent_handle,
|
||||
+ const ExtraSettings& settings) {
|
||||
DCHECK(dbus_thread_linux::GetTaskRunner()->RunsTasksInCurrentSequence());
|
||||
dbus::Bus* bus = AcquireBusOnBusThread();
|
||||
if (!bus->Connect())
|
||||
@@ -515,7 +521,7 @@ void SelectFileDialogLinuxPortal::DialogInfo::SelectFileImplOnBusThread(
|
||||
base::StringPrintf("handle_%d", handle_token_counter_++);
|
||||
|
||||
AppendOptions(&writer, response_handle_token, default_path,
|
||||
- default_path_exists, filter_set);
|
||||
+ default_path_exists, filter_set, settings);
|
||||
|
||||
// The sender part of the handle object contains the D-Bus connection name
|
||||
// without the prefix colon and with all dots replaced with underscores.
|
||||
@@ -545,7 +551,8 @@ void SelectFileDialogLinuxPortal::DialogInfo::AppendOptions(
|
||||
const std::string& response_handle_token,
|
||||
const base::FilePath& default_path,
|
||||
const bool default_path_exists,
|
||||
- const SelectFileDialogLinuxPortal::PortalFilterSet& filter_set) {
|
||||
+ const SelectFileDialogLinuxPortal::PortalFilterSet& filter_set,
|
||||
+ const ExtraSettings& settings) {
|
||||
dbus::MessageWriter options_writer(nullptr);
|
||||
writer->OpenArray("{sv}", &options_writer);
|
||||
|
||||
@@ -553,8 +560,10 @@ void SelectFileDialogLinuxPortal::DialogInfo::AppendOptions(
|
||||
response_handle_token);
|
||||
|
||||
if (type == SelectFileDialog::Type::SELECT_UPLOAD_FOLDER) {
|
||||
- AppendStringOption(&options_writer, kFileChooserOptionAcceptLabel,
|
||||
- l10n_util::GetStringUTF8(
|
||||
+ const std::string accept_label = settings.button_label.empty()
|
||||
+ ? kFileChooserOptionAcceptLabel
|
||||
+ : settings.button_label;
|
||||
+ AppendStringOption(&options_writer, accept_label, l10n_util::GetStringUTF8(
|
||||
IDS_SELECT_UPLOAD_FOLDER_DIALOG_UPLOAD_BUTTON));
|
||||
}
|
||||
|
||||
@@ -562,6 +571,7 @@ void SelectFileDialogLinuxPortal::DialogInfo::AppendOptions(
|
||||
type == SelectFileDialog::Type::SELECT_UPLOAD_FOLDER ||
|
||||
type == SelectFileDialog::Type::SELECT_EXISTING_FOLDER) {
|
||||
AppendBoolOption(&options_writer, kFileChooserOptionDirectory, true);
|
||||
+ AppendBoolOption(&options_writer, kFileChooserOptionMultiple, settings.allow_multiple_selection);
|
||||
} else if (type == SelectFileDialog::Type::SELECT_OPEN_MULTI_FILE) {
|
||||
AppendBoolOption(&options_writer, kFileChooserOptionMultiple, true);
|
||||
}
|
||||
diff --git a/ui/shell_dialogs/select_file_dialog_linux_portal.h b/ui/shell_dialogs/select_file_dialog_linux_portal.h
|
||||
index 59de8f49a1626f34c8bb73c04098244bdccb9c3e..816b7b099be0859096aed2282446b0b2decfaa6a 100644
|
||||
--- a/ui/shell_dialogs/select_file_dialog_linux_portal.h
|
||||
+++ b/ui/shell_dialogs/select_file_dialog_linux_portal.h
|
||||
@@ -115,7 +115,8 @@ class SelectFileDialogLinuxPortal : public SelectFileDialogLinux {
|
||||
const bool default_path_exists,
|
||||
PortalFilterSet filter_set,
|
||||
base::FilePath::StringType default_extension,
|
||||
- std::string parent_handle);
|
||||
+ std::string parent_handle,
|
||||
+ const ExtraSettings& settings);
|
||||
Type type;
|
||||
// The task runner the SelectFileImpl method was called on.
|
||||
scoped_refptr<base::SequencedTaskRunner> main_task_runner;
|
||||
@@ -143,7 +144,8 @@ class SelectFileDialogLinuxPortal : public SelectFileDialogLinux {
|
||||
const std::string& response_handle_token,
|
||||
const base::FilePath& default_path,
|
||||
const bool derfault_path_exists,
|
||||
- const PortalFilterSet& filter_set);
|
||||
+ const PortalFilterSet& filter_set,
|
||||
+ const ExtraSettings& settings);
|
||||
void AppendFilterStruct(dbus::MessageWriter* writer,
|
||||
const PortalFilter& filter);
|
||||
std::vector<base::FilePath> ConvertUrisToPaths(
|
||||
@@ -190,6 +192,7 @@ class SelectFileDialogLinuxPortal : public SelectFileDialogLinux {
|
||||
base::FilePath default_path,
|
||||
PortalFilterSet filter_set,
|
||||
base::FilePath::StringType default_extension,
|
||||
+ const ExtraSettings& settings,
|
||||
std::string parent_handle);
|
||||
|
||||
void DialogCreatedOnMainThread();
|
||||
@@ -0,0 +1,136 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shelley Vohr <shelley.vohr@gmail.com>
|
||||
Date: Tue, 28 May 2024 10:44:06 +0200
|
||||
Subject: feat: enable passing exit code on service process crash
|
||||
|
||||
This patch enables plumbing the exit code of the service process to the
|
||||
browser process when the service process crashes. The process can perform cleanup
|
||||
after the message pipe disconnection, which previously led to racy and incorrect
|
||||
exit codes in some crashing scenarios. To mitigate this, we can rely on
|
||||
ServiceProcessHost::Observer functions, but we need to pass the exit code to
|
||||
the observer.
|
||||
|
||||
diff --git a/content/browser/service_process_host_impl.cc b/content/browser/service_process_host_impl.cc
|
||||
index 75d7bc00759226859af635d66cdfbc3dd565b4a2..6f952e56348f3bf4cd0ddbae2d4bf74dd680ed8a 100644
|
||||
--- a/content/browser/service_process_host_impl.cc
|
||||
+++ b/content/browser/service_process_host_impl.cc
|
||||
@@ -77,12 +77,15 @@ class ServiceProcessTracker {
|
||||
processes_.erase(iter);
|
||||
}
|
||||
|
||||
- void NotifyCrashed(ServiceProcessId id) {
|
||||
+ void NotifyCrashed(ServiceProcessId id, int exit_code) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
auto iter = processes_.find(id);
|
||||
DCHECK(iter != processes_.end());
|
||||
- for (auto& observer : observers_)
|
||||
- observer.OnServiceProcessCrashed(iter->second.Duplicate());
|
||||
+ for (auto& observer : observers_) {
|
||||
+ auto params = iter->second.Duplicate();
|
||||
+ params.set_exit_code(exit_code);
|
||||
+ observer.OnServiceProcessCrashed(params);
|
||||
+ }
|
||||
processes_.erase(iter);
|
||||
}
|
||||
|
||||
@@ -91,6 +94,11 @@ class ServiceProcessTracker {
|
||||
observers_.AddObserver(observer);
|
||||
}
|
||||
|
||||
+ bool HasObserver(ServiceProcessHost::Observer* observer) {
|
||||
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
+ return observers_.HasObserver(observer);
|
||||
+ }
|
||||
+
|
||||
void RemoveObserver(ServiceProcessHost::Observer* observer) {
|
||||
// NOTE: Some tests may remove observers after BrowserThreads are shut down.
|
||||
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
|
||||
@@ -158,7 +166,7 @@ class UtilityProcessClient : public UtilityProcessHost::Client {
|
||||
process_info_->service_process_id());
|
||||
}
|
||||
|
||||
- void OnProcessCrashed() override {
|
||||
+ void OnProcessCrashed(int exit_code) override {
|
||||
// TODO(https://crbug.com/1016027): It is unclear how we can observe
|
||||
// |OnProcessCrashed()| without observing |OnProcessLaunched()| first, but
|
||||
// it can happen on Android. Ignore the notification in this case.
|
||||
@@ -166,7 +174,7 @@ class UtilityProcessClient : public UtilityProcessHost::Client {
|
||||
return;
|
||||
|
||||
GetServiceProcessTracker().NotifyCrashed(
|
||||
- process_info_->service_process_id());
|
||||
+ process_info_->service_process_id(), exit_code);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -233,6 +241,11 @@ void ServiceProcessHost::AddObserver(Observer* observer) {
|
||||
GetServiceProcessTracker().AddObserver(observer);
|
||||
}
|
||||
|
||||
+// static
|
||||
+bool ServiceProcessHost::HasObserver(Observer* observer) {
|
||||
+ return GetServiceProcessTracker().HasObserver(observer);
|
||||
+}
|
||||
+
|
||||
// static
|
||||
void ServiceProcessHost::RemoveObserver(Observer* observer) {
|
||||
GetServiceProcessTracker().RemoveObserver(observer);
|
||||
diff --git a/content/browser/utility_process_host.cc b/content/browser/utility_process_host.cc
|
||||
index e7f30e95727137fc54f8493dfa8eb36b74fbdcb4..51d60ffdabb72f0448d67667813d6fe006a1b3e0 100644
|
||||
--- a/content/browser/utility_process_host.cc
|
||||
+++ b/content/browser/utility_process_host.cc
|
||||
@@ -549,7 +549,7 @@ void UtilityProcessHost::OnProcessCrashed(int exit_code) {
|
||||
// Take ownership of |client_| so the destructor doesn't notify it of
|
||||
// termination.
|
||||
auto client = std::move(client_);
|
||||
- client->OnProcessCrashed();
|
||||
+ client->OnProcessCrashed(exit_code);
|
||||
}
|
||||
|
||||
std::optional<std::string> UtilityProcessHost::GetServiceName() {
|
||||
diff --git a/content/browser/utility_process_host.h b/content/browser/utility_process_host.h
|
||||
index 9bfc30138a01520d59760a49d15dd4819feb0556..1107ad8691869d37196ea9d8dd29ef53e0a7ae10 100644
|
||||
--- a/content/browser/utility_process_host.h
|
||||
+++ b/content/browser/utility_process_host.h
|
||||
@@ -84,7 +84,7 @@ class CONTENT_EXPORT UtilityProcessHost
|
||||
|
||||
virtual void OnProcessLaunched(const base::Process& process) {}
|
||||
virtual void OnProcessTerminatedNormally() {}
|
||||
- virtual void OnProcessCrashed() {}
|
||||
+ virtual void OnProcessCrashed(int exit_code) {}
|
||||
};
|
||||
|
||||
// This class is self-owned. It must be instantiated using new, and shouldn't
|
||||
diff --git a/content/public/browser/service_process_host.h b/content/public/browser/service_process_host.h
|
||||
index 8efbbd030729276114c40b33ee72822b02444a84..bf9325406c7358a3dce4f56d0f66acc0871190cc 100644
|
||||
--- a/content/public/browser/service_process_host.h
|
||||
+++ b/content/public/browser/service_process_host.h
|
||||
@@ -231,6 +231,10 @@ class CONTENT_EXPORT ServiceProcessHost {
|
||||
// removed before destruction. Must be called from the UI thread only.
|
||||
static void AddObserver(Observer* observer);
|
||||
|
||||
+ // Returns true if the given observer is currently registered.
|
||||
+ // Must be called from the UI thread only.
|
||||
+ static bool HasObserver(Observer* observer);
|
||||
+
|
||||
// Removes a registered observer. This must be called some time before
|
||||
// |*observer| is destroyed and must be called from the UI thread only.
|
||||
static void RemoveObserver(Observer* observer);
|
||||
diff --git a/content/public/browser/service_process_info.h b/content/public/browser/service_process_info.h
|
||||
index 1a8656aef341cd3b23af588fb00569b79d6cd100..f904af7ee6bbacf4474e0939855ecf9f2c9a5eaa 100644
|
||||
--- a/content/public/browser/service_process_info.h
|
||||
+++ b/content/public/browser/service_process_info.h
|
||||
@@ -64,7 +64,13 @@ class CONTENT_EXPORT ServiceProcessInfo {
|
||||
const std::optional<GURL>& site() const { return site_; }
|
||||
const base::Process& GetProcess() const { return process_; }
|
||||
|
||||
+ void set_exit_code(int exit_code) { exit_code_ = exit_code; }
|
||||
+ int exit_code() const { return exit_code_; }
|
||||
+
|
||||
private:
|
||||
+ // The exit code of the process, if it has exited.
|
||||
+ int exit_code_;
|
||||
+
|
||||
// The name of the service interface for which the process was launched.
|
||||
std::string service_interface_name_;
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zakhar Voit <voit@google.com>
|
||||
Date: Fri, 7 Jun 2024 11:26:03 +0000
|
||||
Subject: MediaSession: Use a MediaSessionImpl WeakPtr in
|
||||
MediaSessionServiceImpl
|
||||
|
||||
Currently, every time MediaSessionServiceImpl wants to talk to its
|
||||
associated MediaSessionImpl, it recalculates it from its
|
||||
RenderFrameHostId. This can lead to issues where a
|
||||
MediaSessionServiceImpl of a disconnected RenderFrameHost can no longer
|
||||
access the MediaSessionImpl to tell it that it is being deleted,
|
||||
leaving MediaSessionImpl with a dangling raw_ptr.
|
||||
|
||||
(cherry picked from commit 1f0de3303671c6c041930c7f4f8a9ad017a7f211)
|
||||
|
||||
(cherry picked from commit 11c5f7911caab6930812a515eac27e35776ba35c)
|
||||
|
||||
Bug: 338929744
|
||||
Change-Id: I092d217d4a975b67a84280687ed5461a14ead98a
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5577944
|
||||
Commit-Queue: Tommy Steimel <steimel@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/branch-heads/6367@{#1245}
|
||||
Cr-Original-Branched-From: d158c6dc6e3604e6f899041972edf26087a49740-refs/heads/main@{#1274542}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5583452
|
||||
Owners-Override: Michael Ershov <miersh@google.com>
|
||||
Commit-Queue: Michael Ershov <miersh@google.com>
|
||||
Reviewed-by: Dale Curtis <dalecurtis@chromium.org>
|
||||
Reviewed-by: Michael Ershov <miersh@google.com>
|
||||
Cr-Commit-Position: refs/branch-heads/6099@{#2035}
|
||||
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
|
||||
|
||||
diff --git a/content/browser/media/session/media_session_impl.cc b/content/browser/media/session/media_session_impl.cc
|
||||
index 5ccef5240eef2e3b5c82bc50b97331e1b2fb9f31..710aeb26aee5bcfd95fef96fc7b8be7aa27173ad 100644
|
||||
--- a/content/browser/media/session/media_session_impl.cc
|
||||
+++ b/content/browser/media/session/media_session_impl.cc
|
||||
@@ -1669,6 +1669,10 @@ const base::UnguessableToken& MediaSessionImpl::GetRequestId() const {
|
||||
return delegate_->request_id();
|
||||
}
|
||||
|
||||
+base::WeakPtr<MediaSessionImpl> MediaSessionImpl::GetWeakPtr() {
|
||||
+ return weak_factory_.GetWeakPtr();
|
||||
+}
|
||||
+
|
||||
void MediaSessionImpl::RebuildAndNotifyActionsChanged() {
|
||||
std::set<media_session::mojom::MediaSessionAction> actions =
|
||||
routed_service_ ? routed_service_->actions()
|
||||
diff --git a/content/browser/media/session/media_session_impl.h b/content/browser/media/session/media_session_impl.h
|
||||
index 1f30f99fdd94617e3ddb8fb701c01201fbebf9df..af0f967b45e52778837ea716bc8290c6c0e20a6a 100644
|
||||
--- a/content/browser/media/session/media_session_impl.h
|
||||
+++ b/content/browser/media/session/media_session_impl.h
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "base/containers/id_map.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/memory/raw_ptr_exclusion.h"
|
||||
+#include "base/memory/weak_ptr.h"
|
||||
#include "base/timer/timer.h"
|
||||
#include "build/build_config.h"
|
||||
#include "content/browser/media/session/audio_focus_delegate.h"
|
||||
@@ -346,6 +347,9 @@ class MediaSessionImpl : public MediaSession,
|
||||
// Returns the Audio Focus request ID associated with this media session.
|
||||
const base::UnguessableToken& GetRequestId() const;
|
||||
|
||||
+ // Returns a WeakPtr to `this`.
|
||||
+ base::WeakPtr<MediaSessionImpl> GetWeakPtr();
|
||||
+
|
||||
CONTENT_EXPORT bool HasImageCacheForTest(const GURL& image_url) const;
|
||||
|
||||
// Make sure that all observers have received any pending callbacks from us,
|
||||
@@ -641,6 +645,8 @@ class MediaSessionImpl : public MediaSession,
|
||||
|
||||
media_session::mojom::RemotePlaybackMetadataPtr remote_playback_metadata_;
|
||||
|
||||
+ base::WeakPtrFactory<MediaSessionImpl> weak_factory_{this};
|
||||
+
|
||||
WEB_CONTENTS_USER_DATA_KEY_DECL();
|
||||
};
|
||||
|
||||
diff --git a/content/browser/media/session/media_session_service_impl.cc b/content/browser/media/session/media_session_service_impl.cc
|
||||
index 532d1161b5321fbe37552f1caca2d20782356f36..a3ca009421a22d51a9d85f4665dd769319d26c22 100644
|
||||
--- a/content/browser/media/session/media_session_service_impl.cc
|
||||
+++ b/content/browser/media/session/media_session_service_impl.cc
|
||||
@@ -22,14 +22,16 @@ MediaSessionServiceImpl::MediaSessionServiceImpl(
|
||||
: render_frame_host_id_(render_frame_host->GetGlobalId()),
|
||||
playback_state_(blink::mojom::MediaSessionPlaybackState::NONE) {
|
||||
MediaSessionImpl* session = GetMediaSession();
|
||||
- if (session)
|
||||
- session->OnServiceCreated(this);
|
||||
+ if (session) {
|
||||
+ media_session_ = session->GetWeakPtr();
|
||||
+ media_session_->OnServiceCreated(this);
|
||||
+ }
|
||||
}
|
||||
|
||||
MediaSessionServiceImpl::~MediaSessionServiceImpl() {
|
||||
- MediaSessionImpl* session = GetMediaSession();
|
||||
- if (session)
|
||||
- session->OnServiceDestroyed(this);
|
||||
+ if (media_session_) {
|
||||
+ media_session_->OnServiceDestroyed(this);
|
||||
+ }
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -70,17 +72,17 @@ void MediaSessionServiceImpl::SetClient(
|
||||
void MediaSessionServiceImpl::SetPlaybackState(
|
||||
blink::mojom::MediaSessionPlaybackState state) {
|
||||
playback_state_ = state;
|
||||
- MediaSessionImpl* session = GetMediaSession();
|
||||
- if (session)
|
||||
- session->OnMediaSessionPlaybackStateChanged(this);
|
||||
+ if (media_session_) {
|
||||
+ media_session_->OnMediaSessionPlaybackStateChanged(this);
|
||||
+ }
|
||||
}
|
||||
|
||||
void MediaSessionServiceImpl::SetPositionState(
|
||||
const std::optional<media_session::MediaPosition>& position) {
|
||||
position_ = position;
|
||||
- MediaSessionImpl* session = GetMediaSession();
|
||||
- if (session)
|
||||
- session->RebuildAndNotifyMediaPositionChanged();
|
||||
+ if (media_session_) {
|
||||
+ media_session_->RebuildAndNotifyMediaPositionChanged();
|
||||
+ }
|
||||
}
|
||||
|
||||
void MediaSessionServiceImpl::SetMetadata(
|
||||
@@ -102,48 +104,48 @@ void MediaSessionServiceImpl::SetMetadata(
|
||||
metadata_ = std::move(metadata);
|
||||
}
|
||||
|
||||
- MediaSessionImpl* session = GetMediaSession();
|
||||
- if (session)
|
||||
- session->OnMediaSessionMetadataChanged(this);
|
||||
+ if (media_session_) {
|
||||
+ media_session_->OnMediaSessionMetadataChanged(this);
|
||||
+ }
|
||||
}
|
||||
|
||||
void MediaSessionServiceImpl::SetMicrophoneState(
|
||||
media_session::mojom::MicrophoneState microphone_state) {
|
||||
microphone_state_ = microphone_state;
|
||||
- MediaSessionImpl* session = GetMediaSession();
|
||||
- if (session)
|
||||
- session->OnMediaSessionInfoChanged(this);
|
||||
+ if (media_session_) {
|
||||
+ media_session_->OnMediaSessionInfoChanged(this);
|
||||
+ }
|
||||
}
|
||||
|
||||
void MediaSessionServiceImpl::SetCameraState(
|
||||
media_session::mojom::CameraState camera_state) {
|
||||
camera_state_ = camera_state;
|
||||
- MediaSessionImpl* session = GetMediaSession();
|
||||
- if (session)
|
||||
- session->OnMediaSessionInfoChanged(this);
|
||||
+ if (media_session_) {
|
||||
+ media_session_->OnMediaSessionInfoChanged(this);
|
||||
+ }
|
||||
}
|
||||
|
||||
void MediaSessionServiceImpl::EnableAction(
|
||||
media_session::mojom::MediaSessionAction action) {
|
||||
actions_.insert(action);
|
||||
- MediaSessionImpl* session = GetMediaSession();
|
||||
- if (session)
|
||||
- session->OnMediaSessionActionsChanged(this);
|
||||
+ if (media_session_) {
|
||||
+ media_session_->OnMediaSessionActionsChanged(this);
|
||||
+ }
|
||||
}
|
||||
|
||||
void MediaSessionServiceImpl::DisableAction(
|
||||
media_session::mojom::MediaSessionAction action) {
|
||||
actions_.erase(action);
|
||||
- MediaSessionImpl* session = GetMediaSession();
|
||||
- if (session)
|
||||
- session->OnMediaSessionActionsChanged(this);
|
||||
+ if (media_session_) {
|
||||
+ media_session_->OnMediaSessionActionsChanged(this);
|
||||
+ }
|
||||
}
|
||||
|
||||
void MediaSessionServiceImpl::ClearActions() {
|
||||
actions_.clear();
|
||||
- MediaSessionImpl* session = GetMediaSession();
|
||||
- if (session)
|
||||
- session->OnMediaSessionActionsChanged(this);
|
||||
+ if (media_session_) {
|
||||
+ media_session_->OnMediaSessionActionsChanged(this);
|
||||
+ }
|
||||
}
|
||||
|
||||
MediaSessionImpl* MediaSessionServiceImpl::GetMediaSession() {
|
||||
diff --git a/content/browser/media/session/media_session_service_impl.h b/content/browser/media/session/media_session_service_impl.h
|
||||
index 4eeffe2a8bbc532d15e5deb7bc77eebea41326cf..514c043648e70b3c29a57ddc5faabaf85e103491 100644
|
||||
--- a/content/browser/media/session/media_session_service_impl.h
|
||||
+++ b/content/browser/media/session/media_session_service_impl.h
|
||||
@@ -85,6 +85,8 @@ class CONTENT_EXPORT MediaSessionServiceImpl
|
||||
|
||||
const GlobalRenderFrameHostId render_frame_host_id_;
|
||||
|
||||
+ base::WeakPtr<MediaSessionImpl> media_session_;
|
||||
+
|
||||
mojo::Remote<blink::mojom::MediaSessionClient> client_;
|
||||
blink::mojom::MediaSessionPlaybackState playback_state_;
|
||||
blink::mojom::SpecMediaMetadataPtr metadata_;
|
||||
@@ -1,13 +1,13 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: deepak1556 <hop2deep@gmail.com>
|
||||
Date: Thu, 7 Apr 2022 20:30:16 +0900
|
||||
Subject: Make gtk::GetLibGtk and gtk::GetLibGdkPixbuf public
|
||||
Subject: Make gtk::GetLibGdkPixbuf public
|
||||
|
||||
Allows embedders to get a handle to the gtk and
|
||||
gdk_pixbuf libraries already loaded in the process.
|
||||
Allows embedders to get a handle to the gdk_pixbuf
|
||||
library already loaded in the process.
|
||||
|
||||
diff --git a/ui/gtk/gtk_compat.cc b/ui/gtk/gtk_compat.cc
|
||||
index d196e304a43191b6dc82f25b0b4bf24d242edb3c..85d618efa0574b00fc0cb1e5bde5ed725b2a90ab 100644
|
||||
index d196e304a43191b6dc82f25b0b4bf24d242edb3c..0156ed1c3e8e1de8ce875ca9a17e69358074743e 100644
|
||||
--- a/ui/gtk/gtk_compat.cc
|
||||
+++ b/ui/gtk/gtk_compat.cc
|
||||
@@ -66,11 +66,6 @@ void* GetLibGio() {
|
||||
@@ -22,20 +22,7 @@ index d196e304a43191b6dc82f25b0b4bf24d242edb3c..85d618efa0574b00fc0cb1e5bde5ed72
|
||||
void* GetLibGdk3() {
|
||||
static void* libgdk3 = DlOpen("libgdk-3.so.0");
|
||||
return libgdk3;
|
||||
@@ -86,12 +81,6 @@ void* GetLibGtk4(bool check = true) {
|
||||
return libgtk4;
|
||||
}
|
||||
|
||||
-void* GetLibGtk() {
|
||||
- if (GtkCheckVersion(4))
|
||||
- return GetLibGtk4();
|
||||
- return GetLibGtk3();
|
||||
-}
|
||||
-
|
||||
bool LoadGtk3() {
|
||||
if (!GetLibGtk3(false))
|
||||
return false;
|
||||
@@ -134,6 +123,17 @@ gfx::Insets InsetsFromGtkBorder(const GtkBorder& border) {
|
||||
@@ -134,6 +129,11 @@ gfx::Insets InsetsFromGtkBorder(const GtkBorder& border) {
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -43,29 +30,20 @@ index d196e304a43191b6dc82f25b0b4bf24d242edb3c..85d618efa0574b00fc0cb1e5bde5ed72
|
||||
+ static void* libgdk_pixbuf = DlOpen("libgdk_pixbuf-2.0.so.0");
|
||||
+ return libgdk_pixbuf;
|
||||
+}
|
||||
+
|
||||
+void* GetLibGtk() {
|
||||
+ if (GtkCheckVersion(4))
|
||||
+ return GetLibGtk4();
|
||||
+ return GetLibGtk3();
|
||||
+}
|
||||
+
|
||||
bool LoadGtk() {
|
||||
static bool loaded = LoadGtkImpl();
|
||||
return loaded;
|
||||
diff --git a/ui/gtk/gtk_compat.h b/ui/gtk/gtk_compat.h
|
||||
index 409e385fc952662c9887d9a810bb3c547c5be282..1518b681f98b3bc051aed74713a23c016c7b755e 100644
|
||||
index 409e385fc952662c9887d9a810bb3c547c5be282..579ac4f6a39654f1e58ed0eb165c2773e5620475 100644
|
||||
--- a/ui/gtk/gtk_compat.h
|
||||
+++ b/ui/gtk/gtk_compat.h
|
||||
@@ -40,6 +40,12 @@ using SkColor = uint32_t;
|
||||
@@ -40,6 +40,9 @@ using SkColor = uint32_t;
|
||||
|
||||
namespace gtk {
|
||||
|
||||
+// Get handle to the currently loaded gdk_pixbuf library in the process.
|
||||
+void* GetLibGdkPixbuf();
|
||||
+
|
||||
+// Get handle to the currently loaded gtk library in the process.
|
||||
+void* GetLibGtk();
|
||||
+
|
||||
// Loads libgtk and related libraries and returns true on success.
|
||||
bool LoadGtk();
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tom Anderson <thomasanderson@chromium.org>
|
||||
Date: Tue, 27 Feb 2024 00:35:14 +0000
|
||||
Subject: Fix crash when RandR::GetMonitors fails
|
||||
|
||||
R=sky
|
||||
|
||||
Change-Id: Id3c01221cec6edb4b782a273653758c1375c0acb
|
||||
Fixed: 326328413
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5324886
|
||||
Commit-Queue: Scott Violet <sky@chromium.org>
|
||||
Reviewed-by: Scott Violet <sky@chromium.org>
|
||||
Auto-Submit: Thomas Anderson <thomasanderson@chromium.org>
|
||||
Commit-Queue: Thomas Anderson <thomasanderson@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#1265556}
|
||||
|
||||
diff --git a/ui/base/x/x11_display_util.cc b/ui/base/x/x11_display_util.cc
|
||||
index bf3077d80fc0ce31f381d5ff1defef16cfdbee0a..fda1c3cb239210ac7efbf0aa2311548d0142c413 100644
|
||||
--- a/ui/base/x/x11_display_util.cc
|
||||
+++ b/ui/base/x/x11_display_util.cc
|
||||
@@ -44,6 +44,9 @@ constexpr const char kRandrEdidProperty[] = "EDID";
|
||||
std::map<x11::RandR::Output, size_t> GetMonitors(
|
||||
const x11::Response<x11::RandR::GetMonitorsReply>& reply) {
|
||||
std::map<x11::RandR::Output, size_t> output_to_monitor;
|
||||
+ if (!reply) {
|
||||
+ return output_to_monitor;
|
||||
+ }
|
||||
for (size_t monitor = 0; monitor < reply->monitors.size(); monitor++) {
|
||||
for (x11::RandR::Output output : reply->monitors[monitor].outputs) {
|
||||
output_to_monitor[output] = monitor;
|
||||
@@ -0,0 +1,62 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: deepak1556 <hop2deep@gmail.com>
|
||||
Date: Mon, 17 Jun 2024 18:05:47 +0000
|
||||
Subject: Use localized display label only for browser process
|
||||
|
||||
With https://crrev.com/c/5098130, GetPrimaryDisplayRefreshIntervalFromXrandr uses BuildDisplaysFromXRandRInfo
|
||||
to calculate the primary display frequency. In software compositing mode --disable-gpu-compositing,
|
||||
this code path will be called from the gpu process via SoftwareOutputSurface::SwapBuffers and
|
||||
can trigger a crash when attempting to set localized string. This is because on linux,
|
||||
gpu process does not have access to the resource bundle.
|
||||
|
||||
Bug: none
|
||||
Change-Id: I9d66b98c07a1a8671369546d4fc685213904a84f
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5631219
|
||||
Auto-Submit: Deepak Mohan (Robo) <hop2deep@gmail.com>
|
||||
Reviewed-by: Thomas Anderson <thomasanderson@chromium.org>
|
||||
Reviewed-by: Scott Violet <sky@chromium.org>
|
||||
Commit-Queue: Scott Violet <sky@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#1315980}
|
||||
|
||||
diff --git a/ui/base/x/x11_display_util.cc b/ui/base/x/x11_display_util.cc
|
||||
index 373be9bfad6766b8ba50140418263fa14c295689..bf3077d80fc0ce31f381d5ff1defef16cfdbee0a 100644
|
||||
--- a/ui/base/x/x11_display_util.cc
|
||||
+++ b/ui/base/x/x11_display_util.cc
|
||||
@@ -294,6 +294,7 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo(
|
||||
const DisplayConfig& display_config,
|
||||
size_t* primary_display_index_out) {
|
||||
DCHECK(primary_display_index_out);
|
||||
+ auto* command_line = base::CommandLine::ForCurrentProcess();
|
||||
const float primary_scale = display_config.primary_scale;
|
||||
|
||||
auto* connection = x11::Connection::Get();
|
||||
@@ -343,7 +344,7 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo(
|
||||
connection->Flush();
|
||||
|
||||
std::vector<x11::Future<x11::GetPropertyReply>> icc_futures{n_iccs};
|
||||
- if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kHeadless)) {
|
||||
+ if (!command_line->HasSwitch(switches::kHeadless)) {
|
||||
for (size_t monitor = 0; monitor < n_iccs; ++monitor) {
|
||||
icc_futures[monitor] = GetIccProfileFuture(connection, monitor);
|
||||
}
|
||||
@@ -441,11 +442,18 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo(
|
||||
}
|
||||
|
||||
const std::string name(output_info->name.begin(), output_info->name.end());
|
||||
+ auto process_type =
|
||||
+ command_line->GetSwitchValueASCII("type");
|
||||
if (base::StartsWith(name, "eDP") || base::StartsWith(name, "LVDS")) {
|
||||
display::SetInternalDisplayIds({display_id});
|
||||
- // Use localized variant of "Built-in display" for internal displays.
|
||||
+ // For browser process which has access to resource bundle,
|
||||
+ // use localized variant of "Built-in display" for internal displays.
|
||||
// This follows the ozone DRM behavior (i.e. ChromeOS).
|
||||
- display.set_label(l10n_util::GetStringUTF8(IDS_DISPLAY_NAME_INTERNAL));
|
||||
+ if (process_type.empty()) {
|
||||
+ display.set_label(l10n_util::GetStringUTF8(IDS_DISPLAY_NAME_INTERNAL));
|
||||
+ } else {
|
||||
+ display.set_label("Built-in display");
|
||||
+ }
|
||||
} else {
|
||||
display.set_label(edid_parser.display_name());
|
||||
}
|
||||
@@ -13,5 +13,7 @@
|
||||
{ "patch_dir": "src/electron/patches/webrtc", "repo": "src/third_party/webrtc" },
|
||||
{ "patch_dir": "src/electron/patches/reclient-configs", "repo": "src/third_party/engflow-reclient-configs" },
|
||||
{ "patch_dir": "src/electron/patches/angle", "repo": "src/third_party/angle" },
|
||||
{ "patch_dir": "src/electron/patches/DirectXShaderCompiler", "repo": "src/third_party/dawn/third_party/dxc" }
|
||||
{ "patch_dir": "src/electron/patches/DirectXShaderCompiler", "repo": "src/third_party/dawn/third_party/dxc" },
|
||||
{ "patch_dir": "src/electron/patches/libaom", "repo": "src/third_party/libaom/source/libaom"},
|
||||
{ "patch_dir": "src/electron/patches/dawn", "repo": "src/third_party/dawn" }
|
||||
]
|
||||
|
||||
1
patches/dawn/.patches
Normal file
1
patches/dawn/.patches
Normal file
@@ -0,0 +1 @@
|
||||
dawn_dxc_disable_dxc_pass_structurize-loop-exits-for-unroll.patch
|
||||
@@ -0,0 +1,34 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Antonio Maiorano <amaiorano@google.com>
|
||||
Date: Mon, 17 Jun 2024 18:33:47 +0000
|
||||
Subject: dawn/dxc: disable DXC pass 'structurize-loop-exits-for-unroll'
|
||||
|
||||
Multiple security bugs have been reported related to this optimization pass, and after careful consideration, we have decided to disable it.
|
||||
|
||||
Bug: chromium:333508731
|
||||
Bug: chromium:339171223
|
||||
Bug: chromium:339169163
|
||||
Bug: chromium:346595893
|
||||
Change-Id: I5c9d7180ed09e7417c120595937bcb1013b6ce66
|
||||
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/184422
|
||||
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
|
||||
Reviewed-by: Natalie Chouinard <chouinard@google.com>
|
||||
Reviewed-by: Austin Eng <enga@chromium.org>
|
||||
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/194160
|
||||
Reviewed-by: dan sinclair <dsinclair@chromium.org>
|
||||
|
||||
diff --git a/src/dawn/native/d3d/ShaderUtils.cpp b/src/dawn/native/d3d/ShaderUtils.cpp
|
||||
index c0aeea4d192c4498c0e802f4c693e82cab395715..bfc2f0c5ba189e0912310c50a48d5e2233956223 100644
|
||||
--- a/src/dawn/native/d3d/ShaderUtils.cpp
|
||||
+++ b/src/dawn/native/d3d/ShaderUtils.cpp
|
||||
@@ -58,6 +58,10 @@ std::vector<const wchar_t*> GetDXCArguments(std::wstring_view entryPointNameW,
|
||||
arguments.push_back(L"-E");
|
||||
arguments.push_back(entryPointNameW.data());
|
||||
|
||||
+ // TODO(chromium:346595893): Disable buggy DXC pass
|
||||
+ arguments.push_back(L"-opt-disable");
|
||||
+ arguments.push_back(L"structurize-loop-exits-for-unroll");
|
||||
+
|
||||
uint32_t compileFlags = r.compileFlags;
|
||||
if (compileFlags & D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY) {
|
||||
arguments.push_back(L"/Gec");
|
||||
2
patches/libaom/.patches
Normal file
2
patches/libaom/.patches
Normal file
@@ -0,0 +1,2 @@
|
||||
update_codec_config_after_svc_scale_controls.patch
|
||||
encode_api_test_add_repro_for_chromium_339877165.patch
|
||||
@@ -0,0 +1,162 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: James Zern <jzern@google.com>
|
||||
Date: Thu, 16 May 2024 13:44:52 -0700
|
||||
Subject: encode_api_test: add repro for chromium 339877165
|
||||
|
||||
BUG=chromium:339877165
|
||||
|
||||
Change-Id: I69dcc2cda098ec96a34e1e5f7ef557ee8caf5521
|
||||
(cherry picked from commit 01467cdbd524900eed283660836179fd1b2cd536)
|
||||
|
||||
diff --git a/test/encode_api_test.cc b/test/encode_api_test.cc
|
||||
index 605743f9be8ccc776aa3b8dcae0a79e7dc6711e6..c0a79fe734e7985b52bdbaaa5d8dec2c541275e5 100644
|
||||
--- a/test/encode_api_test.cc
|
||||
+++ b/test/encode_api_test.cc
|
||||
@@ -556,6 +556,147 @@ TEST(EncodeAPI, Buganizer310457427) {
|
||||
encoder.Encode(false);
|
||||
}
|
||||
|
||||
+// Reproduces https://crbug.com/339877165.
|
||||
+TEST(EncodeAPI, Buganizer339877165) {
|
||||
+ // Initialize libaom encoder.
|
||||
+ aom_codec_iface_t *const iface = aom_codec_av1_cx();
|
||||
+ aom_codec_ctx_t enc;
|
||||
+ aom_codec_enc_cfg_t cfg;
|
||||
+
|
||||
+ ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_REALTIME),
|
||||
+ AOM_CODEC_OK);
|
||||
+
|
||||
+ cfg.g_w = 2560;
|
||||
+ cfg.g_h = 1600;
|
||||
+ cfg.rc_target_bitrate = 231;
|
||||
+ cfg.rc_end_usage = AOM_CBR;
|
||||
+ cfg.g_threads = 8;
|
||||
+
|
||||
+ ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK);
|
||||
+
|
||||
+ // From libaom_av1_encoder.cc in WebRTC.
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AOME_SET_CPUUSED, 11), AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_CDEF, 1), AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_TPL_MODEL, 0),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_DELTAQ_MODE, 0), AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_ORDER_HINT, 0),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_AQ_MODE, 3), AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AOME_SET_MAX_INTRA_BITRATE_PCT, 300),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_COEFF_COST_UPD_FREQ, 3),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_MODE_COST_UPD_FREQ, 3),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_MV_COST_UPD_FREQ, 3),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_TUNE_CONTENT, AOM_CONTENT_SCREEN),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_PALETTE, 1), AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_TILE_ROWS, 1), AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_TILE_COLUMNS, 2), AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_OBMC, 0), AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_NOISE_SENSITIVITY, 0),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_WARPED_MOTION, 0),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_GLOBAL_MOTION, 0),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_REF_FRAME_MVS, 0),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_SUPERBLOCK_SIZE,
|
||||
+ AOM_SUPERBLOCK_SIZE_DYNAMIC),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_CFL_INTRA, 0),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_SMOOTH_INTRA, 0),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_ANGLE_DELTA, 0),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_FILTER_INTRA, 0),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_INTRA_DEFAULT_TX_ONLY, 1),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_DISABLE_TRELLIS_QUANT, 1),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_DIST_WTD_COMP, 0),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_DIFF_WTD_COMP, 0),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_DUAL_FILTER, 0),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_INTERINTRA_COMP, 0),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_INTERINTRA_WEDGE, 0),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_INTRA_EDGE_FILTER, 0),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_INTRABC, 0), AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_MASKED_COMP, 0),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_PAETH_INTRA, 0),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_QM, 0), AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_RECT_PARTITIONS, 0),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_RESTORATION, 0),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_SMOOTH_INTERINTRA, 0),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_TX64, 0), AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_MAX_REFERENCE_FRAMES, 3),
|
||||
+ AOM_CODEC_OK);
|
||||
+ ASSERT_EQ(aom_codec_enc_config_set(&enc, &cfg), AOM_CODEC_OK);
|
||||
+
|
||||
+ aom_svc_params_t svc_params = {};
|
||||
+ svc_params.number_spatial_layers = 2;
|
||||
+ svc_params.number_temporal_layers = 1;
|
||||
+ svc_params.max_quantizers[0] = svc_params.max_quantizers[1] = 56;
|
||||
+ svc_params.min_quantizers[0] = svc_params.min_quantizers[1] = 10;
|
||||
+ svc_params.scaling_factor_num[0] = svc_params.scaling_factor_num[1] = 1;
|
||||
+ svc_params.scaling_factor_den[0] = 2;
|
||||
+ svc_params.scaling_factor_den[1] = 1;
|
||||
+ svc_params.layer_target_bitrate[0] = cfg.rc_target_bitrate;
|
||||
+ svc_params.framerate_factor[0] = 1;
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_SVC_PARAMS, &svc_params),
|
||||
+ AOM_CODEC_OK);
|
||||
+
|
||||
+ aom_svc_layer_id_t layer_id = {};
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_SVC_LAYER_ID, &layer_id),
|
||||
+ AOM_CODEC_OK);
|
||||
+
|
||||
+ aom_svc_ref_frame_config_t ref_frame_config = {};
|
||||
+ ref_frame_config.refresh[0] = 1;
|
||||
+ ASSERT_EQ(
|
||||
+ aom_codec_control(&enc, AV1E_SET_SVC_REF_FRAME_CONFIG, &ref_frame_config),
|
||||
+ AOM_CODEC_OK);
|
||||
+
|
||||
+ // Create input image.
|
||||
+ aom_image_t *const image =
|
||||
+ CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h);
|
||||
+ ASSERT_NE(image, nullptr);
|
||||
+
|
||||
+ // Encode layer 0.
|
||||
+ ASSERT_EQ(aom_codec_encode(&enc, image, 0, 1, 0), AOM_CODEC_OK);
|
||||
+
|
||||
+ layer_id.spatial_layer_id = 1;
|
||||
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_SVC_LAYER_ID, &layer_id),
|
||||
+ AOM_CODEC_OK);
|
||||
+
|
||||
+ ref_frame_config.refresh[0] = 0;
|
||||
+ ASSERT_EQ(
|
||||
+ aom_codec_control(&enc, AV1E_SET_SVC_REF_FRAME_CONFIG, &ref_frame_config),
|
||||
+ AOM_CODEC_OK);
|
||||
+
|
||||
+ // Encode layer 1.
|
||||
+ ASSERT_EQ(aom_codec_encode(&enc, image, 0, 1, 0), AOM_CODEC_OK);
|
||||
+
|
||||
+ // Free resources.
|
||||
+ aom_img_free(image);
|
||||
+ aom_codec_destroy(&enc);
|
||||
+}
|
||||
+
|
||||
class EncodeAPIParameterized
|
||||
: public testing::TestWithParam<std::tuple<
|
||||
/*usage=*/unsigned int, /*speed=*/int, /*aq_mode=*/unsigned int>> {};
|
||||
@@ -0,0 +1,196 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: James Zern <jzern@google.com>
|
||||
Date: Tue, 14 May 2024 17:54:10 -0700
|
||||
Subject: update codec config after svc/scale controls
|
||||
|
||||
This ensures the encoder state/allocations stay in sync with scaling and
|
||||
svc layer changes. In the SVC case, depending on the resolution,
|
||||
differences in the chosen superblock size among layers may have caused a
|
||||
crash. This was reproducible in WebRTC in screen content mode.
|
||||
|
||||
The fix is based on a change by Yuan Tong (tongyuan200097) [1]. It
|
||||
refreshes the encoder config after AOME_SET_SCALEMODE,
|
||||
AOME_SET_NUMBER_SPATIAL_LAYERS and AV1E_SET_SVC_PARAMS if no frames have
|
||||
been encoded. AV1E_SET_SVC_PARAMS was missed in the original change.
|
||||
|
||||
[1]: https://aomedia-review.googlesource.com/c/aom/+/171941/2
|
||||
|
||||
Bug: chromium:339877165
|
||||
Change-Id: Ib3d2a123b159898d7c7e19c81e89ff148920e1f1
|
||||
(cherry picked from commit e42f4b1980bbbc772aa886d8b43a885461d7b89e)
|
||||
|
||||
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
|
||||
index 9214feb4e6f9dd068444e76bf8073a0bbe772134..68d6de21845a4e635f67f0a972126563d8f4fb7c 100644
|
||||
--- a/av1/av1_cx_iface.c
|
||||
+++ b/av1/av1_cx_iface.c
|
||||
@@ -1602,37 +1602,42 @@ static aom_codec_err_t ctrl_get_baseline_gf_interval(aom_codec_alg_priv_t *ctx,
|
||||
return AOM_CODEC_OK;
|
||||
}
|
||||
|
||||
+static aom_codec_err_t update_encoder_cfg(aom_codec_alg_priv_t *ctx) {
|
||||
+ set_encoder_config(&ctx->oxcf, &ctx->cfg, &ctx->extra_cfg);
|
||||
+ av1_check_fpmt_config(ctx->ppi, &ctx->oxcf);
|
||||
+ bool is_sb_size_changed = false;
|
||||
+ av1_change_config_seq(ctx->ppi, &ctx->oxcf, &is_sb_size_changed);
|
||||
+ for (int i = 0; i < ctx->ppi->num_fp_contexts; i++) {
|
||||
+ AV1_COMP *const cpi = ctx->ppi->parallel_cpi[i];
|
||||
+ struct aom_internal_error_info *const error = cpi->common.error;
|
||||
+ if (setjmp(error->jmp)) {
|
||||
+ error->setjmp = 0;
|
||||
+ return error->error_code;
|
||||
+ }
|
||||
+ error->setjmp = 1;
|
||||
+ av1_change_config(cpi, &ctx->oxcf, is_sb_size_changed);
|
||||
+ error->setjmp = 0;
|
||||
+ }
|
||||
+ if (ctx->ppi->cpi_lap != NULL) {
|
||||
+ AV1_COMP *const cpi_lap = ctx->ppi->cpi_lap;
|
||||
+ struct aom_internal_error_info *const error = cpi_lap->common.error;
|
||||
+ if (setjmp(error->jmp)) {
|
||||
+ error->setjmp = 0;
|
||||
+ return error->error_code;
|
||||
+ }
|
||||
+ error->setjmp = 1;
|
||||
+ av1_change_config(cpi_lap, &ctx->oxcf, is_sb_size_changed);
|
||||
+ error->setjmp = 0;
|
||||
+ }
|
||||
+ return AOM_CODEC_OK;
|
||||
+}
|
||||
+
|
||||
static aom_codec_err_t update_extra_cfg(aom_codec_alg_priv_t *ctx,
|
||||
const struct av1_extracfg *extra_cfg) {
|
||||
const aom_codec_err_t res = validate_config(ctx, &ctx->cfg, extra_cfg);
|
||||
if (res == AOM_CODEC_OK) {
|
||||
ctx->extra_cfg = *extra_cfg;
|
||||
- set_encoder_config(&ctx->oxcf, &ctx->cfg, &ctx->extra_cfg);
|
||||
- av1_check_fpmt_config(ctx->ppi, &ctx->oxcf);
|
||||
- bool is_sb_size_changed = false;
|
||||
- av1_change_config_seq(ctx->ppi, &ctx->oxcf, &is_sb_size_changed);
|
||||
- for (int i = 0; i < ctx->ppi->num_fp_contexts; i++) {
|
||||
- AV1_COMP *const cpi = ctx->ppi->parallel_cpi[i];
|
||||
- struct aom_internal_error_info *const error = cpi->common.error;
|
||||
- if (setjmp(error->jmp)) {
|
||||
- error->setjmp = 0;
|
||||
- return error->error_code;
|
||||
- }
|
||||
- error->setjmp = 1;
|
||||
- av1_change_config(cpi, &ctx->oxcf, is_sb_size_changed);
|
||||
- error->setjmp = 0;
|
||||
- }
|
||||
- if (ctx->ppi->cpi_lap != NULL) {
|
||||
- AV1_COMP *const cpi_lap = ctx->ppi->cpi_lap;
|
||||
- struct aom_internal_error_info *const error = cpi_lap->common.error;
|
||||
- if (setjmp(error->jmp)) {
|
||||
- error->setjmp = 0;
|
||||
- return error->error_code;
|
||||
- }
|
||||
- error->setjmp = 1;
|
||||
- av1_change_config(cpi_lap, &ctx->oxcf, is_sb_size_changed);
|
||||
- error->setjmp = 0;
|
||||
- }
|
||||
+ return update_encoder_cfg(ctx);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -3573,11 +3578,23 @@ static aom_codec_err_t ctrl_set_scale_mode(aom_codec_alg_priv_t *ctx,
|
||||
aom_scaling_mode_t *const mode = va_arg(args, aom_scaling_mode_t *);
|
||||
|
||||
if (mode) {
|
||||
- const int res = av1_set_internal_size(
|
||||
- &ctx->ppi->cpi->oxcf, &ctx->ppi->cpi->resize_pending_params,
|
||||
- mode->h_scaling_mode, mode->v_scaling_mode);
|
||||
- av1_check_fpmt_config(ctx->ppi, &ctx->ppi->cpi->oxcf);
|
||||
- return (res == 0) ? AOM_CODEC_OK : AOM_CODEC_INVALID_PARAM;
|
||||
+ AV1EncoderConfig *const oxcf =
|
||||
+ ctx->ppi->seq_params_locked ? &ctx->ppi->cpi->oxcf : &ctx->oxcf;
|
||||
+ const int res =
|
||||
+ av1_set_internal_size(oxcf, &ctx->ppi->cpi->resize_pending_params,
|
||||
+ mode->h_scaling_mode, mode->v_scaling_mode);
|
||||
+ if (res == 0) {
|
||||
+ // update_encoder_cfg() is somewhat costly and this control may be called
|
||||
+ // multiple times, so update_encoder_cfg() is only called to ensure frame
|
||||
+ // and superblock sizes are updated before they're fixed by the first
|
||||
+ // encode call.
|
||||
+ if (ctx->ppi->seq_params_locked) {
|
||||
+ av1_check_fpmt_config(ctx->ppi, &ctx->ppi->cpi->oxcf);
|
||||
+ return AOM_CODEC_OK;
|
||||
+ }
|
||||
+ return update_encoder_cfg(ctx);
|
||||
+ }
|
||||
+ return AOM_CODEC_INVALID_PARAM;
|
||||
} else {
|
||||
return AOM_CODEC_INVALID_PARAM;
|
||||
}
|
||||
@@ -3598,6 +3615,13 @@ static aom_codec_err_t ctrl_set_number_spatial_layers(aom_codec_alg_priv_t *ctx,
|
||||
if (number_spatial_layers > MAX_NUM_SPATIAL_LAYERS)
|
||||
return AOM_CODEC_INVALID_PARAM;
|
||||
ctx->ppi->number_spatial_layers = number_spatial_layers;
|
||||
+ // update_encoder_cfg() is somewhat costly and this control may be called
|
||||
+ // multiple times, so update_encoder_cfg() is only called to ensure frame and
|
||||
+ // superblock sizes are updated before they're fixed by the first encode
|
||||
+ // call.
|
||||
+ if (!ctx->ppi->seq_params_locked) {
|
||||
+ return update_encoder_cfg(ctx);
|
||||
+ }
|
||||
return AOM_CODEC_OK;
|
||||
}
|
||||
|
||||
@@ -3615,8 +3639,6 @@ static aom_codec_err_t ctrl_set_svc_params(aom_codec_alg_priv_t *ctx,
|
||||
va_list args) {
|
||||
AV1_PRIMARY *const ppi = ctx->ppi;
|
||||
AV1_COMP *const cpi = ppi->cpi;
|
||||
- AV1_COMMON *const cm = &cpi->common;
|
||||
- AV1EncoderConfig *oxcf = &cpi->oxcf;
|
||||
aom_svc_params_t *const params = va_arg(args, aom_svc_params_t *);
|
||||
int64_t target_bandwidth = 0;
|
||||
ppi->number_spatial_layers = params->number_spatial_layers;
|
||||
@@ -3656,19 +3678,38 @@ static aom_codec_err_t ctrl_set_svc_params(aom_codec_alg_priv_t *ctx,
|
||||
target_bandwidth += lc->layer_target_bitrate;
|
||||
}
|
||||
}
|
||||
- if (cm->current_frame.frame_number == 0) {
|
||||
- if (!cpi->ppi->seq_params_locked) {
|
||||
- SequenceHeader *const seq_params = &ppi->seq_params;
|
||||
- seq_params->operating_points_cnt_minus_1 =
|
||||
- ppi->number_spatial_layers * ppi->number_temporal_layers - 1;
|
||||
- av1_init_seq_coding_tools(ppi, &cpi->oxcf, 1);
|
||||
- }
|
||||
+
|
||||
+ if (ppi->seq_params_locked) {
|
||||
+ AV1EncoderConfig *const oxcf = &cpi->oxcf;
|
||||
+ // Keep ctx->oxcf in sync in case further codec controls are made prior
|
||||
+ // to encoding.
|
||||
+ ctx->oxcf.rc_cfg.target_bandwidth = oxcf->rc_cfg.target_bandwidth =
|
||||
+ target_bandwidth;
|
||||
+ set_primary_rc_buffer_sizes(oxcf, ppi);
|
||||
+ av1_update_layer_context_change_config(cpi, target_bandwidth);
|
||||
+ check_reset_rc_flag(cpi);
|
||||
+ } else {
|
||||
+ // Note av1_init_layer_context() relies on cpi->oxcf. The order of that
|
||||
+ // call and the ones in the other half of this block (which
|
||||
+ // update_encoder_cfg() transitively makes) is important. So we keep
|
||||
+ // ctx->oxcf and cpi->oxcf in sync here as update_encoder_cfg() will
|
||||
+ // overwrite cpi->oxcf with ctx->oxcf.
|
||||
+ ctx->oxcf.rc_cfg.target_bandwidth = cpi->oxcf.rc_cfg.target_bandwidth =
|
||||
+ target_bandwidth;
|
||||
+ SequenceHeader *const seq_params = &ppi->seq_params;
|
||||
+ seq_params->operating_points_cnt_minus_1 =
|
||||
+ ppi->number_spatial_layers * ppi->number_temporal_layers - 1;
|
||||
+
|
||||
av1_init_layer_context(cpi);
|
||||
+ // update_encoder_cfg() is somewhat costly and this control may be called
|
||||
+ // multiple times, so update_encoder_cfg() is only called to ensure frame
|
||||
+ // and superblock sizes are updated before they're fixed by the first
|
||||
+ // encode call.
|
||||
+ return update_encoder_cfg(ctx);
|
||||
}
|
||||
- oxcf->rc_cfg.target_bandwidth = target_bandwidth;
|
||||
- set_primary_rc_buffer_sizes(oxcf, cpi->ppi);
|
||||
- av1_update_layer_context_change_config(cpi, target_bandwidth);
|
||||
- check_reset_rc_flag(cpi);
|
||||
+ } else if (!ppi->seq_params_locked) {
|
||||
+ // Ensure frame and superblock sizes are updated.
|
||||
+ return update_encoder_cfg(ctx);
|
||||
}
|
||||
av1_check_fpmt_config(ctx->ppi, &ctx->ppi->cpi->oxcf);
|
||||
return AOM_CODEC_OK;
|
||||
@@ -54,3 +54,6 @@ fix_revert_src_lb_reducing_c_calls_of_esm_legacy_main_resolve.patch
|
||||
src_preload_function_for_environment.patch
|
||||
fs_fix_wtf-8_decoding_issue.patch
|
||||
stream_do_not_defer_construction_by_one_microtick.patch
|
||||
deps_disable_io_uring_support_in_libuv_by_default.patch
|
||||
src_deps_disable_setuid_etc_if_io_uring_enabled.patch
|
||||
build_support_python_3_12.patch
|
||||
|
||||
35
patches/node/build_support_python_3_12.patch
Normal file
35
patches/node/build_support_python_3_12.patch
Normal file
@@ -0,0 +1,35 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shi Pujin <shipujin@loongson.cn>
|
||||
Date: Mon, 6 Nov 2023 22:11:01 +0800
|
||||
Subject: build: support Python 3.12
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
PR-URL: https://github.com/nodejs/node/pull/50209
|
||||
Reviewed-By: Michaël Zasso <targos@protonmail.com>
|
||||
Reviewed-By: Christian Clauss <cclauss@me.com>
|
||||
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
|
||||
Reviewed-By: Richard Lau <rlau@redhat.com>
|
||||
|
||||
diff --git a/configure b/configure
|
||||
index fefb313c9cd13ce336cc229f173057594c8b08ec..711a3014b9a67ffdab89ded67c8e8132c7afb9a0 100755
|
||||
--- a/configure
|
||||
+++ b/configure
|
||||
@@ -4,6 +4,7 @@
|
||||
# Note that the mix of single and double quotes is intentional,
|
||||
# as is the fact that the ] goes on a new line.
|
||||
_=[ 'exec' '/bin/sh' '-c' '''
|
||||
+command -v python3.12 >/dev/null && exec python3.12 "$0" "$@"
|
||||
command -v python3.11 >/dev/null && exec python3.11 "$0" "$@"
|
||||
command -v python3.10 >/dev/null && exec python3.10 "$0" "$@"
|
||||
command -v python3.9 >/dev/null && exec python3.9 "$0" "$@"
|
||||
@@ -23,7 +24,7 @@ except ImportError:
|
||||
from distutils.spawn import find_executable as which
|
||||
|
||||
print('Node.js configure: Found Python {}.{}.{}...'.format(*sys.version_info))
|
||||
-acceptable_pythons = ((3, 11), (3, 10), (3, 9), (3, 8), (3, 7), (3, 6))
|
||||
+acceptable_pythons = ((3, 12), (3, 11), (3, 10), (3, 9), (3, 8), (3, 7), (3, 6))
|
||||
if sys.version_info[:2] in acceptable_pythons:
|
||||
import configure
|
||||
else:
|
||||
@@ -0,0 +1,70 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= <tniessen@tnie.de>
|
||||
Date: Tue, 19 Sep 2023 16:01:49 +0000
|
||||
Subject: deps: disable io_uring support in libuv by default
|
||||
|
||||
setuid() does not affect libuv's internal io_uring operations if
|
||||
initialized before the call to setuid(). This potentially allows the
|
||||
process to perform privileged operations despite presumably having
|
||||
dropped such privileges through a call to setuid(). Similar concerns
|
||||
apply to other functions that modify the process's user identity.
|
||||
|
||||
This commit changes libuv's io_uring behavior from opt-out (through
|
||||
UV_USE_IO_URING=0) to opt-in (through UV_USE_IO_URING=1) until we figure
|
||||
out a better long-term solution.
|
||||
|
||||
PR-URL: https://github.com/nodejs-private/node-private/pull/529
|
||||
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
|
||||
CVE-ID: CVE-2024-22017
|
||||
|
||||
diff --git a/deps/uv/src/unix/linux.c b/deps/uv/src/unix/linux.c
|
||||
index 48b9c2c43e104079d3ccb5d830d1d79f891fb1a3..656206c6ca8e808a840e006d776eeb64b4b14923 100644
|
||||
--- a/deps/uv/src/unix/linux.c
|
||||
+++ b/deps/uv/src/unix/linux.c
|
||||
@@ -431,8 +431,9 @@ static int uv__use_io_uring(void) {
|
||||
use = atomic_load_explicit(&use_io_uring, memory_order_relaxed);
|
||||
|
||||
if (use == 0) {
|
||||
+ /* Disable io_uring by default due to CVE-2024-22017. */
|
||||
val = getenv("UV_USE_IO_URING");
|
||||
- use = val == NULL || atoi(val) ? 1 : -1;
|
||||
+ use = val != NULL && atoi(val) ? 1 : -1;
|
||||
atomic_store_explicit(&use_io_uring, use, memory_order_relaxed);
|
||||
}
|
||||
|
||||
diff --git a/doc/api/cli.md b/doc/api/cli.md
|
||||
index f50b22f729c28386823d64ef8c9d5fc36c0bf9b1..053c0f94aef5b1681d1ab0513bcc76063ab3a2a6 100644
|
||||
--- a/doc/api/cli.md
|
||||
+++ b/doc/api/cli.md
|
||||
@@ -2596,6 +2596,22 @@ threadpool by setting the `'UV_THREADPOOL_SIZE'` environment variable to a value
|
||||
greater than `4` (its current default value). For more information, see the
|
||||
[libuv threadpool documentation][].
|
||||
|
||||
+### `UV_USE_IO_URING=value`
|
||||
+
|
||||
+Enable or disable libuv's use of `io_uring` on supported platforms.
|
||||
+
|
||||
+On supported platforms, `io_uring` can significantly improve the performance of
|
||||
+various asynchronous I/O operations.
|
||||
+
|
||||
+`io_uring` is disabled by default due to security concerns. When `io_uring`
|
||||
+is enabled, applications must not change the user identity of the process at
|
||||
+runtime, neither through JavaScript functions such as [`process.setuid()`][] nor
|
||||
+through native addons that can invoke system functions such as [`setuid(2)`][].
|
||||
+
|
||||
+This environment variable is implemented by a dependency of Node.js and may be
|
||||
+removed in future versions of Node.js. No stability guarantees are provided for
|
||||
+the behavior of this environment variable.
|
||||
+
|
||||
## Useful V8 options
|
||||
|
||||
V8 has its own set of CLI options. Any V8 CLI option that is provided to `node`
|
||||
@@ -2693,6 +2709,8 @@ done
|
||||
[`dnsPromises.lookup()`]: dns.md#dnspromiseslookuphostname-options
|
||||
[`import` specifier]: esm.md#import-specifiers
|
||||
[`process.setUncaughtExceptionCaptureCallback()`]: process.md#processsetuncaughtexceptioncapturecallbackfn
|
||||
+[`process.setuid()`]: process.md#processsetuidid
|
||||
+[`setuid(2)`]: https://man7.org/linux/man-pages/man2/setuid.2.html
|
||||
[`tls.DEFAULT_MAX_VERSION`]: tls.md#tlsdefault_max_version
|
||||
[`tls.DEFAULT_MIN_VERSION`]: tls.md#tlsdefault_min_version
|
||||
[`unhandledRejection`]: process.md#event-unhandledrejection
|
||||
@@ -0,0 +1,217 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= <tniessen@tnie.de>
|
||||
Date: Mon, 9 Oct 2023 08:10:00 +0000
|
||||
Subject: src,deps: disable setuid() etc if io_uring enabled
|
||||
|
||||
Within Node.js, attempt to determine if libuv is using io_uring. If it
|
||||
is, disable process.setuid() and other user identity setters.
|
||||
|
||||
We cannot fully prevent users from changing the process's user identity,
|
||||
but this should still prevent some accidental, dangerous scenarios.
|
||||
|
||||
PR-URL: https://github.com/nodejs-private/node-private/pull/529
|
||||
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
|
||||
CVE-ID: CVE-2024-22017
|
||||
|
||||
diff --git a/deps/uv/src/unix/linux.c b/deps/uv/src/unix/linux.c
|
||||
index 656206c6ca8e808a840e006d776eeb64b4b14923..0c99718510fe1ca449ec685f323171475ab16552 100644
|
||||
--- a/deps/uv/src/unix/linux.c
|
||||
+++ b/deps/uv/src/unix/linux.c
|
||||
@@ -442,6 +442,14 @@ static int uv__use_io_uring(void) {
|
||||
}
|
||||
|
||||
|
||||
+UV_EXTERN int uv__node_patch_is_using_io_uring(void) {
|
||||
+ // This function exists only in the modified copy of libuv in the Node.js
|
||||
+ // repository. Node.js checks if this function exists and, if it does, uses it
|
||||
+ // to determine whether libuv is using io_uring or not.
|
||||
+ return uv__use_io_uring();
|
||||
+}
|
||||
+
|
||||
+
|
||||
static void uv__iou_init(int epollfd,
|
||||
struct uv__iou* iou,
|
||||
uint32_t entries,
|
||||
diff --git a/doc/api/cli.md b/doc/api/cli.md
|
||||
index 053c0f94aef5b1681d1ab0513bcc76063ab3a2a6..9b32639532bf6377aade96b86faccf050a396e63 100644
|
||||
--- a/doc/api/cli.md
|
||||
+++ b/doc/api/cli.md
|
||||
@@ -2605,8 +2605,9 @@ various asynchronous I/O operations.
|
||||
|
||||
`io_uring` is disabled by default due to security concerns. When `io_uring`
|
||||
is enabled, applications must not change the user identity of the process at
|
||||
-runtime, neither through JavaScript functions such as [`process.setuid()`][] nor
|
||||
-through native addons that can invoke system functions such as [`setuid(2)`][].
|
||||
+runtime. In this case, JavaScript functions such as [`process.setuid()`][] are
|
||||
+unavailable, and native addons must not invoke system functions such as
|
||||
+[`setuid(2)`][].
|
||||
|
||||
This environment variable is implemented by a dependency of Node.js and may be
|
||||
removed in future versions of Node.js. No stability guarantees are provided for
|
||||
diff --git a/src/node_credentials.cc b/src/node_credentials.cc
|
||||
index c1f7a4f2acbdf66a45230e2b9fdd860d9d3b4458..3b5eec8244024f58713c668c9dcd84617a18db88 100644
|
||||
--- a/src/node_credentials.cc
|
||||
+++ b/src/node_credentials.cc
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "env-inl.h"
|
||||
+#include "node_errors.h"
|
||||
#include "node_external_reference.h"
|
||||
#include "node_internals.h"
|
||||
#include "util-inl.h"
|
||||
@@ -12,6 +13,7 @@
|
||||
#include <unistd.h> // setuid, getuid
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
+#include <dlfcn.h> // dlsym()
|
||||
#include <linux/capability.h>
|
||||
#include <sys/auxv.h>
|
||||
#include <sys/syscall.h>
|
||||
@@ -232,6 +234,45 @@ static gid_t gid_by_name(Isolate* isolate, Local<Value> value) {
|
||||
}
|
||||
}
|
||||
|
||||
+#ifdef __linux__
|
||||
+extern "C" {
|
||||
+int uv__node_patch_is_using_io_uring(void);
|
||||
+
|
||||
+int uv__node_patch_is_using_io_uring(void) __attribute__((weak));
|
||||
+
|
||||
+typedef int (*is_using_io_uring_fn)(void);
|
||||
+}
|
||||
+#endif // __linux__
|
||||
+
|
||||
+static bool UvMightBeUsingIoUring() {
|
||||
+#ifdef __linux__
|
||||
+ // Support for io_uring is only included in libuv 1.45.0 and later, and only
|
||||
+ // on Linux (and Android, but there it is always disabled). The patch that we
|
||||
+ // apply to libuv to work around the io_uring security issue adds a function
|
||||
+ // that tells us whether io_uring is being used. If that function is not
|
||||
+ // present, we assume that we are dynamically linking against an unpatched
|
||||
+ // version.
|
||||
+ static std::atomic<is_using_io_uring_fn> check =
|
||||
+ uv__node_patch_is_using_io_uring;
|
||||
+ if (check == nullptr) {
|
||||
+ check = reinterpret_cast<is_using_io_uring_fn>(
|
||||
+ dlsym(RTLD_DEFAULT, "uv__node_patch_is_using_io_uring"));
|
||||
+ }
|
||||
+ return uv_version() >= 0x012d00u && (check == nullptr || (*check)());
|
||||
+#else
|
||||
+ return false;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+static bool ThrowIfUvMightBeUsingIoUring(Environment* env, const char* fn) {
|
||||
+ if (UvMightBeUsingIoUring()) {
|
||||
+ node::THROW_ERR_INVALID_STATE(
|
||||
+ env, "%s() disabled: io_uring may be enabled. See CVE-2024-22017.", fn);
|
||||
+ return true;
|
||||
+ }
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
static void GetUid(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
CHECK(env->has_run_bootstrapping_code());
|
||||
@@ -267,6 +308,8 @@ static void SetGid(const FunctionCallbackInfo<Value>& args) {
|
||||
CHECK_EQ(args.Length(), 1);
|
||||
CHECK(args[0]->IsUint32() || args[0]->IsString());
|
||||
|
||||
+ if (ThrowIfUvMightBeUsingIoUring(env, "setgid")) return;
|
||||
+
|
||||
gid_t gid = gid_by_name(env->isolate(), args[0]);
|
||||
|
||||
if (gid == gid_not_found) {
|
||||
@@ -286,6 +329,8 @@ static void SetEGid(const FunctionCallbackInfo<Value>& args) {
|
||||
CHECK_EQ(args.Length(), 1);
|
||||
CHECK(args[0]->IsUint32() || args[0]->IsString());
|
||||
|
||||
+ if (ThrowIfUvMightBeUsingIoUring(env, "setegid")) return;
|
||||
+
|
||||
gid_t gid = gid_by_name(env->isolate(), args[0]);
|
||||
|
||||
if (gid == gid_not_found) {
|
||||
@@ -305,6 +350,8 @@ static void SetUid(const FunctionCallbackInfo<Value>& args) {
|
||||
CHECK_EQ(args.Length(), 1);
|
||||
CHECK(args[0]->IsUint32() || args[0]->IsString());
|
||||
|
||||
+ if (ThrowIfUvMightBeUsingIoUring(env, "setuid")) return;
|
||||
+
|
||||
uid_t uid = uid_by_name(env->isolate(), args[0]);
|
||||
|
||||
if (uid == uid_not_found) {
|
||||
@@ -324,6 +371,8 @@ static void SetEUid(const FunctionCallbackInfo<Value>& args) {
|
||||
CHECK_EQ(args.Length(), 1);
|
||||
CHECK(args[0]->IsUint32() || args[0]->IsString());
|
||||
|
||||
+ if (ThrowIfUvMightBeUsingIoUring(env, "seteuid")) return;
|
||||
+
|
||||
uid_t uid = uid_by_name(env->isolate(), args[0]);
|
||||
|
||||
if (uid == uid_not_found) {
|
||||
@@ -364,6 +413,8 @@ static void SetGroups(const FunctionCallbackInfo<Value>& args) {
|
||||
CHECK_EQ(args.Length(), 1);
|
||||
CHECK(args[0]->IsArray());
|
||||
|
||||
+ if (ThrowIfUvMightBeUsingIoUring(env, "setgroups")) return;
|
||||
+
|
||||
Local<Array> groups_list = args[0].As<Array>();
|
||||
size_t size = groups_list->Length();
|
||||
MaybeStackBuffer<gid_t, 64> groups(size);
|
||||
@@ -395,6 +446,8 @@ static void InitGroups(const FunctionCallbackInfo<Value>& args) {
|
||||
CHECK(args[0]->IsUint32() || args[0]->IsString());
|
||||
CHECK(args[1]->IsUint32() || args[1]->IsString());
|
||||
|
||||
+ if (ThrowIfUvMightBeUsingIoUring(env, "initgroups")) return;
|
||||
+
|
||||
Utf8Value arg0(env->isolate(), args[0]);
|
||||
gid_t extra_group;
|
||||
bool must_free;
|
||||
diff --git a/test/parallel/test-process-setuid-io-uring.js b/test/parallel/test-process-setuid-io-uring.js
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..93193ac2f8ab99f0cf8f2de368bc27958c92be76
|
||||
--- /dev/null
|
||||
+++ b/test/parallel/test-process-setuid-io-uring.js
|
||||
@@ -0,0 +1,43 @@
|
||||
+'use strict';
|
||||
+const common = require('../common');
|
||||
+
|
||||
+const assert = require('node:assert');
|
||||
+const { execFileSync } = require('node:child_process');
|
||||
+
|
||||
+if (!common.isLinux) {
|
||||
+ common.skip('test is Linux specific');
|
||||
+}
|
||||
+
|
||||
+if (process.arch !== 'x64' && process.arch !== 'arm64') {
|
||||
+ common.skip('io_uring support on this architecture is uncertain');
|
||||
+}
|
||||
+
|
||||
+const kv = /^(\d+)\.(\d+)\.(\d+)/.exec(execFileSync('uname', ['-r'])).slice(1).map((n) => parseInt(n, 10));
|
||||
+if (((kv[0] << 16) | (kv[1] << 8) | kv[2]) < 0x050ABA) {
|
||||
+ common.skip('io_uring is likely buggy due to old kernel');
|
||||
+}
|
||||
+
|
||||
+const userIdentitySetters = [
|
||||
+ ['setuid', [1000]],
|
||||
+ ['seteuid', [1000]],
|
||||
+ ['setgid', [1000]],
|
||||
+ ['setegid', [1000]],
|
||||
+ ['setgroups', [[1000]]],
|
||||
+ ['initgroups', ['nodeuser', 1000]],
|
||||
+];
|
||||
+
|
||||
+for (const [fnName, args] of userIdentitySetters) {
|
||||
+ const call = `process.${fnName}(${args.map((a) => JSON.stringify(a)).join(', ')})`;
|
||||
+ const code = `try { ${call}; } catch (err) { console.log(err); }`;
|
||||
+
|
||||
+ const stdout = execFileSync(process.execPath, ['-e', code], {
|
||||
+ encoding: 'utf8',
|
||||
+ env: { ...process.env, UV_USE_IO_URING: '1' },
|
||||
+ });
|
||||
+
|
||||
+ const msg = new RegExp(`^Error: ${fnName}\\(\\) disabled: io_uring may be enabled\\. See CVE-[X0-9]{4}-`);
|
||||
+ assert.match(stdout, msg);
|
||||
+ assert.match(stdout, /code: 'ERR_INVALID_STATE'/);
|
||||
+
|
||||
+ console.log(call, stdout.slice(0, stdout.indexOf('\n')));
|
||||
+}
|
||||
@@ -1,3 +1,12 @@
|
||||
chore_allow_customizing_microtask_policy_per_context.patch
|
||||
deps_add_v8_object_setinternalfieldfornodecore.patch
|
||||
merged_wasm_gc_scan_the_code_field_of_the_wasminternalfunction.patch
|
||||
cherry-pick-f320600cd1f4.patch
|
||||
cherry-pick-b3c01ac1e60a.patch
|
||||
cherry-pick-6503a987d966.patch
|
||||
cherry-pick-3e037e195e50.patch
|
||||
cherry-pick-e7b64c6ee185.patch
|
||||
cherry-pick-f911ff372723.patch
|
||||
cherry-pick-8b400f9b7d66.patch
|
||||
cherry-pick-ba6cab40612d.patch
|
||||
merged_wasm_add_missing_type_canonicalization_for_exceptions_js.patch
|
||||
|
||||
41
patches/v8/cherry-pick-3e037e195e50.patch
Normal file
41
patches/v8/cherry-pick-3e037e195e50.patch
Normal file
@@ -0,0 +1,41 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shu-yu Guo <syg@chromium.org>
|
||||
Date: Tue, 21 May 2024 10:06:20 -0700
|
||||
Subject: Using FunctionParsingScope for parsing class static blocks
|
||||
|
||||
Class static blocks contain statements, don't inherit the
|
||||
ExpressionScope stack.
|
||||
|
||||
Bug: 341663589
|
||||
Change-Id: Id52a60d77781201a706fcf2290d7d103f39bed83
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5553030
|
||||
Commit-Queue: Shu-yu Guo <syg@chromium.org>
|
||||
Commit-Queue: Adam Klein <adamk@chromium.org>
|
||||
Reviewed-by: Adam Klein <adamk@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#94014}
|
||||
|
||||
diff --git a/src/ast/scopes.cc b/src/ast/scopes.cc
|
||||
index 6dfcd45cf208e58a2fc0cd18ba3b115bae35a0d5..61b8fbf0cfcaa02a92ead411e4bcbc1f36dfdad3 100644
|
||||
--- a/src/ast/scopes.cc
|
||||
+++ b/src/ast/scopes.cc
|
||||
@@ -2441,7 +2441,7 @@ bool Scope::MustAllocate(Variable* var) {
|
||||
var->set_is_used();
|
||||
if (inner_scope_calls_eval_ && !var->is_this()) var->SetMaybeAssigned();
|
||||
}
|
||||
- DCHECK(!var->has_forced_context_allocation() || var->is_used());
|
||||
+ CHECK(!var->has_forced_context_allocation() || var->is_used());
|
||||
// Global variables do not need to be allocated.
|
||||
return !var->IsGlobalObjectProperty() && var->is_used();
|
||||
}
|
||||
diff --git a/src/parsing/parser-base.h b/src/parsing/parser-base.h
|
||||
index ac35090ca5d129c58c0e4fb31ee2e2456e202dce..059133f32d30c94e400de96313734b64c5421b09 100644
|
||||
--- a/src/parsing/parser-base.h
|
||||
+++ b/src/parsing/parser-base.h
|
||||
@@ -2619,6 +2619,7 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseClassStaticBlock(
|
||||
}
|
||||
|
||||
FunctionState initializer_state(&function_state_, &scope_, initializer_scope);
|
||||
+ FunctionParsingScope body_parsing_scope(impl());
|
||||
AcceptINScope accept_in(this, true);
|
||||
|
||||
// Each static block has its own var and lexical scope, so make a new var
|
||||
56
patches/v8/cherry-pick-6503a987d966.patch
Normal file
56
patches/v8/cherry-pick-6503a987d966.patch
Normal file
@@ -0,0 +1,56 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Victor Gomes <victorgomes@chromium.org>
|
||||
Date: Thu, 21 Mar 2024 09:59:19 +0100
|
||||
Subject: Deal with large strings in NoSideEffectsErrorToString
|
||||
|
||||
If name is too big, StringBuilder will fail to even add
|
||||
"<a very large string>" suffix.
|
||||
|
||||
In this case, we truncate name first.
|
||||
|
||||
Bug: 329699609
|
||||
Change-Id: I6e4440c07eae84371f44b54f88127e2c70af0db5
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5378286
|
||||
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
|
||||
Reviewed-by: Patrick Thier <pthier@chromium.org>
|
||||
Auto-Submit: Victor Gomes <victorgomes@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#92932}
|
||||
|
||||
diff --git a/src/objects/objects.cc b/src/objects/objects.cc
|
||||
index ed640e14dd43b3a1268afd196db8d7a0cb8601da..06e81c96c504e27eb218ca60d67a7bd4b4f4487f 100644
|
||||
--- a/src/objects/objects.cc
|
||||
+++ b/src/objects/objects.cc
|
||||
@@ -469,14 +469,27 @@ Handle<String> NoSideEffectsErrorToString(Isolate* isolate,
|
||||
if (name_str->length() == 0) return msg_str;
|
||||
if (msg_str->length() == 0) return name_str;
|
||||
|
||||
- IncrementalStringBuilder builder(isolate);
|
||||
- builder.AppendString(name_str);
|
||||
- builder.AppendCStringLiteral(": ");
|
||||
+ constexpr const char error_suffix[] = "<a very large string>";
|
||||
+ constexpr int error_suffix_size = sizeof(error_suffix);
|
||||
+ int suffix_size = std::min(error_suffix_size, msg_str->length());
|
||||
|
||||
- if (builder.Length() + msg_str->length() <= String::kMaxLength) {
|
||||
- builder.AppendString(msg_str);
|
||||
+ IncrementalStringBuilder builder(isolate);
|
||||
+ if (name_str->length() + suffix_size + 2 /* ": " */ > String::kMaxLength) {
|
||||
+ constexpr const char connector[] = "... : ";
|
||||
+ int connector_size = sizeof(connector);
|
||||
+ Handle<String> truncated_name = isolate->factory()->NewProperSubString(
|
||||
+ name_str, 0, name_str->length() - error_suffix_size - connector_size);
|
||||
+ builder.AppendString(truncated_name);
|
||||
+ builder.AppendCStringLiteral(connector);
|
||||
+ builder.AppendCStringLiteral(error_suffix);
|
||||
} else {
|
||||
- builder.AppendCStringLiteral("<a very large string>");
|
||||
+ builder.AppendString(name_str);
|
||||
+ builder.AppendCStringLiteral(": ");
|
||||
+ if (builder.Length() + msg_str->length() <= String::kMaxLength) {
|
||||
+ builder.AppendString(msg_str);
|
||||
+ } else {
|
||||
+ builder.AppendCStringLiteral(error_suffix);
|
||||
+ }
|
||||
}
|
||||
|
||||
return builder.Finish().ToHandleChecked();
|
||||
98
patches/v8/cherry-pick-8b400f9b7d66.patch
Normal file
98
patches/v8/cherry-pick-8b400f9b7d66.patch
Normal file
@@ -0,0 +1,98 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jakob Kummerow <jkummerow@chromium.org>
|
||||
Date: Thu, 6 Jun 2024 16:44:37 +0200
|
||||
Subject: Merged: [wasm] Enforce maximum number of canonicalized types
|
||||
|
||||
Storing canonical indices in ValueTypes doesn't work well if the
|
||||
canonical index is too large.
|
||||
|
||||
Fixed: 344608204
|
||||
(cherry picked from commit 422cdc5eddcadb53b8eafb099722fb211a35739e)
|
||||
|
||||
Change-Id: Id281d6a38e8f2c64c42352f2d3dd3df54e289525
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5625825
|
||||
Auto-Submit: Jakob Kummerow <jkummerow@chromium.org>
|
||||
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
|
||||
Reviewed-by: Matthias Liedtke <mliedtke@chromium.org>
|
||||
Commit-Queue: Matthias Liedtke <mliedtke@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/12.6@{#30}
|
||||
Cr-Branched-From: 3c9fa12db3183a6f4ea53d2675adb66ea1194529-refs/heads/12.6.228@{#2}
|
||||
Cr-Branched-From: 981bb15ba4dbf9e2381dfc94ec2c4af0b9c6a0b6-refs/heads/main@{#93835}
|
||||
|
||||
diff --git a/src/wasm/canonical-types.cc b/src/wasm/canonical-types.cc
|
||||
index ea6e0d6c6a49c281f715a005bcd40e1fb25ee802..a048c8bddb841f4d08234374e8e4e50d0a3f2c3c 100644
|
||||
--- a/src/wasm/canonical-types.cc
|
||||
+++ b/src/wasm/canonical-types.cc
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "src/wasm/canonical-types.h"
|
||||
|
||||
+#include "src/init/v8.h"
|
||||
#include "src/wasm/std-object-sizes.h"
|
||||
#include "src/wasm/wasm-engine.h"
|
||||
|
||||
@@ -20,6 +21,19 @@ TypeCanonicalizer::TypeCanonicalizer() {
|
||||
AddPredefinedArrayType(kPredefinedArrayI16Index, kWasmI16);
|
||||
}
|
||||
|
||||
+// We currently store canonical indices in {ValueType} instances, so they
|
||||
+// must fit into the range of valid module-relative (non-canonical) type
|
||||
+// indices.
|
||||
+// TODO(jkummerow): Raise this limit, to make long-lived WasmEngines scale
|
||||
+// better. Plan: stop constructing ValueTypes from canonical type indices.
|
||||
+static constexpr size_t kMaxCanonicalTypes = kV8MaxWasmTypes;
|
||||
+
|
||||
+void TypeCanonicalizer::CheckMaxCanonicalIndex() const {
|
||||
+ if (canonical_supertypes_.size() > kMaxCanonicalTypes) {
|
||||
+ V8::FatalProcessOutOfMemory(nullptr, "too many canonicalized types");
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void TypeCanonicalizer::AddRecursiveGroup(WasmModule* module, uint32_t size) {
|
||||
AddRecursiveGroup(module, size,
|
||||
static_cast<uint32_t>(module->types.size() - size));
|
||||
@@ -60,6 +74,7 @@ void TypeCanonicalizer::AddRecursiveGroup(WasmModule* module, uint32_t size,
|
||||
uint32_t first_canonical_index =
|
||||
static_cast<uint32_t>(canonical_supertypes_.size());
|
||||
canonical_supertypes_.resize(first_canonical_index + size);
|
||||
+ CheckMaxCanonicalIndex();
|
||||
for (uint32_t i = 0; i < size; i++) {
|
||||
CanonicalType& canonical_type = group.types[i];
|
||||
// Compute the canonical index of the supertype: If it is relative, we
|
||||
@@ -106,6 +121,7 @@ void TypeCanonicalizer::AddRecursiveSingletonGroup(WasmModule* module,
|
||||
uint32_t first_canonical_index =
|
||||
static_cast<uint32_t>(canonical_supertypes_.size());
|
||||
canonical_supertypes_.resize(first_canonical_index + 1);
|
||||
+ CheckMaxCanonicalIndex();
|
||||
CanonicalType& canonical_type = group.type;
|
||||
// Compute the canonical index of the supertype: If it is relative, we
|
||||
// need to add {first_canonical_index}.
|
||||
@@ -149,6 +165,7 @@ uint32_t TypeCanonicalizer::AddRecursiveGroup(const FunctionSig* sig) {
|
||||
group.type.is_relative_supertype = false;
|
||||
canonical_singleton_groups_.emplace(group, canonical_index);
|
||||
canonical_supertypes_.emplace_back(kNoSuperType);
|
||||
+ CheckMaxCanonicalIndex();
|
||||
return canonical_index;
|
||||
}
|
||||
|
||||
@@ -164,6 +181,7 @@ void TypeCanonicalizer::AddPredefinedArrayType(uint32_t index,
|
||||
group.type.is_relative_supertype = false;
|
||||
canonical_singleton_groups_.emplace(group, index);
|
||||
canonical_supertypes_.emplace_back(kNoSuperType);
|
||||
+ DCHECK_LE(canonical_supertypes_.size(), kMaxCanonicalTypes);
|
||||
}
|
||||
|
||||
ValueType TypeCanonicalizer::CanonicalizeValueType(
|
||||
diff --git a/src/wasm/canonical-types.h b/src/wasm/canonical-types.h
|
||||
index 7a882acaa00c5e826b7e8adc0a27817f28450c3c..c35d350626f6cbbd8b8f8197940a0127b674c15c 100644
|
||||
--- a/src/wasm/canonical-types.h
|
||||
+++ b/src/wasm/canonical-types.h
|
||||
@@ -161,6 +161,8 @@ class TypeCanonicalizer {
|
||||
ValueType CanonicalizeValueType(const WasmModule* module, ValueType type,
|
||||
uint32_t recursive_group_start) const;
|
||||
|
||||
+ void CheckMaxCanonicalIndex() const;
|
||||
+
|
||||
std::vector<uint32_t> canonical_supertypes_;
|
||||
// Maps groups of size >=2 to the canonical id of the first type.
|
||||
std::unordered_map<CanonicalGroup, uint32_t, base::hash<CanonicalGroup>>
|
||||
76
patches/v8/cherry-pick-b3c01ac1e60a.patch
Normal file
76
patches/v8/cherry-pick-b3c01ac1e60a.patch
Normal file
@@ -0,0 +1,76 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shu-yu Guo <syg@chromium.org>
|
||||
Date: Mon, 13 May 2024 11:23:20 -0700
|
||||
Subject: Don't build AccessInfo for storing to module exports
|
||||
|
||||
Bug: 340221135
|
||||
Change-Id: I5af35be6ebf6a69db1c4687107503575b23973c4
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5534518
|
||||
Reviewed-by: Adam Klein <adamk@chromium.org>
|
||||
Commit-Queue: Shu-yu Guo <syg@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#93872}
|
||||
|
||||
diff --git a/src/compiler/access-info.cc b/src/compiler/access-info.cc
|
||||
index 7cff878839c85cd9c6571ee48f1a0fce081f4471..9d022ba402d7bfdd5ca745a4193ee0de0e3d755e 100644
|
||||
--- a/src/compiler/access-info.cc
|
||||
+++ b/src/compiler/access-info.cc
|
||||
@@ -526,6 +526,14 @@ PropertyAccessInfo AccessorAccessInfoHelper(
|
||||
Cell::cast(module_namespace->module()->exports()->Lookup(
|
||||
isolate, name.object(),
|
||||
Smi::ToInt(Object::GetHash(*name.object())))));
|
||||
+ if (IsAnyStore(access_mode)) {
|
||||
+ // ES#sec-module-namespace-exotic-objects-set-p-v-receiver
|
||||
+ // ES#sec-module-namespace-exotic-objects-defineownproperty-p-desc
|
||||
+ //
|
||||
+ // Storing to a module namespace object is always an error or a no-op in
|
||||
+ // JS.
|
||||
+ return PropertyAccessInfo::Invalid(zone);
|
||||
+ }
|
||||
if (IsTheHole(cell->value(kRelaxedLoad), isolate)) {
|
||||
// This module has not been fully initialized yet.
|
||||
return PropertyAccessInfo::Invalid(zone);
|
||||
diff --git a/src/maglev/maglev-graph-builder.cc b/src/maglev/maglev-graph-builder.cc
|
||||
index 8a5b4483d148192d3106e75874f042ccc6b36e56..728105c0aaccbaeb018eb9b9a660b5acba4650d8 100644
|
||||
--- a/src/maglev/maglev-graph-builder.cc
|
||||
+++ b/src/maglev/maglev-graph-builder.cc
|
||||
@@ -3914,19 +3914,28 @@ ReduceResult MaglevGraphBuilder::TryBuildPropertyStore(
|
||||
access_info.holder().value());
|
||||
}
|
||||
|
||||
- if (access_info.IsFastAccessorConstant()) {
|
||||
- return TryBuildPropertySetterCall(access_info, receiver,
|
||||
- GetAccumulatorTagged());
|
||||
- } else {
|
||||
- DCHECK(access_info.IsDataField() || access_info.IsFastDataConstant());
|
||||
- ReduceResult res = TryBuildStoreField(access_info, receiver, access_mode);
|
||||
- if (res.IsDone()) {
|
||||
- RecordKnownProperty(receiver, name,
|
||||
- current_interpreter_frame_.accumulator(),
|
||||
- AccessInfoGuaranteedConst(access_info), access_mode);
|
||||
- return res;
|
||||
+ switch (access_info.kind()) {
|
||||
+ case compiler::PropertyAccessInfo::kFastAccessorConstant:
|
||||
+ return TryBuildPropertySetterCall(access_info, receiver,
|
||||
+ GetAccumulatorTagged());
|
||||
+ case compiler::PropertyAccessInfo::kDataField:
|
||||
+ case compiler::PropertyAccessInfo::kFastDataConstant: {
|
||||
+ ReduceResult res = TryBuildStoreField(access_info, receiver, access_mode);
|
||||
+ if (res.IsDone()) {
|
||||
+ RecordKnownProperty(
|
||||
+ receiver, name, current_interpreter_frame_.accumulator(),
|
||||
+ AccessInfoGuaranteedConst(access_info), access_mode);
|
||||
+ return res;
|
||||
+ }
|
||||
+ return ReduceResult::Fail();
|
||||
}
|
||||
- return ReduceResult::Fail();
|
||||
+ case compiler::PropertyAccessInfo::kInvalid:
|
||||
+ case compiler::PropertyAccessInfo::kNotFound:
|
||||
+ case compiler::PropertyAccessInfo::kDictionaryProtoDataConstant:
|
||||
+ case compiler::PropertyAccessInfo::kDictionaryProtoAccessorConstant:
|
||||
+ case compiler::PropertyAccessInfo::kModuleExport:
|
||||
+ case compiler::PropertyAccessInfo::kStringLength:
|
||||
+ UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
92
patches/v8/cherry-pick-ba6cab40612d.patch
Normal file
92
patches/v8/cherry-pick-ba6cab40612d.patch
Normal file
@@ -0,0 +1,92 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jakob Kummerow <jkummerow@chromium.org>
|
||||
Date: Thu, 13 Jun 2024 12:26:46 +0200
|
||||
Subject: Merged: [wasm][liftoff][arm64] Fix DropExceptionValueAtOffset
|
||||
|
||||
We cannot exit the iteration early, we must update all entries
|
||||
in the cache state.
|
||||
|
||||
Fixed: 343748812
|
||||
(cherry picked from commit 910cb91733dc47b8f4a3dc9f1ca640b728f97aad)
|
||||
|
||||
Change-Id: Ib342467f35360baaa14cd098b258bd1acf4189a7
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5626023
|
||||
Commit-Queue: Matthias Liedtke <mliedtke@chromium.org>
|
||||
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
|
||||
Reviewed-by: Matthias Liedtke <mliedtke@chromium.org>
|
||||
Auto-Submit: Jakob Kummerow <jkummerow@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/12.6@{#32}
|
||||
Cr-Branched-From: 3c9fa12db3183a6f4ea53d2675adb66ea1194529-refs/heads/12.6.228@{#2}
|
||||
Cr-Branched-From: 981bb15ba4dbf9e2381dfc94ec2c4af0b9c6a0b6-refs/heads/main@{#93835}
|
||||
|
||||
diff --git a/src/wasm/baseline/liftoff-assembler.cc b/src/wasm/baseline/liftoff-assembler.cc
|
||||
index 821b6b80495849129c2c499302ac393278f72e92..e1ca7bebdc8408e21715dd0fc9861a474b989bcc 100644
|
||||
--- a/src/wasm/baseline/liftoff-assembler.cc
|
||||
+++ b/src/wasm/baseline/liftoff-assembler.cc
|
||||
@@ -430,12 +430,13 @@ void LiftoffAssembler::DropExceptionValueAtOffset(int offset) {
|
||||
slot != end; ++slot) {
|
||||
*slot = *(slot + 1);
|
||||
stack_offset = NextSpillOffset(slot->kind(), stack_offset);
|
||||
- // Padding could allow us to exit early.
|
||||
- if (slot->offset() == stack_offset) break;
|
||||
- if (slot->is_stack()) {
|
||||
- MoveStackValue(stack_offset, slot->offset(), slot->kind());
|
||||
+ // Padding could cause some spill offsets to remain the same.
|
||||
+ if (slot->offset() != stack_offset) {
|
||||
+ if (slot->is_stack()) {
|
||||
+ MoveStackValue(stack_offset, slot->offset(), slot->kind());
|
||||
+ }
|
||||
+ slot->set_offset(stack_offset);
|
||||
}
|
||||
- slot->set_offset(stack_offset);
|
||||
}
|
||||
cache_state_.stack_state.pop_back();
|
||||
}
|
||||
diff --git a/test/mjsunit/mjsunit.status b/test/mjsunit/mjsunit.status
|
||||
index a7af302742da61501378af52ab32d0662fc6dd9c..def43115ba6cf4e4201d26c2949436c029b5379d 100644
|
||||
--- a/test/mjsunit/mjsunit.status
|
||||
+++ b/test/mjsunit/mjsunit.status
|
||||
@@ -1689,6 +1689,7 @@
|
||||
'regress/wasm/regress-1487077': [SKIP],
|
||||
'regress/wasm/regress-1500812': [SKIP],
|
||||
'regress/wasm/regress-323694592': [SKIP],
|
||||
+ 'regress/wasm/regress-343748812': [SKIP],
|
||||
'regress/wasm/regress-crbug-1338980': [SKIP],
|
||||
'regress/wasm/regress-crbug-1355070': [SKIP],
|
||||
'regress/wasm/regress-crbug-1356718': [SKIP],
|
||||
diff --git a/test/mjsunit/regress/wasm/regress-343748812.js b/test/mjsunit/regress/wasm/regress-343748812.js
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..8dc456c413665e97c5f8e48f95a65370cf051753
|
||||
--- /dev/null
|
||||
+++ b/test/mjsunit/regress/wasm/regress-343748812.js
|
||||
@@ -0,0 +1,30 @@
|
||||
+// Copyright 2024 the V8 project authors. All rights reserved.
|
||||
+// Use of this source code is governed by a BSD-style license that can be
|
||||
+// found in the LICENSE file.
|
||||
+
|
||||
+d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
|
||||
+
|
||||
+const builder = new WasmModuleBuilder();
|
||||
+let $sig0 = builder.addType(kSig_v_v);
|
||||
+let $sig7 = builder.addType(
|
||||
+ makeSig([], [ kWasmExternRef, kWasmS128, kWasmExternRef ]));
|
||||
+let $func0 = builder.addImport('imports', 'func0', $sig0);
|
||||
+builder.addFunction("main", $sig0).exportFunc()
|
||||
+ .addLocals(kWasmExternRef, 3)
|
||||
+ .addBody([
|
||||
+ kExprTry, $sig7,
|
||||
+ kExprCallFunction, $func0,
|
||||
+ kExprUnreachable,
|
||||
+ kExprCatchAll,
|
||||
+ kExprRefNull, kExternRefCode,
|
||||
+ ...wasmS128Const([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
|
||||
+ kExprRefNull, kExternRefCode,
|
||||
+ kExprEnd,
|
||||
+ kExprDrop,
|
||||
+ kExprDrop,
|
||||
+ kExprDrop,
|
||||
+ ]);
|
||||
+
|
||||
+var instance = builder.instantiate({'imports': { 'func0': () => {} }});
|
||||
+
|
||||
+assertThrows(instance.exports.main, WebAssembly.RuntimeError, /unreachable/);
|
||||
31
patches/v8/cherry-pick-e7b64c6ee185.patch
Normal file
31
patches/v8/cherry-pick-e7b64c6ee185.patch
Normal file
@@ -0,0 +1,31 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Liedtke <mliedtke@chromium.org>
|
||||
Date: Fri, 10 May 2024 10:38:29 +0200
|
||||
Subject: Merged: [builtins] HasOnlySimpleElements is false for non-JSObjects
|
||||
|
||||
Bug: 338908243
|
||||
(cherry picked from commit cc05792346fb017eaa961ee7d35cf1f9bb53bb0a)
|
||||
|
||||
Change-Id: I9b5c2333924a54169ea3fa48e67e7db2ec67f6b9
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5545380
|
||||
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
|
||||
Commit-Queue: Matthias Liedtke <mliedtke@chromium.org>
|
||||
Auto-Submit: Matthias Liedtke <mliedtke@chromium.org>
|
||||
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/12.4@{#34}
|
||||
Cr-Branched-From: 309640da62fae0485c7e4f64829627c92d53b35d-refs/heads/12.4.254@{#1}
|
||||
Cr-Branched-From: 5dc24701432278556a9829d27c532f974643e6df-refs/heads/main@{#92862}
|
||||
|
||||
diff --git a/src/builtins/builtins-array.cc b/src/builtins/builtins-array.cc
|
||||
index 60dc19367aa38997721ed85df6210f9de3a44313..dc82b658df09e5850ef2688fae1d748cb9873917 100644
|
||||
--- a/src/builtins/builtins-array.cc
|
||||
+++ b/src/builtins/builtins-array.cc
|
||||
@@ -51,7 +51,7 @@ inline bool HasOnlySimpleElements(Isolate* isolate,
|
||||
DisallowGarbageCollection no_gc;
|
||||
PrototypeIterator iter(isolate, receiver, kStartAtReceiver);
|
||||
for (; !iter.IsAtEnd(); iter.Advance()) {
|
||||
- if (IsJSProxy(iter.GetCurrent())) return false;
|
||||
+ if (!IsJSObject(iter.GetCurrent())) return false;
|
||||
Tagged<JSObject> current = iter.GetCurrent<JSObject>();
|
||||
if (!HasSimpleElements(current)) return false;
|
||||
}
|
||||
27
patches/v8/cherry-pick-f320600cd1f4.patch
Normal file
27
patches/v8/cherry-pick-f320600cd1f4.patch
Normal file
@@ -0,0 +1,27 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shu-yu Guo <syg@chromium.org>
|
||||
Date: Thu, 9 May 2024 12:03:28 -0700
|
||||
Subject: Only normalize JSObject targets in SetOrCopyDataProperties
|
||||
|
||||
Bug: 339458194
|
||||
Change-Id: I4d6eebdd921971fa28d7c474535d978900ba633f
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5527397
|
||||
Reviewed-by: Rezvan Mahdavi Hezaveh <rezvan@chromium.org>
|
||||
Commit-Queue: Shu-yu Guo <syg@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#93811}
|
||||
|
||||
diff --git a/src/objects/js-objects.cc b/src/objects/js-objects.cc
|
||||
index 32e1e89fc53217fe188c1f764bd97c03dadf35a2..0381a9f65a9e6cdfb30881077e4a442cd2a10802 100644
|
||||
--- a/src/objects/js-objects.cc
|
||||
+++ b/src/objects/js-objects.cc
|
||||
@@ -429,9 +429,7 @@ Maybe<bool> JSReceiver::SetOrCopyDataProperties(
|
||||
Nothing<bool>());
|
||||
|
||||
if (!from->HasFastProperties() && target->HasFastProperties() &&
|
||||
- !IsJSGlobalProxy(*target)) {
|
||||
- // JSProxy is always in slow-mode.
|
||||
- DCHECK(!IsJSProxy(*target));
|
||||
+ IsJSObject(*target) && !IsJSGlobalProxy(*target)) {
|
||||
// Convert to slow properties if we're guaranteed to overflow the number of
|
||||
// descriptors.
|
||||
int source_length;
|
||||
45
patches/v8/cherry-pick-f911ff372723.patch
Normal file
45
patches/v8/cherry-pick-f911ff372723.patch
Normal file
@@ -0,0 +1,45 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shu-yu Guo <syg@chromium.org>
|
||||
Date: Fri, 10 May 2024 12:08:04 -0700
|
||||
Subject: Merged: [ic] Use slow stub element handler for non-JSObjects
|
||||
|
||||
Fixed: 339736513
|
||||
(cherry picked from commit 8a69c7880844ab00ee2f32079579a040a87eedca)
|
||||
|
||||
Change-Id: If87462eb044c194798a32cb25a5f3648ff823196
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5555847
|
||||
Commit-Queue: Shu-yu Guo <syg@chromium.org>
|
||||
Reviewed-by: Adam Klein <adamk@chromium.org>
|
||||
Commit-Queue: Adam Klein <adamk@chromium.org>
|
||||
Auto-Submit: Shu-yu Guo <syg@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/12.4@{#36}
|
||||
Cr-Branched-From: 309640da62fae0485c7e4f64829627c92d53b35d-refs/heads/12.4.254@{#1}
|
||||
Cr-Branched-From: 5dc24701432278556a9829d27c532f974643e6df-refs/heads/main@{#92862}
|
||||
|
||||
diff --git a/src/ic/ic.cc b/src/ic/ic.cc
|
||||
index 61bb82aff98e4273b651801b875416c686de872e..34cf7eb6d2f5ef74b37103a6ee2356b8825d3f58 100644
|
||||
--- a/src/ic/ic.cc
|
||||
+++ b/src/ic/ic.cc
|
||||
@@ -2349,15 +2349,16 @@ Handle<Object> KeyedStoreIC::StoreElementHandler(
|
||||
isolate()),
|
||||
IsStoreInArrayLiteralIC());
|
||||
|
||||
- if (IsJSProxyMap(*receiver_map)) {
|
||||
+ if (!IsJSObjectMap(*receiver_map)) {
|
||||
// DefineKeyedOwnIC, which is used to define computed fields in instances,
|
||||
- // should be handled by the slow stub.
|
||||
- if (IsDefineKeyedOwnIC()) {
|
||||
- TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_SlowStub);
|
||||
- return StoreHandler::StoreSlow(isolate(), store_mode);
|
||||
+ // should handled by the slow stub below instead of the proxy stub.
|
||||
+ if (IsJSProxyMap(*receiver_map) && !IsDefineKeyedOwnIC()) {
|
||||
+ return StoreHandler::StoreProxy(isolate());
|
||||
}
|
||||
|
||||
- return StoreHandler::StoreProxy(isolate());
|
||||
+ // Wasm objects or other kind of special objects go through the slow stub.
|
||||
+ TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_SlowStub);
|
||||
+ return StoreHandler::StoreSlow(isolate(), store_mode);
|
||||
}
|
||||
|
||||
// TODO(ishell): move to StoreHandler::StoreElement().
|
||||
@@ -0,0 +1,152 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Thibaud Michaud <thibaudm@chromium.org>
|
||||
Date: Tue, 18 Jun 2024 11:34:17 +0200
|
||||
Subject: Merged: [wasm] Add missing type canonicalization for exceptions JS
|
||||
API
|
||||
|
||||
When we encode a JS value in a wasm exception, canonicalize the type
|
||||
stored in the tag's signature first. Canonicalize it using the tag's
|
||||
original module by storing the instance on the tag object.
|
||||
|
||||
R=jkummerow@chromium.org
|
||||
|
||||
Bug: 346197738
|
||||
(cherry picked from commit 89dc6eab605cde2ffaa92dd9acf461caa63478de)
|
||||
|
||||
Change-Id: I9a0b42702b1e5f7ef25091ed99c9bb00849bbc10
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5633661
|
||||
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
|
||||
Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/12.6@{#36}
|
||||
Cr-Branched-From: 3c9fa12db3183a6f4ea53d2675adb66ea1194529-refs/heads/12.6.228@{#2}
|
||||
Cr-Branched-From: 981bb15ba4dbf9e2381dfc94ec2c4af0b9c6a0b6-refs/heads/main@{#93835}
|
||||
|
||||
diff --git a/src/wasm/module-instantiate.cc b/src/wasm/module-instantiate.cc
|
||||
index debe7e03329f64eeac248e3af7271da464bb819c..fe43e398a4b11b2858bed85f05231bbc0c30062a 100644
|
||||
--- a/src/wasm/module-instantiate.cc
|
||||
+++ b/src/wasm/module-instantiate.cc
|
||||
@@ -2591,8 +2591,10 @@ void InstanceBuilder::ProcessExports(
|
||||
isolate_);
|
||||
uint32_t canonical_sig_index =
|
||||
module_->isorecursive_canonical_type_ids[tag.sig_index];
|
||||
+ Handle<WasmInstanceObject> instance =
|
||||
+ handle(trusted_instance_data->instance_object(), isolate_);
|
||||
wrapper = WasmTagObject::New(isolate_, tag.sig, canonical_sig_index,
|
||||
- tag_object);
|
||||
+ tag_object, instance);
|
||||
tags_wrappers_[exp.index] = wrapper;
|
||||
}
|
||||
value = wrapper;
|
||||
diff --git a/src/wasm/wasm-js.cc b/src/wasm/wasm-js.cc
|
||||
index 6595f651b707fab4081e76f94fd0eabba7f5755b..1ad851c9998e6296c28e2c04aa8501de8b49ec1d 100644
|
||||
--- a/src/wasm/wasm-js.cc
|
||||
+++ b/src/wasm/wasm-js.cc
|
||||
@@ -1855,7 +1855,8 @@ void WebAssemblyTagImpl(const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
i::wasm::GetWasmEngine()->type_canonicalizer()->AddRecursiveGroup(&sig);
|
||||
|
||||
i::Handle<i::JSObject> tag_object =
|
||||
- i::WasmTagObject::New(i_isolate, &sig, canonical_type_index, tag);
|
||||
+ i::WasmTagObject::New(i_isolate, &sig, canonical_type_index, tag,
|
||||
+ i_isolate->factory()->undefined_value());
|
||||
info.GetReturnValue().Set(Utils::ToLocal(tag_object));
|
||||
}
|
||||
|
||||
@@ -1901,6 +1902,7 @@ uint32_t GetEncodedSize(i::Handle<i::WasmTagObject> tag_object) {
|
||||
|
||||
void EncodeExceptionValues(v8::Isolate* isolate,
|
||||
i::Handle<i::PodArray<i::wasm::ValueType>> signature,
|
||||
+ i::Handle<i::WasmTagObject> tag_object,
|
||||
const Local<Value>& arg, ErrorThrower* thrower,
|
||||
i::Handle<i::FixedArray> values_out) {
|
||||
Local<Context> context = isolate->GetCurrentContext();
|
||||
@@ -1958,6 +1960,19 @@ void EncodeExceptionValues(v8::Isolate* isolate,
|
||||
case i::wasm::kRefNull: {
|
||||
const char* error_message;
|
||||
i::Handle<i::Object> value_handle = Utils::OpenHandle(*value);
|
||||
+
|
||||
+ if (type.has_index()) {
|
||||
+ // Canonicalize the type using the tag's original module.
|
||||
+ i::Tagged<i::HeapObject> maybe_instance = tag_object->instance();
|
||||
+ CHECK(!i::IsUndefined(maybe_instance));
|
||||
+ auto instance = i::WasmInstanceObject::cast(maybe_instance);
|
||||
+ const i::wasm::WasmModule* module = instance->module();
|
||||
+ uint32_t canonical_index =
|
||||
+ module->isorecursive_canonical_type_ids[type.ref_index()];
|
||||
+ type = i::wasm::ValueType::RefMaybeNull(canonical_index,
|
||||
+ type.nullability());
|
||||
+ }
|
||||
+
|
||||
if (!internal::wasm::JSToWasmObject(i_isolate, value_handle, type,
|
||||
&error_message)
|
||||
.ToHandle(&value_handle)) {
|
||||
@@ -2013,7 +2028,8 @@ void WebAssemblyExceptionImpl(const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
runtime_exception));
|
||||
i::Handle<i::PodArray<i::wasm::ValueType>> signature(
|
||||
tag_object->serialized_signature(), i_isolate);
|
||||
- EncodeExceptionValues(isolate, signature, info[1], &thrower, values);
|
||||
+ EncodeExceptionValues(isolate, signature, tag_object, info[1], &thrower,
|
||||
+ values);
|
||||
if (thrower.error()) return;
|
||||
|
||||
// Third argument: optional ExceptionOption ({traceStack: <bool>}).
|
||||
@@ -3228,9 +3244,9 @@ void WasmJs::PrepareForSnapshot(Isolate* isolate) {
|
||||
// Note the canonical_type_index is reset in WasmJs::Install s.t.
|
||||
// type_canonicalizer bookkeeping remains valid.
|
||||
static constexpr uint32_t kInitialCanonicalTypeIndex = 0;
|
||||
- Handle<JSObject> js_tag_object =
|
||||
- WasmTagObject::New(isolate, &kWasmExceptionTagSignature,
|
||||
- kInitialCanonicalTypeIndex, js_tag);
|
||||
+ Handle<JSObject> js_tag_object = WasmTagObject::New(
|
||||
+ isolate, &kWasmExceptionTagSignature, kInitialCanonicalTypeIndex,
|
||||
+ js_tag, isolate->factory()->undefined_value());
|
||||
native_context->set_wasm_js_tag(*js_tag_object);
|
||||
JSObject::AddProperty(isolate, webassembly, "JSTag", js_tag_object,
|
||||
ro_attributes);
|
||||
diff --git a/src/wasm/wasm-objects.cc b/src/wasm/wasm-objects.cc
|
||||
index 2747ab23b574d658173e9077696b10fc774698a0..c487cb6cf02d7b65b4a593f299d28af689e850a8 100644
|
||||
--- a/src/wasm/wasm-objects.cc
|
||||
+++ b/src/wasm/wasm-objects.cc
|
||||
@@ -1884,7 +1884,8 @@ void WasmArray::SetTaggedElement(uint32_t index, Handle<Object> value,
|
||||
Handle<WasmTagObject> WasmTagObject::New(Isolate* isolate,
|
||||
const wasm::FunctionSig* sig,
|
||||
uint32_t canonical_type_index,
|
||||
- Handle<HeapObject> tag) {
|
||||
+ Handle<HeapObject> tag,
|
||||
+ Handle<HeapObject> instance) {
|
||||
Handle<JSFunction> tag_cons(isolate->native_context()->wasm_tag_constructor(),
|
||||
isolate);
|
||||
|
||||
@@ -1905,6 +1906,7 @@ Handle<WasmTagObject> WasmTagObject::New(Isolate* isolate,
|
||||
tag_wrapper->set_serialized_signature(*serialized_sig);
|
||||
tag_wrapper->set_canonical_type_index(canonical_type_index);
|
||||
tag_wrapper->set_tag(*tag);
|
||||
+ tag_wrapper->set_instance(*instance);
|
||||
|
||||
return tag_wrapper;
|
||||
}
|
||||
diff --git a/src/wasm/wasm-objects.h b/src/wasm/wasm-objects.h
|
||||
index dc43d5e686ae63000f02eaa8df8c4fb3caf7b7eb..794b56c1f9a8e39b1b71d8d39f2fe417e0bf54e1 100644
|
||||
--- a/src/wasm/wasm-objects.h
|
||||
+++ b/src/wasm/wasm-objects.h
|
||||
@@ -607,7 +607,8 @@ class WasmTagObject
|
||||
static Handle<WasmTagObject> New(Isolate* isolate,
|
||||
const wasm::FunctionSig* sig,
|
||||
uint32_t canonical_type_index,
|
||||
- Handle<HeapObject> tag);
|
||||
+ Handle<HeapObject> tag,
|
||||
+ Handle<HeapObject> instance);
|
||||
|
||||
TQ_OBJECT_CONSTRUCTORS(WasmTagObject)
|
||||
};
|
||||
diff --git a/src/wasm/wasm-objects.tq b/src/wasm/wasm-objects.tq
|
||||
index 9f204366041e49837252736ad1b83d9f5a9f815d..9287a5066846db7a775c13ae7889dc8c38dd4129 100644
|
||||
--- a/src/wasm/wasm-objects.tq
|
||||
+++ b/src/wasm/wasm-objects.tq
|
||||
@@ -185,6 +185,7 @@ extern class WasmGlobalObject extends JSObject {
|
||||
extern class WasmTagObject extends JSObject {
|
||||
serialized_signature: PodArrayOfWasmValueType;
|
||||
tag: HeapObject;
|
||||
+ instance: WasmInstanceObject|Undefined;
|
||||
canonical_type_index: Smi;
|
||||
}
|
||||
|
||||
91
script/actions/move-artifacts.sh
Executable file
91
script/actions/move-artifacts.sh
Executable file
@@ -0,0 +1,91 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ "`uname`" == "Darwin" ]; then
|
||||
if [ -z "$MAS_BUILD" ]; then
|
||||
BUILD_TYPE="darwin"
|
||||
else
|
||||
BUILD_TYPE="mas"
|
||||
fi
|
||||
elif [ "`uname`" == "Linux" ]; then
|
||||
BUILD_TYPE="linux"
|
||||
else
|
||||
echo "Unsupported platform"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
GENERATED_ARTIFACTS="generated_artifacts_${BUILD_TYPE}_${TARGET_ARCH}"
|
||||
|
||||
echo Creating $GENERATED_ARTIFACTS...
|
||||
rm -rf $GENERATED_ARTIFACTS
|
||||
mkdir $GENERATED_ARTIFACTS
|
||||
|
||||
SRC_ARTIFACTS="src_artifacts_${BUILD_TYPE}_${TARGET_ARCH}"
|
||||
|
||||
echo Creating $SRC_ARTIFACTS...
|
||||
rm -rf $SRC_ARTIFACTS
|
||||
mkdir $SRC_ARTIFACTS
|
||||
|
||||
mv_if_exist() {
|
||||
if [ -f "$1" ] || [ -d "$1" ]; then
|
||||
echo Storing $1
|
||||
mv $1 $GENERATED_ARTIFACTS
|
||||
else
|
||||
echo Skipping $1 - It is not present on disk
|
||||
fi
|
||||
}
|
||||
|
||||
cp_if_exist() {
|
||||
if [ -f "$1" ] || [ -d "$1" ]; then
|
||||
echo Storing $1
|
||||
cp $1 $GENERATED_ARTIFACTS
|
||||
else
|
||||
echo Skipping $1 - It is not present on disk
|
||||
fi
|
||||
}
|
||||
|
||||
move_src_dirs_if_exist() {
|
||||
mkdir src_artifacts
|
||||
|
||||
for dir in \
|
||||
src/out/Default/gen/node_headers \
|
||||
src/out/Default/overlapped-checker \
|
||||
src/out/Default/ffmpeg \
|
||||
src/out/Default/hunspell_dictionaries \
|
||||
src/third_party/electron_node \
|
||||
src/third_party/nan \
|
||||
src/cross-arch-snapshots \
|
||||
src/third_party/llvm-build \
|
||||
src/build/linux \
|
||||
src/buildtools/mac \
|
||||
src/buildtools/third_party/libc++ \
|
||||
src/buildtools/third_party/libc++abi \
|
||||
src/third_party/libc++ \
|
||||
src/third_party/libc++abi \
|
||||
src/out/Default/obj/buildtools/third_party \
|
||||
src/v8/tools/builtins-pgo
|
||||
do
|
||||
if [ -d "$dir" ]; then
|
||||
mkdir -p src_artifacts/$(dirname $dir)
|
||||
cp -r $dir/ src_artifacts/$dir
|
||||
fi
|
||||
done
|
||||
|
||||
tar -C src_artifacts -cf src_artifacts.tar ./
|
||||
|
||||
echo Storing src_artifacts.tar
|
||||
mv src_artifacts.tar $SRC_ARTIFACTS
|
||||
}
|
||||
|
||||
# Generated Artifacts
|
||||
mv_if_exist src/out/Default/dist.zip
|
||||
mv_if_exist src/out/Default/gen/node_headers.tar.gz
|
||||
mv_if_exist src/out/Default/symbols.zip
|
||||
mv_if_exist src/out/Default/mksnapshot.zip
|
||||
mv_if_exist src/out/Default/chromedriver.zip
|
||||
mv_if_exist src/out/ffmpeg/ffmpeg.zip
|
||||
mv_if_exist src/out/Default/hunspell_dictionaries.zip
|
||||
mv_if_exist src/cross-arch-snapshots
|
||||
cp_if_exist src/out/electron_ninja_log
|
||||
cp_if_exist src/out/Default/.ninja_log
|
||||
|
||||
move_src_dirs_if_exist
|
||||
40
script/actions/restore-artifacts.sh
Executable file
40
script/actions/restore-artifacts.sh
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
|
||||
GENERATED_ARTIFACTS="generated_artifacts_${BUILD_TYPE}_${TARGET_ARCH}"
|
||||
SRC_ARTIFACTS="src_artifacts_${BUILD_TYPE}_${TARGET_ARCH}"
|
||||
|
||||
mv_if_exist() {
|
||||
if [ -f "${GENERATED_ARTIFACTS}/$1" ] || [ -d "${GENERATED_ARTIFACTS}/$1" ]; then
|
||||
echo Restoring $1 to $2
|
||||
mkdir -p $2
|
||||
mv $GENERATED_ARTIFACTS/$1 $2
|
||||
else
|
||||
echo Skipping $1 - It is not present on disk
|
||||
fi
|
||||
}
|
||||
|
||||
untar_if_exist() {
|
||||
if [ -f "${SRC_ARTIFACTS}/$1" ] || [ -d "${SRC_ARTIFACTS}/$1" ]; then
|
||||
echo Restoring $1 to current directory
|
||||
tar -xf ${SRC_ARTIFACTS}/$1
|
||||
else
|
||||
echo Skipping $1 - It is not present on disk
|
||||
fi
|
||||
}
|
||||
|
||||
echo Restoring artifacts from $GENERATED_ARTIFACTS
|
||||
|
||||
# Restore generated artifacts
|
||||
mv_if_exist dist.zip src/out/Default
|
||||
mv_if_exist node_headers.tar.gz src/out/Default/gen
|
||||
mv_if_exist symbols.zip src/out/Default
|
||||
mv_if_exist mksnapshot.zip src/out/Default
|
||||
mv_if_exist chromedriver.zip src/out/Default
|
||||
mv_if_exist ffmpeg.zip src/out/ffmpeg
|
||||
mv_if_exist hunspell_dictionaries.zip src/out/Default
|
||||
mv_if_exist cross-arch-snapshots src
|
||||
|
||||
echo Restoring artifacts from $SRC_ARTIFACTS
|
||||
|
||||
# Restore src artifacts
|
||||
untar_if_exist src_artifacts.tar
|
||||
7
script/actions/run-tests.sh
Executable file
7
script/actions/run-tests.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
export DISPLAY=:99
|
||||
Xvfb :99 -screen 0 1024x768x16 -ac &
|
||||
XVFB_PID=$!
|
||||
node "$@"
|
||||
@@ -39,7 +39,7 @@ def read_electron_args():
|
||||
for line in f:
|
||||
if line.startswith('#'):
|
||||
continue
|
||||
m = re.match('([\w_]+) = (.+)', line)
|
||||
m = re.match('(\w+) = (.+)', line)
|
||||
if m == None:
|
||||
continue
|
||||
args[m.group(1)] = m.group(2)
|
||||
|
||||
@@ -17,6 +17,14 @@ const args = require('minimist')(process.argv.slice(2), {
|
||||
string: ['only']
|
||||
});
|
||||
|
||||
const getNodeGypVersion = () => {
|
||||
const nanPackageJSONPath = path.join(NAN_DIR, 'package.json');
|
||||
const nanPackageJSON = JSON.parse(fs.readFileSync(nanPackageJSONPath, 'utf8'));
|
||||
const { devDependencies } = nanPackageJSON;
|
||||
const nodeGypVersion = devDependencies['node-gyp'];
|
||||
return nodeGypVersion || 'latest';
|
||||
};
|
||||
|
||||
async function main () {
|
||||
const outDir = utils.getOutDir({ shouldLog: true });
|
||||
const nodeDir = path.resolve(BASE, 'out', outDir, 'gen', 'node_headers');
|
||||
@@ -90,16 +98,17 @@ async function main () {
|
||||
env.LDFLAGS = ldflags;
|
||||
}
|
||||
|
||||
const { status: buildStatus } = cp.spawnSync(NPX_CMD, ['node-gyp', 'rebuild', '--verbose', '--directory', 'test', '-j', 'max'], {
|
||||
const nodeGypVersion = getNodeGypVersion();
|
||||
const { status: buildStatus, signal } = cp.spawnSync(NPX_CMD, [`node-gyp@${nodeGypVersion}`, 'rebuild', '--verbose', '--directory', 'test', '-j', 'max'], {
|
||||
env,
|
||||
cwd: NAN_DIR,
|
||||
stdio: 'inherit',
|
||||
shell: process.platform === 'win32'
|
||||
});
|
||||
|
||||
if (buildStatus !== 0) {
|
||||
if (buildStatus !== 0 || signal != null) {
|
||||
console.error('Failed to build nan test modules');
|
||||
return process.exit(buildStatus);
|
||||
return process.exit(buildStatus !== 0 ? buildStatus : signal);
|
||||
}
|
||||
|
||||
const { status: installStatus } = cp.spawnSync(NPX_CMD, [`yarn@${YARN_VERSION}`, 'install'], {
|
||||
@@ -108,9 +117,10 @@ async function main () {
|
||||
stdio: 'inherit',
|
||||
shell: process.platform === 'win32'
|
||||
});
|
||||
if (installStatus !== 0) {
|
||||
|
||||
if (installStatus !== 0 || signal != null) {
|
||||
console.error('Failed to install nan node_modules');
|
||||
return process.exit(installStatus);
|
||||
return process.exit(installStatus !== 0 ? installStatus : signal);
|
||||
}
|
||||
|
||||
const onlyTests = args.only && args.only.split(',');
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
"parallel/test-crypto-padding-aes256",
|
||||
"parallel/test-crypto-secure-heap",
|
||||
"parallel/test-dgram-send-cb-quelches-error",
|
||||
"parallel/test-domain-error-types",
|
||||
"parallel/test-fs-utimes-y2K38",
|
||||
"parallel/test-http2-clean-output",
|
||||
"parallel/test-http2-https-fallback.js",
|
||||
|
||||
@@ -3,9 +3,16 @@ if (!process.env.CI) require('dotenv-safe').load();
|
||||
const assert = require('node:assert');
|
||||
const got = require('got');
|
||||
|
||||
const { Octokit } = require('@octokit/rest');
|
||||
const octokit = new Octokit({
|
||||
auth: process.env.ELECTRON_GITHUB_TOKEN
|
||||
});
|
||||
|
||||
const BUILD_APPVEYOR_URL = 'https://ci.appveyor.com/api/builds';
|
||||
const CIRCLECI_PIPELINE_URL = 'https://circleci.com/api/v2/project/gh/electron/electron/pipeline';
|
||||
const CIRCLECI_WAIT_TIME = process.env.CIRCLECI_WAIT_TIME || 30000;
|
||||
const GH_ACTIONS_PIPELINE_URL = 'https://github.com/electron/electron/actions';
|
||||
const GH_ACTIONS_API_URL = '/repos/electron/electron/actions';
|
||||
|
||||
const GH_ACTIONS_WAIT_TIME = process.env.GH_ACTIONS_WAIT_TIME || 30000;
|
||||
|
||||
const appVeyorJobs = {
|
||||
'electron-x64': 'electron-x64-release',
|
||||
@@ -13,16 +20,11 @@ const appVeyorJobs = {
|
||||
'electron-woa': 'electron-woa-release'
|
||||
};
|
||||
|
||||
const circleCIPublishWorkflows = [
|
||||
const ghActionsPublishWorkflows = [
|
||||
'linux-publish',
|
||||
'macos-publish'
|
||||
];
|
||||
|
||||
const circleCIPublishIndividualArches = {
|
||||
'macos-publish': ['osx-x64', 'mas-x64', 'osx-arm64', 'mas-arm64'],
|
||||
'linux-publish': ['arm', 'arm64', 'x64']
|
||||
};
|
||||
|
||||
let jobRequestedCount = 0;
|
||||
|
||||
async function makeRequest ({ auth, username, password, url, headers, body, method }) {
|
||||
@@ -53,8 +55,8 @@ async function makeRequest ({ auth, username, password, url, headers, body, meth
|
||||
return JSON.parse(response.body);
|
||||
}
|
||||
|
||||
async function circleCIcall (targetBranch, workflowName, options) {
|
||||
console.log(`Triggering CircleCI to run build job: ${workflowName} on branch: ${targetBranch} with release flag.`);
|
||||
async function githubActionsCall (targetBranch, workflowName, options) {
|
||||
console.log(`Triggering GitHub Actions to run build job: ${workflowName} on branch: ${targetBranch} with release flag.`);
|
||||
const buildRequest = {
|
||||
branch: targetBranch,
|
||||
parameters: {}
|
||||
@@ -65,145 +67,99 @@ async function circleCIcall (targetBranch, workflowName, options) {
|
||||
buildRequest.parameters['upload-to-storage'] = '1';
|
||||
}
|
||||
buildRequest.parameters[`run-${workflowName}`] = true;
|
||||
if (options.arch) {
|
||||
const validArches = circleCIPublishIndividualArches[workflowName];
|
||||
assert(validArches.includes(options.arch), `Unknown CircleCI architecture "${options.arch}". Valid values are ${JSON.stringify(validArches)}`);
|
||||
buildRequest.parameters['macos-publish-arch-limit'] = options.arch;
|
||||
}
|
||||
|
||||
jobRequestedCount++;
|
||||
// The logic below expects that the CircleCI workflows for releases each
|
||||
// contain only one job in order to maintain compatibility with sudowoodo.
|
||||
// If the workflows are changed in the CircleCI config.yml, this logic will
|
||||
// also need to be changed as well as possibly changing sudowoodo.
|
||||
try {
|
||||
const circleResponse = await circleCIRequest(CIRCLECI_PIPELINE_URL, 'POST', buildRequest);
|
||||
console.log(`CircleCI release build pipeline ${circleResponse.id} for ${workflowName} triggered.`);
|
||||
const workflowId = await getCircleCIWorkflowId(circleResponse.id);
|
||||
if (workflowId === -1) {
|
||||
const commits = await octokit.repos.listCommits({
|
||||
owner: 'electron',
|
||||
repo: 'electron',
|
||||
sha: targetBranch,
|
||||
per_page: 5
|
||||
});
|
||||
if (!commits.data.length) {
|
||||
console.error('Could not fetch most recent commits for GitHub Actions, returning early');
|
||||
}
|
||||
|
||||
await octokit.request(`POST ${GH_ACTIONS_API_URL}/workflows/${workflowName}.yml/dispatches`, {
|
||||
ref: `refs/tags/${options.newVersion}`,
|
||||
inputs: {
|
||||
...buildRequest.parameters
|
||||
},
|
||||
headers: {
|
||||
'X-GitHub-Api-Version': '2022-11-28'
|
||||
}
|
||||
});
|
||||
|
||||
const runNumber = await getGitHubActionsRun(workflowName, commits.data[0].sha);
|
||||
if (runNumber === -1) {
|
||||
return;
|
||||
}
|
||||
const workFlowUrl = `https://circleci.com/workflow-run/${workflowId}`;
|
||||
|
||||
console.log(`GitHub Actions release build pipeline ${runNumber} for ${workflowName} triggered.`);
|
||||
const runUrl = `${GH_ACTIONS_PIPELINE_URL}/runs/${runNumber}`;
|
||||
|
||||
if (options.runningPublishWorkflows) {
|
||||
console.log(`CircleCI release workflow request for ${workflowName} successful. Check ${workFlowUrl} for status.`);
|
||||
console.log(`GitHub Actions release workflow request for ${workflowName} successful. Check ${runUrl} for status.`);
|
||||
} else {
|
||||
console.log(`CircleCI release build workflow running at https://circleci.com/workflow-run/${workflowId} for ${workflowName}.`);
|
||||
const jobNumber = await getCircleCIJobNumber(workflowId);
|
||||
if (jobNumber === -1) {
|
||||
return;
|
||||
}
|
||||
const jobUrl = `https://circleci.com/gh/electron/electron/${jobNumber}`;
|
||||
console.log(`CircleCI release build request for ${workflowName} successful. Check ${jobUrl} for status.`);
|
||||
console.log(`GitHub Actions release build workflow running at ${GH_ACTIONS_PIPELINE_URL}/runs/${runNumber} for ${workflowName}.`);
|
||||
console.log(`GitHub Actions release build request for ${workflowName} successful. Check ${runUrl} for status.`);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Error calling CircleCI: ', err);
|
||||
console.log('Error calling GitHub Actions: ', err);
|
||||
}
|
||||
}
|
||||
|
||||
async function getCircleCIWorkflowId (pipelineId) {
|
||||
const pipelineInfoUrl = `https://circleci.com/api/v2/pipeline/${pipelineId}`;
|
||||
let workflowId = 0;
|
||||
while (workflowId === 0) {
|
||||
const pipelineInfo = await circleCIRequest(pipelineInfoUrl, 'GET');
|
||||
switch (pipelineInfo.state) {
|
||||
case 'created': {
|
||||
const workflows = await circleCIRequest(`${pipelineInfoUrl}/workflow`, 'GET');
|
||||
// The logic below expects three workflow.items: publish, lint, & setup
|
||||
if (workflows.items.length === 3) {
|
||||
workflowId = workflows.items.find(item => item.name.includes('publish')).id;
|
||||
break;
|
||||
}
|
||||
console.log('Unexpected number of workflows, response was:', workflows);
|
||||
workflowId = -1;
|
||||
break;
|
||||
async function getGitHubActionsRun (workflowId, headCommit) {
|
||||
let runNumber = 0;
|
||||
let actionRun;
|
||||
while (runNumber === 0) {
|
||||
const actionsRuns = await octokit.request(`GET ${GH_ACTIONS_API_URL}/workflows/${workflowId}.yml/runs`, {
|
||||
headers: {
|
||||
'X-GitHub-Api-Version': '2022-11-28'
|
||||
}
|
||||
case 'error': {
|
||||
console.log('Error retrieving workflows, response was:', pipelineInfo);
|
||||
workflowId = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, CIRCLECI_WAIT_TIME));
|
||||
}
|
||||
return workflowId;
|
||||
}
|
||||
|
||||
async function getCircleCIJobNumber (workflowId) {
|
||||
const jobInfoUrl = `https://circleci.com/api/v2/workflow/${workflowId}/job`;
|
||||
let jobNumber = 0;
|
||||
while (jobNumber === 0) {
|
||||
const jobInfo = await circleCIRequest(jobInfoUrl, 'GET');
|
||||
if (!jobInfo.items) {
|
||||
continue;
|
||||
}
|
||||
if (jobInfo.items.length !== 1) {
|
||||
console.log('Unexpected number of jobs, response was:', jobInfo);
|
||||
jobNumber = -1;
|
||||
});
|
||||
if (!actionsRuns.data.workflow_runs.length) {
|
||||
console.log(`No current workflow_runs found for ${workflowId}, response was: ${actionsRuns.data.workflow_runs}`);
|
||||
runNumber = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (jobInfo.items[0].status) {
|
||||
case 'not_running':
|
||||
case 'queued':
|
||||
case 'running': {
|
||||
if (jobInfo.items[0].job_number && !isNaN(jobInfo.items[0].job_number)) {
|
||||
jobNumber = jobInfo.items[0].job_number;
|
||||
for (const run of actionsRuns.data.workflow_runs) {
|
||||
if (run.head_sha === headCommit) {
|
||||
console.log(`GitHub Actions run ${run.html_url} found for ${headCommit}, waiting on status.`);
|
||||
actionRun = run;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (actionRun) {
|
||||
switch (actionRun.status) {
|
||||
case 'in_progress':
|
||||
case 'pending':
|
||||
case 'queued':
|
||||
case 'requested':
|
||||
case 'waiting': {
|
||||
if (actionRun.id && !isNaN(actionRun.id)) {
|
||||
console.log(`GitHub Actions run ${actionRun.status} for ${actionRun.html_url}.`);
|
||||
runNumber = actionRun.id;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'action_required':
|
||||
case 'cancelled':
|
||||
case 'failure':
|
||||
case 'skipped':
|
||||
case 'timed_out':
|
||||
case 'failed': {
|
||||
console.log(`Error workflow run returned a status of ${actionRun.status} for ${actionRun.html_url}`);
|
||||
runNumber = -1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'canceled':
|
||||
case 'error':
|
||||
case 'infrastructure_fail':
|
||||
case 'timedout':
|
||||
case 'not_run':
|
||||
case 'failed': {
|
||||
console.log(`Error job returned a status of ${jobInfo.items[0].status}, response was:`, jobInfo);
|
||||
jobNumber = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, CIRCLECI_WAIT_TIME));
|
||||
}
|
||||
return jobNumber;
|
||||
}
|
||||
|
||||
async function circleCIRequest (url, method, requestBody) {
|
||||
const requestOpts = {
|
||||
username: process.env.CIRCLE_TOKEN,
|
||||
password: '',
|
||||
method,
|
||||
url,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json'
|
||||
}
|
||||
};
|
||||
if (requestBody) {
|
||||
requestOpts.body = JSON.stringify(requestBody);
|
||||
}
|
||||
|
||||
return makeRequest(requestOpts, true).catch(err => {
|
||||
if (err.response?.body) {
|
||||
console.error('Could not call CircleCI: ', {
|
||||
statusCode: err.response.statusCode,
|
||||
body: JSON.parse(err.response.body)
|
||||
});
|
||||
} else {
|
||||
console.error('Error calling CircleCI:', err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function buildAppVeyor (targetBranch, options) {
|
||||
const validJobs = Object.keys(appVeyorJobs);
|
||||
if (options.job) {
|
||||
assert(validJobs.includes(options.job), `Unknown AppVeyor CI job name: ${options.job}. Valid values are: ${validJobs}.`);
|
||||
callAppVeyor(targetBranch, options.job, options);
|
||||
} else {
|
||||
for (const job of validJobs) {
|
||||
callAppVeyor(targetBranch, job, options);
|
||||
await new Promise(resolve => setTimeout(resolve, GH_ACTIONS_WAIT_TIME));
|
||||
}
|
||||
}
|
||||
return runNumber;
|
||||
}
|
||||
|
||||
async function callAppVeyor (targetBranch, job, options) {
|
||||
@@ -252,15 +208,27 @@ async function callAppVeyor (targetBranch, job, options) {
|
||||
}
|
||||
}
|
||||
|
||||
function buildCircleCI (targetBranch, options) {
|
||||
function buildAppVeyor (targetBranch, options) {
|
||||
const validJobs = Object.keys(appVeyorJobs);
|
||||
if (options.job) {
|
||||
assert(circleCIPublishWorkflows.includes(options.job), `Unknown CircleCI workflow name: ${options.job}. Valid values are: ${circleCIPublishWorkflows}.`);
|
||||
circleCIcall(targetBranch, options.job, options);
|
||||
assert(validJobs.includes(options.job), `Unknown AppVeyor CI job name: ${options.job}. Valid values are: ${validJobs}.`);
|
||||
callAppVeyor(targetBranch, options.job, options);
|
||||
} else {
|
||||
for (const job of validJobs) {
|
||||
callAppVeyor(targetBranch, job, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function buildGHActions (targetBranch, options) {
|
||||
if (options.job) {
|
||||
assert(ghActionsPublishWorkflows.includes(options.job), `Unknown GitHub Actions workflow name: ${options.job}. Valid values are: ${ghActionsPublishWorkflows}.`);
|
||||
githubActionsCall(targetBranch, options.job, options);
|
||||
} else {
|
||||
assert(!options.arch, 'Cannot provide a single architecture while building all workflows, please specify a single workflow via --workflow');
|
||||
options.runningPublishWorkflows = true;
|
||||
for (const job of circleCIPublishWorkflows) {
|
||||
circleCIcall(targetBranch, job, options);
|
||||
for (const job of ghActionsPublishWorkflows) {
|
||||
githubActionsCall(targetBranch, job, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -268,8 +236,8 @@ function buildCircleCI (targetBranch, options) {
|
||||
function runRelease (targetBranch, options) {
|
||||
if (options.ci) {
|
||||
switch (options.ci) {
|
||||
case 'CircleCI': {
|
||||
buildCircleCI(targetBranch, options);
|
||||
case 'GitHubActions': {
|
||||
buildGHActions(targetBranch, options);
|
||||
break;
|
||||
}
|
||||
case 'AppVeyor': {
|
||||
@@ -282,8 +250,8 @@ function runRelease (targetBranch, options) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
buildCircleCI(targetBranch, options);
|
||||
buildAppVeyor(targetBranch, options);
|
||||
buildGHActions(targetBranch, options);
|
||||
}
|
||||
console.log(`${jobRequestedCount} jobs were requested.`);
|
||||
}
|
||||
@@ -297,8 +265,8 @@ if (require.main === module) {
|
||||
const targetBranch = args._[0];
|
||||
if (args._.length < 1) {
|
||||
console.log(`Trigger CI to build release builds of electron.
|
||||
Usage: ci-release-build.js [--job=CI_JOB_NAME] [--arch=INDIVIDUAL_ARCH] [--ci=CircleCI|AppVeyor]
|
||||
[--ghRelease] [--circleBuildNum=xxx] [--appveyorJobId=xxx] [--commit=sha] TARGET_BRANCH
|
||||
Usage: ci-release-build.js [--job=CI_JOB_NAME] [--arch=INDIVIDUAL_ARCH] [--ci=AppVeyor|GitHubActions]
|
||||
[--ghRelease] [--appveyorJobId=xxx] [--commit=sha] TARGET_BRANCH
|
||||
`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,11 @@ const readline = require('node:readline');
|
||||
const releaseNotesGenerator = require('./notes/index.js');
|
||||
const { getCurrentBranch, ELECTRON_DIR } = require('../lib/utils.js');
|
||||
const bumpType = args._[0];
|
||||
const targetRepo = bumpType === 'nightly' ? 'nightlies' : 'electron';
|
||||
const targetRepo = getRepo();
|
||||
|
||||
function getRepo () {
|
||||
return bumpType === 'nightly' ? 'nightlies' : 'electron';
|
||||
}
|
||||
|
||||
const octokit = new Octokit({
|
||||
auth: process.env.ELECTRON_GITHUB_TOKEN
|
||||
@@ -138,9 +142,10 @@ async function pushRelease (branch) {
|
||||
}
|
||||
}
|
||||
|
||||
async function runReleaseBuilds (branch) {
|
||||
async function runReleaseBuilds (branch, newVersion) {
|
||||
await ciReleaseBuild(branch, {
|
||||
ghRelease: true
|
||||
ghRelease: true,
|
||||
newVersion
|
||||
});
|
||||
}
|
||||
|
||||
@@ -170,6 +175,8 @@ async function verifyNewVersion () {
|
||||
console.log(`${fail} Aborting release of ${newVersion}`);
|
||||
process.exit();
|
||||
}
|
||||
|
||||
return newVersion;
|
||||
}
|
||||
|
||||
async function promptForVersion (version) {
|
||||
@@ -205,10 +212,10 @@ async function prepareRelease (isBeta, notesOnly) {
|
||||
} else {
|
||||
const changes = await changesToRelease();
|
||||
if (changes) {
|
||||
await verifyNewVersion();
|
||||
const newVersion = await verifyNewVersion();
|
||||
await createRelease(currentBranch, isBeta);
|
||||
await pushRelease(currentBranch);
|
||||
await runReleaseBuilds(currentBranch);
|
||||
await runReleaseBuilds(currentBranch, newVersion);
|
||||
} else {
|
||||
console.log('There are no new changes to this branch since the last release, aborting release.');
|
||||
process.exit(1);
|
||||
|
||||
32
script/split-tests.js
Executable file
32
script/split-tests.js
Executable file
@@ -0,0 +1,32 @@
|
||||
const fs = require('node:fs');
|
||||
const glob = require('glob');
|
||||
|
||||
const currentShard = parseInt(process.argv[2], 10);
|
||||
const shardCount = parseInt(process.argv[3], 10);
|
||||
|
||||
const specFiles = glob.sync('spec/*-spec.ts');
|
||||
|
||||
const buckets = [];
|
||||
|
||||
for (let i = 0; i < shardCount; i++) {
|
||||
buckets.push([]);
|
||||
}
|
||||
|
||||
const testsInSpecFile = Object.create(null);
|
||||
for (const specFile of specFiles) {
|
||||
const testContent = fs.readFileSync(specFile, 'utf8');
|
||||
testsInSpecFile[specFile] = testContent.split('it(').length;
|
||||
}
|
||||
|
||||
specFiles.sort((a, b) => {
|
||||
return testsInSpecFile[b] - testsInSpecFile[a];
|
||||
});
|
||||
|
||||
let shard = 0;
|
||||
for (const specFile of specFiles) {
|
||||
buckets[shard].push(specFile);
|
||||
shard++;
|
||||
if (shard === shardCount) shard = 0;
|
||||
}
|
||||
|
||||
console.log(buckets[currentShard - 1].join(' '));
|
||||
@@ -884,12 +884,6 @@ void App::BrowserChildProcessCrashedOrKilled(
|
||||
if (!data.name.empty()) {
|
||||
details.Set("name", data.name);
|
||||
}
|
||||
if (data.process_type == content::PROCESS_TYPE_UTILITY) {
|
||||
base::ProcessId pid = data.GetProcess().Pid();
|
||||
auto utility_process_wrapper = UtilityProcessWrapper::FromProcessId(pid);
|
||||
if (utility_process_wrapper)
|
||||
utility_process_wrapper->Shutdown(info.exit_code);
|
||||
}
|
||||
Emit("child-process-gone", details);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "base/containers/contains.h"
|
||||
#include "base/task/single_thread_task_runner.h"
|
||||
#include "content/public/common/color_parser.h"
|
||||
#include "electron/buildflags/buildflags.h"
|
||||
#include "gin/dictionary.h"
|
||||
#include "shell/browser/api/electron_api_browser_view.h"
|
||||
@@ -37,6 +38,7 @@
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
#include "shell/browser/ui/views/win_frame_view.h"
|
||||
#include "shell/browser/ui/win/taskbar_host.h"
|
||||
#include "ui/base/win/shell.h"
|
||||
#endif
|
||||
@@ -1134,6 +1136,63 @@ void BaseWindow::SetAppDetails(const gin_helper::Dictionary& options) {
|
||||
relaunch_command, relaunch_display_name,
|
||||
window_->GetAcceleratedWidget());
|
||||
}
|
||||
|
||||
void BaseWindow::SetTitleBarOverlay(const gin_helper::Dictionary& options,
|
||||
gin_helper::Arguments* args) {
|
||||
// Ensure WCO is already enabled on this window
|
||||
if (!window_->titlebar_overlay_enabled()) {
|
||||
args->ThrowError("Titlebar overlay is not enabled");
|
||||
return;
|
||||
}
|
||||
|
||||
auto* window = static_cast<NativeWindowViews*>(window_.get());
|
||||
bool updated = false;
|
||||
|
||||
// Check and update the button color
|
||||
std::string btn_color;
|
||||
if (options.Get(options::kOverlayButtonColor, &btn_color)) {
|
||||
// Parse the string as a CSS color
|
||||
SkColor color;
|
||||
if (!content::ParseCssColorString(btn_color, &color)) {
|
||||
args->ThrowError("Could not parse color as CSS color");
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the view
|
||||
window->set_overlay_button_color(color);
|
||||
updated = true;
|
||||
}
|
||||
|
||||
// Check and update the symbol color
|
||||
std::string symbol_color;
|
||||
if (options.Get(options::kOverlaySymbolColor, &symbol_color)) {
|
||||
// Parse the string as a CSS color
|
||||
SkColor color;
|
||||
if (!content::ParseCssColorString(symbol_color, &color)) {
|
||||
args->ThrowError("Could not parse symbol color as CSS color");
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the view
|
||||
window->set_overlay_symbol_color(color);
|
||||
updated = true;
|
||||
}
|
||||
|
||||
// Check and update the height
|
||||
int height = 0;
|
||||
if (options.Get(options::kOverlayHeight, &height)) {
|
||||
window->set_titlebar_overlay_height(height);
|
||||
updated = true;
|
||||
}
|
||||
|
||||
// If anything was updated, invalidate the layout and schedule a paint of the
|
||||
// window's frame view
|
||||
if (updated) {
|
||||
auto* frame_view = static_cast<WinFrameView*>(
|
||||
window->widget()->non_client_view()->frame_view());
|
||||
frame_view->InvalidateCaptionButtons();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int32_t BaseWindow::GetID() const {
|
||||
@@ -1351,6 +1410,7 @@ void BaseWindow::BuildPrototype(v8::Isolate* isolate,
|
||||
.SetMethod("setThumbnailClip", &BaseWindow::SetThumbnailClip)
|
||||
.SetMethod("setThumbnailToolTip", &BaseWindow::SetThumbnailToolTip)
|
||||
.SetMethod("setAppDetails", &BaseWindow::SetAppDetails)
|
||||
.SetMethod("setTitleBarOverlay", &BaseWindow::SetTitleBarOverlay)
|
||||
#endif
|
||||
.SetProperty("id", &BaseWindow::GetID);
|
||||
}
|
||||
|
||||
@@ -251,6 +251,8 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>,
|
||||
bool SetThumbnailClip(const gfx::Rect& region);
|
||||
bool SetThumbnailToolTip(const std::string& tooltip);
|
||||
void SetAppDetails(const gin_helper::Dictionary& options);
|
||||
void SetTitleBarOverlay(const gin_helper::Dictionary& options,
|
||||
gin_helper::Arguments* args);
|
||||
#endif
|
||||
int32_t GetID() const;
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "content/browser/web_contents/web_contents_impl.h" // nogncheck
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "content/public/common/color_parser.h"
|
||||
#include "shell/browser/api/electron_api_web_contents_view.h"
|
||||
#include "shell/browser/browser.h"
|
||||
#include "shell/browser/native_browser_view.h"
|
||||
@@ -28,10 +27,6 @@
|
||||
#include "shell/browser/native_window_views.h"
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
#include "shell/browser/ui/views/win_frame_view.h"
|
||||
#endif
|
||||
|
||||
namespace electron::api {
|
||||
|
||||
BrowserWindow::BrowserWindow(gin::Arguments* args,
|
||||
@@ -332,65 +327,6 @@ v8::Local<v8::Value> BrowserWindow::GetWebContents(v8::Isolate* isolate) {
|
||||
return v8::Local<v8::Value>::New(isolate, web_contents_);
|
||||
}
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
void BrowserWindow::SetTitleBarOverlay(const gin_helper::Dictionary& options,
|
||||
gin_helper::Arguments* args) {
|
||||
// Ensure WCO is already enabled on this window
|
||||
if (!window_->titlebar_overlay_enabled()) {
|
||||
args->ThrowError("Titlebar overlay is not enabled");
|
||||
return;
|
||||
}
|
||||
|
||||
auto* window = static_cast<NativeWindowViews*>(window_.get());
|
||||
bool updated = false;
|
||||
|
||||
// Check and update the button color
|
||||
std::string btn_color;
|
||||
if (options.Get(options::kOverlayButtonColor, &btn_color)) {
|
||||
// Parse the string as a CSS color
|
||||
SkColor color;
|
||||
if (!content::ParseCssColorString(btn_color, &color)) {
|
||||
args->ThrowError("Could not parse color as CSS color");
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the view
|
||||
window->set_overlay_button_color(color);
|
||||
updated = true;
|
||||
}
|
||||
|
||||
// Check and update the symbol color
|
||||
std::string symbol_color;
|
||||
if (options.Get(options::kOverlaySymbolColor, &symbol_color)) {
|
||||
// Parse the string as a CSS color
|
||||
SkColor color;
|
||||
if (!content::ParseCssColorString(symbol_color, &color)) {
|
||||
args->ThrowError("Could not parse symbol color as CSS color");
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the view
|
||||
window->set_overlay_symbol_color(color);
|
||||
updated = true;
|
||||
}
|
||||
|
||||
// Check and update the height
|
||||
int height = 0;
|
||||
if (options.Get(options::kOverlayHeight, &height)) {
|
||||
window->set_titlebar_overlay_height(height);
|
||||
updated = true;
|
||||
}
|
||||
|
||||
// If anything was updated, invalidate the layout and schedule a paint of the
|
||||
// window's frame view
|
||||
if (updated) {
|
||||
auto* frame_view = static_cast<WinFrameView*>(
|
||||
window->widget()->non_client_view()->frame_view());
|
||||
frame_view->InvalidateCaptionButtons();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void BrowserWindow::ScheduleUnresponsiveEvent(int ms) {
|
||||
if (!window_unresponsive_closure_.IsCancelled())
|
||||
return;
|
||||
@@ -448,9 +384,6 @@ void BrowserWindow::BuildPrototype(v8::Isolate* isolate,
|
||||
.SetMethod("focusOnWebView", &BrowserWindow::FocusOnWebView)
|
||||
.SetMethod("blurWebView", &BrowserWindow::BlurWebView)
|
||||
.SetMethod("isWebViewFocused", &BrowserWindow::IsWebViewFocused)
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
.SetMethod("setTitleBarOverlay", &BrowserWindow::SetTitleBarOverlay)
|
||||
#endif
|
||||
.SetProperty("webContents", &BrowserWindow::GetWebContents);
|
||||
}
|
||||
|
||||
|
||||
@@ -79,10 +79,6 @@ class BrowserWindow : public BaseWindow,
|
||||
void BlurWebView();
|
||||
bool IsWebViewFocused();
|
||||
v8::Local<v8::Value> GetWebContents(v8::Isolate* isolate);
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
void SetTitleBarOverlay(const gin_helper::Dictionary& options,
|
||||
gin_helper::Arguments* args);
|
||||
#endif
|
||||
|
||||
private:
|
||||
// Helpers.
|
||||
|
||||
@@ -171,25 +171,96 @@ base::Time ParseTimeProperty(const std::optional<double>& value) {
|
||||
return base::Time::FromSecondsSinceUnixEpoch(*value);
|
||||
}
|
||||
|
||||
std::string_view InclusionStatusToString(net::CookieInclusionStatus status) {
|
||||
if (status.HasExclusionReason(net::CookieInclusionStatus::EXCLUDE_HTTP_ONLY))
|
||||
return "Failed to create httponly cookie";
|
||||
if (status.HasExclusionReason(
|
||||
net::CookieInclusionStatus::EXCLUDE_SECURE_ONLY))
|
||||
return "Cannot create a secure cookie from an insecure URL";
|
||||
if (status.HasExclusionReason(
|
||||
net::CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE))
|
||||
return "Failed to parse cookie";
|
||||
if (status.HasExclusionReason(
|
||||
net::CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN))
|
||||
return "Failed to set cookie with an invalid domain attribute";
|
||||
if (status.HasExclusionReason(
|
||||
net::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX))
|
||||
return "Failed because the cookie violated prefix rules.";
|
||||
if (status.HasExclusionReason(
|
||||
net::CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME))
|
||||
return "Cannot set cookie for current scheme";
|
||||
return "Setting cookie failed";
|
||||
const std::string InclusionStatusToString(net::CookieInclusionStatus status) {
|
||||
// See net/cookies/cookie_inclusion_status.h for cookie error descriptions.
|
||||
constexpr std::array<
|
||||
std::pair<net::CookieInclusionStatus::ExclusionReason, std::string_view>,
|
||||
net::CookieInclusionStatus::ExclusionReason::NUM_EXCLUSION_REASONS>
|
||||
exclusion_reasons = {
|
||||
{{net::CookieInclusionStatus::EXCLUDE_HTTP_ONLY,
|
||||
"The cookie was HttpOnly, but the attempted access was through a "
|
||||
"non-HTTP API."},
|
||||
{net::CookieInclusionStatus::EXCLUDE_SECURE_ONLY,
|
||||
"The cookie was Secure, but the URL was not allowed to access "
|
||||
"Secure cookies."},
|
||||
{net::CookieInclusionStatus::EXCLUDE_DOMAIN_MISMATCH,
|
||||
"The cookie's domain attribute did not match the domain of the URL "
|
||||
"attempting access."},
|
||||
{net::CookieInclusionStatus::EXCLUDE_NOT_ON_PATH,
|
||||
"The cookie's path attribute did not match the path of the URL "
|
||||
"attempting access."},
|
||||
{net::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT,
|
||||
"The cookie had SameSite=Strict, and the attempted access did not "
|
||||
"have an appropriate SameSiteCookieContext"},
|
||||
{net::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX,
|
||||
"The cookie had SameSite=Lax, and the attempted access did not "
|
||||
"have "
|
||||
"an appropriate SameSiteCookieContext"},
|
||||
{net::CookieInclusionStatus::
|
||||
EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
|
||||
"The cookie did not specify a SameSite attribute, and therefore "
|
||||
"was "
|
||||
"treated as if it were SameSite=Lax, and the attempted access did "
|
||||
"not have an appropriate SameSiteCookieContext."},
|
||||
{net::CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE,
|
||||
"The cookie specified SameSite=None, but it was not Secure."},
|
||||
{net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES,
|
||||
"Caller did not allow access to the cookie."},
|
||||
{net::CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE,
|
||||
"The cookie was malformed and could not be stored"},
|
||||
{net::CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME,
|
||||
"Attempted to set a cookie from a scheme that does not support "
|
||||
"cookies."},
|
||||
{net::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE,
|
||||
"The cookie would have overwritten a Secure cookie, and was not "
|
||||
"allowed to do so."},
|
||||
{net::CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY,
|
||||
"The cookie would have overwritten an HttpOnly cookie, and was not "
|
||||
"allowed to do so."},
|
||||
{net::CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN,
|
||||
"The cookie was set with an invalid Domain attribute."},
|
||||
{net::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX,
|
||||
"The cookie was set with an invalid __Host- or __Secure- prefix."},
|
||||
{net::CookieInclusionStatus::EXCLUDE_INVALID_PARTITIONED,
|
||||
"Cookie was set with an invalid Partitioned attribute, which is "
|
||||
"only valid if the cookie has a __Host- prefix."},
|
||||
{net::CookieInclusionStatus::
|
||||
EXCLUDE_NAME_VALUE_PAIR_EXCEEDS_MAX_SIZE,
|
||||
"The cookie exceeded the name/value pair size limit."},
|
||||
{net::CookieInclusionStatus::
|
||||
EXCLUDE_ATTRIBUTE_VALUE_EXCEEDS_MAX_SIZE,
|
||||
"Cookie exceeded the attribute size limit."},
|
||||
{net::CookieInclusionStatus::EXCLUDE_DOMAIN_NON_ASCII,
|
||||
"The cookie was set with a Domain attribute containing non ASCII "
|
||||
"characters."},
|
||||
{net::CookieInclusionStatus::
|
||||
EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET,
|
||||
"The cookie is blocked by third-party cookie blocking but the two "
|
||||
"sites are in the same First-Party Set"},
|
||||
{net::CookieInclusionStatus::EXCLUDE_PORT_MISMATCH,
|
||||
"The cookie's source_port did not match the port of the request."},
|
||||
{net::CookieInclusionStatus::EXCLUDE_SCHEME_MISMATCH,
|
||||
"The cookie's source_scheme did not match the scheme of the "
|
||||
"request."},
|
||||
{net::CookieInclusionStatus::EXCLUDE_SHADOWING_DOMAIN,
|
||||
"The cookie is a domain cookie and has the same name as an origin "
|
||||
"cookie on this origin."},
|
||||
{net::CookieInclusionStatus::EXCLUDE_DISALLOWED_CHARACTER,
|
||||
"The cookie contains ASCII control characters"},
|
||||
{net::CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT,
|
||||
"The cookie is blocked for third-party cookie phaseout."},
|
||||
{net::CookieInclusionStatus::EXCLUDE_NO_COOKIE_CONTENT,
|
||||
"The cookie contains no content or only whitespace."}}};
|
||||
|
||||
std::string reason = "Failed to set cookie - ";
|
||||
for (const auto& [val, str] : exclusion_reasons) {
|
||||
if (status.HasExclusionReason(val)) {
|
||||
reason += str;
|
||||
}
|
||||
}
|
||||
|
||||
reason += status.GetDebugString();
|
||||
return reason;
|
||||
}
|
||||
|
||||
std::string StringToCookieSameSite(const std::string* str_ptr,
|
||||
|
||||
@@ -145,6 +145,9 @@ UtilityProcessWrapper::UtilityProcessWrapper(
|
||||
}
|
||||
}
|
||||
|
||||
if (!content::ServiceProcessHost::HasObserver(this))
|
||||
content::ServiceProcessHost::AddObserver(this);
|
||||
|
||||
mojo::PendingReceiver<node::mojom::NodeService> receiver =
|
||||
node_service_remote_.BindNewPipeAndPassReceiver();
|
||||
|
||||
@@ -172,9 +175,10 @@ UtilityProcessWrapper::UtilityProcessWrapper(
|
||||
: content::ChildProcessHost::CHILD_NORMAL)
|
||||
#endif
|
||||
.WithProcessCallback(
|
||||
base::BindOnce(&UtilityProcessWrapper::OnServiceProcessLaunched,
|
||||
base::BindOnce(&UtilityProcessWrapper::OnServiceProcessLaunch,
|
||||
weak_factory_.GetWeakPtr()))
|
||||
.Pass());
|
||||
|
||||
node_service_remote_.set_disconnect_with_reason_handler(
|
||||
base::BindOnce(&UtilityProcessWrapper::OnServiceProcessDisconnected,
|
||||
weak_factory_.GetWeakPtr()));
|
||||
@@ -210,37 +214,61 @@ UtilityProcessWrapper::UtilityProcessWrapper(
|
||||
network_context->CreateHostResolver(
|
||||
{}, host_resolver.InitWithNewPipeAndPassReceiver());
|
||||
params->host_resolver = std::move(host_resolver);
|
||||
|
||||
node_service_remote_->Initialize(std::move(params));
|
||||
}
|
||||
|
||||
UtilityProcessWrapper::~UtilityProcessWrapper() = default;
|
||||
UtilityProcessWrapper::~UtilityProcessWrapper() {
|
||||
content::ServiceProcessHost::RemoveObserver(this);
|
||||
}
|
||||
|
||||
void UtilityProcessWrapper::OnServiceProcessLaunched(
|
||||
void UtilityProcessWrapper::OnServiceProcessLaunch(
|
||||
const base::Process& process) {
|
||||
DCHECK(node_service_remote_.is_connected());
|
||||
pid_ = process.Pid();
|
||||
GetAllUtilityProcessWrappers().AddWithID(this, pid_);
|
||||
if (stdout_read_fd_ != -1) {
|
||||
if (stdout_read_fd_ != -1)
|
||||
EmitWithoutEvent("stdout", stdout_read_fd_);
|
||||
}
|
||||
if (stderr_read_fd_ != -1) {
|
||||
if (stderr_read_fd_ != -1)
|
||||
EmitWithoutEvent("stderr", stderr_read_fd_);
|
||||
}
|
||||
// Emit 'spawn' event
|
||||
EmitWithoutEvent("spawn");
|
||||
}
|
||||
|
||||
void UtilityProcessWrapper::OnServiceProcessDisconnected(
|
||||
uint32_t error_code,
|
||||
const std::string& description) {
|
||||
void UtilityProcessWrapper::HandleTermination(uint64_t exit_code) {
|
||||
if (pid_ != base::kNullProcessId)
|
||||
GetAllUtilityProcessWrappers().Remove(pid_);
|
||||
CloseConnectorPort();
|
||||
// Emit 'exit' event
|
||||
EmitWithoutEvent("exit", error_code);
|
||||
|
||||
EmitWithoutEvent("exit", exit_code);
|
||||
|
||||
Unpin();
|
||||
}
|
||||
|
||||
void UtilityProcessWrapper::OnServiceProcessDisconnected(
|
||||
uint32_t exit_code,
|
||||
const std::string& description) {
|
||||
if (description == "process_exit_termination")
|
||||
HandleTermination(exit_code);
|
||||
}
|
||||
|
||||
void UtilityProcessWrapper::OnServiceProcessTerminatedNormally(
|
||||
const content::ServiceProcessInfo& info) {
|
||||
if (!info.IsService<node::mojom::NodeService>() ||
|
||||
info.GetProcess().Pid() != pid_)
|
||||
return;
|
||||
|
||||
HandleTermination(info.exit_code());
|
||||
}
|
||||
|
||||
void UtilityProcessWrapper::OnServiceProcessCrashed(
|
||||
const content::ServiceProcessInfo& info) {
|
||||
if (!info.IsService<node::mojom::NodeService>() ||
|
||||
info.GetProcess().Pid() != pid_)
|
||||
return;
|
||||
|
||||
HandleTermination(info.exit_code());
|
||||
}
|
||||
|
||||
void UtilityProcessWrapper::CloseConnectorPort() {
|
||||
if (!connector_closed_ && connector_->is_valid()) {
|
||||
host_port_.GiveDisentangledHandle(connector_->PassMessagePipe());
|
||||
@@ -250,7 +278,7 @@ void UtilityProcessWrapper::CloseConnectorPort() {
|
||||
}
|
||||
}
|
||||
|
||||
void UtilityProcessWrapper::Shutdown(int exit_code) {
|
||||
void UtilityProcessWrapper::Shutdown(uint64_t exit_code) {
|
||||
if (pid_ != base::kNullProcessId)
|
||||
GetAllUtilityProcessWrappers().Remove(pid_);
|
||||
node_service_remote_.reset();
|
||||
|
||||
@@ -13,9 +13,11 @@
|
||||
#include "base/environment.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/process/process_handle.h"
|
||||
#include "content/public/browser/service_process_host.h"
|
||||
#include "gin/wrappable.h"
|
||||
#include "mojo/public/cpp/bindings/connector.h"
|
||||
#include "mojo/public/cpp/bindings/message.h"
|
||||
#include "mojo/public/cpp/bindings/receiver.h"
|
||||
#include "mojo/public/cpp/bindings/remote.h"
|
||||
#include "shell/browser/event_emitter_mixin.h"
|
||||
#include "shell/common/gin_helper/pinnable.h"
|
||||
@@ -38,7 +40,8 @@ class UtilityProcessWrapper
|
||||
: public gin::Wrappable<UtilityProcessWrapper>,
|
||||
public gin_helper::Pinnable<UtilityProcessWrapper>,
|
||||
public gin_helper::EventEmitterMixin<UtilityProcessWrapper>,
|
||||
public mojo::MessageReceiver {
|
||||
public mojo::MessageReceiver,
|
||||
public content::ServiceProcessHost::Observer {
|
||||
public:
|
||||
enum class IOHandle : size_t { STDIN = 0, STDOUT = 1, STDERR = 2 };
|
||||
enum class IOType { IO_PIPE, IO_INHERIT, IO_IGNORE };
|
||||
@@ -47,7 +50,7 @@ class UtilityProcessWrapper
|
||||
static gin::Handle<UtilityProcessWrapper> Create(gin::Arguments* args);
|
||||
static raw_ptr<UtilityProcessWrapper> FromProcessId(base::ProcessId pid);
|
||||
|
||||
void Shutdown(int exit_code);
|
||||
void Shutdown(uint64_t exit_code);
|
||||
|
||||
// gin::Wrappable
|
||||
static gin::WrapperInfo kWrapperInfo;
|
||||
@@ -62,11 +65,11 @@ class UtilityProcessWrapper
|
||||
base::EnvironmentMap env_map,
|
||||
base::FilePath current_working_directory,
|
||||
bool use_plugin_helper);
|
||||
void OnServiceProcessDisconnected(uint32_t error_code,
|
||||
const std::string& description);
|
||||
void OnServiceProcessLaunched(const base::Process& process);
|
||||
void OnServiceProcessLaunch(const base::Process& process);
|
||||
void CloseConnectorPort();
|
||||
|
||||
void HandleTermination(uint64_t exit_code);
|
||||
|
||||
void PostMessage(gin::Arguments* args);
|
||||
bool Kill() const;
|
||||
v8::Local<v8::Value> GetOSProcessId(v8::Isolate* isolate) const;
|
||||
@@ -74,6 +77,15 @@ class UtilityProcessWrapper
|
||||
// mojo::MessageReceiver
|
||||
bool Accept(mojo::Message* mojo_message) override;
|
||||
|
||||
// content::ServiceProcessHost::Observer
|
||||
void OnServiceProcessTerminatedNormally(
|
||||
const content::ServiceProcessInfo& info) override;
|
||||
void OnServiceProcessCrashed(
|
||||
const content::ServiceProcessInfo& info) override;
|
||||
|
||||
void OnServiceProcessDisconnected(uint32_t exit_code,
|
||||
const std::string& description);
|
||||
|
||||
base::ProcessId pid_ = base::kNullProcessId;
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
// Non-owning handles, these will be closed when the
|
||||
|
||||
@@ -235,6 +235,10 @@ class Browser : public WindowListObserver {
|
||||
// Set docks' icon.
|
||||
void DockSetIcon(v8::Isolate* isolate, v8::Local<v8::Value> icon);
|
||||
|
||||
void SetLaunchedAtLogin(bool launched_at_login) {
|
||||
was_launched_at_login_ = launched_at_login;
|
||||
}
|
||||
|
||||
#endif // BUILDFLAG(IS_MAC)
|
||||
|
||||
void ShowAboutPanel();
|
||||
@@ -369,6 +373,7 @@ class Browser : public WindowListObserver {
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
std::unique_ptr<ui::ScopedPasswordInputEnabler> password_input_enabler_;
|
||||
base::Time last_dock_show_;
|
||||
bool was_launched_at_login_;
|
||||
#endif
|
||||
|
||||
base::Value::Dict about_panel_options_;
|
||||
|
||||
@@ -389,6 +389,7 @@ Browser::LoginItemSettings Browser::GetLoginItemSettings(
|
||||
platform_util::GetLoginItemEnabled(options.type, options.service_name);
|
||||
settings.open_at_login =
|
||||
status == "enabled" || status == "enabled-deprecated";
|
||||
settings.opened_at_login = was_launched_at_login_;
|
||||
if (@available(macOS 13, *))
|
||||
settings.status = status;
|
||||
#else
|
||||
@@ -402,6 +403,7 @@ Browser::LoginItemSettings Browser::GetLoginItemSettings(
|
||||
settings = settings_deprecated;
|
||||
} else {
|
||||
settings.open_at_login = status == "enabled";
|
||||
settings.opened_at_login = was_launched_at_login_;
|
||||
settings.status = status;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -398,12 +398,6 @@ void ElectronBrowserMainParts::ToolkitInitialized() {
|
||||
CHECK(linux_ui);
|
||||
linux_ui_getter_ = std::make_unique<LinuxUiGetterImpl>();
|
||||
|
||||
// Try loading gtk symbols used by Electron.
|
||||
electron::InitializeElectron_gtk(gtk::GetLibGtk());
|
||||
if (!electron::IsElectron_gtkInitialized()) {
|
||||
electron::UninitializeElectron_gtk();
|
||||
}
|
||||
|
||||
electron::InitializeElectron_gdk_pixbuf(gtk::GetLibGdkPixbuf());
|
||||
CHECK(electron::IsElectron_gdk_pixbufInitialized())
|
||||
<< "Failed to initialize libgdk_pixbuf-2.0.so.0";
|
||||
|
||||
@@ -342,13 +342,12 @@ void ElectronExtensionsBrowserClient::BroadcastEventToRenderers(
|
||||
return;
|
||||
}
|
||||
|
||||
auto event = std::make_unique<extensions::Event>(histogram_value, event_name,
|
||||
args.Clone());
|
||||
for (auto const& [key, browser_context] :
|
||||
ElectronBrowserContext::browser_context_map()) {
|
||||
if (browser_context) {
|
||||
extensions::EventRouter::Get(browser_context.get())
|
||||
->BroadcastEvent(std::move(event));
|
||||
->BroadcastEvent(std::make_unique<extensions::Event>(
|
||||
histogram_value, event_name, args.Clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,8 +46,8 @@ class ElectronHidDelegate::ContextObservation
|
||||
ContextObservation(ElectronHidDelegate* parent,
|
||||
content::BrowserContext* browser_context)
|
||||
: parent_(parent), browser_context_(browser_context) {
|
||||
auto* chooser_context = GetChooserContext(browser_context_);
|
||||
device_observation_.Observe(chooser_context);
|
||||
if (auto* chooser_context = GetChooserContext(browser_context_))
|
||||
device_observation_.Observe(chooser_context);
|
||||
}
|
||||
|
||||
ContextObservation(ContextObservation&) = delete;
|
||||
|
||||
@@ -282,13 +282,10 @@ class TracingControllerImpl : public node::tracing::TracingController {
|
||||
v8::Isolate* JavascriptEnvironment::Initialize(uv_loop_t* event_loop,
|
||||
bool setup_wasm_streaming) {
|
||||
auto* cmd = base::CommandLine::ForCurrentProcess();
|
||||
|
||||
// --js-flags.
|
||||
std::string js_flags =
|
||||
cmd->GetSwitchValueASCII(blink::switches::kJavaScriptFlags);
|
||||
js_flags.append(" --no-freeze-flags-after-init");
|
||||
if (!js_flags.empty())
|
||||
v8::V8::SetFlagsFromString(js_flags.c_str(), js_flags.size());
|
||||
std::string js_flags = "--no-freeze-flags-after-init ";
|
||||
js_flags.append(cmd->GetSwitchValueASCII(blink::switches::kJavaScriptFlags));
|
||||
v8::V8::SetFlagsFromString(js_flags.c_str(), js_flags.size());
|
||||
|
||||
// The V8Platform of gin relies on Chromium's task schedule, which has not
|
||||
// been started at this point, so we have to rely on Node's V8Platform.
|
||||
|
||||
@@ -84,6 +84,14 @@ static NSDictionary* UNNotificationResponseToNSDictionary(
|
||||
}
|
||||
}
|
||||
|
||||
NSAppleEventDescriptor* event =
|
||||
NSAppleEventManager.sharedAppleEventManager.currentAppleEvent;
|
||||
BOOL launched_as_login_item =
|
||||
(event.eventID == kAEOpenApplication &&
|
||||
[event paramDescriptorForKeyword:keyAEPropData].enumCodeValue ==
|
||||
keyAELaunchedAsLogInItem);
|
||||
electron::Browser::Get()->SetLaunchedAtLogin(launched_as_login_item);
|
||||
|
||||
electron::Browser::Get()->DidFinishLaunching(
|
||||
electron::NSDictionaryToValue(notification_info));
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <wrl\wrappers\corewrappers.h>
|
||||
|
||||
#include "base/environment.h"
|
||||
#include "base/hash/hash.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/strcat.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
@@ -71,6 +72,10 @@ void DebugLog(std::string_view log_msg) {
|
||||
LOG(INFO) << log_msg;
|
||||
}
|
||||
|
||||
std::wstring GetTag(const std::string& notification_id) {
|
||||
return base::NumberToWString(base::Hash(notification_id));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
@@ -146,7 +151,7 @@ void WindowsToastNotification::Remove() {
|
||||
return;
|
||||
|
||||
ScopedHString group(kGroup);
|
||||
ScopedHString tag(base::as_wcstr(base::UTF8ToUTF16(notification_id())));
|
||||
ScopedHString tag(GetTag(notification_id()));
|
||||
notification_history->RemoveGroupedTagWithId(tag, group, app_id);
|
||||
}
|
||||
|
||||
@@ -199,7 +204,7 @@ HRESULT WindowsToastNotification::ShowInternal(
|
||||
REPORT_AND_RETURN_IF_FAILED(toast2->put_Group(group),
|
||||
"WinAPI: Setting group failed");
|
||||
|
||||
ScopedHString tag(base::as_wcstr(base::UTF8ToUTF16(notification_id())));
|
||||
ScopedHString tag(GetTag(notification_id()));
|
||||
REPORT_AND_RETURN_IF_FAILED(toast2->put_Tag(tag),
|
||||
"WinAPI: Setting tag failed");
|
||||
|
||||
|
||||
@@ -1,395 +0,0 @@
|
||||
// Copyright (c) 2014 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/functional/callback.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/memory/raw_ptr_exclusion.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "electron/electron_gtk_stubs.h"
|
||||
#include "shell/browser/javascript_environment.h"
|
||||
#include "shell/browser/native_window_views.h"
|
||||
#include "shell/browser/ui/file_dialog.h"
|
||||
#include "shell/browser/ui/gtk_util.h"
|
||||
#include "shell/common/gin_converters/file_path_converter.h"
|
||||
#include "shell/common/thread_restrictions.h"
|
||||
#include "ui/base/glib/scoped_gsignal.h"
|
||||
#include "ui/gtk/gtk_ui.h" // nogncheck
|
||||
#include "ui/gtk/gtk_util.h" // nogncheck
|
||||
|
||||
namespace file_dialog {
|
||||
|
||||
DialogSettings::DialogSettings() = default;
|
||||
DialogSettings::DialogSettings(const DialogSettings&) = default;
|
||||
DialogSettings::~DialogSettings() = default;
|
||||
|
||||
namespace {
|
||||
|
||||
static const int kPreviewWidth = 256;
|
||||
static const int kPreviewHeight = 512;
|
||||
|
||||
std::string MakeCaseInsensitivePattern(const std::string& extension) {
|
||||
// If the extension is the "all files" extension, no change needed.
|
||||
if (extension == "*")
|
||||
return extension;
|
||||
|
||||
std::string pattern("*.");
|
||||
for (char ch : extension) {
|
||||
if (!base::IsAsciiAlpha(ch)) {
|
||||
pattern.push_back(ch);
|
||||
continue;
|
||||
}
|
||||
|
||||
pattern.push_back('[');
|
||||
pattern.push_back(base::ToLowerASCII(ch));
|
||||
pattern.push_back(base::ToUpperASCII(ch));
|
||||
pattern.push_back(']');
|
||||
}
|
||||
|
||||
return pattern;
|
||||
}
|
||||
|
||||
class FileChooserDialog {
|
||||
public:
|
||||
FileChooserDialog(GtkFileChooserAction action, const DialogSettings& settings)
|
||||
: parent_(
|
||||
static_cast<electron::NativeWindowViews*>(settings.parent_window)),
|
||||
filters_(settings.filters) {
|
||||
auto label = settings.button_label;
|
||||
|
||||
if (electron::IsElectron_gtkInitialized()) {
|
||||
dialog_ = GTK_FILE_CHOOSER(gtk_file_chooser_native_new(
|
||||
settings.title.c_str(), nullptr, action,
|
||||
label.empty() ? nullptr : label.c_str(), nullptr));
|
||||
} else {
|
||||
const char* confirm_text = gtk_util::GetOkLabel();
|
||||
if (!label.empty())
|
||||
confirm_text = label.c_str();
|
||||
else if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
|
||||
confirm_text = gtk_util::GetSaveLabel();
|
||||
else if (action == GTK_FILE_CHOOSER_ACTION_OPEN)
|
||||
confirm_text = gtk_util::GetOpenLabel();
|
||||
|
||||
dialog_ = GTK_FILE_CHOOSER(gtk_file_chooser_dialog_new(
|
||||
settings.title.c_str(), nullptr, action, gtk_util::GetCancelLabel(),
|
||||
GTK_RESPONSE_CANCEL, confirm_text, GTK_RESPONSE_ACCEPT, nullptr));
|
||||
}
|
||||
|
||||
if (parent_) {
|
||||
parent_->SetEnabled(false);
|
||||
if (electron::IsElectron_gtkInitialized()) {
|
||||
gtk_native_dialog_set_modal(GTK_NATIVE_DIALOG(dialog_), TRUE);
|
||||
} else {
|
||||
gtk::SetGtkTransientForAura(GTK_WIDGET(dialog_),
|
||||
parent_->GetNativeWindow());
|
||||
gtk_window_set_modal(GTK_WINDOW(dialog_), TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
|
||||
gtk_file_chooser_set_do_overwrite_confirmation(dialog_, TRUE);
|
||||
if (action != GTK_FILE_CHOOSER_ACTION_OPEN)
|
||||
gtk_file_chooser_set_create_folders(dialog_, TRUE);
|
||||
|
||||
if (!settings.default_path.empty()) {
|
||||
electron::ScopedAllowBlockingForElectron allow_blocking;
|
||||
if (base::DirectoryExists(settings.default_path)) {
|
||||
gtk_file_chooser_set_current_folder(
|
||||
dialog_, settings.default_path.value().c_str());
|
||||
} else {
|
||||
if (settings.default_path.IsAbsolute()) {
|
||||
gtk_file_chooser_set_current_folder(
|
||||
dialog_, settings.default_path.DirName().value().c_str());
|
||||
}
|
||||
|
||||
gtk_file_chooser_set_current_name(
|
||||
GTK_FILE_CHOOSER(dialog_),
|
||||
settings.default_path.BaseName().value().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (!settings.filters.empty())
|
||||
AddFilters(settings.filters);
|
||||
|
||||
// GtkFileChooserNative does not support preview widgets through the
|
||||
// org.freedesktop.portal.FileChooser portal. In the case of running through
|
||||
// the org.freedesktop.portal.FileChooser portal, anything having to do with
|
||||
// the update-preview signal or the preview widget will just be ignored.
|
||||
if (!electron::IsElectron_gtkInitialized()) {
|
||||
preview_ = gtk_image_new();
|
||||
signals_.emplace_back(
|
||||
dialog_, "update-preview",
|
||||
base::BindRepeating(&FileChooserDialog::OnUpdatePreview,
|
||||
base::Unretained(this)));
|
||||
gtk_file_chooser_set_preview_widget(dialog_, preview_);
|
||||
}
|
||||
}
|
||||
|
||||
~FileChooserDialog() {
|
||||
if (electron::IsElectron_gtkInitialized()) {
|
||||
gtk_native_dialog_destroy(GTK_NATIVE_DIALOG(dialog_));
|
||||
} else {
|
||||
gtk_widget_destroy(GTK_WIDGET(dialog_));
|
||||
}
|
||||
|
||||
if (parent_)
|
||||
parent_->SetEnabled(true);
|
||||
}
|
||||
|
||||
// disable copy
|
||||
FileChooserDialog(const FileChooserDialog&) = delete;
|
||||
FileChooserDialog& operator=(const FileChooserDialog&) = delete;
|
||||
|
||||
void SetupOpenProperties(int properties) {
|
||||
const auto hasProp = [properties](OpenFileDialogProperty prop) {
|
||||
return gboolean((properties & prop) != 0);
|
||||
};
|
||||
auto* file_chooser = dialog();
|
||||
gtk_file_chooser_set_select_multiple(file_chooser,
|
||||
hasProp(OPEN_DIALOG_MULTI_SELECTIONS));
|
||||
gtk_file_chooser_set_show_hidden(file_chooser,
|
||||
hasProp(OPEN_DIALOG_SHOW_HIDDEN_FILES));
|
||||
}
|
||||
|
||||
void SetupSaveProperties(int properties) {
|
||||
const auto hasProp = [properties](SaveFileDialogProperty prop) {
|
||||
return gboolean((properties & prop) != 0);
|
||||
};
|
||||
auto* file_chooser = dialog();
|
||||
gtk_file_chooser_set_show_hidden(file_chooser,
|
||||
hasProp(SAVE_DIALOG_SHOW_HIDDEN_FILES));
|
||||
gtk_file_chooser_set_do_overwrite_confirmation(
|
||||
file_chooser, hasProp(SAVE_DIALOG_SHOW_OVERWRITE_CONFIRMATION));
|
||||
}
|
||||
|
||||
void RunAsynchronous() {
|
||||
signals_.emplace_back(
|
||||
GTK_WIDGET(dialog_), "response",
|
||||
base::BindRepeating(&FileChooserDialog::OnFileDialogResponse,
|
||||
base::Unretained(this)));
|
||||
if (electron::IsElectron_gtkInitialized()) {
|
||||
gtk_native_dialog_show(GTK_NATIVE_DIALOG(dialog_));
|
||||
} else {
|
||||
gtk_widget_show_all(GTK_WIDGET(dialog_));
|
||||
gtk::GtkUi::GetPlatform()->ShowGtkWindow(GTK_WINDOW(dialog_));
|
||||
}
|
||||
}
|
||||
|
||||
void RunSaveAsynchronous(
|
||||
gin_helper::Promise<gin_helper::Dictionary> promise) {
|
||||
save_promise_ =
|
||||
std::make_unique<gin_helper::Promise<gin_helper::Dictionary>>(
|
||||
std::move(promise));
|
||||
RunAsynchronous();
|
||||
}
|
||||
|
||||
void RunOpenAsynchronous(
|
||||
gin_helper::Promise<gin_helper::Dictionary> promise) {
|
||||
open_promise_ =
|
||||
std::make_unique<gin_helper::Promise<gin_helper::Dictionary>>(
|
||||
std::move(promise));
|
||||
RunAsynchronous();
|
||||
}
|
||||
|
||||
base::FilePath GetFileName() const {
|
||||
gchar* filename = gtk_file_chooser_get_filename(dialog_);
|
||||
const base::FilePath path(filename);
|
||||
g_free(filename);
|
||||
return path;
|
||||
}
|
||||
|
||||
std::vector<base::FilePath> GetFileNames() const {
|
||||
std::vector<base::FilePath> paths;
|
||||
auto* filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog_));
|
||||
for (auto* iter = filenames; iter != nullptr; iter = iter->next) {
|
||||
auto* filename = static_cast<char*>(iter->data);
|
||||
paths.emplace_back(filename);
|
||||
g_free(filename);
|
||||
}
|
||||
g_slist_free(filenames);
|
||||
return paths;
|
||||
}
|
||||
|
||||
void OnFileDialogResponse(GtkWidget* widget, int response);
|
||||
|
||||
GtkFileChooser* dialog() const { return dialog_; }
|
||||
|
||||
private:
|
||||
void AddFilters(const Filters& filters);
|
||||
|
||||
raw_ptr<electron::NativeWindowViews> parent_;
|
||||
|
||||
RAW_PTR_EXCLUSION GtkFileChooser* dialog_;
|
||||
RAW_PTR_EXCLUSION GtkWidget* preview_;
|
||||
|
||||
Filters filters_;
|
||||
std::unique_ptr<gin_helper::Promise<gin_helper::Dictionary>> save_promise_;
|
||||
std::unique_ptr<gin_helper::Promise<gin_helper::Dictionary>> open_promise_;
|
||||
|
||||
// Callback for when we update the preview for the selection.
|
||||
void OnUpdatePreview(GtkFileChooser* chooser);
|
||||
|
||||
std::vector<ScopedGSignal> signals_;
|
||||
};
|
||||
|
||||
void FileChooserDialog::OnFileDialogResponse(GtkWidget* widget, int response) {
|
||||
if (electron::IsElectron_gtkInitialized()) {
|
||||
gtk_native_dialog_hide(GTK_NATIVE_DIALOG(dialog_));
|
||||
} else {
|
||||
gtk_widget_hide(GTK_WIDGET(dialog_));
|
||||
}
|
||||
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
if (save_promise_) {
|
||||
auto dict = gin_helper::Dictionary::CreateEmpty(save_promise_->isolate());
|
||||
if (response == GTK_RESPONSE_ACCEPT) {
|
||||
dict.Set("canceled", false);
|
||||
dict.Set("filePath", GetFileName());
|
||||
} else {
|
||||
dict.Set("canceled", true);
|
||||
dict.Set("filePath", base::FilePath());
|
||||
}
|
||||
save_promise_->Resolve(dict);
|
||||
} else if (open_promise_) {
|
||||
auto dict = gin_helper::Dictionary::CreateEmpty(open_promise_->isolate());
|
||||
if (response == GTK_RESPONSE_ACCEPT) {
|
||||
dict.Set("canceled", false);
|
||||
dict.Set("filePaths", GetFileNames());
|
||||
} else {
|
||||
dict.Set("canceled", true);
|
||||
dict.Set("filePaths", std::vector<base::FilePath>());
|
||||
}
|
||||
open_promise_->Resolve(dict);
|
||||
}
|
||||
delete this;
|
||||
}
|
||||
|
||||
void FileChooserDialog::AddFilters(const Filters& filters) {
|
||||
for (const auto& filter : filters) {
|
||||
GtkFileFilter* gtk_filter = gtk_file_filter_new();
|
||||
|
||||
for (const auto& extension : filter.second) {
|
||||
std::string pattern = MakeCaseInsensitivePattern(extension);
|
||||
gtk_file_filter_add_pattern(gtk_filter, pattern.c_str());
|
||||
}
|
||||
|
||||
gtk_file_filter_set_name(gtk_filter, filter.first.c_str());
|
||||
gtk_file_chooser_add_filter(dialog_, gtk_filter);
|
||||
}
|
||||
}
|
||||
|
||||
bool CanPreview(const struct stat& st) {
|
||||
// Only preview regular files; pipes may hang.
|
||||
// See https://crbug.com/534754.
|
||||
if (!S_ISREG(st.st_mode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't preview huge files; they may crash.
|
||||
// https://github.com/electron/electron/issues/31630
|
||||
// Setting an arbitrary filesize max t at 100 MB here.
|
||||
constexpr off_t ArbitraryMax = 100000000ULL;
|
||||
return st.st_size < ArbitraryMax;
|
||||
}
|
||||
|
||||
void FileChooserDialog::OnUpdatePreview(GtkFileChooser* chooser) {
|
||||
CHECK(!electron::IsElectron_gtkInitialized());
|
||||
gchar* filename = gtk_file_chooser_get_preview_filename(chooser);
|
||||
if (!filename) {
|
||||
gtk_file_chooser_set_preview_widget_active(chooser, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
struct stat sb;
|
||||
if (stat(filename, &sb) != 0 || !CanPreview(sb)) {
|
||||
g_free(filename);
|
||||
gtk_file_chooser_set_preview_widget_active(chooser, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
// This will preserve the image's aspect ratio.
|
||||
GdkPixbuf* pixbuf = gdk_pixbuf_new_from_file_at_size(filename, kPreviewWidth,
|
||||
kPreviewHeight, nullptr);
|
||||
g_free(filename);
|
||||
if (pixbuf) {
|
||||
gtk_image_set_from_pixbuf(GTK_IMAGE(preview_), pixbuf);
|
||||
g_object_unref(pixbuf);
|
||||
}
|
||||
gtk_file_chooser_set_preview_widget_active(chooser, pixbuf ? TRUE : FALSE);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void ShowFileDialog(const FileChooserDialog& dialog) {
|
||||
// gtk_native_dialog_run() will call gtk_native_dialog_show() for us.
|
||||
if (!electron::IsElectron_gtkInitialized()) {
|
||||
gtk_widget_show_all(GTK_WIDGET(dialog.dialog()));
|
||||
}
|
||||
}
|
||||
|
||||
int RunFileDialog(const FileChooserDialog& dialog) {
|
||||
int response = 0;
|
||||
if (electron::IsElectron_gtkInitialized()) {
|
||||
response = gtk_native_dialog_run(GTK_NATIVE_DIALOG(dialog.dialog()));
|
||||
} else {
|
||||
response = gtk_dialog_run(GTK_DIALOG(dialog.dialog()));
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
bool ShowOpenDialogSync(const DialogSettings& settings,
|
||||
std::vector<base::FilePath>* paths) {
|
||||
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
|
||||
if (settings.properties & OPEN_DIALOG_OPEN_DIRECTORY)
|
||||
action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
|
||||
FileChooserDialog open_dialog(action, settings);
|
||||
open_dialog.SetupOpenProperties(settings.properties);
|
||||
|
||||
ShowFileDialog(open_dialog);
|
||||
|
||||
const int response = RunFileDialog(open_dialog);
|
||||
if (response == GTK_RESPONSE_ACCEPT) {
|
||||
*paths = open_dialog.GetFileNames();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ShowOpenDialog(const DialogSettings& settings,
|
||||
gin_helper::Promise<gin_helper::Dictionary> promise) {
|
||||
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
|
||||
if (settings.properties & OPEN_DIALOG_OPEN_DIRECTORY)
|
||||
action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
|
||||
FileChooserDialog* open_dialog = new FileChooserDialog(action, settings);
|
||||
open_dialog->SetupOpenProperties(settings.properties);
|
||||
open_dialog->RunOpenAsynchronous(std::move(promise));
|
||||
}
|
||||
|
||||
bool ShowSaveDialogSync(const DialogSettings& settings, base::FilePath* path) {
|
||||
FileChooserDialog save_dialog(GTK_FILE_CHOOSER_ACTION_SAVE, settings);
|
||||
save_dialog.SetupSaveProperties(settings.properties);
|
||||
|
||||
ShowFileDialog(save_dialog);
|
||||
|
||||
const int response = RunFileDialog(save_dialog);
|
||||
if (response == GTK_RESPONSE_ACCEPT) {
|
||||
*path = save_dialog.GetFileName();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ShowSaveDialog(const DialogSettings& settings,
|
||||
gin_helper::Promise<gin_helper::Dictionary> promise) {
|
||||
FileChooserDialog* save_dialog =
|
||||
new FileChooserDialog(GTK_FILE_CHOOSER_ACTION_SAVE, settings);
|
||||
save_dialog->RunSaveAsynchronous(std::move(promise));
|
||||
}
|
||||
|
||||
} // namespace file_dialog
|
||||
253
shell/browser/ui/file_dialog_linux.cc
Normal file
253
shell/browser/ui/file_dialog_linux.cc
Normal file
@@ -0,0 +1,253 @@
|
||||
// Copyright (c) 2024 Microsoft, GmbH.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/functional/callback.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/memory/raw_ptr_exclusion.h"
|
||||
#include "base/run_loop.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "shell/browser/javascript_environment.h"
|
||||
#include "shell/browser/native_window_views.h"
|
||||
#include "shell/browser/ui/file_dialog.h"
|
||||
#include "shell/common/gin_converters/callback_converter.h"
|
||||
#include "shell/common/gin_converters/file_path_converter.h"
|
||||
#include "ui/gtk/select_file_dialog_linux_gtk.h" // nogncheck
|
||||
#include "ui/shell_dialogs/select_file_dialog.h"
|
||||
#include "ui/shell_dialogs/selected_file_info.h"
|
||||
|
||||
namespace file_dialog {
|
||||
|
||||
DialogSettings::DialogSettings() = default;
|
||||
DialogSettings::DialogSettings(const DialogSettings&) = default;
|
||||
DialogSettings::~DialogSettings() = default;
|
||||
|
||||
namespace {
|
||||
|
||||
ui::SelectFileDialog::Type GetDialogType(int properties) {
|
||||
if (properties & OPEN_DIALOG_OPEN_DIRECTORY)
|
||||
return ui::SelectFileDialog::SELECT_FOLDER;
|
||||
|
||||
if (properties & OPEN_DIALOG_MULTI_SELECTIONS)
|
||||
return ui::SelectFileDialog::SELECT_OPEN_MULTI_FILE;
|
||||
|
||||
return ui::SelectFileDialog::SELECT_OPEN_FILE;
|
||||
}
|
||||
|
||||
ui::SelectFileDialog::FileTypeInfo GetFilterInfo(const Filters& filters) {
|
||||
ui::SelectFileDialog::FileTypeInfo file_type_info;
|
||||
|
||||
for (const auto& [name, extension_group] : filters) {
|
||||
file_type_info.extension_description_overrides.push_back(
|
||||
base::UTF8ToUTF16(name));
|
||||
|
||||
const bool has_all_files_wildcard = base::ranges::any_of(
|
||||
extension_group, [](const auto& ext) { return ext == "*"; });
|
||||
if (has_all_files_wildcard) {
|
||||
file_type_info.include_all_files = true;
|
||||
} else {
|
||||
file_type_info.extensions.emplace_back(extension_group);
|
||||
}
|
||||
}
|
||||
|
||||
return file_type_info;
|
||||
}
|
||||
|
||||
class FileChooserDialog : public ui::SelectFileDialog::Listener {
|
||||
public:
|
||||
enum class DialogType { OPEN, SAVE };
|
||||
|
||||
FileChooserDialog() { dialog_ = ui::SelectFileDialog::Create(this, nullptr); }
|
||||
|
||||
~FileChooserDialog() override = default;
|
||||
|
||||
ui::SelectFileDialogLinux::ExtraSettings GetExtraSettings(
|
||||
const DialogSettings& settings) {
|
||||
ui::SelectFileDialogLinux::ExtraSettings extra;
|
||||
extra.button_label = settings.button_label;
|
||||
extra.show_overwrite_confirmation =
|
||||
settings.properties & SAVE_DIALOG_SHOW_OVERWRITE_CONFIRMATION;
|
||||
extra.allow_multiple_selection =
|
||||
settings.properties & OPEN_DIALOG_MULTI_SELECTIONS;
|
||||
if (type_ == DialogType::SAVE) {
|
||||
extra.show_hidden = settings.properties & SAVE_DIALOG_SHOW_HIDDEN_FILES;
|
||||
} else {
|
||||
extra.show_hidden = settings.properties & OPEN_DIALOG_SHOW_HIDDEN_FILES;
|
||||
}
|
||||
|
||||
return extra;
|
||||
}
|
||||
|
||||
void RunSaveDialogImpl(const DialogSettings& settings) {
|
||||
type_ = DialogType::SAVE;
|
||||
ui::SelectFileDialog::FileTypeInfo file_info =
|
||||
GetFilterInfo(settings.filters);
|
||||
auto extra_settings = GetExtraSettings(settings);
|
||||
dialog_->SelectFile(
|
||||
ui::SelectFileDialog::SELECT_SAVEAS_FILE,
|
||||
base::UTF8ToUTF16(settings.title), settings.default_path,
|
||||
&file_info /* file_types */, 0 /* file_type_index */,
|
||||
base::FilePath::StringType() /* default_extension */,
|
||||
settings.parent_window ? settings.parent_window->GetNativeWindow()
|
||||
: nullptr,
|
||||
static_cast<void*>(&extra_settings));
|
||||
}
|
||||
|
||||
void RunSaveDialog(gin_helper::Promise<gin_helper::Dictionary> promise,
|
||||
const DialogSettings& settings) {
|
||||
promise_ = std::move(promise);
|
||||
RunSaveDialogImpl(settings);
|
||||
}
|
||||
|
||||
void RunSaveDialog(base::OnceCallback<void(gin_helper::Dictionary)> callback,
|
||||
const DialogSettings& settings) {
|
||||
callback_ = std::move(callback);
|
||||
RunSaveDialogImpl(settings);
|
||||
}
|
||||
|
||||
void RunOpenDialogImpl(const DialogSettings& settings) {
|
||||
type_ = DialogType::OPEN;
|
||||
ui::SelectFileDialog::FileTypeInfo file_info =
|
||||
GetFilterInfo(settings.filters);
|
||||
auto extra_settings = GetExtraSettings(settings);
|
||||
dialog_->SelectFile(
|
||||
GetDialogType(settings.properties), base::UTF8ToUTF16(settings.title),
|
||||
settings.default_path, &file_info, 0 /* file_type_index */,
|
||||
base::FilePath::StringType() /* default_extension */,
|
||||
settings.parent_window ? settings.parent_window->GetNativeWindow()
|
||||
: nullptr,
|
||||
static_cast<void*>(&extra_settings));
|
||||
}
|
||||
|
||||
void RunOpenDialog(gin_helper::Promise<gin_helper::Dictionary> promise,
|
||||
const DialogSettings& settings) {
|
||||
promise_ = std::move(promise);
|
||||
RunOpenDialogImpl(settings);
|
||||
}
|
||||
|
||||
void RunOpenDialog(base::OnceCallback<void(gin_helper::Dictionary)> callback,
|
||||
const DialogSettings& settings) {
|
||||
callback_ = std::move(callback);
|
||||
RunOpenDialogImpl(settings);
|
||||
}
|
||||
|
||||
void FileSelected(const ui::SelectedFileInfo& file,
|
||||
int index,
|
||||
void* params) override {
|
||||
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto dict = gin_helper::Dictionary::CreateEmpty(isolate);
|
||||
dict.Set("canceled", false);
|
||||
if (type_ == DialogType::SAVE) {
|
||||
dict.Set("filePath", file.file_path);
|
||||
} else {
|
||||
dict.Set("filePaths", std::vector<base::FilePath>{file.file_path});
|
||||
}
|
||||
|
||||
if (callback_) {
|
||||
std::move(callback_).Run(dict);
|
||||
} else {
|
||||
promise_.Resolve(dict);
|
||||
}
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
void MultiFilesSelected(const std::vector<ui::SelectedFileInfo>& files,
|
||||
void* params) override {
|
||||
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto dict = gin_helper::Dictionary::CreateEmpty(isolate);
|
||||
dict.Set("canceled", false);
|
||||
dict.Set("filePaths", ui::SelectedFileInfoListToFilePathList(files));
|
||||
|
||||
if (callback_) {
|
||||
std::move(callback_).Run(dict);
|
||||
} else {
|
||||
promise_.Resolve(dict);
|
||||
}
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
void FileSelectionCanceled(void* params) override {
|
||||
v8::Isolate* isolate = electron::JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
auto dict = gin_helper::Dictionary::CreateEmpty(isolate);
|
||||
dict.Set("canceled", true);
|
||||
if (type_ == DialogType::SAVE) {
|
||||
dict.Set("filePath", base::FilePath());
|
||||
} else {
|
||||
dict.Set("filePaths", std::vector<base::FilePath>());
|
||||
}
|
||||
|
||||
if (callback_) {
|
||||
std::move(callback_).Run(dict);
|
||||
} else {
|
||||
promise_.Resolve(dict);
|
||||
}
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
private:
|
||||
DialogType type_;
|
||||
scoped_refptr<ui::SelectFileDialog> dialog_;
|
||||
base::OnceCallback<void(gin_helper::Dictionary)> callback_;
|
||||
gin_helper::Promise<gin_helper::Dictionary> promise_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
bool ShowOpenDialogSync(const DialogSettings& settings,
|
||||
std::vector<base::FilePath>* paths) {
|
||||
base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
|
||||
auto cb = base::BindOnce(
|
||||
[](base::RepeatingClosure cb, std::vector<base::FilePath>* file_paths,
|
||||
gin_helper::Dictionary result) {
|
||||
result.Get("filePaths", file_paths);
|
||||
std::move(cb).Run();
|
||||
},
|
||||
run_loop.QuitClosure(), paths);
|
||||
|
||||
FileChooserDialog* dialog = new FileChooserDialog();
|
||||
dialog->RunOpenDialog(std::move(cb), settings);
|
||||
run_loop.Run();
|
||||
return !paths->empty();
|
||||
}
|
||||
|
||||
void ShowOpenDialog(const DialogSettings& settings,
|
||||
gin_helper::Promise<gin_helper::Dictionary> promise) {
|
||||
FileChooserDialog* dialog = new FileChooserDialog();
|
||||
dialog->RunOpenDialog(std::move(promise), settings);
|
||||
}
|
||||
|
||||
bool ShowSaveDialogSync(const DialogSettings& settings, base::FilePath* path) {
|
||||
base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
|
||||
auto cb = base::BindOnce(
|
||||
[](base::RepeatingClosure cb, base::FilePath* file_path,
|
||||
gin_helper::Dictionary result) {
|
||||
result.Get("filePath", file_path);
|
||||
std::move(cb).Run();
|
||||
},
|
||||
run_loop.QuitClosure(), path);
|
||||
|
||||
FileChooserDialog* dialog = new FileChooserDialog();
|
||||
dialog->RunSaveDialog(std::move(cb), settings);
|
||||
run_loop.Run();
|
||||
return !path->empty();
|
||||
}
|
||||
|
||||
void ShowSaveDialog(const DialogSettings& settings,
|
||||
gin_helper::Promise<gin_helper::Dictionary> promise) {
|
||||
FileChooserDialog* dialog = new FileChooserDialog();
|
||||
dialog->RunSaveDialog(std::move(promise), settings);
|
||||
}
|
||||
|
||||
} // namespace file_dialog
|
||||
@@ -97,7 +97,8 @@ class ElectronUsbDelegate::ContextObservation
|
||||
content::BrowserContext* browser_context)
|
||||
: parent_(parent), browser_context_(browser_context) {
|
||||
auto* chooser_context = GetChooserContext(browser_context_);
|
||||
device_observation_.Observe(chooser_context);
|
||||
if (chooser_context)
|
||||
device_observation_.Observe(chooser_context);
|
||||
}
|
||||
ContextObservation(ContextObservation&) = delete;
|
||||
ContextObservation& operator=(ContextObservation&) = delete;
|
||||
@@ -177,6 +178,9 @@ std::unique_ptr<UsbChooser> ElectronUsbDelegate::RunChooser(
|
||||
bool ElectronUsbDelegate::CanRequestDevicePermission(
|
||||
content::BrowserContext* browser_context,
|
||||
const url::Origin& origin) {
|
||||
if (!browser_context)
|
||||
return false;
|
||||
|
||||
base::Value::Dict details;
|
||||
details.Set("securityOrigin", origin.GetURL().spec());
|
||||
auto* permission_manager = static_cast<ElectronPermissionManager*>(
|
||||
@@ -191,32 +195,46 @@ void ElectronUsbDelegate::RevokeDevicePermissionWebInitiated(
|
||||
content::BrowserContext* browser_context,
|
||||
const url::Origin& origin,
|
||||
const device::mojom::UsbDeviceInfo& device) {
|
||||
GetChooserContext(browser_context)
|
||||
->RevokeDevicePermissionWebInitiated(origin, device);
|
||||
auto* chooser_context = GetChooserContext(browser_context);
|
||||
if (chooser_context) {
|
||||
chooser_context->RevokeDevicePermissionWebInitiated(origin, device);
|
||||
}
|
||||
}
|
||||
|
||||
const device::mojom::UsbDeviceInfo* ElectronUsbDelegate::GetDeviceInfo(
|
||||
content::BrowserContext* browser_context,
|
||||
const std::string& guid) {
|
||||
return GetChooserContext(browser_context)->GetDeviceInfo(guid);
|
||||
auto* chooser_context = GetChooserContext(browser_context);
|
||||
if (!chooser_context)
|
||||
return nullptr;
|
||||
return chooser_context->GetDeviceInfo(guid);
|
||||
}
|
||||
|
||||
bool ElectronUsbDelegate::HasDevicePermission(
|
||||
content::BrowserContext* browser_context,
|
||||
content::RenderFrameHost* frame,
|
||||
const url::Origin& origin,
|
||||
const device::mojom::UsbDeviceInfo& device) {
|
||||
if (IsDevicePermissionAutoGranted(origin, device))
|
||||
const device::mojom::UsbDeviceInfo& device_info) {
|
||||
if (IsDevicePermissionAutoGranted(origin, device_info))
|
||||
return true;
|
||||
|
||||
auto* chooser_context = GetChooserContext(browser_context);
|
||||
if (!chooser_context)
|
||||
return false;
|
||||
|
||||
return GetChooserContext(browser_context)
|
||||
->HasDevicePermission(origin, device);
|
||||
->HasDevicePermission(origin, device_info);
|
||||
}
|
||||
|
||||
void ElectronUsbDelegate::GetDevices(
|
||||
content::BrowserContext* browser_context,
|
||||
blink::mojom::WebUsbService::GetDevicesCallback callback) {
|
||||
GetChooserContext(browser_context)->GetDevices(std::move(callback));
|
||||
auto* chooser_context = GetChooserContext(browser_context);
|
||||
if (!chooser_context) {
|
||||
std::move(callback).Run(std::vector<device::mojom::UsbDeviceInfoPtr>());
|
||||
return;
|
||||
}
|
||||
chooser_context->GetDevices(std::move(callback));
|
||||
}
|
||||
|
||||
void ElectronUsbDelegate::GetDevice(
|
||||
@@ -225,25 +243,35 @@ void ElectronUsbDelegate::GetDevice(
|
||||
base::span<const uint8_t> blocked_interface_classes,
|
||||
mojo::PendingReceiver<device::mojom::UsbDevice> device_receiver,
|
||||
mojo::PendingRemote<device::mojom::UsbDeviceClient> device_client) {
|
||||
GetChooserContext(browser_context)
|
||||
->GetDevice(guid, blocked_interface_classes, std::move(device_receiver),
|
||||
std::move(device_client));
|
||||
auto* chooser_context = GetChooserContext(browser_context);
|
||||
if (chooser_context) {
|
||||
chooser_context->GetDevice(guid, blocked_interface_classes,
|
||||
std::move(device_receiver),
|
||||
std::move(device_client));
|
||||
}
|
||||
}
|
||||
|
||||
void ElectronUsbDelegate::AddObserver(content::BrowserContext* browser_context,
|
||||
Observer* observer) {
|
||||
if (!browser_context)
|
||||
return;
|
||||
|
||||
GetContextObserver(browser_context)->AddObserver(observer);
|
||||
}
|
||||
|
||||
void ElectronUsbDelegate::RemoveObserver(
|
||||
content::BrowserContext* browser_context,
|
||||
Observer* observer) {
|
||||
if (!browser_context)
|
||||
return;
|
||||
|
||||
GetContextObserver(browser_context)->RemoveObserver(observer);
|
||||
}
|
||||
|
||||
ElectronUsbDelegate::ContextObservation*
|
||||
ElectronUsbDelegate::GetContextObserver(
|
||||
content::BrowserContext* browser_context) {
|
||||
CHECK(browser_context);
|
||||
if (!base::Contains(observations_, browser_context)) {
|
||||
observations_.emplace(browser_context, std::make_unique<ContextObservation>(
|
||||
this, browser_context));
|
||||
|
||||
@@ -56,10 +56,11 @@ class ElectronUsbDelegate : public content::UsbDelegate {
|
||||
const device::mojom::UsbDeviceInfo* GetDeviceInfo(
|
||||
content::BrowserContext* browser_context,
|
||||
const std::string& guid) override;
|
||||
bool HasDevicePermission(content::BrowserContext* browser_context,
|
||||
content::RenderFrameHost* frame,
|
||||
const url::Origin& origin,
|
||||
const device::mojom::UsbDeviceInfo& device) override;
|
||||
bool HasDevicePermission(
|
||||
content::BrowserContext* browser_context,
|
||||
content::RenderFrameHost* frame,
|
||||
const url::Origin& origin,
|
||||
const device::mojom::UsbDeviceInfo& device_info) override;
|
||||
void GetDevices(
|
||||
content::BrowserContext* browser_context,
|
||||
blink::mojom::WebUsbService::GetDevicesCallback callback) override;
|
||||
|
||||
@@ -13,29 +13,32 @@ v8::Local<v8::Value> CallMethodWithArgs(v8::Isolate* isolate,
|
||||
v8::Local<v8::Object> obj,
|
||||
const char* method,
|
||||
ValueVector* args) {
|
||||
// Only set up the node::CallbackScope if there's a node environment.
|
||||
// An active node::Environment is required for node::MakeCallback.
|
||||
std::unique_ptr<node::CallbackScope> callback_scope;
|
||||
if (node::Environment::GetCurrent(isolate)) {
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
callback_scope = std::make_unique<node::CallbackScope>(
|
||||
isolate, v8::Object::New(isolate), node::async_context{0, 0});
|
||||
} else {
|
||||
return v8::Boolean::New(isolate, false);
|
||||
}
|
||||
|
||||
// Perform microtask checkpoint after running JavaScript.
|
||||
gin_helper::MicrotasksScope microtasks_scope(
|
||||
isolate, obj->GetCreationContextChecked()->GetMicrotaskQueue(), true);
|
||||
// Use node::MakeCallback to call the callback, and it will also run pending
|
||||
// tasks in Node.js.
|
||||
|
||||
// node::MakeCallback will also run pending tasks in Node.js.
|
||||
v8::MaybeLocal<v8::Value> ret = node::MakeCallback(
|
||||
isolate, obj, method, args->size(), args->data(), {0, 0});
|
||||
|
||||
// If the JS function throws an exception (doesn't return a value) the result
|
||||
// of MakeCallback will be empty and therefore ToLocal will be false, in this
|
||||
// case we need to return "false" as that indicates that the event emitter did
|
||||
// not handle the event
|
||||
v8::Local<v8::Value> localRet;
|
||||
if (ret.ToLocal(&localRet)) {
|
||||
if (ret.ToLocal(&localRet))
|
||||
return localRet;
|
||||
}
|
||||
|
||||
return v8::Boolean::New(isolate, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ SMAppService* GetServiceForType(const std::string& type,
|
||||
return [SMAppService agentServiceWithPlistName:service_name];
|
||||
} else if (type == "daemonService") {
|
||||
return [SMAppService daemonServiceWithPlistName:service_name];
|
||||
} else if (type == "loginService") {
|
||||
} else if (type == "loginItemService") {
|
||||
return [SMAppService loginItemServiceWithIdentifier:service_name];
|
||||
} else {
|
||||
LOG(ERROR) << "Unrecognized login item type";
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user