diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 9abee6864b8ee6..78d06c501e8835 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -15,7 +15,7 @@
]
},
"microsoft.dotnet.xharness.cli": {
- "version": "9.0.0-prerelease.24203.1",
+ "version": "9.0.0-prerelease.24208.1",
"commands": [
"xharness"
]
diff --git a/.github/workflows/bump-chrome-version.yml b/.github/workflows/bump-chrome-version.yml
index 65427d63f657ce..fc2f09cf3d01f7 100644
--- a/.github/workflows/bump-chrome-version.yml
+++ b/.github/workflows/bump-chrome-version.yml
@@ -27,7 +27,7 @@ jobs:
run: >-
make -C src/mono/wasm build-tasks &&
PATH=$PWD/.dotnet:$PATH dotnet build eng/testing/bump-chrome-version.proj -p:Configuration=Release &&
- git add eng/testing/ChromeVersions.props &&
+ git add eng/testing/BrowserVersions.props &&
cat eng/testing/bump-chrome-pr.env >> "$GITHUB_ENV"
- name: Check for changes
diff --git a/.github/workflows/locker.yml b/.github/workflows/locker.yml
index 2b7ab003275844..bea3f2fa09f983 100644
--- a/.github/workflows/locker.yml
+++ b/.github/workflows/locker.yml
@@ -20,13 +20,14 @@ permissions:
jobs:
main:
runs-on: ubuntu-latest
+ if: ${{ github.repository_owner == 'dotnet' }}
steps:
- name: Checkout Actions
uses: actions/checkout@v4
with:
repository: "microsoft/vscode-github-triage-actions"
path: ./actions
- ref: cd16cd2aad6ba2da74bb6c6f7293adddd579a90e
+ ref: 066bee9cefa6f0b4bf306040ff36fc7d96a6d56d # locker action commit sha
- name: Install Actions
run: npm install --production --prefix ./actions
- name: Run Locker
diff --git a/Directory.Build.targets b/Directory.Build.targets
index f731eedc390c36..1161d409dec1ab 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -86,9 +86,10 @@
-
+
$(SystemReflectionMetadataLoadContextVersion)
+ $(SystemTextJsonVersion)
-
+
https://github.com/dotnet/icu
- 1441a3fcbfa87c94b98a27605b06db7dd862f3e4
+ 0ea0175965771285846b5d077bebe5946036a595
https://github.com/dotnet/msquic
@@ -12,9 +12,9 @@
https://github.com/dotnet/wcf
7f504aabb1988e9a093c1e74d8040bd52feb2f01
-
+
https://github.com/dotnet/emsdk
- c42ff642a91a8aa4345de1728c3fa585ec13e1e6
+ 19c9523f5c2dd091b49959700723af795d6ad2b4
https://github.com/dotnet/llvm-project
@@ -58,24 +58,24 @@
a045dd54a4c44723c215d992288160eb1401bb7f
-
+
https://github.com/dotnet/cecil
- 9c8ea966df62f764523b51772763e74e71040a92
+ 861f49c137941b9722a43e5993ccac7716c8528c
-
+
https://github.com/dotnet/cecil
- 9c8ea966df62f764523b51772763e74e71040a92
+ 861f49c137941b9722a43e5993ccac7716c8528c
-
+
https://github.com/dotnet/emsdk
- c42ff642a91a8aa4345de1728c3fa585ec13e1e6
+ 19c9523f5c2dd091b49959700723af795d6ad2b4
-
+
https://github.com/dotnet/emsdk
- c42ff642a91a8aa4345de1728c3fa585ec13e1e6
+ 19c9523f5c2dd091b49959700723af795d6ad2b4
@@ -85,146 +85,146 @@
-
+
https://github.com/dotnet/source-build-externals
- 83566118e44922c30d146654d42c7c3745cc119d
+ 5a273649709de76f61957e3d69e1f031e5ac82e2
-
+
https://github.com/dotnet/arcade
- 87b015b938e5400d6e57afd7650348c17a764b73
+ 8ec8057ac5073b6b2e3fcb0a33d588d2a3357ad3
-
+
https://github.com/dotnet/arcade
- 87b015b938e5400d6e57afd7650348c17a764b73
+ 8ec8057ac5073b6b2e3fcb0a33d588d2a3357ad3
-
+
https://github.com/dotnet/arcade
- 87b015b938e5400d6e57afd7650348c17a764b73
+ 8ec8057ac5073b6b2e3fcb0a33d588d2a3357ad3
-
+
https://github.com/dotnet/arcade
- 87b015b938e5400d6e57afd7650348c17a764b73
+ 8ec8057ac5073b6b2e3fcb0a33d588d2a3357ad3
-
+
https://github.com/dotnet/arcade
- 87b015b938e5400d6e57afd7650348c17a764b73
+ 8ec8057ac5073b6b2e3fcb0a33d588d2a3357ad3
-
+
https://github.com/dotnet/arcade
- 87b015b938e5400d6e57afd7650348c17a764b73
+ 8ec8057ac5073b6b2e3fcb0a33d588d2a3357ad3
-
+
https://github.com/dotnet/arcade
- 87b015b938e5400d6e57afd7650348c17a764b73
+ 8ec8057ac5073b6b2e3fcb0a33d588d2a3357ad3
-
+
https://github.com/dotnet/arcade
- 87b015b938e5400d6e57afd7650348c17a764b73
+ 8ec8057ac5073b6b2e3fcb0a33d588d2a3357ad3
-
+
https://github.com/dotnet/arcade
- 87b015b938e5400d6e57afd7650348c17a764b73
+ 8ec8057ac5073b6b2e3fcb0a33d588d2a3357ad3
-
+
https://github.com/dotnet/arcade
- 87b015b938e5400d6e57afd7650348c17a764b73
+ 8ec8057ac5073b6b2e3fcb0a33d588d2a3357ad3
-
+
https://github.com/dotnet/arcade
- 87b015b938e5400d6e57afd7650348c17a764b73
+ 8ec8057ac5073b6b2e3fcb0a33d588d2a3357ad3
-
+
https://github.com/dotnet/arcade
- 87b015b938e5400d6e57afd7650348c17a764b73
+ 8ec8057ac5073b6b2e3fcb0a33d588d2a3357ad3
-
+
https://github.com/dotnet/arcade
- 87b015b938e5400d6e57afd7650348c17a764b73
+ 8ec8057ac5073b6b2e3fcb0a33d588d2a3357ad3
-
+
https://github.com/dotnet/arcade
- 87b015b938e5400d6e57afd7650348c17a764b73
+ 8ec8057ac5073b6b2e3fcb0a33d588d2a3357ad3
-
+
https://github.com/dotnet/arcade
- 87b015b938e5400d6e57afd7650348c17a764b73
+ 8ec8057ac5073b6b2e3fcb0a33d588d2a3357ad3
-
+
https://github.com/dotnet/arcade
- 87b015b938e5400d6e57afd7650348c17a764b73
+ 8ec8057ac5073b6b2e3fcb0a33d588d2a3357ad3
-
+
https://github.com/dotnet/arcade
- 87b015b938e5400d6e57afd7650348c17a764b73
+ 8ec8057ac5073b6b2e3fcb0a33d588d2a3357ad3
-
+
https://github.com/dotnet/arcade
- 87b015b938e5400d6e57afd7650348c17a764b73
+ 8ec8057ac5073b6b2e3fcb0a33d588d2a3357ad3
-
+
https://github.com/dotnet/arcade
- 87b015b938e5400d6e57afd7650348c17a764b73
+ 8ec8057ac5073b6b2e3fcb0a33d588d2a3357ad3
-
+
https://github.com/dotnet/arcade
- 87b015b938e5400d6e57afd7650348c17a764b73
+ 8ec8057ac5073b6b2e3fcb0a33d588d2a3357ad3
-
+
https://github.com/dotnet/runtime-assets
- f4d56683216389e84003fabcc73b929ba5012e3d
+ 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e
-
+
https://github.com/dotnet/runtime-assets
- f4d56683216389e84003fabcc73b929ba5012e3d
+ 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e
-
+
https://github.com/dotnet/runtime-assets
- f4d56683216389e84003fabcc73b929ba5012e3d
+ 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e
-
+
https://github.com/dotnet/runtime-assets
- f4d56683216389e84003fabcc73b929ba5012e3d
+ 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e
-
+
https://github.com/dotnet/runtime-assets
- f4d56683216389e84003fabcc73b929ba5012e3d
+ 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e
-
+
https://github.com/dotnet/runtime-assets
- f4d56683216389e84003fabcc73b929ba5012e3d
+ 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e
-
+
https://github.com/dotnet/runtime-assets
- f4d56683216389e84003fabcc73b929ba5012e3d
+ 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e
-
+
https://github.com/dotnet/runtime-assets
- f4d56683216389e84003fabcc73b929ba5012e3d
+ 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e
-
+
https://github.com/dotnet/runtime-assets
- f4d56683216389e84003fabcc73b929ba5012e3d
+ 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e
-
+
https://github.com/dotnet/runtime-assets
- f4d56683216389e84003fabcc73b929ba5012e3d
+ 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e
-
+
https://github.com/dotnet/runtime-assets
- f4d56683216389e84003fabcc73b929ba5012e3d
+ 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e
-
+
https://github.com/dotnet/runtime-assets
- f4d56683216389e84003fabcc73b929ba5012e3d
+ 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e
-
+
https://github.com/dotnet/runtime-assets
- f4d56683216389e84003fabcc73b929ba5012e3d
+ 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e
https://github.com/dotnet/llvm-project
@@ -282,59 +282,59 @@
https://github.com/dotnet/llvm-project
26f8c30340764cfa7fa9090dc01a36c222bf09c1
-
+
https://github.com/dotnet/runtime
- ec4437be46d8b90bc9fa6740c556bd860d9fe5ab
+ 85fbd98765c47a867564fff6ae18cc92423cdc66
-
+
https://github.com/dotnet/runtime
- ec4437be46d8b90bc9fa6740c556bd860d9fe5ab
+ 85fbd98765c47a867564fff6ae18cc92423cdc66
-
+
https://github.com/dotnet/runtime
- ec4437be46d8b90bc9fa6740c556bd860d9fe5ab
+ 85fbd98765c47a867564fff6ae18cc92423cdc66
-
+
https://github.com/dotnet/runtime
- ec4437be46d8b90bc9fa6740c556bd860d9fe5ab
+ 85fbd98765c47a867564fff6ae18cc92423cdc66
-
+
https://github.com/dotnet/runtime
- ec4437be46d8b90bc9fa6740c556bd860d9fe5ab
+ 85fbd98765c47a867564fff6ae18cc92423cdc66
-
+
https://github.com/dotnet/runtime
- ec4437be46d8b90bc9fa6740c556bd860d9fe5ab
+ 85fbd98765c47a867564fff6ae18cc92423cdc66
-
+
https://github.com/dotnet/runtime
- ec4437be46d8b90bc9fa6740c556bd860d9fe5ab
+ 85fbd98765c47a867564fff6ae18cc92423cdc66
-
+
https://github.com/dotnet/runtime
- ec4437be46d8b90bc9fa6740c556bd860d9fe5ab
+ 85fbd98765c47a867564fff6ae18cc92423cdc66
-
+
https://github.com/dotnet/runtime
- ec4437be46d8b90bc9fa6740c556bd860d9fe5ab
+ 85fbd98765c47a867564fff6ae18cc92423cdc66
-
+
https://github.com/dotnet/xharness
- 28af9496b0e260f7e66ec549b39f1410ee9743d1
+ 50b43ece7daf9f8a88ac16a95a4f8647a4c71c4b
-
+
https://github.com/dotnet/xharness
- 28af9496b0e260f7e66ec549b39f1410ee9743d1
+ 50b43ece7daf9f8a88ac16a95a4f8647a4c71c4b
-
+
https://github.com/dotnet/xharness
- 28af9496b0e260f7e66ec549b39f1410ee9743d1
+ 50b43ece7daf9f8a88ac16a95a4f8647a4c71c4b
-
+
https://github.com/dotnet/arcade
- 87b015b938e5400d6e57afd7650348c17a764b73
+ 8ec8057ac5073b6b2e3fcb0a33d588d2a3357ad3
https://dev.azure.com/dnceng/internal/_git/dotnet-optimization
@@ -352,48 +352,48 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-optimization
78a5b978e1965c1335edb4b9a22bc4d6ff5a77a6
-
+
https://github.com/dotnet/hotreload-utils
- 668ee30182fea845064853c46be5f54ac6efd110
+ 4670b9e37293570f8d93d6af40c4710e2686bf67
-
+
https://github.com/dotnet/runtime-assets
- f4d56683216389e84003fabcc73b929ba5012e3d
+ 30b6a8d9d3af5681e4caef1ea453619a4b0e9f2e
-
+
https://github.com/dotnet/roslyn
- 84c5476ef3111c9abd78d43e65063280bb7202d9
+ ca66296efa86bd8078508fe7b38b91b415364f78
-
+
https://github.com/dotnet/roslyn
- 84c5476ef3111c9abd78d43e65063280bb7202d9
+ ca66296efa86bd8078508fe7b38b91b415364f78
-
+
https://github.com/dotnet/roslyn
- 84c5476ef3111c9abd78d43e65063280bb7202d9
+ ca66296efa86bd8078508fe7b38b91b415364f78
-
+
https://github.com/dotnet/roslyn-analyzers
- 4d72fc19879fbc78a12d3a84ed60e7d17777d8b7
+ b07c100bfc66013a8444172d00cfa04c9ceb5a97
-
+
https://github.com/dotnet/roslyn-analyzers
- 4d72fc19879fbc78a12d3a84ed60e7d17777d8b7
+ b07c100bfc66013a8444172d00cfa04c9ceb5a97
-
+
https://github.com/dotnet/roslyn
- 84c5476ef3111c9abd78d43e65063280bb7202d9
+ ca66296efa86bd8078508fe7b38b91b415364f78
-
+
https://github.com/dotnet/sdk
- 219a6fc9954d632d7c119b31d59ff1516ff04d98
+ cf8c24575410adf397c0823fd7061f9451049ea1
-
+
https://github.com/dotnet/sdk
- 219a6fc9954d632d7c119b31d59ff1516ff04d98
+ cf8c24575410adf397c0823fd7061f9451049ea1
@@ -410,9 +410,9 @@
https://github.com/NuGet/NuGet.Client
8fef55f5a55a3b4f2c96cd1a9b5ddc51d4b927f8
-
+
https://github.com/dotnet/installer
- 0bfd2dd757482b30745b799ee0a92cad3d8f5b50
+ 7380c301c1ce7d022dd365dd78c4004a2881edaf
diff --git a/eng/Versions.props b/eng/Versions.props
index ecb7db8e76cbab..46b53f8ae070c9 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -34,17 +34,17 @@
- 3.11.0-beta1.24212.1
- 9.0.0-preview.24212.1
+ 3.11.0-beta1.24216.2
+ 9.0.0-preview.24216.2
- 4.11.0-1.24214.4
- 4.11.0-1.24214.4
- 4.11.0-1.24214.4
+ 4.11.0-1.24215.10
+ 4.11.0-1.24215.10
+ 4.11.0-1.24215.10
- 9.0.100-preview.4.24175.4
+ 9.0.100-preview.4.24215.1
- 9.0.0-beta.24212.4
- 9.0.0-beta.24212.4
- 9.0.0-beta.24212.4
- 9.0.0-beta.24212.4
- 2.6.7-beta.24212.4
- 9.0.0-beta.24212.4
- 2.6.7-beta.24212.4
- 9.0.0-beta.24212.4
- 9.0.0-beta.24212.4
- 9.0.0-beta.24212.4
- 9.0.0-beta.24212.4
- 9.0.0-beta.24212.4
- 9.0.0-beta.24212.4
- 9.0.0-beta.24212.4
- 9.0.0-beta.24212.4
- 9.0.0-beta.24212.4
+ 9.0.0-beta.24217.1
+ 9.0.0-beta.24217.1
+ 9.0.0-beta.24217.1
+ 9.0.0-beta.24217.1
+ 2.6.7-beta.24217.1
+ 9.0.0-beta.24217.1
+ 2.6.7-beta.24217.1
+ 9.0.0-beta.24217.1
+ 9.0.0-beta.24217.1
+ 9.0.0-beta.24217.1
+ 9.0.0-beta.24217.1
+ 9.0.0-beta.24217.1
+ 9.0.0-beta.24217.1
+ 9.0.0-beta.24217.1
+ 9.0.0-beta.24217.1
+ 9.0.0-beta.24217.1
1.4.0
6.0.0-preview.1.102
- 9.0.0-preview.4.24201.1
+ 9.0.0-preview.4.24215.1
6.0.0
- 9.0.0-preview.4.24201.1
+ 9.0.0-preview.4.24215.1
6.0.0
1.1.1
@@ -119,38 +119,39 @@
8.0.0
5.0.0
4.5.5
- 9.0.0-preview.4.24201.1
- 9.0.0-preview.4.24201.1
+ 9.0.0-preview.4.24215.1
+ 9.0.0-preview.4.24215.1
6.0.0
5.0.0
5.0.0
5.0.0
7.0.0
- 9.0.0-preview.4.24201.1
+ 9.0.0-preview.4.24215.1
6.0.0
7.0.0
4.5.4
4.5.0
- 9.0.0-preview.4.24201.1
+ 9.0.0-preview.4.24215.1
8.0.0
+ 8.0.0
8.0.0
8.0.0
- 9.0.0-beta.24205.1
- 9.0.0-beta.24205.1
- 9.0.0-beta.24205.1
- 9.0.0-beta.24205.1
- 9.0.0-beta.24205.1
- 9.0.0-beta.24205.1
- 9.0.0-beta.24205.1
- 9.0.0-beta.24205.1
- 9.0.0-beta.24205.1
- 9.0.0-beta.24205.1
- 9.0.0-beta.24205.1
- 9.0.0-beta.24205.1
- 9.0.0-beta.24205.1
- 9.0.0-beta.24205.1
+ 9.0.0-beta.24215.1
+ 9.0.0-beta.24215.1
+ 9.0.0-beta.24215.1
+ 9.0.0-beta.24215.1
+ 9.0.0-beta.24215.1
+ 9.0.0-beta.24215.1
+ 9.0.0-beta.24215.1
+ 9.0.0-beta.24215.1
+ 9.0.0-beta.24215.1
+ 9.0.0-beta.24215.1
+ 9.0.0-beta.24215.1
+ 9.0.0-beta.24215.1
+ 9.0.0-beta.24215.1
+ 9.0.0-beta.24215.1
1.0.0-prerelease.24106.4
1.0.0-prerelease.24106.4
@@ -178,10 +179,10 @@
1.4.0
17.4.0-preview-20220707-01
- 9.0.0-prerelease.24203.1
- 9.0.0-prerelease.24203.1
- 9.0.0-prerelease.24203.1
- 9.0.0-alpha.0.24201.1
+ 9.0.0-prerelease.24208.1
+ 9.0.0-prerelease.24208.1
+ 9.0.0-prerelease.24208.1
+ 9.0.0-alpha.0.24215.1
3.12.0
4.5.0
6.0.0
@@ -207,11 +208,11 @@
8.0.0-preview-20230918.1
- 0.11.4-alpha.24168.1
+ 0.11.4-alpha.24215.1
- 9.0.0-preview.4.24201.1
+ 9.0.0-preview.4.24215.1
- 9.0.0-preview.4.24201.1
+ 9.0.0-preview.4.24215.1
2.3.5
9.0.0-alpha.1.24167.3
@@ -234,9 +235,9 @@
Note: when the name is updated, make sure to update dependency name in eng/pipelines/common/xplat-setup.yml
like - DarcDependenciesChanged.Microsoft_NET_Workload_Emscripten_Current_Manifest-9_0_100_Transport
-->
- 9.0.0-preview.4.24209.5
+ 9.0.0-preview.4.24215.3
$(MicrosoftNETWorkloadEmscriptenCurrentManifest90100TransportVersion)
- 9.0.0-preview.4.24209.5
+ 9.0.0-preview.4.24215.3
1.1.87-gba258badda
1.0.0-v3.14.0.5722
@@ -253,7 +254,7 @@
3.1.7
1.0.406601
- 9.0.100-preview.4.24208.2
+ 9.0.100-preview.4.24215.2
$(MicrosoftDotnetSdkInternalVersion)
diff --git a/eng/common/templates-official/job/job.yml b/eng/common/templates-official/job/job.yml
index c63e17e863ed17..761acc5eb624c6 100644
--- a/eng/common/templates-official/job/job.yml
+++ b/eng/common/templates-official/job/job.yml
@@ -210,7 +210,7 @@ jobs:
- task: 1ES.PublishPipelineArtifact@1
inputs:
targetPath: 'artifacts/log'
- artifactName: ${{ coalesce(parameters.artifacts.publish.logs.name, 'Logs_Build_$(Agent.Os)_$(_BuildConfig)') }}
+ artifactName: ${{ coalesce(parameters.artifacts.publish.logs.name, 'Logs_Build_$(Agent.Os)_$(_BuildConfig)_Attempt$(System.JobAttempt)') }}
displayName: 'Publish logs'
continueOnError: true
condition: always()
diff --git a/eng/common/templates-official/job/onelocbuild.yml b/eng/common/templates-official/job/onelocbuild.yml
index ba9ba49303292a..52b4d05d3f8dd6 100644
--- a/eng/common/templates-official/job/onelocbuild.yml
+++ b/eng/common/templates-official/job/onelocbuild.yml
@@ -56,7 +56,7 @@ jobs:
# If it's not devdiv, it's dnceng
${{ if ne(variables['System.TeamProject'], 'DevDiv') }}:
name: $(DncEngInternalBuildPool)
- image: 1es-windows-2022-pt
+ image: 1es-windows-2022
os: windows
steps:
diff --git a/eng/common/templates-official/job/source-build.yml b/eng/common/templates-official/job/source-build.yml
index c918720931f49a..2180e97a284f84 100644
--- a/eng/common/templates-official/job/source-build.yml
+++ b/eng/common/templates-official/job/source-build.yml
@@ -52,7 +52,7 @@ jobs:
${{ if eq(variables['System.TeamProject'], 'internal') }}:
name: $[replace(replace(eq(contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release'), 'true'), True, 'NetCore1ESPool-Svc-Internal'), False, 'NetCore1ESPool-Internal')]
- image: 1es-mariner-2-pt
+ image: 1es-mariner-2
os: linux
${{ if ne(parameters.platform.pool, '') }}:
diff --git a/eng/common/templates-official/post-build/post-build.yml b/eng/common/templates-official/post-build/post-build.yml
index d286e956bdfa40..da1f40958b450d 100644
--- a/eng/common/templates-official/post-build/post-build.yml
+++ b/eng/common/templates-official/post-build/post-build.yml
@@ -110,7 +110,7 @@ stages:
# If it's not devdiv, it's dnceng
${{ else }}:
name: $(DncEngInternalBuildPool)
- image: 1es-windows-2022-pt
+ image: 1es-windows-2022
os: windows
steps:
@@ -150,7 +150,7 @@ stages:
# If it's not devdiv, it's dnceng
${{ else }}:
name: $(DncEngInternalBuildPool)
- image: 1es-windows-2022-pt
+ image: 1es-windows-2022
os: windows
steps:
- template: setup-maestro-vars.yml
@@ -208,7 +208,7 @@ stages:
# If it's not devdiv, it's dnceng
${{ else }}:
name: $(DncEngInternalBuildPool)
- image: 1es-windows-2022-pt
+ image: 1es-windows-2022
os: windows
steps:
- template: setup-maestro-vars.yml
diff --git a/eng/common/templates-official/variables/pool-providers.yml b/eng/common/templates-official/variables/pool-providers.yml
index beab7d1bfba062..1f308b24efc43d 100644
--- a/eng/common/templates-official/variables/pool-providers.yml
+++ b/eng/common/templates-official/variables/pool-providers.yml
@@ -23,7 +23,7 @@
#
# pool:
# name: $(DncEngInternalBuildPool)
-# image: 1es-windows-2022-pt
+# image: 1es-windows-2022
variables:
# Coalesce the target and source branches so we know when a PR targets a release branch
diff --git a/eng/pipelines/common/evaluate-default-paths.yml b/eng/pipelines/common/evaluate-default-paths.yml
index edbc1c618f6066..d954a1ddacbb57 100644
--- a/eng/pipelines/common/evaluate-default-paths.yml
+++ b/eng/pipelines/common/evaluate-default-paths.yml
@@ -7,7 +7,7 @@ parameters:
_const_paths:
_wasm_specific_only: [
eng/testing/bump-chrome-version.proj
- eng/testing/ChromeVersions.props
+ eng/testing/BrowserVersions.props
eng/testing/WasmRunner*
eng/testing/WasiRunner*
eng/testing/scenarios/BuildWasiAppsJobsList.txt
@@ -22,6 +22,7 @@ parameters:
src/libraries/sendtohelix-browser.targets
src/libraries/sendtohelix-wasi.targets
src/libraries/sendtohelix-wasm.targets
+ src/libraries/System.Runtime.InteropServices.JavaScript/*
src/mono/mono/**/*wasm*
src/mono/nuget/Microsoft.NET.Runtime.WebAssembly.Sdk/*
src/mono/nuget/Microsoft.NET.Runtime.WebAssembly.Wasi.Sdk/*
@@ -57,7 +58,7 @@ parameters:
]
_wasm_chrome: [
eng/testing/bump-chrome-version.proj
- eng/testing/ChromeVersions.props
+ eng/testing/BrowserVersions.props
]
_perf_pipeline_specific_only: [
eng/pipelines/runtime-wasm-perf.yml
diff --git a/eng/pipelines/common/templates/pipeline-with-resources.yml b/eng/pipelines/common/templates/pipeline-with-resources.yml
index 5ae3a3f7a38f56..b9db26f6cb151c 100644
--- a/eng/pipelines/common/templates/pipeline-with-resources.yml
+++ b/eng/pipelines/common/templates/pipeline-with-resources.yml
@@ -17,7 +17,7 @@ extends:
containers:
linux_arm:
- image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-cross-arm
+ image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-arm-net8.0
env:
ROOTFS_DIR: /crossrootfs/arm
@@ -33,17 +33,17 @@ extends:
ROOTFS_DIR: /crossrootfs/arm64
linux_musl_x64:
- image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-cross-amd64-alpine
+ image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-amd64-alpine-net8.0
env:
ROOTFS_DIR: /crossrootfs/x64
linux_musl_arm:
- image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-cross-arm-alpine
+ image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-arm-alpine-net8.0
env:
ROOTFS_DIR: /crossrootfs/arm
linux_musl_arm64:
- image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-cross-arm64-alpine
+ image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-arm64-alpine-net8.0
env:
ROOTFS_DIR: /crossrootfs/arm64
@@ -56,12 +56,12 @@ extends:
image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-android-docker
linux_x64:
- image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-cross-amd64
+ image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-amd64-net8.0
env:
ROOTFS_DIR: /crossrootfs/x64
linux_x86:
- image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-cross-x86
+ image: mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-cross-x86-net8.0
env:
ROOTFS_DIR: /crossrootfs/x86
diff --git a/eng/pipelines/common/templates/wasm-library-aot-tests.yml b/eng/pipelines/common/templates/wasm-library-aot-tests.yml
index 9937d44ef21f67..cc86f4fd710fb2 100644
--- a/eng/pipelines/common/templates/wasm-library-aot-tests.yml
+++ b/eng/pipelines/common/templates/wasm-library-aot-tests.yml
@@ -31,7 +31,9 @@ jobs:
shouldRunSmokeOnly: ${{ parameters.shouldRunSmokeOnly }}
shouldContinueOnError: ${{ parameters.shouldContinueOnError }}
scenarios:
- - ${{ if eq(platform, 'browser_wasm_win') }}:
- - WasmTestOnBrowser
- - ${{ if ne(platform, 'browser_wasm_win') }}:
+ - ${{ if eq(platform, 'browser_wasm') }}:
- normal
+ - ${{ if eq(platform, 'browser_wasm_win') }}:
+ - WasmTestOnChrome
+ - ${{ if or(eq(platform, 'wasi_wasm_win'), eq(platform, 'wasi_wasm')) }}:
+ - WasmTestOnWasmtime
diff --git a/eng/pipelines/common/templates/wasm-library-tests.yml b/eng/pipelines/common/templates/wasm-library-tests.yml
index 3765b35c30af96..b3193f4a495a59 100644
--- a/eng/pipelines/common/templates/wasm-library-tests.yml
+++ b/eng/pipelines/common/templates/wasm-library-tests.yml
@@ -61,7 +61,7 @@ jobs:
- name: _wasmRunSmokeTestsOnlyArg
value: /p:RunSmokeTestsOnly=$(shouldRunSmokeOnlyVar)
- name: chromeInstallArg
- ${{ if containsValue(parameters.scenarios, 'wasmtestonbrowser') }}:
+ ${{ if containsValue(parameters.scenarios, 'WasmTestOnChrome') }}:
value: /p:InstallChromeForTests=true
${{ else }}:
value: ''
diff --git a/eng/pipelines/coreclr/templates/run-performance-job.yml b/eng/pipelines/coreclr/templates/run-performance-job.yml
index 65b1cb3b78443c..2b61558e2fc97f 100644
--- a/eng/pipelines/coreclr/templates/run-performance-job.yml
+++ b/eng/pipelines/coreclr/templates/run-performance-job.yml
@@ -93,6 +93,7 @@ jobs:
echo "** Installing prerequistes **";
echo "** Waiting for dpkg to unlock (up to 2 minutes) **" &&
timeout 2m bash -c 'while sudo fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1; do if [ -z "$printed" ]; then echo "Waiting for dpkg lock to be released... Lock is held by: $(ps -o cmd= -p $(sudo fuser /var/lib/dpkg/lock-frontend))"; printed=1; fi; echo "Waiting 5 seconds to check again"; sleep 5; done;' &&
+ sudo apt-get remove -y lttng-modules-dkms &&
sudo apt-get -y install python3-pip &&
python3 -m pip install --user -U pip &&
sudo apt-get -y install python3-venv &&
@@ -194,4 +195,4 @@ jobs:
WorkItemDirectory: '$(WorkItemDirectory)' # WorkItemDirectory can not be empty, so we send it some docs to keep it happy
CorrelationPayloadDirectory: '$(PayloadDirectory)' # it gets checked out to a folder with shorter path than WorkItemDirectory so we can avoid file name too long exceptions
ProjectFile: ${{ parameters.projectFile }}
- osGroup: ${{ parameters.osGroup }}
\ No newline at end of file
+ osGroup: ${{ parameters.osGroup }}
diff --git a/eng/pipelines/extra-platforms/runtime-extra-platforms-wasm.yml b/eng/pipelines/extra-platforms/runtime-extra-platforms-wasm.yml
index fc8d757233cd45..ec77f76a85828c 100644
--- a/eng/pipelines/extra-platforms/runtime-extra-platforms-wasm.yml
+++ b/eng/pipelines/extra-platforms/runtime-extra-platforms-wasm.yml
@@ -90,7 +90,7 @@ jobs:
isWasmOnlyBuild: ${{ parameters.isWasmOnlyBuild }}
scenarios:
- normal
- - WasmTestOnBrowser
+ - WasmTestOnChrome
# this only runs on the extra pipeline
- template: /eng/pipelines/common/templates/wasm-library-tests.yml
@@ -114,7 +114,7 @@ jobs:
isExtraPlatformsBuild: ${{ parameters.isExtraPlatformsBuild }}
isWasmOnlyBuild: ${{ parameters.isWasmOnlyBuild }}
scenarios:
- - WasmTestOnBrowser
+ - WasmTestOnChrome
- WasmTestOnNodeJS
# EAT Library tests - only run on linux
@@ -198,7 +198,7 @@ jobs:
alwaysRun: true
scenarios:
- normal
- - WasmTestOnBrowser
+ - WasmTestOnChrome
- WasmTestOnNodeJS
# Hybrid Globalization AOT tests
@@ -215,7 +215,7 @@ jobs:
alwaysRun: true
scenarios:
- normal
- - WasmTestOnBrowser
+ - WasmTestOnChrome
- WasmTestOnNodeJS
- ${{ if and(ne(parameters.isRollingBuild, true), ne(parameters.excludeNonLibTests, true), ne(parameters.debuggerTestsOnly, true)) }}:
diff --git a/eng/pipelines/runtime-wasm-perf.yml b/eng/pipelines/runtime-wasm-perf.yml
index 91e508e2c9669d..39645a501ecf25 100644
--- a/eng/pipelines/runtime-wasm-perf.yml
+++ b/eng/pipelines/runtime-wasm-perf.yml
@@ -16,7 +16,7 @@ pr:
- eng/pipelines/coreclr/templates/run-perf*
- eng/pipelines/coreclr/templates/run-scenarios-job.yml
- eng/testing/performance/*
- - eng/testing/ChromeVersions.props
+ - eng/testing/BrowserVersions.props
variables:
- template: /eng/pipelines/common/variables.yml
diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml
index ace914f9ecf60b..284a2aafb0888a 100644
--- a/eng/pipelines/runtime.yml
+++ b/eng/pipelines/runtime.yml
@@ -824,7 +824,7 @@ extends:
extraBuildArgs: /p:AotHostArchitecture=x64 /p:AotHostOS=$(_hostedOS)
scenarios:
- normal
- - WasmTestOnBrowser
+ - WasmTestOnChrome
- template: /eng/pipelines/common/templates/wasm-library-tests.yml
parameters:
@@ -833,7 +833,7 @@ extends:
alwaysRun: ${{ variables.isRollingBuild }}
extraBuildArgs: /p:AotHostArchitecture=x64 /p:AotHostOS=$(_hostedOS)
scenarios:
- - WasmTestOnBrowser
+ - WasmTestOnChrome
# Library tests with full threading
- template: /eng/pipelines/common/templates/wasm-library-tests.yml
@@ -846,7 +846,7 @@ extends:
alwaysRun: ${{ variables.isRollingBuild }}
shouldRunSmokeOnly: onLibrariesAndIllinkChanges
scenarios:
- - WasmTestOnBrowser
+ - WasmTestOnChrome
#- WasmTestOnNodeJS - this is not supported yet, https://github.com/dotnet/runtime/issues/85592
# EAT Library tests - only run on linux
@@ -935,7 +935,7 @@ extends:
shouldRunSmokeOnly: true
alwaysRun: ${{ variables.isRollingBuild }}
scenarios:
- - normal
+ - WasmTestOnWasmtime
- template: /eng/pipelines/common/templates/simple-wasm-build-tests.yml
parameters:
diff --git a/eng/testing/ChromeVersions.props b/eng/testing/BrowserVersions.props
similarity index 83%
rename from eng/testing/ChromeVersions.props
rename to eng/testing/BrowserVersions.props
index bb40a987e44df6..b1e85302a8ed3a 100644
--- a/eng/testing/ChromeVersions.props
+++ b/eng/testing/BrowserVersions.props
@@ -8,5 +8,7 @@
1250580
https://storage.googleapis.com/chromium-browser-snapshots/Win_x64/1250586
12.3.219
+ 124.0.2
+ 0.34.0
diff --git a/eng/testing/WasiRunnerAOTTemplate.sh b/eng/testing/WasiRunnerAOTTemplate.sh
deleted file mode 100644
index b45c553b67c566..00000000000000
--- a/eng/testing/WasiRunnerAOTTemplate.sh
+++ /dev/null
@@ -1,90 +0,0 @@
-#!/usr/bin/env bash
-
-# SetCommands defined in eng\testing\tests.wasm.targets
-[[SetCommands]]
-[[SetCommandsEcho]]
-
-EXECUTION_DIR=$(dirname $0)
-if [[ -n "$3" ]]; then
- SCENARIO=$3
-fi
-
-export PATH=$PREPEND_PATH:$PATH
-
-if [[ -z "$HELIX_WORKITEM_UPLOAD_ROOT" ]]; then
- XHARNESS_OUT="$EXECUTION_DIR/xharness-output"
-else
- XHARNESS_OUT="$HELIX_WORKITEM_UPLOAD_ROOT/xharness-output"
-fi
-
-if [[ -n "$XHARNESS_CLI_PATH" ]]; then
- # When running in CI, we only have the .NET runtime available
- # We need to call the XHarness CLI DLL directly via dotnet exec
- HARNESS_RUNNER="dotnet exec $XHARNESS_CLI_PATH"
-else
- HARNESS_RUNNER="dotnet xharness"
-fi
-
-if [[ -z "$XHARNESS_COMMAND" ]]; then
- XHARNESS_COMMAND="test"
-fi
-
-echo PATH=$PATH
-echo EXECUTION_DIR=$EXECUTION_DIR
-echo SCENARIO=$SCENARIO
-echo XHARNESS_OUT=$XHARNESS_OUT
-echo XHARNESS_CLI_PATH=$XHARNESS_CLI_PATH
-echo HARNESS_RUNNER=$HARNESS_RUNNER
-echo XHARNESS_COMMAND=$XHARNESS_COMMAND
-echo XHARNESS_ARGS=$XHARNESS_ARGS
-
-function _buildAOTFunc()
-{
- local projectFile=$1
- local binLog=$2
- shift 2
-
- time dotnet msbuild $projectFile /bl:$binLog $*
- local buildExitCode=$?
-
- echo "\n** Performance summary for the build **\n"
- dotnet msbuild $binLog -clp:PerformanceSummary -v:q -nologo
- if [[ "$(uname -s)" == "Linux" && $buildExitCode -ne 0 ]]; then
- echo "\nLast few messages from dmesg:\n"
- local lastLines=`dmesg | tail -n 20`
- echo $lastLines
-
- if [[ "$lastLines" =~ "oom-kill" ]]; then
- return 9200 # OOM
- fi
- fi
-
- echo
- echo
-
- if [[ $buildExitCode -ne 0 ]]; then
- return 9100 # aot build failure
- fi
-
- return 0
-}
-
-pushd $EXECUTION_DIR
-
-# ========================= BEGIN Test Execution =============================
-echo ----- start $(date) =============== To repro directly: =====================================================
-echo pushd $EXECUTION_DIR
-# RunCommands defined in eng\testing\tests.wasm.targets
-[[RunCommandsEcho]]
-echo popd
-echo ===========================================================================================================
-pushd $EXECUTION_DIR
-# RunCommands defined in eng\testing\tests.wasm.targets
-[[RunCommands]]
-_exitCode=$?
-popd
-echo ----- end $(date) ----- exit code $_exitCode ----------------------------------------------------------
-
-echo "XHarness artifacts: $XHARNESS_OUT"
-
-exit $_exitCode
diff --git a/eng/testing/WasiRunnerTemplate.sh b/eng/testing/WasiRunnerTemplate.sh
index 7a3752d321172a..66e6731e03f26b 100644
--- a/eng/testing/WasiRunnerTemplate.sh
+++ b/eng/testing/WasiRunnerTemplate.sh
@@ -47,6 +47,37 @@ echo HARNESS_RUNNER=$HARNESS_RUNNER
echo XHARNESS_COMMAND=$XHARNESS_COMMAND
echo XHARNESS_ARGS=$XHARNESS_ARGS
+function _buildAOTFunc()
+{
+ local projectFile=$1
+ local binLog=$2
+ shift 2
+
+ time dotnet msbuild $projectFile /bl:$binLog $*
+ local buildExitCode=$?
+
+ echo "\n** Performance summary for the build **\n"
+ dotnet msbuild $binLog -clp:PerformanceSummary -v:q -nologo
+ if [[ "$(uname -s)" == "Linux" && $buildExitCode -ne 0 ]]; then
+ echo "\nLast few messages from dmesg:\n"
+ local lastLines=`dmesg | tail -n 20`
+ echo $lastLines
+
+ if [[ "$lastLines" =~ "oom-kill" ]]; then
+ return 9200 # OOM
+ fi
+ fi
+
+ echo
+ echo
+
+ if [[ $buildExitCode -ne 0 ]]; then
+ return 9100 # aot build failure
+ fi
+
+ return 0
+}
+
pushd $EXECUTION_DIR
# ========================= BEGIN Test Execution =============================
diff --git a/eng/testing/WasmRunnerAOTTemplate.sh b/eng/testing/WasmRunnerAOTTemplate.sh
deleted file mode 100644
index 1e17a2a4770edf..00000000000000
--- a/eng/testing/WasmRunnerAOTTemplate.sh
+++ /dev/null
@@ -1,130 +0,0 @@
-#!/usr/bin/env bash
-
-# SetCommands defined in eng\testing\tests.wasm.targets
-[[SetCommands]]
-[[SetCommandsEcho]]
-
-export PATH="$HOME/.jsvu/bin:$PATH"
-export PATH=$PREPEND_PATH:$PATH
-
-EXECUTION_DIR=$(dirname $0)
-if [[ -n "$3" ]]; then
- SCENARIO=$3
-fi
-
-if [[ -z "$HELIX_WORKITEM_UPLOAD_ROOT" ]]; then
- XHARNESS_OUT="$EXECUTION_DIR/xharness-output"
-else
- XHARNESS_OUT="$HELIX_WORKITEM_UPLOAD_ROOT/xharness-output"
-fi
-
-if [[ -n "$XHARNESS_CLI_PATH" ]]; then
- # When running in CI, we only have the .NET runtime available
- # We need to call the XHarness CLI DLL directly via dotnet exec
- HARNESS_RUNNER="dotnet exec $XHARNESS_CLI_PATH"
-else
- HARNESS_RUNNER="dotnet xharness"
-fi
-
-if [[ -z "$XHARNESS_COMMAND" ]]; then
- if [[ "$SCENARIO" == "WasmTestOnBrowser" || "$SCENARIO" == "wasmtestonbrowser" ]]; then
- XHARNESS_COMMAND="test-browser"
- else
- XHARNESS_COMMAND="test"
- fi
-fi
-
-if [[ "$XHARNESS_COMMAND" == "test" ]]; then
- if [[ -z "$JS_ENGINE_ARGS" ]]; then
- JS_ENGINE_ARGS="--engine-arg=--stack-trace-limit=1000"
- if [[ "$SCENARIO" != "WasmTestOnNodeJS" && "$SCENARIO" != "wasmtestonnodejs" ]]; then
- JS_ENGINE_ARGS="$JS_ENGINE_ARGS --engine-arg=--module"
- fi
- if [[ "$SCENARIO" == "WasmTestOnNodeJS" || "$SCENARIO" == "wasmtestonnodejs" ]]; then
- JS_ENGINE_ARGS="$JS_ENGINE_ARGS --engine-arg=--experimental-wasm-eh"
- fi
- fi
-
- if [[ -z "$MAIN_JS" ]]; then
- MAIN_JS="--js-file=test-main.js"
- fi
-
- if [[ -z "$JS_ENGINE" ]]; then
- if [[ "$SCENARIO" == "WasmTestOnNodeJS" || "$SCENARIO" == "wasmtestonnodejs" ]]; then
- JS_ENGINE="--engine=NodeJS"
- else
- JS_ENGINE="--engine=V8"
- if [[ -n "$V8_PATH_FOR_TESTS" ]]; then
- JS_ENGINE_ARGS="$JS_ENGINE_ARGS --js-engine-path=$V8_PATH_FOR_TESTS"
- fi
- fi
- fi
-fi
-
-if [[ -z "$XHARNESS_ARGS" ]]; then
- XHARNESS_ARGS="$JS_ENGINE $JS_ENGINE_ARGS $MAIN_JS"
-fi
-
-echo PATH=$PATH
-echo EXECUTION_DIR=$EXECUTION_DIR
-echo SCENARIO=$SCENARIO
-echo XHARNESS_OUT=$XHARNESS_OUT
-echo XHARNESS_CLI_PATH=$XHARNESS_CLI_PATH
-echo HARNESS_RUNNER=$HARNESS_RUNNER
-echo XHARNESS_COMMAND=$XHARNESS_COMMAND
-echo MAIN_JS=$MAIN_JS
-echo JS_ENGINE=$JS_ENGINE
-echo JS_ENGINE_ARGS=$JS_ENGINE_ARGS
-echo XHARNESS_ARGS=$XHARNESS_ARGS
-
-function _buildAOTFunc()
-{
- local projectFile=$1
- local binLog=$2
- shift 2
-
- time dotnet msbuild $projectFile /bl:$binLog $*
- local buildExitCode=$?
-
- echo "\n** Performance summary for the build **\n"
- dotnet msbuild $binLog -clp:PerformanceSummary -v:q -nologo
- if [[ "$(uname -s)" == "Linux" && $buildExitCode -ne 0 ]]; then
- echo "\nLast few messages from dmesg:\n"
- local lastLines=`dmesg | tail -n 20`
- echo $lastLines
-
- if [[ "$lastLines" =~ "oom-kill" ]]; then
- return 9200 # OOM
- fi
- fi
-
- echo
- echo
-
- if [[ $buildExitCode -ne 0 ]]; then
- return 9100 # aot build failure
- fi
-
- return 0
-}
-
-
-pushd $EXECUTION_DIR
-
-# ========================= BEGIN Test Execution =============================
-echo ----- start $(date) =============== To repro directly: =====================================================
-echo pushd $EXECUTION_DIR
-# RunCommands defined in eng\testing\tests.wasm.targets
-[[RunCommandsEcho]]
-echo popd
-echo ===========================================================================================================
-pushd $EXECUTION_DIR
-# RunCommands defined in eng\testing\tests.wasm.targets
-[[RunCommands]]
-_exitCode=$?
-popd
-echo ----- end $(date) ----- exit code $_exitCode ----------------------------------------------------------
-
-echo "XHarness artifacts: $XHARNESS_OUT"
-
-exit $_exitCode
diff --git a/eng/testing/WasmRunnerTemplate.cmd b/eng/testing/WasmRunnerTemplate.cmd
index f92cee17cc9df7..0c7f3dc2195d26 100644
--- a/eng/testing/WasmRunnerTemplate.cmd
+++ b/eng/testing/WasmRunnerTemplate.cmd
@@ -27,7 +27,7 @@ if [%XHARNESS_CLI_PATH%] NEQ [] (
)
if [%XHARNESS_COMMAND%] == [] (
- if /I [%SCENARIO%]==[WasmTestOnBrowser] (
+ if /I [%SCENARIO%]==[WasmTestOnChrome] (
set XHARNESS_COMMAND=test-browser
) else (
set XHARNESS_COMMAND=test
diff --git a/eng/testing/WasmRunnerTemplate.sh b/eng/testing/WasmRunnerTemplate.sh
index 4f5856546fc56b..bd7f1faadf3556 100644
--- a/eng/testing/WasmRunnerTemplate.sh
+++ b/eng/testing/WasmRunnerTemplate.sh
@@ -26,7 +26,7 @@ else
fi
if [[ -z "$XHARNESS_COMMAND" ]]; then
- if [[ "$SCENARIO" == "WasmTestOnBrowser" || "$SCENARIO" == "wasmtestonbrowser" ]]; then
+ if [[ "$SCENARIO" == "WasmTestOnChrome" || "$SCENARIO" == "wasmtestonchrome" ]]; then
XHARNESS_COMMAND="test-browser"
else
XHARNESS_COMMAND="test"
@@ -88,6 +88,38 @@ echo JS_ENGINE=$JS_ENGINE
echo JS_ENGINE_ARGS=$JS_ENGINE_ARGS
echo XHARNESS_ARGS=$XHARNESS_ARGS
+function _buildAOTFunc()
+{
+ local projectFile=$1
+ local binLog=$2
+ shift 2
+
+ time dotnet msbuild $projectFile /bl:$binLog $*
+ local buildExitCode=$?
+
+ echo "\n** Performance summary for the build **\n"
+ dotnet msbuild $binLog -clp:PerformanceSummary -v:q -nologo
+ if [[ "$(uname -s)" == "Linux" && $buildExitCode -ne 0 ]]; then
+ echo "\nLast few messages from dmesg:\n"
+ local lastLines=`dmesg | tail -n 20`
+ echo $lastLines
+
+ if [[ "$lastLines" =~ "oom-kill" ]]; then
+ return 9200 # OOM
+ fi
+ fi
+
+ echo
+ echo
+
+ if [[ $buildExitCode -ne 0 ]]; then
+ return 9100 # aot build failure
+ fi
+
+ return 0
+}
+
+
pushd $EXECUTION_DIR
# ========================= BEGIN Test Execution =============================
diff --git a/eng/testing/bump-chrome-version.proj b/eng/testing/bump-chrome-version.proj
index 334e37bfd32ba7..77fc525f8c8034 100644
--- a/eng/testing/bump-chrome-version.proj
+++ b/eng/testing/bump-chrome-version.proj
@@ -3,7 +3,7 @@
- $(RepositoryEngineeringDir)testing\ChromeVersions.props
+ $(RepositoryEngineeringDir)testing\BrowserVersions.props
$(RepositoryEngineeringDir)testing\bump-chrome-pr.env
diff --git a/eng/testing/helix-extension-example.targets b/eng/testing/helix-extension-example.targets
index e14095c075678b..77b3490d5001ae 100644
--- a/eng/testing/helix-extension-example.targets
+++ b/eng/testing/helix-extension-example.targets
@@ -1,5 +1,5 @@
-
+
$(HelixExtensionTargets);_AddHelixCrypoItems
<_CryptoProjectName>System.Security.Cryptography.Tests
diff --git a/eng/testing/performance/performance-setup.sh b/eng/testing/performance/performance-setup.sh
index ff04015375a388..489b3a22cccd5f 100755
--- a/eng/testing/performance/performance-setup.sh
+++ b/eng/testing/performance/performance-setup.sh
@@ -451,7 +451,7 @@ if [[ -n "$wasm_bundle_directory" ]]; then
# get required version
if [[ -z "$v8_version" ]]; then
- v8_version=`grep linux_V8Version $source_directory/eng/testing/ChromeVersions.props | sed -e 's,.*>\([^\<]*\)<.*,\1,g' | cut -d. -f 1-3`
+ v8_version=`grep linux_V8Version $source_directory/eng/testing/BrowserVersions.props | sed -e 's,.*>\([^\<]*\)<.*,\1,g' | cut -d. -f 1-3`
echo "V8 version: $v8_version"
fi
if [[ -z "$javascript_engine_path" ]]; then
diff --git a/eng/testing/tests.browser.targets b/eng/testing/tests.browser.targets
index 982b8589e76c14..ccfc96f5211cd1 100644
--- a/eng/testing/tests.browser.targets
+++ b/eng/testing/tests.browser.targets
@@ -26,7 +26,10 @@
true
+ '$(Scenario)' == 'WasmTestOnChrome'">true
+ true
- <_WasmBrowserPathForTests Condition="'$(BROWSER_PATH_FOR_TESTS)' != ''">$(BROWSER_PATH_FOR_TESTS)
- <_WasmBrowserPathForTests Condition="'$(_WasmBrowserPathForTests)' == '' and '$(InstallChromeForTests)' == 'true'">$(ChromeBinaryPath)
+ <_WasmChromePathForTests Condition="'$(CHROME_PATH_FOR_TESTS)' != ''">$(CHROME_PATH_FOR_TESTS)
+ <_WasmChromePathForTests Condition="'$(_WasmChromePathForTests)' == '' and '$(InstallChromeForTests)' == 'true'">$(ChromeBinaryPath)
+
+ <_WasmFirefoxPathForTests Condition="'$(FIREFOX_PATH_FOR_TESTS)' != ''">$(FIREFOX_PATH_FOR_TESTS)
+ <_WasmFirefoxPathForTests Condition="'$(_WasmFirefoxPathForTests)' == '' and '$(InstallFirefoxForTests)' == 'true'">$(FirefoxBinaryPath)
<_WasmJSEnginePathForTests Condition="'$(V8_PATH_FOR_TESTS)' != ''">$(V8_PATH_FOR_TESTS)
<_WasmJSEnginePathForTests Condition="'$(_WasmJSEnginePathForTests)' == '' and '$(InstallV8ForTests)' == 'true'">$(V8BinaryPath)
@@ -107,7 +113,8 @@
<_XHarnessArgs >$(_XHarnessArgs) -s dotnet.native.js.symbols
<_XHarnessArgs Condition="'$(_UseWasmSymbolicator)' == 'true'" >$(_XHarnessArgs) --symbol-patterns wasm-symbol-patterns.txt
<_XHarnessArgs Condition="'$(_UseWasmSymbolicator)' == 'true'" >$(_XHarnessArgs) --symbolicator WasmSymbolicator.dll,Microsoft.WebAssembly.Internal.SymbolicatorWrapperForXHarness
- <_XHarnessArgs Condition="'$(_WasmBrowserPathForTests)' != ''" >$(_XHarnessArgs) "--browser-path=$(_WasmBrowserPathForTests)"
+ <_XHarnessArgs Condition="'$(_WasmChromePathForTests)' != ''" >$(_XHarnessArgs) "--browser-path=$(_WasmChromePathForTests)"
+ <_XHarnessArgs Condition="'$(_WasmFirefoxPathForTests)' != ''" >$(_XHarnessArgs) "--browser-path=$(_WasmFirefoxPathForTests)"
<_XHarnessArgs Condition="'$(WasmXHarnessTestsTimeout)' != ''" >$(_XHarnessArgs) "--timeout=$(WasmXHarnessTestsTimeout)"
<_XHarnessArgs Condition="'$(WasmXHarnessVerbosity)' != ''" >$(_XHarnessArgs) --verbosity=$(WasmXHarnessVerbosity)
<_XHarnessArgs Condition="'$(WasmXHarnessArgsCli)' != ''" >$(_XHarnessArgs) $(WasmXHarnessArgsCli)
@@ -252,6 +259,7 @@
+
@@ -259,6 +267,7 @@
+
diff --git a/eng/testing/tests.targets b/eng/testing/tests.targets
index d2a13edf8555cc..4ffbd60c365dc0 100644
--- a/eng/testing/tests.targets
+++ b/eng/testing/tests.targets
@@ -9,11 +9,9 @@
AppleHelixRunnerTemplate.sh
AppleRunnerTemplate.sh
AndroidRunnerTemplate.sh
- WasiRunnerAOTTemplate.sh
- WasiRunnerTemplate.sh
+ WasiRunnerTemplate.sh
WasiRunnerTemplate.cmd
- WasmRunnerAOTTemplate.sh
- WasmRunnerTemplate.sh
+ WasmRunnerTemplate.sh
WasmRunnerTemplate.cmd
BionicRunnerTemplate.sh
BionicRunnerTemplate.cmd
diff --git a/eng/testing/wasm-provisioning.targets b/eng/testing/wasm-provisioning.targets
index 4852fd5ecc2ec7..47076a23770dd3 100644
--- a/eng/testing/wasm-provisioning.targets
+++ b/eng/testing/wasm-provisioning.targets
@@ -11,21 +11,30 @@
false
+ false
false
- $(ArtifactsBinDir)firefox\
- $([MSBuild]::NormalizePath($(FirefoxDir), '.install-firefox-$(FirefoxRevision).stamp'))
<_BrowserStampDir>$(ArtifactsBinDir)\
Build
-
+
- 108.0.1
- https://ftp.mozilla.org/pub/firefox/releases/$(FirefoxRevision)/linux-x86_64/en-US/firefox-$(FirefoxRevision).tar.bz2
+ https://ftp.mozilla.org/pub/firefox/releases/$(linux_FirefoxRevision)/linux-x86_64/en-US/firefox-$(linux_FirefoxRevision).tar.bz2
+ https://github.com/mozilla/geckodriver/releases/download/v$(linux_GeckoDriverRevision)/geckodriver-v$(linux_GeckoDriverRevision)-linux64.tar.gz
firefox
+ geckodriver
+ $(ArtifactsBinDir)firefox\
+ firefox
+ geckodriver
+ $(ArtifactsBinDir)geckodriver\
+ $([MSBuild]::NormalizePath($(FirefoxDir), '.install-firefox-$(linux_FirefoxRevision).stamp'))
+ $([MSBuild]::NormalizePath($(GeckoDriverDir), '.install-geckodriver-$(linux_GeckoDriverRevision).stamp'))
+
+ $([MSBuild]::NormalizePath($(FirefoxDir), $(FirefoxDirName), $(FirefoxBinaryName)))
+ $([MSBuild]::NormalizePath($(GeckoDriverDir), $(GeckoDriverDirName), $(GeckoDriverBinaryName)))
@@ -84,12 +93,6 @@
$([MSBuild]::NormalizePath($(V8Dir), $(V8BinaryName)))
-
- 108.0.1
- https://ftp.mozilla.org/pub/firefox/releases/$(FirefoxRevision)/linux-x86_64/en-US/firefox-$(FirefoxRevision).tar.bz2
- firefox
-
-
@@ -97,7 +100,7 @@
+ Text="No %24(ChromeVersion) set. This can be set in eng/testing/BrowserVersions.props" />
@@ -125,7 +128,7 @@
+ Text="No %24(ChromeVersion) set. This can be set in eng/testing/BrowserVersions.props" />
@@ -188,6 +191,9 @@ export __SCRIPT_DIR=%24( cd -- "%24( dirname -- "%24{BASH_SOURCE[0]}" )" &>
+
+
@@ -205,4 +211,36 @@ export __SCRIPT_DIR=%24( cd -- "%24( dirname -- "%24{BASH_SOURCE[0]}" )" &>
+
+
+
+ <_StampFile Include="$(_BrowserStampDir).install-geckodriver*.stamp" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_GeckoDriverBinaryPath>$([MSBuild]::NormalizePath($(GeckoDriverDir), $(GeckoDriverBinaryName)))
+
+
+
+
+
+
+
+
diff --git a/global.json b/global.json
index 83e43bb2a46732..4348e778e29b42 100644
--- a/global.json
+++ b/global.json
@@ -8,11 +8,11 @@
"dotnet": "9.0.100-preview.3.24204.13"
},
"msbuild-sdks": {
- "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.24212.4",
- "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.24212.4",
- "Microsoft.DotNet.SharedFramework.Sdk": "9.0.0-beta.24212.4",
+ "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.24217.1",
+ "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.24217.1",
+ "Microsoft.DotNet.SharedFramework.Sdk": "9.0.0-beta.24217.1",
"Microsoft.Build.NoTargets": "3.7.0",
"Microsoft.Build.Traversal": "3.4.0",
- "Microsoft.NET.Sdk.IL": "9.0.0-preview.4.24201.1"
+ "Microsoft.NET.Sdk.IL": "9.0.0-preview.4.24215.1"
}
}
diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
index 9ef1024c449da8..fdd395fe520a01 100644
--- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -39,6 +39,7 @@
$(TargetArchitecture)
arm
+ AnyCPU
true
false
@@ -59,28 +60,21 @@
- x64
- false
$(DefineConstants);TARGET_AMD64
- x86
$(DefineConstants);TARGET_X86
- arm
$(DefineConstants);TARGET_ARM
- AnyCPU
$(DefineConstants);TARGET_ARM64
- AnyCPU
$(DefineConstants);TARGET_LOONGARCH64
- AnyCPU
$(DefineConstants);TARGET_RISCV64
diff --git a/src/coreclr/debug/daccess/CMakeLists.txt b/src/coreclr/debug/daccess/CMakeLists.txt
index 5332e957c9eca1..9ed71521d4283d 100644
--- a/src/coreclr/debug/daccess/CMakeLists.txt
+++ b/src/coreclr/debug/daccess/CMakeLists.txt
@@ -1,5 +1,7 @@
add_definitions(-DFEATURE_NO_HOST)
+add_subdirectory(${CLR_SRC_NATIVE_DIR}/managed/cdacreader/cmake ${CLR_ARTIFACTS_OBJ_DIR}/cdacreader)
+
include_directories(BEFORE ${VM_DIR})
include_directories(BEFORE ${VM_DIR}/${ARCH_SOURCES_DIR})
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR})
@@ -12,6 +14,7 @@ if(CLR_CMAKE_HOST_UNIX)
endif(CLR_CMAKE_HOST_UNIX)
set(DACCESS_SOURCES
+ cdac.cpp
dacdbiimpl.cpp
dacdbiimpllocks.cpp
dacdbiimplstackwalk.cpp
@@ -40,6 +43,7 @@ convert_to_absolute_path(DACCESS_SOURCES ${DACCESS_SOURCES})
add_library_clr(daccess ${DACCESS_SOURCES})
set_target_properties(daccess PROPERTIES DAC_COMPONENT TRUE)
target_precompile_headers(daccess PRIVATE [["stdafx.h"]])
+target_link_libraries(daccess PRIVATE cdacreader_api)
add_dependencies(daccess eventing_headers)
diff --git a/src/coreclr/debug/daccess/cdac.cpp b/src/coreclr/debug/daccess/cdac.cpp
new file mode 100644
index 00000000000000..78625bf67f2d72
--- /dev/null
+++ b/src/coreclr/debug/daccess/cdac.cpp
@@ -0,0 +1,88 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "cdac.h"
+#include
+#include
+#include "dbgutil.h"
+#include
+
+#define CDAC_LIB_NAME MAKEDLLNAME_W(W("cdacreader"))
+
+namespace
+{
+ bool TryLoadCDACLibrary(HMODULE *phCDAC)
+ {
+ // Load cdacreader from next to DAC binary
+ PathString path;
+ if (FAILED(GetClrModuleDirectory(path)))
+ return false;
+
+ path.Append(CDAC_LIB_NAME);
+ *phCDAC = CLRLoadLibrary(path.GetUnicode());
+ if (*phCDAC == NULL)
+ return false;
+
+ return true;
+ }
+
+ int ReadFromTargetCallback(uint64_t addr, uint8_t* dest, uint32_t count, void* context)
+ {
+ CDAC* cdac = reinterpret_cast(context);
+ return cdac->ReadFromTarget(addr, dest, count);
+ }
+}
+
+CDAC CDAC::Create(uint64_t descriptorAddr, ICorDebugDataTarget* target)
+{
+ HMODULE cdacLib;
+ if (!TryLoadCDACLibrary(&cdacLib))
+ return CDAC::Invalid();
+
+ return CDAC{cdacLib, descriptorAddr, target};
+}
+
+CDAC::CDAC(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target)
+ : m_module(module)
+ , m_target{target}
+{
+ if (m_module == NULL)
+ {
+ m_cdac_handle = NULL;
+ return;
+ }
+
+ decltype(&cdac_reader_init) init = reinterpret_cast(::GetProcAddress(m_module, "cdac_reader_init"));
+ decltype(&cdac_reader_get_sos_interface) getSosInterface = reinterpret_cast(::GetProcAddress(m_module, "cdac_reader_get_sos_interface"));
+ _ASSERTE(init != nullptr && getSosInterface != nullptr);
+
+ init(descriptorAddr, &ReadFromTargetCallback, this, &m_cdac_handle);
+ getSosInterface(m_cdac_handle, &m_sos);
+}
+
+CDAC::~CDAC()
+{
+ if (m_cdac_handle != NULL)
+ {
+ decltype(&cdac_reader_free) free = reinterpret_cast(::GetProcAddress(m_module, "cdac_reader_free"));
+ _ASSERTE(free != nullptr);
+ free(m_cdac_handle);
+ }
+
+ if (m_module != NULL)
+ ::FreeLibrary(m_module);
+}
+
+IUnknown* CDAC::SosInterface()
+{
+ return m_sos;
+}
+
+int CDAC::ReadFromTarget(uint64_t addr, uint8_t* dest, uint32_t count)
+{
+ HRESULT hr = ReadFromDataTarget(m_target, addr, dest, count);
+ if (FAILED(hr))
+ return hr;
+
+ return S_OK;
+}
diff --git a/src/coreclr/debug/daccess/cdac.h b/src/coreclr/debug/daccess/cdac.h
new file mode 100644
index 00000000000000..54418dc549f1f0
--- /dev/null
+++ b/src/coreclr/debug/daccess/cdac.h
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#ifndef CDAC_H
+#define CDAC_H
+
+class CDAC final
+{
+public: // static
+ static CDAC Create(uint64_t descriptorAddr, ICorDebugDataTarget *pDataTarget);
+
+ static CDAC Invalid()
+ {
+ return CDAC{nullptr, 0, nullptr};
+ }
+
+public:
+ CDAC(const CDAC&) = delete;
+ CDAC& operator=(const CDAC&) = delete;
+
+ CDAC(CDAC&& other)
+ : m_module{ other.m_module }
+ , m_cdac_handle{ other.m_cdac_handle }
+ , m_target{ other.m_target }
+ , m_sos{ other.m_sos.Extract() }
+ {
+ other.m_module = NULL;
+ other.m_cdac_handle = 0;
+ other.m_target = NULL;
+ other.m_sos = NULL;
+ }
+
+ CDAC& operator=(CDAC&& other)
+ {
+ m_module = other.m_module;
+ m_cdac_handle = other.m_cdac_handle;
+ m_target = other.m_target;
+ m_sos = other.m_sos.Extract();
+
+ other.m_module = NULL;
+ other.m_cdac_handle = 0;
+ other.m_target = NULL;
+ other.m_sos = NULL;
+
+ return *this;
+ }
+
+ ~CDAC();
+
+ bool IsValid() const
+ {
+ return m_module != NULL && m_cdac_handle != 0;
+ }
+
+ // This does not AddRef the returned interface
+ IUnknown* SosInterface();
+ int ReadFromTarget(uint64_t addr, uint8_t* dest, uint32_t count);
+
+private:
+ CDAC(HMODULE module, uint64_t descriptorAddr, ICorDebugDataTarget* target);
+
+private:
+ HMODULE m_module;
+ intptr_t m_cdac_handle;
+ ICorDebugDataTarget* m_target;
+ NonVMComHolder m_sos;
+};
+
+#endif // CDAC_H
diff --git a/src/coreclr/debug/daccess/daccess.cpp b/src/coreclr/debug/daccess/daccess.cpp
index ca8c76bf5b81f7..66ddb02f888eec 100644
--- a/src/coreclr/debug/daccess/daccess.cpp
+++ b/src/coreclr/debug/daccess/daccess.cpp
@@ -23,6 +23,8 @@
#include "dwreport.h"
#include "primitives.h"
#include "dbgutil.h"
+#include "cdac.h"
+#include
#ifdef USE_DAC_TABLE_RVA
#include
@@ -3034,6 +3036,7 @@ class DacStreamManager
//----------------------------------------------------------------------------
ClrDataAccess::ClrDataAccess(ICorDebugDataTarget * pTarget, ICLRDataTarget * pLegacyTarget/*=0*/)
+ : m_cdac{CDAC::Invalid()}
{
SUPPORTS_DAC_HOST_ONLY; // ctor does no marshalling - don't check with DacCop
@@ -3123,7 +3126,6 @@ ClrDataAccess::ClrDataAccess(ICorDebugDataTarget * pTarget, ICLRDataTarget * pLe
// see ClrDataAccess::VerifyDlls for details.
m_fEnableDllVerificationAsserts = false;
#endif
-
}
ClrDataAccess::~ClrDataAccess(void)
@@ -5491,6 +5493,28 @@ ClrDataAccess::Initialize(void)
IfFailRet(GetDacGlobalValues());
IfFailRet(DacGetHostVtPtrs());
+ CLRConfigNoCache enable = CLRConfigNoCache::Get("ENABLE_CDAC");
+ if (enable.IsSet())
+ {
+ DWORD val;
+ if (enable.TryAsInteger(10, val) && val == 1)
+ {
+ // TODO: [cdac] Get contract descriptor from exported symbol
+ uint64_t contractDescriptorAddr = 0;
+ //if (TryGetSymbol(m_pTarget, m_globalBase, "DotNetRuntimeContractDescriptor", &contractDescriptorAddr))
+ {
+ m_cdac = CDAC::Create(contractDescriptorAddr, m_pTarget);
+ if (m_cdac.IsValid())
+ {
+ // Get SOS interfaces from the cDAC if available.
+ IUnknown* unk = m_cdac.SosInterface();
+ (void)unk->QueryInterface(__uuidof(ISOSDacInterface), (void**)&m_cdacSos);
+ (void)unk->QueryInterface(__uuidof(ISOSDacInterface9), (void**)&m_cdacSos9);
+ }
+ }
+ }
+ }
+
//
// DAC is now setup and ready to use
//
diff --git a/src/coreclr/debug/daccess/dacimpl.h b/src/coreclr/debug/daccess/dacimpl.h
index e698eed4c1803b..081ff88da81572 100644
--- a/src/coreclr/debug/daccess/dacimpl.h
+++ b/src/coreclr/debug/daccess/dacimpl.h
@@ -794,6 +794,7 @@ class DacStreamManager;
#endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
+#include "cdac.h"
//----------------------------------------------------------------------------
//
@@ -1208,7 +1209,7 @@ class ClrDataAccess
CLRDATA_ADDRESS *allocLimit);
// ISOSDacInterface13
- virtual HRESULT STDMETHODCALLTYPE TraverseLoaderHeap(CLRDATA_ADDRESS loaderHeapAddr, LoaderHeapKind kind, VISITHEAP pCallback);
+ virtual HRESULT STDMETHODCALLTYPE TraverseLoaderHeap(CLRDATA_ADDRESS loaderHeapAddr, LoaderHeapKind kind, VISITHEAP pCallback);
virtual HRESULT STDMETHODCALLTYPE GetDomainLoaderAllocator(CLRDATA_ADDRESS domainAddress, CLRDATA_ADDRESS *pLoaderAllocator);
virtual HRESULT STDMETHODCALLTYPE GetLoaderAllocatorHeapNames(int count, const char **ppNames, int *pNeeded);
virtual HRESULT STDMETHODCALLTYPE GetLoaderAllocatorHeaps(CLRDATA_ADDRESS loaderAllocator, int count, CLRDATA_ADDRESS *pLoaderHeaps, LoaderHeapKind *pKinds, int *pNeeded);
@@ -1221,13 +1222,15 @@ class ClrDataAccess
virtual HRESULT STDMETHODCALLTYPE GetStaticBaseAddress(CLRDATA_ADDRESS methodTable, CLRDATA_ADDRESS *nonGCStaticsAddress, CLRDATA_ADDRESS *GCStaticsAddress);
virtual HRESULT STDMETHODCALLTYPE GetThreadStaticBaseAddress(CLRDATA_ADDRESS methodTable, CLRDATA_ADDRESS thread, CLRDATA_ADDRESS *nonGCStaticsAddress, CLRDATA_ADDRESS *GCStaticsAddress);
virtual HRESULT STDMETHODCALLTYPE GetMethodTableInitializationFlags(CLRDATA_ADDRESS methodTable, MethodTableInitializationFlags *initializationStatus);
-
+
//
// ClrDataAccess.
//
HRESULT Initialize(void);
+ HRESULT GetThreadStoreDataImpl(struct DacpThreadStoreData *data);
+
BOOL IsExceptionFromManagedCode(EXCEPTION_RECORD * pExceptionRecord);
#ifndef TARGET_UNIX
HRESULT GetWatsonBuckets(DWORD dwThreadId, GenericModeBlock * pGM);
@@ -1414,6 +1417,10 @@ class ClrDataAccess
ULONG32 m_instanceAge;
bool m_debugMode;
+ CDAC m_cdac;
+ NonVMComHolder m_cdacSos;
+ NonVMComHolder m_cdacSos9;
+
#ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
protected:
@@ -1964,7 +1971,7 @@ class DacMemoryEnumerator : public DefaultCOMImplGetThreadStoreData(threadStoreData);
+ if (FAILED(hr))
+ {
+ hr = GetThreadStoreDataImpl(threadStoreData);
+ }
+#ifdef _DEBUG
+ else
+ {
+ // Assert that the data is the same as what we get from the DAC.
+ DacpThreadStoreData threadStoreDataLocal;
+ HRESULT hrLocal = GetThreadStoreDataImpl(&threadStoreDataLocal);
+ _ASSERTE(hr == hrLocal);
+ _ASSERTE(threadStoreData->threadCount == threadStoreDataLocal.threadCount);
+ _ASSERTE(threadStoreData->unstartedThreadCount == threadStoreDataLocal.unstartedThreadCount);
+ _ASSERTE(threadStoreData->backgroundThreadCount == threadStoreDataLocal.backgroundThreadCount);
+ _ASSERTE(threadStoreData->pendingThreadCount == threadStoreDataLocal.pendingThreadCount);
+ _ASSERTE(threadStoreData->deadThreadCount == threadStoreDataLocal.deadThreadCount);
+ _ASSERTE(threadStoreData->fHostConfig == threadStoreDataLocal.fHostConfig);
+ _ASSERTE(threadStoreData->firstThread == threadStoreDataLocal.firstThread);
+ _ASSERTE(threadStoreData->finalizerThread == threadStoreDataLocal.finalizerThread);
+ _ASSERTE(threadStoreData->gcThread == threadStoreDataLocal.gcThread);
+ }
+#endif
}
else
{
- // initialize the fields of our local structure
- threadStoreData->threadCount = threadStore->m_ThreadCount;
- threadStoreData->unstartedThreadCount = threadStore->m_UnstartedThreadCount;
- threadStoreData->backgroundThreadCount = threadStore->m_BackgroundThreadCount;
- threadStoreData->pendingThreadCount = threadStore->m_PendingThreadCount;
- threadStoreData->deadThreadCount = threadStore->m_DeadThreadCount;
- threadStoreData->fHostConfig = FALSE;
-
- // identify the "important" threads
- threadStoreData->firstThread = HOST_CDADDR(threadStore->m_ThreadList.GetHead());
- threadStoreData->finalizerThread = HOST_CDADDR(g_pFinalizerThread);
- threadStoreData->gcThread = HOST_CDADDR(g_pSuspensionThread);
+ hr = GetThreadStoreDataImpl(threadStoreData);
}
SOSDacLeave();
return hr;
}
+HRESULT ClrDataAccess::GetThreadStoreDataImpl(struct DacpThreadStoreData *threadStoreData)
+{
+ ThreadStore* threadStore = ThreadStore::s_pThreadStore;
+ if (!threadStore)
+ return E_UNEXPECTED;
+
+ // initialize the fields of our local structure
+ threadStoreData->threadCount = threadStore->m_ThreadCount;
+ threadStoreData->unstartedThreadCount = threadStore->m_UnstartedThreadCount;
+ threadStoreData->backgroundThreadCount = threadStore->m_BackgroundThreadCount;
+ threadStoreData->pendingThreadCount = threadStore->m_PendingThreadCount;
+ threadStoreData->deadThreadCount = threadStore->m_DeadThreadCount;
+ threadStoreData->fHostConfig = FALSE;
+
+ // identify the "important" threads
+ threadStoreData->firstThread = HOST_CDADDR(threadStore->m_ThreadList.GetHead());
+ threadStoreData->finalizerThread = HOST_CDADDR(g_pFinalizerThread);
+ threadStoreData->gcThread = HOST_CDADDR(g_pSuspensionThread);
+
+ return S_OK;
+}
+
HRESULT
ClrDataAccess::GetStressLogAddress(CLRDATA_ADDRESS *stressLog)
{
@@ -4951,7 +4986,15 @@ HRESULT ClrDataAccess::GetBreakingChangeVersion(int* pVersion)
if (pVersion == nullptr)
return E_INVALIDARG;
- *pVersion = SOS_BREAKING_CHANGE_VERSION;
+ if (m_cdacSos9 != nullptr && SUCCEEDED(m_cdacSos9->GetBreakingChangeVersion(pVersion)))
+ {
+ _ASSERTE(*pVersion == SOS_BREAKING_CHANGE_VERSION);
+ }
+ else
+ {
+ *pVersion = SOS_BREAKING_CHANGE_VERSION;
+ }
+
return S_OK;
}
@@ -5406,10 +5449,10 @@ HRESULT STDMETHODCALLTYPE ClrDataAccess::GetStaticBaseAddress(CLRDATA_ADDRESS me
{
if (!nonGCStaticsAddress && !GCStaticsAddress)
return E_POINTER;
-
+
if (!methodTable)
return E_INVALIDARG;
-
+
SOSDacEnter();
PTR_MethodTable mTable = PTR_MethodTable(TO_TADDR(methodTable));
@@ -5440,13 +5483,13 @@ HRESULT STDMETHODCALLTYPE ClrDataAccess::GetThreadStaticBaseAddress(CLRDATA_ADDR
{
if (!nonGCStaticsAddress && !GCStaticsAddress)
return E_POINTER;
-
+
if (!methodTable)
return E_INVALIDARG;
if (!threadPtr)
return E_INVALIDARG;
-
+
SOSDacEnter();
PTR_MethodTable mTable = PTR_MethodTable(TO_TADDR(methodTable));
diff --git a/src/coreclr/dlls/mscorrc/mscorrc.rc b/src/coreclr/dlls/mscorrc/mscorrc.rc
index b95946881f10ed..5b4faf05edb44f 100644
--- a/src/coreclr/dlls/mscorrc/mscorrc.rc
+++ b/src/coreclr/dlls/mscorrc/mscorrc.rc
@@ -113,7 +113,6 @@ BEGIN
COR_E_FILELOAD "Unable to load file '%1'."
COR_E_ASSEMBLYEXPECTED "The module '%1' was expected to contain an assembly manifest."
FUSION_E_REF_DEF_MISMATCH "The located assembly's manifest definition with name '%1' does not match the assembly reference."
- FUSION_E_PRIVATE_ASM_DISALLOWED "Assembly '%1' is required to be strongly named."
FUSION_E_INVALID_NAME "The given assembly name, '%1', was invalid."
FUSION_E_APP_DOMAIN_LOCKED "The requested assembly version conflicts with what is already bound in the app domain or specified in the manifest."
IDS_EE_HASH_VAL_FAILED "Hash validation failed for file or assembly '%1'."
diff --git a/src/coreclr/ilasm/writer.cpp b/src/coreclr/ilasm/writer.cpp
index 6405461a9d396f..20d70c57204f4f 100644
--- a/src/coreclr/ilasm/writer.cpp
+++ b/src/coreclr/ilasm/writer.cpp
@@ -34,6 +34,14 @@ HRESULT Assembler::InitMetaData()
if (FAILED(hr))
goto exit;
+ if(m_wzMetadataVersion)
+ {
+ VARIANT optionValue;
+ V_VT(&optionValue) = VT_BSTR;
+ V_BSTR(&optionValue) = m_wzMetadataVersion; // IMetaDataDispenserEx does not require proper BSTR
+ hr = m_pDisp->SetOption(MetaDataRuntimeVersion, &optionValue);
+ }
+
hr = m_pDisp->DefineScope(CLSID_CorMetaDataRuntime, 0, IID_IMetaDataEmit3,
(IUnknown **)&m_pEmitter);
if (FAILED(hr))
diff --git a/src/coreclr/inc/corerror.xml b/src/coreclr/inc/corerror.xml
index 1d4129305fa680..68c9a1aa5dfb3c 100644
--- a/src/coreclr/inc/corerror.xml
+++ b/src/coreclr/inc/corerror.xml
@@ -172,12 +172,6 @@
The located assembly's manifest definition does not match the assembly reference.
-
- FUSION_E_PRIVATE_ASM_DISALLOWED
- "A strongly-named assembly is required."
- A strongly-named assembly is required.
-
-
FUSION_E_INVALID_NAME
"The given assembly name was invalid."
diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h
index 35f7d2f0bdf862..ff82759f6aab64 100644
--- a/src/coreclr/inc/corinfo.h
+++ b/src/coreclr/inc/corinfo.h
@@ -2709,6 +2709,11 @@ class ICorStaticInfo
CORINFO_CLASS_HANDLE cls
) = 0;
+ // Returns whether a class handle represents a Nullable type, if that can be statically determined.
+ virtual TypeCompareState isNullableType(
+ CORINFO_CLASS_HANDLE cls
+ ) = 0;
+
// Returns TypeCompareState::Must if cls is known to be an enum.
// For enums with known exact type returns the underlying
// type in underlyingType when the provided pointer is
diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h
index 2348162d948545..98b47dced2beb0 100644
--- a/src/coreclr/inc/icorjitinfoimpl_generated.h
+++ b/src/coreclr/inc/icorjitinfoimpl_generated.h
@@ -344,6 +344,9 @@ bool isMoreSpecificType(
bool isExactType(
CORINFO_CLASS_HANDLE cls) override;
+TypeCompareState isNullableType(
+ CORINFO_CLASS_HANDLE cls) override;
+
TypeCompareState isEnum(
CORINFO_CLASS_HANDLE cls,
CORINFO_CLASS_HANDLE* underlyingType) override;
diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h
index 0e9f6e2940bcb3..743abdaff86aea 100644
--- a/src/coreclr/inc/jiteeversionguid.h
+++ b/src/coreclr/inc/jiteeversionguid.h
@@ -43,11 +43,11 @@ typedef const GUID *LPCGUID;
#define GUID_DEFINED
#endif // !GUID_DEFINED
-constexpr GUID JITEEVersionIdentifier = { /* 3c216494-65f8-49e2-b69a-7f272193bcc6 */
- 0x3c216494,
- 0x65f8,
- 0x49e2,
- {0xb6, 0x9a, 0x7f, 0x27, 0x21, 0x93, 0xbc, 0xc6}
+constexpr GUID JITEEVersionIdentifier = { /* 8f046bcb-ca5f-4692-9277-898b71cb7938 */
+ 0x8f046bcb,
+ 0xca5f,
+ 0x4692,
+ {0x92, 0x77, 0x89, 0x8b, 0x71, 0xcb, 0x79, 0x38}
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h
index 30c499518e007c..2e2573a911993d 100644
--- a/src/coreclr/jit/ICorJitInfo_names_generated.h
+++ b/src/coreclr/jit/ICorJitInfo_names_generated.h
@@ -85,6 +85,7 @@ DEF_CLR_API(compareTypesForCast)
DEF_CLR_API(compareTypesForEquality)
DEF_CLR_API(isMoreSpecificType)
DEF_CLR_API(isExactType)
+DEF_CLR_API(isNullableType)
DEF_CLR_API(isEnum)
DEF_CLR_API(getParentType)
DEF_CLR_API(getChildType)
diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp
index 77af720739ecee..85db2ec5efffa5 100644
--- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp
+++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp
@@ -804,6 +804,15 @@ bool WrapICorJitInfo::isExactType(
return temp;
}
+TypeCompareState WrapICorJitInfo::isNullableType(
+ CORINFO_CLASS_HANDLE cls)
+{
+ API_ENTER(isNullableType);
+ TypeCompareState temp = wrapHnd->isNullableType(cls);
+ API_LEAVE(isNullableType);
+ return temp;
+}
+
TypeCompareState WrapICorJitInfo::isEnum(
CORINFO_CLASS_HANDLE cls,
CORINFO_CLASS_HANDLE* underlyingType)
diff --git a/src/coreclr/jit/abi.cpp b/src/coreclr/jit/abi.cpp
index e80533fc783a06..fd899b899546b1 100644
--- a/src/coreclr/jit/abi.cpp
+++ b/src/coreclr/jit/abi.cpp
@@ -281,10 +281,7 @@ bool ABIPassingInformation::IsSplitAcrossRegistersAndStack() const
//
ABIPassingInformation ABIPassingInformation::FromSegment(Compiler* comp, const ABIPassingSegment& segment)
{
- ABIPassingInformation info;
- info.NumSegments = 1;
- info.Segments = new (comp, CMK_ABI) ABIPassingSegment(segment);
- return info;
+ return {1, new (comp, CMK_ABI) ABIPassingSegment(segment)};
}
#ifdef DEBUG
diff --git a/src/coreclr/jit/abi.h b/src/coreclr/jit/abi.h
index 1e51a14d9c09a5..97232bf911c4a3 100644
--- a/src/coreclr/jit/abi.h
+++ b/src/coreclr/jit/abi.h
@@ -48,9 +48,16 @@ struct ABIPassingInformation
// multiple register segments and a struct segment.
// - On Windows x64, all parameters always fit into one stack slot or
// register, and thus always have NumSegments == 1
+ // - On RISC-V, structs can be split out over 2 segments, each can be an integer/float register or a stack slot
unsigned NumSegments = 0;
ABIPassingSegment* Segments = nullptr;
+ ABIPassingInformation(unsigned numSegments = 0, ABIPassingSegment* segments = nullptr)
+ : NumSegments(numSegments)
+ , Segments(segments)
+ {
+ }
+
bool HasAnyRegisterSegment() const;
bool HasAnyStackSegment() const;
bool HasExactlyOneRegisterSegment() const;
@@ -77,7 +84,7 @@ class RegisterQueue
{
}
- unsigned Count()
+ unsigned Count() const
{
return m_numRegs - m_index;
}
@@ -179,6 +186,22 @@ class Arm32Classifier
WellKnownArg wellKnownParam);
};
+class RiscV64Classifier
+{
+ const ClassifierInfo& m_info;
+ RegisterQueue m_intRegs;
+ RegisterQueue m_floatRegs;
+ unsigned m_stackArgSize = 0;
+
+public:
+ RiscV64Classifier(const ClassifierInfo& info);
+
+ ABIPassingInformation Classify(Compiler* comp,
+ var_types type,
+ ClassLayout* structLayout,
+ WellKnownArg wellKnownParam);
+};
+
#if defined(TARGET_X86)
typedef X86Classifier PlatformClassifier;
#elif defined(WINDOWS_AMD64_ABI)
@@ -189,6 +212,8 @@ typedef SysVX64Classifier PlatformClassifier;
typedef Arm64Classifier PlatformClassifier;
#elif defined(TARGET_ARM)
typedef Arm32Classifier PlatformClassifier;
+#elif defined(TARGET_RISCV64)
+typedef RiscV64Classifier PlatformClassifier;
#endif
#ifdef SWIFT_SUPPORT
diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp
index d55e21b078e9e6..b3d52ce9773e48 100644
--- a/src/coreclr/jit/assertionprop.cpp
+++ b/src/coreclr/jit/assertionprop.cpp
@@ -769,9 +769,9 @@ void Compiler::optPrintAssertion(AssertionDsc* curAssertion, AssertionIndex asse
}
else if (curAssertion->op1.kind == O1K_ARR_BND)
{
- printf("[idx:");
+ printf("[idx: " FMT_VN, curAssertion->op1.bnd.vnIdx);
vnStore->vnDump(this, curAssertion->op1.bnd.vnIdx);
- printf(";len:");
+ printf("; len: " FMT_VN, curAssertion->op1.bnd.vnLen);
vnStore->vnDump(this, curAssertion->op1.bnd.vnLen);
printf("]");
}
diff --git a/src/coreclr/jit/block.h b/src/coreclr/jit/block.h
index 500b5274b6f41c..168f29cca084dd 100644
--- a/src/coreclr/jit/block.h
+++ b/src/coreclr/jit/block.h
@@ -587,10 +587,6 @@ struct FlowEdge
// The destination of the control flow
BasicBlock* m_destBlock;
- // Edge weights
- weight_t m_edgeWeightMin;
- weight_t m_edgeWeightMax;
-
// Likelihood that m_sourceBlock transfers control along this edge.
// Values in range [0..1]
weight_t m_likelihood;
@@ -606,8 +602,6 @@ struct FlowEdge
: m_nextPredEdge(rest)
, m_sourceBlock(sourceBlock)
, m_destBlock(destBlock)
- , m_edgeWeightMin(0)
- , m_edgeWeightMax(0)
, m_likelihood(0)
, m_dupCount(0)
#ifdef DEBUG
@@ -655,24 +649,6 @@ struct FlowEdge
m_destBlock = newBlock;
}
- weight_t edgeWeightMin() const
- {
- return m_edgeWeightMin;
- }
-
- weight_t edgeWeightMax() const
- {
- return m_edgeWeightMax;
- }
-
- // These two methods are used to set new values for edge weights.
- // They return false if the newWeight is not between the current [min..max]
- // when slop is non-zero we allow for the case where our weights might be off by 'slop'
- //
- bool setEdgeWeightMinChecked(weight_t newWeight, BasicBlock* bDst, weight_t slop, bool* wbUsedSlop);
- bool setEdgeWeightMaxChecked(weight_t newWeight, BasicBlock* bDst, weight_t slop, bool* wbUsedSlop);
- void setEdgeWeights(weight_t newMinWeight, weight_t newMaxWeight, BasicBlock* bDst);
-
weight_t getLikelihood() const
{
assert(m_likelihoodSet);
diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp
index d4e8d58db741b7..8695545cc934a3 100644
--- a/src/coreclr/jit/codegenarm64.cpp
+++ b/src/coreclr/jit/codegenarm64.cpp
@@ -2655,6 +2655,48 @@ void CodeGen::genCodeForBinary(GenTreeOp* tree)
genProduceReg(tree);
return;
}
+ else if (op2->OperIs(GT_ROR) && op2->isContained())
+ {
+ assert(varTypeIsIntegral(tree));
+
+ GenTree* a = op1;
+ GenTree* b = op2->gtGetOp1();
+ GenTree* c = op2->gtGetOp2();
+
+ // The rotate amount needs to be contained as well
+ assert(c->isContained() && c->IsCnsIntOrI());
+
+ instruction ins = genGetInsForOper(tree->OperGet(), targetType);
+ insOpts opt = INS_OPTS_NONE;
+
+ if ((tree->gtFlags & GTF_SET_FLAGS) != 0)
+ {
+ // A subset of operations can still set flags
+
+ switch (oper)
+ {
+ case GT_AND:
+ {
+ ins = INS_ands;
+ break;
+ }
+
+ default:
+ {
+ noway_assert(!"Unexpected BinaryOp with GTF_SET_FLAGS set");
+ }
+ }
+ }
+
+ assert(op2->OperIs(GT_ROR));
+ opt = INS_OPTS_ROR;
+
+ emit->emitIns_R_R_R_I(ins, emitActualTypeSize(tree), targetReg, a->GetRegNum(), b->GetRegNum(),
+ c->AsIntConCommon()->IconValue(), opt);
+
+ genProduceReg(tree);
+ return;
+ }
else if (op2->OperIs(GT_CAST) && op2->isContained())
{
assert(varTypeIsIntegral(tree));
diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp
index 9660b0c98be9d7..b982ae640e5556 100644
--- a/src/coreclr/jit/codegencommon.cpp
+++ b/src/coreclr/jit/codegencommon.cpp
@@ -1831,8 +1831,7 @@ void CodeGen::genGenerateMachineCode()
if (compiler->fgHaveProfileWeights())
{
- printf("; with %s: edge weights are %s, and fgCalledCount is " FMT_WT "\n",
- compiler->compGetPgoSourceName(), compiler->fgHaveValidEdgeWeights ? "valid" : "invalid",
+ printf("; with %s: fgCalledCount is " FMT_WT "\n", compiler->compGetPgoSourceName(),
compiler->fgCalledCount);
}
diff --git a/src/coreclr/jit/codegenlinear.cpp b/src/coreclr/jit/codegenlinear.cpp
index 0b373a94fd3f80..145c074b8fc681 100644
--- a/src/coreclr/jit/codegenlinear.cpp
+++ b/src/coreclr/jit/codegenlinear.cpp
@@ -1657,7 +1657,7 @@ void CodeGen::genConsumeRegs(GenTree* tree)
}
#endif // FEATURE_HW_INTRINSICS
#endif // TARGET_XARCH
- else if (tree->OperIs(GT_BITCAST, GT_NEG, GT_CAST, GT_LSH, GT_RSH, GT_RSZ, GT_BSWAP, GT_BSWAP16))
+ else if (tree->OperIs(GT_BITCAST, GT_NEG, GT_CAST, GT_LSH, GT_RSH, GT_RSZ, GT_ROR, GT_BSWAP, GT_BSWAP16))
{
genConsumeRegs(tree->gtGetOp1());
}
diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp
index d534caf2d3adb2..a32867660a01c3 100644
--- a/src/coreclr/jit/compiler.cpp
+++ b/src/coreclr/jit/compiler.cpp
@@ -4910,9 +4910,9 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
//
DoPhase(this, PHASE_GS_COOKIE, &Compiler::gsPhase);
- // Compute the block and edge weights
+ // Compute the block weights
//
- DoPhase(this, PHASE_COMPUTE_EDGE_WEIGHTS, &Compiler::fgComputeBlockAndEdgeWeights);
+ DoPhase(this, PHASE_COMPUTE_BLOCK_WEIGHTS, &Compiler::fgComputeBlockWeights);
if (UsesFunclets())
{
@@ -5148,10 +5148,6 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
// update the flowgraph if we modified it during the optimization phase
//
DoPhase(this, PHASE_OPT_UPDATE_FLOW_GRAPH, &Compiler::fgUpdateFlowGraphPhase);
-
- // Recompute the edge weight if we have modified the flow graph
- //
- DoPhase(this, PHASE_COMPUTE_EDGE_WEIGHTS2, &Compiler::fgComputeEdgeWeights);
}
// Iterate if requested, resetting annotations first.
diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h
index 8f15dbe77446ec..819c20629de134 100644
--- a/src/coreclr/jit/compiler.h
+++ b/src/coreclr/jit/compiler.h
@@ -1593,12 +1593,11 @@ enum API_ICorJitInfo_Names
enum class ProfileChecks : unsigned int
{
CHECK_NONE = 0,
- CHECK_CLASSIC = 1 << 0, // check "classic" jit weights
- CHECK_HASLIKELIHOOD = 1 << 1, // check all FlowEdges for hasLikelihood
- CHECK_LIKELIHOODSUM = 1 << 2, // check block successor likelihoods sum to 1
- CHECK_LIKELY = 1 << 3, // fully check likelihood based weights
- RAISE_ASSERT = 1 << 4, // assert on check failure
- CHECK_ALL_BLOCKS = 1 << 5, // check blocks even if bbHasProfileWeight is false
+ CHECK_HASLIKELIHOOD = 1 << 0, // check all FlowEdges for hasLikelihood
+ CHECK_LIKELIHOODSUM = 1 << 1, // check block succesor likelihoods sum to 1
+ CHECK_LIKELY = 1 << 2, // fully check likelihood based weights
+ RAISE_ASSERT = 1 << 3, // assert on check failure
+ CHECK_ALL_BLOCKS = 1 << 4, // check blocks even if bbHasProfileWeight is false
};
inline constexpr ProfileChecks operator ~(ProfileChecks a)
@@ -5207,14 +5206,10 @@ class Compiler
// - Rationalization links all nodes into linear form which is kept until
// the end of compilation. The first and last nodes are stored in the block.
NodeThreading fgNodeThreading;
- bool fgCanRelocateEHRegions; // true if we are allowed to relocate the EH regions
- bool fgEdgeWeightsComputed; // true after we have called fgComputeEdgeWeights
- bool fgHaveValidEdgeWeights; // true if we were successful in computing all of the edge weights
- bool fgSlopUsedInEdgeWeights; // true if their was some slop used when computing the edge weights
- bool fgRangeUsedInEdgeWeights; // true if some of the edgeWeight are expressed in Min..Max form
- weight_t fgCalledCount; // count of the number of times this method was called
- // This is derived from the profile data
- // or is BB_UNITY_WEIGHT when we don't have profile data
+ bool fgCanRelocateEHRegions; // true if we are allowed to relocate the EH regions
+ weight_t fgCalledCount; // count of the number of times this method was called
+ // This is derived from the profile data
+ // or is BB_UNITY_WEIGHT when we don't have profile data
bool fgFuncletsCreated; // true if the funclet creation phase has been run
@@ -5693,6 +5688,9 @@ class Compiler
// Adds the exception sets for the current tree node which is performing a division or modulus operation
void fgValueNumberAddExceptionSetForDivision(GenTree* tree);
+ // Compute exceptions for a division operation
+ ValueNumPair fgValueNumberDivisionExceptions(genTreeOps oper, GenTree* dividend, GenTree* divisor);
+
// Adds the exception set for the current tree node which is performing a overflow checking operation
void fgValueNumberAddExceptionSetForOverflow(GenTree* tree);
@@ -6047,10 +6045,9 @@ class Compiler
#ifdef DEBUG
void fgPrintEdgeWeights();
#endif
- PhaseStatus fgComputeBlockAndEdgeWeights();
+ PhaseStatus fgComputeBlockWeights();
bool fgComputeMissingBlockWeights(weight_t* returnWeight);
bool fgComputeCalledCount(weight_t returnWeight);
- PhaseStatus fgComputeEdgeWeights();
bool fgReorderBlocks(bool useProfile);
@@ -6868,7 +6865,6 @@ class Compiler
BasicBlock* optTryAdvanceLoopCompactionInsertionPoint(FlowGraphNaturalLoop* loop, BasicBlock* insertionPoint, BasicBlock* top, BasicBlock* bottom);
bool optCreatePreheader(FlowGraphNaturalLoop* loop);
void optSetWeightForPreheaderOrExit(FlowGraphNaturalLoop* loop, BasicBlock* block);
- weight_t optEstimateEdgeLikelihood(BasicBlock* from, BasicBlock* to, bool* fromProfile);
bool optCanonicalizeExits(FlowGraphNaturalLoop* loop);
bool optCanonicalizeExit(FlowGraphNaturalLoop* loop, BasicBlock* exit);
diff --git a/src/coreclr/jit/compphases.h b/src/coreclr/jit/compphases.h
index 950313286d26fe..6f2783f889721c 100644
--- a/src/coreclr/jit/compphases.h
+++ b/src/coreclr/jit/compphases.h
@@ -55,7 +55,7 @@ CompPhaseNameMacro(PHASE_MORPH_GLOBAL, "Morph - Global",
CompPhaseNameMacro(PHASE_POST_MORPH, "Post-Morph", false, -1, false)
CompPhaseNameMacro(PHASE_MORPH_END, "Morph - Finish", false, -1, true)
CompPhaseNameMacro(PHASE_GS_COOKIE, "GS Cookie", false, -1, false)
-CompPhaseNameMacro(PHASE_COMPUTE_EDGE_WEIGHTS, "Compute edge weights (1, false)",false, -1, false)
+CompPhaseNameMacro(PHASE_COMPUTE_BLOCK_WEIGHTS, "Compute block weights", false, -1, false)
CompPhaseNameMacro(PHASE_CREATE_FUNCLETS, "Create EH funclets", false, -1, false)
CompPhaseNameMacro(PHASE_HEAD_TAIL_MERGE, "Head and tail merge", false, -1, false)
CompPhaseNameMacro(PHASE_MERGE_THROWS, "Merge throw blocks", false, -1, false)
@@ -95,7 +95,6 @@ CompPhaseNameMacro(PHASE_ASSERTION_PROP_MAIN, "Assertion prop",
CompPhaseNameMacro(PHASE_IF_CONVERSION, "If conversion", false, -1, false)
CompPhaseNameMacro(PHASE_VN_BASED_DEAD_STORE_REMOVAL,"VN-based dead store removal", false, -1, false)
CompPhaseNameMacro(PHASE_OPT_UPDATE_FLOW_GRAPH, "Update flow graph opt pass", false, -1, false)
-CompPhaseNameMacro(PHASE_COMPUTE_EDGE_WEIGHTS2, "Compute edge weights (2, false)",false, -1, false)
CompPhaseNameMacro(PHASE_STRESS_SPLIT_TREE, "Stress gtSplitTree", false, -1, false)
CompPhaseNameMacro(PHASE_EXPAND_RTLOOKUPS, "Expand runtime lookups", false, -1, true)
CompPhaseNameMacro(PHASE_EXPAND_STATIC_INIT, "Expand static init", false, -1, true)
diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp
index 8cbecbee7ca2c1..1638dfec507324 100644
--- a/src/coreclr/jit/fgbasic.cpp
+++ b/src/coreclr/jit/fgbasic.cpp
@@ -23,12 +23,8 @@ void Compiler::fgInit()
/* We haven't yet computed the bbPreds lists */
fgPredsComputed = false;
- /* We haven't yet computed the edge weight */
- fgEdgeWeightsComputed = false;
- fgHaveValidEdgeWeights = false;
- fgSlopUsedInEdgeWeights = false;
- fgRangeUsedInEdgeWeights = true;
- fgCalledCount = BB_ZERO_WEIGHT;
+ /* We haven't yet computed block weights */
+ fgCalledCount = BB_ZERO_WEIGHT;
/* Initialize the basic block list */
@@ -5446,6 +5442,7 @@ BasicBlock* Compiler::fgConnectFallThrough(BasicBlock* bSrc, BasicBlock* bDst)
// Add a new block after bSrc which jumps to 'bDst'
jmpBlk = fgNewBBafter(BBJ_ALWAYS, bSrc, true);
FlowEdge* const oldEdge = bSrc->GetFalseEdge();
+
// Access the likelihood of oldEdge before
// it gets reset by SetTargetEdge below.
//
@@ -5457,29 +5454,9 @@ BasicBlock* Compiler::fgConnectFallThrough(BasicBlock* bSrc, BasicBlock* bDst)
// When adding a new jmpBlk we will set the bbWeight and bbFlags
//
- if (fgHaveValidEdgeWeights && fgHaveProfileWeights())
+ if (fgHaveProfileWeights())
{
- jmpBlk->bbWeight = (newEdge->edgeWeightMin() + newEdge->edgeWeightMax()) / 2;
- if (bSrc->bbWeight == BB_ZERO_WEIGHT)
- {
- jmpBlk->bbWeight = BB_ZERO_WEIGHT;
- }
-
- if (jmpBlk->bbWeight == BB_ZERO_WEIGHT)
- {
- jmpBlk->SetFlags(BBF_RUN_RARELY);
- }
-
- weight_t weightDiff = (newEdge->edgeWeightMax() - newEdge->edgeWeightMin());
- weight_t slop = BasicBlock::GetSlopFraction(bSrc, bDst);
- //
- // If the [min/max] values for our edge weight is within the slop factor
- // then we will set the BBF_PROF_WEIGHT flag for the block
- //
- if (weightDiff <= slop)
- {
- jmpBlk->SetFlags(BBF_PROF_WEIGHT);
- }
+ jmpBlk->setBBProfileWeight(newEdge->getLikelyWeight());
}
else
{
diff --git a/src/coreclr/jit/fgdiagnostic.cpp b/src/coreclr/jit/fgdiagnostic.cpp
index 6311d189186bdd..c70573b5879a45 100644
--- a/src/coreclr/jit/fgdiagnostic.cpp
+++ b/src/coreclr/jit/fgdiagnostic.cpp
@@ -28,26 +28,17 @@ void Compiler::fgPrintEdgeWeights()
printf(FMT_BB " ", bSrc->bbNum);
- if (edge->edgeWeightMin() < BB_MAX_WEIGHT)
+ const weight_t weight = edge->getLikelyWeight();
+
+ if (weight < BB_MAX_WEIGHT)
{
- printf("(%f", edge->edgeWeightMin());
+ printf("(%f)", weight);
}
else
{
- printf("(MAX");
- }
- if (edge->edgeWeightMin() != edge->edgeWeightMax())
- {
- if (edge->edgeWeightMax() < BB_MAX_WEIGHT)
- {
- printf("..%f", edge->edgeWeightMax());
- }
- else
- {
- printf("..MAX");
- }
+ printf("(MAX)");
}
- printf(")");
+
if (edge->getNextPredEdge() != nullptr)
{
printf(", ");
@@ -735,7 +726,6 @@ bool Compiler::fgDumpFlowGraph(Phases phase, PhasePosition pos)
JITDUMP("Writing out flow graph %s phase %s\n", (pos == PhasePosition::PrePhase) ? "before" : "after",
PhaseNames[phase]);
- bool validWeights = fgHaveValidEdgeWeights;
double weightDivisor = (double)BasicBlock::getCalledCount(this);
const char* escapedString;
const char* regionString = "NONE";
@@ -791,14 +781,6 @@ bool Compiler::fgDumpFlowGraph(Phases phase, PhasePosition pos)
{
fprintf(fgxFile, "\n hasLoops=\"true\"");
}
- if (validWeights)
- {
- fprintf(fgxFile, "\n validEdgeWeights=\"true\"");
- if (!fgSlopUsedInEdgeWeights && !fgRangeUsedInEdgeWeights)
- {
- fprintf(fgxFile, "\n exactEdgeWeights=\"true\"");
- }
- }
if (fgFirstColdBlock != nullptr)
{
fprintf(fgxFile, "\n firstColdBlock=\"%d\"", fgFirstColdBlock->bbNum);
@@ -1081,11 +1063,8 @@ bool Compiler::fgDumpFlowGraph(Phases phase, PhasePosition pos)
fprintf(fgxFile, " [");
}
- if (validWeights)
- {
- weight_t edgeWeight = (edge->edgeWeightMin() + edge->edgeWeightMax()) / 2;
- fprintf(fgxFile, "%slabel=\"%7.2f\"", sep, (double)edgeWeight / weightDivisor);
- }
+ const weight_t edgeWeight = edge->getLikelyWeight();
+ fprintf(fgxFile, "%slabel=\"%7.2f\"", sep, (double)edgeWeight / weightDivisor);
fprintf(fgxFile, "];\n");
}
@@ -1106,32 +1085,22 @@ bool Compiler::fgDumpFlowGraph(Phases phase, PhasePosition pos)
fprintf(fgxFile, "\n switchDefault=\"true\"");
}
}
- if (validWeights)
- {
- weight_t edgeWeight = (edge->edgeWeightMin() + edge->edgeWeightMax()) / 2;
- fprintf(fgxFile, "\n weight=");
- fprintfDouble(fgxFile, ((double)edgeWeight) / weightDivisor);
- if (edge->edgeWeightMin() != edge->edgeWeightMax())
+ const weight_t edgeWeight = edge->getLikelyWeight();
+ fprintf(fgxFile, "\n weight=");
+ fprintfDouble(fgxFile, ((double)edgeWeight) / weightDivisor);
+
+ if (edgeWeight > 0)
+ {
+ if (edgeWeight < bSource->bbWeight)
{
- fprintf(fgxFile, "\n minWeight=");
- fprintfDouble(fgxFile, ((double)edge->edgeWeightMin()) / weightDivisor);
- fprintf(fgxFile, "\n maxWeight=");
- fprintfDouble(fgxFile, ((double)edge->edgeWeightMax()) / weightDivisor);
+ fprintf(fgxFile, "\n out=");
+ fprintfDouble(fgxFile, ((double)edgeWeight) / sourceWeightDivisor);
}
-
- if (edgeWeight > 0)
+ if (edgeWeight < bTarget->bbWeight)
{
- if (edgeWeight < bSource->bbWeight)
- {
- fprintf(fgxFile, "\n out=");
- fprintfDouble(fgxFile, ((double)edgeWeight) / sourceWeightDivisor);
- }
- if (edgeWeight < bTarget->bbWeight)
- {
- fprintf(fgxFile, "\n in=");
- fprintfDouble(fgxFile, ((double)edgeWeight) / targetWeightDivisor);
- }
+ fprintf(fgxFile, "\n in=");
+ fprintfDouble(fgxFile, ((double)edgeWeight) / targetWeightDivisor);
}
}
}
diff --git a/src/coreclr/jit/fgflow.cpp b/src/coreclr/jit/fgflow.cpp
index f4f650f6b5d341..c1060e1373d606 100644
--- a/src/coreclr/jit/fgflow.cpp
+++ b/src/coreclr/jit/fgflow.cpp
@@ -191,42 +191,6 @@ FlowEdge* Compiler::fgAddRefPred(BasicBlock* block, BasicBlock* blockPred, FlowE
//
flow->setLikelihood(oldEdge->getLikelihood());
}
-
- if (fgHaveValidEdgeWeights)
- {
- // We are creating an edge from blockPred to block
- // and we have already computed the edge weights, so
- // we will try to setup this new edge with valid edge weights.
- //
- if (oldEdge != nullptr)
- {
- // If our caller has given us the old edge weights
- // then we will use them.
- //
- flow->setEdgeWeights(oldEdge->edgeWeightMin(), oldEdge->edgeWeightMax(), block);
- }
- else
- {
- // Set the max edge weight to be the minimum of block's or blockPred's weight
- //
- weight_t newWeightMax = min(block->bbWeight, blockPred->bbWeight);
-
- // If we are inserting a conditional block the minimum weight is zero,
- // otherwise it is the same as the edge's max weight.
- if (blockPred->NumSucc() > 1)
- {
- flow->setEdgeWeights(BB_ZERO_WEIGHT, newWeightMax, block);
- }
- else
- {
- flow->setEdgeWeights(flow->edgeWeightMax(), newWeightMax, block);
- }
- }
- }
- else
- {
- flow->setEdgeWeights(BB_ZERO_WEIGHT, BB_MAX_WEIGHT, block);
- }
}
// Pred list should (still) be ordered.
diff --git a/src/coreclr/jit/fgopt.cpp b/src/coreclr/jit/fgopt.cpp
index 33ee13bf9b6895..c1b919d37830a2 100644
--- a/src/coreclr/jit/fgopt.cpp
+++ b/src/coreclr/jit/fgopt.cpp
@@ -1449,33 +1449,14 @@ bool Compiler::fgOptimizeBranchToEmptyUnconditional(BasicBlock* block, BasicBloc
//
// When we optimize a branch to branch we need to update the profile weight
- // of bDest by subtracting out the block/edge weight of the path that is being optimized.
+ // of bDest by subtracting out the weight of the path that is being optimized.
//
- if (fgHaveValidEdgeWeights && bDest->hasProfileWeight())
+ if (bDest->hasProfileWeight())
{
- FlowEdge* edge1 = fgGetPredForBlock(bDest, block);
- noway_assert(edge1 != nullptr);
+ FlowEdge* const edge = fgGetPredForBlock(bDest, block);
+ noway_assert(edge != nullptr);
- weight_t edgeWeight;
-
- if (edge1->edgeWeightMin() != edge1->edgeWeightMax())
- {
- //
- // We only have an estimate for the edge weight
- //
- edgeWeight = (edge1->edgeWeightMin() + edge1->edgeWeightMax()) / 2;
- //
- // Clear the profile weight flag
- //
- bDest->RemoveFlags(BBF_PROF_WEIGHT);
- }
- else
- {
- //
- // We only have the exact edge weight
- //
- edgeWeight = edge1->edgeWeightMin();
- }
+ const weight_t edgeWeight = edge->getLikelyWeight();
//
// Update the bDest->bbWeight
@@ -1489,36 +1470,6 @@ bool Compiler::fgOptimizeBranchToEmptyUnconditional(BasicBlock* block, BasicBloc
bDest->bbWeight = BB_ZERO_WEIGHT;
bDest->SetFlags(BBF_RUN_RARELY); // Set the RarelyRun flag
}
-
- FlowEdge* edge2 = bDest->GetTargetEdge();
-
- if (edge2 != nullptr)
- {
- //
- // Update the edge2 min/max weights
- //
- weight_t newEdge2Min;
- weight_t newEdge2Max;
-
- if (edge2->edgeWeightMin() > edge1->edgeWeightMin())
- {
- newEdge2Min = edge2->edgeWeightMin() - edge1->edgeWeightMin();
- }
- else
- {
- newEdge2Min = BB_ZERO_WEIGHT;
- }
-
- if (edge2->edgeWeightMax() > edge1->edgeWeightMin())
- {
- newEdge2Max = edge2->edgeWeightMax() - edge1->edgeWeightMin();
- }
- else
- {
- newEdge2Max = BB_ZERO_WEIGHT;
- }
- edge2->setEdgeWeights(newEdge2Min, newEdge2Max, bDest);
- }
}
// Optimize the JUMP to empty unconditional JUMP to go to the new target
@@ -1709,7 +1660,7 @@ bool Compiler::fgOptimizeEmptyBlock(BasicBlock* block)
break;
}
- // When using profile weights, fgComputeEdgeWeights expects the first non-internal block to have profile
+ // When using profile weights, fgComputeCalledCount expects the first non-internal block to have profile
// weight.
// Make sure we don't break that invariant.
if (fgIsUsingProfileWeights() && block->hasProfileWeight() && !block->HasFlag(BBF_INTERNAL))
@@ -1805,29 +1756,24 @@ bool Compiler::fgOptimizeSwitchBranches(BasicBlock* block)
{
//
// When we optimize a branch to branch we need to update the profile weight
- // of bDest by subtracting out the block/edge weight of the path that is being optimized.
+ // of bDest by subtracting out the block weight of the path that is being optimized.
//
+ FlowEdge* const oldEdge = *jmpTab;
+
if (fgIsUsingProfileWeights() && bDest->hasProfileWeight())
{
- if (fgHaveValidEdgeWeights)
+ weight_t const branchThroughWeight = oldEdge->getLikelyWeight();
+ if (bDest->bbWeight > branchThroughWeight)
{
- FlowEdge* edge = *jmpTab;
- weight_t branchThroughWeight = edge->edgeWeightMin();
-
- if (bDest->bbWeight > branchThroughWeight)
- {
- bDest->bbWeight -= branchThroughWeight;
- }
- else
- {
- bDest->bbWeight = BB_ZERO_WEIGHT;
- bDest->SetFlags(BBF_RUN_RARELY);
- }
+ bDest->bbWeight -= branchThroughWeight;
+ }
+ else
+ {
+ bDest->bbSetRunRarely();
}
}
// Update the switch jump table
- FlowEdge* const oldEdge = *jmpTab;
fgRemoveRefPred(oldEdge);
FlowEdge* const newEdge = fgAddRefPred(bNewDest, block, oldEdge);
*jmpTab = newEdge;
@@ -3041,47 +2987,9 @@ bool Compiler::fgOptimizeSwitchJumps()
newBlock->setBBProfileWeight(blockToNewBlockWeight);
- blockToTargetEdge->setEdgeWeights(blockToTargetWeight, blockToTargetWeight, dominantTarget);
blockToTargetEdge->setLikelihood(fraction);
- blockToNewBlockEdge->setEdgeWeights(blockToNewBlockWeight, blockToNewBlockWeight, block);
blockToNewBlockEdge->setLikelihood(max(0.0, 1.0 - fraction));
- // There may be other switch cases that lead to this same block, but there's just
- // one edge in the flowgraph. So we need to subtract off the profile data that now flows
- // along the peeled edge.
- //
- for (FlowEdge* pred = dominantTarget->bbPreds; pred != nullptr; pred = pred->getNextPredEdge())
- {
- if (pred->getSourceBlock() == newBlock)
- {
- if (pred->getDupCount() == 1)
- {
- // The only switch case leading to the dominant target was the one we peeled.
- // So the edge from the switch now has zero weight.
- //
- pred->setEdgeWeights(BB_ZERO_WEIGHT, BB_ZERO_WEIGHT, dominantTarget);
- }
- else
- {
- // Other switch cases also lead to the dominant target.
- // Subtract off the weight we transferred to the peel.
- //
- weight_t newMinWeight = pred->edgeWeightMin() - blockToTargetWeight;
- weight_t newMaxWeight = pred->edgeWeightMax() - blockToTargetWeight;
-
- if (newMinWeight < BB_ZERO_WEIGHT)
- {
- newMinWeight = BB_ZERO_WEIGHT;
- }
- if (newMaxWeight < BB_ZERO_WEIGHT)
- {
- newMaxWeight = BB_ZERO_WEIGHT;
- }
- pred->setEdgeWeights(newMinWeight, newMaxWeight, dominantTarget);
- }
- }
- }
-
// For now we leave the switch as is, since there's no way
// to indicate that one of the cases is now unreachable.
//
@@ -3633,43 +3541,19 @@ bool Compiler::fgReorderBlocks(bool useProfile)
//
bool moveDestUp = true;
- if (fgHaveValidEdgeWeights)
- {
- //
- // The edge bPrev -> bDest must have a higher minimum weight
- // than every other edge into bDest
- //
- FlowEdge* edgeFromPrev = bPrev->GetTargetEdge();
- noway_assert(edgeFromPrev != nullptr);
+ //
+ // The edge bPrev -> bDest must have a higher weight
+ // than every other edge into bDest
+ //
+ weight_t const weightToBeat = bPrev->GetTargetEdge()->getLikelyWeight();
- // Examine all of the other edges into bDest
- for (FlowEdge* const edge : bDest->PredEdges())
- {
- if (edge != edgeFromPrev)
- {
- if (edge->edgeWeightMax() >= edgeFromPrev->edgeWeightMin())
- {
- moveDestUp = false;
- break;
- }
- }
- }
- }
- else
+ // Examine all of the other edges into bDest
+ for (FlowEdge* const edge : bDest->PredEdges())
{
- //
- // The block bPrev must have a higher weight
- // than every other block that goes into bDest
- //
-
- // Examine all of the other edges into bDest
- for (BasicBlock* const predBlock : bDest->PredBlocks())
+ if (edge->getLikelyWeight() > weightToBeat)
{
- if ((predBlock != bPrev) && (predBlock->bbWeight >= bPrev->bbWeight))
- {
- moveDestUp = false;
- break;
- }
+ moveDestUp = false;
+ break;
}
}
@@ -3703,98 +3587,43 @@ bool Compiler::fgReorderBlocks(bool useProfile)
{
noway_assert(bPrev->KindIs(BBJ_COND));
//
- // We will reverse branch if the taken-jump to bDest ratio (i.e. 'takenRatio')
- // is more than 51%
+ // We will reverse branch if the true edge's likelihood is more than 51%.
//
- // We will setup profHotWeight to be maximum bbWeight that a block
- // could have for us not to want to reverse the conditional branch
+ // We will set up profHotWeight to be maximum bbWeight that a block
+ // could have for us not to want to reverse the conditional branch.
//
// We will consider all blocks that have less weight than profHotWeight to be
- // uncommonly run blocks as compared with the hot path of bPrev taken-jump to bDest
+ // uncommonly run blocks compared to the weight of bPrev's true edge.
+ //
+ // We will check if bPrev's true edge weight
+ // is more than twice bPrev's false edge weight.
+ //
+ // bPrev --> [BB04, weight 100]
+ // | \.
+ // falseEdge ---------------> O \.
+ // [likelihood=0.33] V \.
+ // block --> [BB05, weight 33] \.
+ // \.
+ // trueEdge ------------------------------> O
+ // [likelihood=0.67] |
+ // V
+ // bDest ---------------> [BB08, weight 67]
//
- if (fgHaveValidEdgeWeights)
+ assert(bPrev->FalseTargetIs(block));
+ FlowEdge* trueEdge = bPrev->GetTrueEdge();
+ FlowEdge* falseEdge = bPrev->GetFalseEdge();
+ noway_assert(trueEdge != nullptr);
+ noway_assert(falseEdge != nullptr);
+
+ // If we take the true branch more than half the time, we will reverse the branch.
+ if (trueEdge->getLikelihood() < 0.51)
{
- // We have valid edge weights, however even with valid edge weights
- // we may have a minimum and maximum range for each edges value
- //
- // We will check that the min weight of the bPrev to bDest edge
- // is more than twice the max weight of the bPrev to block edge.
- //
- // bPrev --> [BB04, weight 31]
- // | \.
- // edgeToBlock -------------> O \.
- // [min=8,max=10] V \.
- // block --> [BB05, weight 10] \.
- // \.
- // edgeToDest ----------------------------> O
- // [min=21,max=23] |
- // V
- // bDest ---------------> [BB08, weight 21]
- //
- assert(bPrev->FalseTargetIs(block));
- FlowEdge* edgeToDest = bPrev->GetTrueEdge();
- FlowEdge* edgeToBlock = bPrev->GetFalseEdge();
- noway_assert(edgeToDest != nullptr);
- noway_assert(edgeToBlock != nullptr);
- //
- // Calculate the taken ratio
- // A takenRation of 0.10 means taken 10% of the time, not taken 90% of the time
- // A takenRation of 0.50 means taken 50% of the time, not taken 50% of the time
- // A takenRation of 0.90 means taken 90% of the time, not taken 10% of the time
- //
- double takenCount =
- ((double)edgeToDest->edgeWeightMin() + (double)edgeToDest->edgeWeightMax()) / 2.0;
- double notTakenCount =
- ((double)edgeToBlock->edgeWeightMin() + (double)edgeToBlock->edgeWeightMax()) / 2.0;
- double totalCount = takenCount + notTakenCount;
-
- // If the takenRatio (takenCount / totalCount) is greater or equal to 51% then we will reverse
- // the branch
- if (takenCount < (0.51 * totalCount))
- {
- reorderBlock = false;
- }
- else
- {
- // set profHotWeight
- profHotWeight = (edgeToBlock->edgeWeightMin() + edgeToBlock->edgeWeightMax()) / 2 - 1;
- }
+ reorderBlock = false;
}
else
{
- // We don't have valid edge weight so we will be more conservative
- // We could have bPrev, block or bDest as part of a loop and thus have extra weight
- //
- // We will do two checks:
- // 1. Check that the weight of bDest is at least two times more than block
- // 2. Check that the weight of bPrev is at least three times more than block
- //
- // bPrev --> [BB04, weight 31]
- // | \.
- // V \.
- // block --> [BB05, weight 10] \.
- // \.
- // |
- // V
- // bDest ---------------> [BB08, weight 21]
- //
- // For this case weightDest is calculated as (21+1)/2 or 11
- // and weightPrev is calculated as (31+2)/3 also 11
- //
- // Generally both weightDest and weightPrev should calculate
- // the same value unless bPrev or bDest are part of a loop
- //
- weight_t weightDest = bDest->isMaxBBWeight() ? bDest->bbWeight : (bDest->bbWeight + 1) / 2;
- weight_t weightPrev = bPrev->isMaxBBWeight() ? bPrev->bbWeight : (bPrev->bbWeight + 2) / 3;
-
- // select the lower of weightDest and weightPrev
- profHotWeight = (weightDest < weightPrev) ? weightDest : weightPrev;
-
- // if the weight of block is greater (or equal) to profHotWeight then we don't reverse the cond
- if (block->bbWeight >= profHotWeight)
- {
- reorderBlock = false;
- }
+ // set profHotWeight
+ profHotWeight = falseEdge->getLikelyWeight() - 1;
}
}
}
@@ -4906,9 +4735,9 @@ bool Compiler::fgUpdateFlowGraph(bool doTailDuplication /* = false */, bool isPh
//
if (fgIsUsingProfileWeights())
{
- // if block and bdest are in different hot/cold regions we can't do this optimization
+ // if block and bDest are in different hot/cold regions we can't do this optimization
// because we can't allow fall-through into the cold region.
- if (!fgEdgeWeightsComputed || fgInDifferentRegions(block, bDest))
+ if (fgInDifferentRegions(block, bDest))
{
optimizeJump = false;
}
diff --git a/src/coreclr/jit/fgprofile.cpp b/src/coreclr/jit/fgprofile.cpp
index 7a46e14155b116..79cd63e3ac3b51 100644
--- a/src/coreclr/jit/fgprofile.cpp
+++ b/src/coreclr/jit/fgprofile.cpp
@@ -4257,265 +4257,17 @@ bool Compiler::fgIncorporateEdgeCounts()
return e.IsGood();
}
-//------------------------------------------------------------------------
-// setEdgeWeightMinChecked: possibly update minimum edge weight
-//
-// Arguments:
-// newWeight - proposed new weight
-// bDst - destination block for edge
-// slop - profile slush fund
-// wbUsedSlop [out] - true if we tapped into the slush fund
-//
-// Returns:
-// true if the edge weight was adjusted
-// false if the edge weight update was inconsistent with the
-// edge's current [min,max}
-//
-bool FlowEdge::setEdgeWeightMinChecked(weight_t newWeight, BasicBlock* bDst, weight_t slop, bool* wbUsedSlop)
-{
- // Negative weights are nonsensical.
- //
- // If we can't cover the deficit with slop, fail.
- // If we can, set the new weight to zero.
- //
- bool usedSlop = false;
-
- if (newWeight < BB_ZERO_WEIGHT)
- {
- if ((newWeight + slop) < BB_ZERO_WEIGHT)
- {
- return false;
- }
-
- newWeight = BB_ZERO_WEIGHT;
- usedSlop = true;
- }
-
- bool result = false;
-
- if ((newWeight <= m_edgeWeightMax) && (newWeight >= m_edgeWeightMin))
- {
- m_edgeWeightMin = newWeight;
- result = true;
- }
- else if (slop > 0)
- {
- // We allow for a small amount of inaccuracy in block weight counts.
- if (m_edgeWeightMax < newWeight)
- {
- // We have already determined that this edge's weight
- // is less than newWeight, so we just allow for the slop
- if (newWeight <= (m_edgeWeightMax + slop))
- {
- result = true;
- usedSlop = true;
-
- if (m_edgeWeightMax != BB_ZERO_WEIGHT)
- {
- // We will raise m_edgeWeightMin and Max towards newWeight
- m_edgeWeightMin = m_edgeWeightMax;
- m_edgeWeightMax = newWeight;
- }
- }
- }
- else if (m_edgeWeightMin > newWeight)
- {
- // We have already determined that this edge's weight
- // is more than newWeight, so we just allow for the slop
- if ((newWeight + slop) >= m_edgeWeightMin)
- {
- result = true;
- usedSlop = true;
-
- if (m_edgeWeightMax != BB_ZERO_WEIGHT)
- {
- // We will lower m_edgeWeightMin towards newWeight
- // But not below zero.
- //
- m_edgeWeightMin = max(BB_ZERO_WEIGHT, newWeight);
- }
- }
- }
-
- // If we are returning true then we should have adjusted the range so that
- // the newWeight is in new range [Min..Max] or fgEdgeWeightMax is zero.
- //
- if (result)
- {
- assert((m_edgeWeightMax == BB_ZERO_WEIGHT) ||
- ((newWeight <= m_edgeWeightMax) && (newWeight >= m_edgeWeightMin)));
- }
- }
-
- if (result && usedSlop && (wbUsedSlop != nullptr))
- {
- *wbUsedSlop = true;
- }
-
-#if DEBUG
- if (result)
- {
- JITDUMP("Updated min weight of " FMT_BB " -> " FMT_BB " to [" FMT_WT ".." FMT_WT "]\n", getSourceBlock()->bbNum,
- bDst->bbNum, m_edgeWeightMin, m_edgeWeightMax);
- }
- else
- {
- JITDUMP("Not adjusting min weight of " FMT_BB " -> " FMT_BB "; new value " FMT_WT " not in range [" FMT_WT
- ".." FMT_WT "] (+/- " FMT_WT ")\n",
- getSourceBlock()->bbNum, bDst->bbNum, newWeight, m_edgeWeightMin, m_edgeWeightMax, slop);
- result = false; // break here
- }
-#endif // DEBUG
-
- return result;
-}
-
-//------------------------------------------------------------------------
-// setEdgeWeightMaxChecked: possibly update maximum edge weight
-//
-// Arguments:
-// newWeight - proposed new weight
-// bDst - destination block for edge
-// slop - profile slush fund
-// wbUsedSlop [out] - true if we tapped into the slush fund
-//
-// Returns:
-// true if the edge weight was adjusted
-// false if the edge weight update was inconsistent with the
-// edge's current [min,max}
-//
-bool FlowEdge::setEdgeWeightMaxChecked(weight_t newWeight, BasicBlock* bDst, weight_t slop, bool* wbUsedSlop)
-{
- // Negative weights are nonsensical.
- //
- // If we can't cover the deficit with slop, fail.
- // If we can, set the new weight to zero.
- //
- bool usedSlop = false;
-
- if (newWeight < BB_ZERO_WEIGHT)
- {
- if ((newWeight + slop) < BB_ZERO_WEIGHT)
- {
- return false;
- }
-
- newWeight = BB_ZERO_WEIGHT;
- usedSlop = true;
- }
-
- bool result = false;
-
- if ((newWeight >= m_edgeWeightMin) && (newWeight <= m_edgeWeightMax))
- {
- m_edgeWeightMax = newWeight;
- result = true;
- }
- else if (slop > 0)
- {
- // We allow for a small amount of inaccuracy in block weight counts.
- if (m_edgeWeightMax < newWeight)
- {
- // We have already determined that this edge's weight
- // is less than newWeight, so we just allow for the slop
- if (newWeight <= (m_edgeWeightMax + slop))
- {
- result = true;
- usedSlop = true;
-
- if (m_edgeWeightMax != BB_ZERO_WEIGHT)
- {
- // We will allow this to raise m_edgeWeightMax towards newWeight
- m_edgeWeightMax = newWeight;
- }
- }
- }
- else if (m_edgeWeightMin > newWeight)
- {
- // We have already determined that this edge's weight
- // is more than newWeight, so we just allow for the slop
- if ((newWeight + slop) >= m_edgeWeightMin)
- {
- result = true;
- usedSlop = true;
-
- if (m_edgeWeightMax != BB_ZERO_WEIGHT)
- {
- // We will allow this to lower m_edgeWeightMin and Max towards newWeight
- m_edgeWeightMax = m_edgeWeightMin;
- m_edgeWeightMin = newWeight;
- }
- }
- }
-
- // If we are returning true then we should have adjusted the range so that
- // the newWeight is in new range [Min..Max] or fgEdgeWeightMax is zero
- if (result)
- {
- assert((m_edgeWeightMax == BB_ZERO_WEIGHT) ||
- ((newWeight <= m_edgeWeightMax) && (newWeight >= m_edgeWeightMin)));
- }
- }
-
- if (result && usedSlop && (wbUsedSlop != nullptr))
- {
- *wbUsedSlop = true;
- }
-
-#if DEBUG
- if (result)
- {
- JITDUMP("Updated max weight of " FMT_BB " -> " FMT_BB " to [" FMT_WT ".." FMT_WT "]\n", getSourceBlock()->bbNum,
- bDst->bbNum, m_edgeWeightMin, m_edgeWeightMax);
- }
- else
- {
- JITDUMP("Not adjusting max weight of " FMT_BB " -> " FMT_BB "; new value " FMT_WT " not in range [" FMT_WT
- ".." FMT_WT "] (+/- " FMT_WT ")\n",
- getSourceBlock()->bbNum, bDst->bbNum, newWeight, m_edgeWeightMin, m_edgeWeightMax, slop);
- result = false; // break here
- }
-#endif // DEBUG
-
- return result;
-}
-
-//------------------------------------------------------------------------
-// setEdgeWeights: Sets the minimum lower (m_edgeWeightMin) value
-// and the maximum upper (m_edgeWeightMax) value
-// Asserts that the max value is greater or equal to the min value
-//
-// Arguments:
-// theMinWeight - the new minimum lower (m_edgeWeightMin)
-// theMaxWeight - the new maximum upper (m_edgeWeightMin)
-// bDst - the destination block for the edge
-//
-void FlowEdge::setEdgeWeights(weight_t theMinWeight, weight_t theMaxWeight, BasicBlock* bDst)
-{
- assert(theMinWeight <= theMaxWeight);
- assert(theMinWeight >= 0.0);
- assert(theMaxWeight >= 0.0);
-
- JITDUMP("Setting edge weights for " FMT_BB " -> " FMT_BB " to [" FMT_WT " .. " FMT_WT "]\n",
- getSourceBlock()->bbNum, bDst->bbNum, theMinWeight, theMaxWeight);
-
- m_edgeWeightMin = theMinWeight;
- m_edgeWeightMax = theMaxWeight;
-}
-
//-------------------------------------------------------------
-// fgComputeBlockAndEdgeWeights: determine weights for blocks
-// and optionally for edges
+// fgComputeBlockWeights: determine weights for blocks
//
// Returns:
// Suitable phase status
//
-PhaseStatus Compiler::fgComputeBlockAndEdgeWeights()
+PhaseStatus Compiler::fgComputeBlockWeights()
{
const bool usingProfileWeights = fgIsUsingProfileWeights();
bool madeChanges = false;
fgModified = false;
- fgHaveValidEdgeWeights = false;
fgCalledCount = BB_UNITY_WEIGHT;
#if DEBUG
@@ -4539,13 +4291,6 @@ PhaseStatus Compiler::fgComputeBlockAndEdgeWeights()
JITDUMP(" -- no profile data, so using default called count\n");
}
- PhaseStatus edgeStatus = fgComputeEdgeWeights();
-
- if (edgeStatus != PhaseStatus::MODIFIED_NOTHING)
- {
- return edgeStatus;
- }
-
return madeChanges ? PhaseStatus::MODIFIED_EVERYTHING : PhaseStatus::MODIFIED_NOTHING;
}
@@ -4785,405 +4530,6 @@ bool Compiler::fgComputeCalledCount(weight_t returnWeight)
return madeChanges;
}
-//-------------------------------------------------------------
-// fgComputeEdgeWeights: compute edge weights from block weights
-//
-// Returns:
-// Suitable phase status
-//
-PhaseStatus Compiler::fgComputeEdgeWeights()
-{
- const bool isOptimizing = opts.OptimizationEnabled();
- const bool usingProfileWeights = fgIsUsingProfileWeights();
-
- if (!isOptimizing || !usingProfileWeights)
- {
- JITDUMP(" -- not optimizing or no profile data, so not computing edge weights\n");
- return PhaseStatus::MODIFIED_NOTHING;
- }
-
- BasicBlock* bSrc;
- BasicBlock* bDst;
- weight_t slop;
- unsigned goodEdgeCountCurrent = 0;
- unsigned goodEdgeCountPrevious = 0;
- bool inconsistentProfileData = false;
- bool hasIncompleteEdgeWeights = false;
- bool usedSlop = false;
- unsigned numEdges = 0;
- unsigned iterations = 0;
-
- JITDUMP("Initial weight assignments\n\n");
-
- // Now we will compute the initial m_edgeWeightMin and m_edgeWeightMax values
- for (bDst = fgFirstBB; bDst != nullptr; bDst = bDst->Next())
- {
- weight_t bDstWeight = bDst->bbWeight;
-
- // We subtract out the called count so that bDstWeight is
- // the sum of all edges that go into this block from this method.
- //
- if (bDst == fgFirstBB)
- {
- bDstWeight -= fgCalledCount;
- }
-
- for (FlowEdge* const edge : bDst->PredEdges())
- {
- bool assignOK = true;
-
- bSrc = edge->getSourceBlock();
- // We are processing the control flow edge (bSrc -> bDst)
-
- numEdges++;
-
- //
- // If the bSrc or bDst blocks do not have exact profile weights
- // then we must reset any values that they currently have
- //
-
- if (!bSrc->hasProfileWeight() || !bDst->hasProfileWeight())
- {
- edge->setEdgeWeights(BB_ZERO_WEIGHT, BB_MAX_WEIGHT, bDst);
- }
-
- slop = BasicBlock::GetSlopFraction(bSrc, bDst) + 1;
- switch (bSrc->GetKind())
- {
- case BBJ_ALWAYS:
- case BBJ_EHCATCHRET:
- case BBJ_CALLFINALLY:
- case BBJ_CALLFINALLYRET:
- // We know the exact edge weight
- assignOK &= edge->setEdgeWeightMinChecked(bSrc->bbWeight, bDst, slop, &usedSlop);
- assignOK &= edge->setEdgeWeightMaxChecked(bSrc->bbWeight, bDst, slop, &usedSlop);
- break;
-
- case BBJ_COND:
- case BBJ_SWITCH:
- case BBJ_EHFINALLYRET:
- case BBJ_EHFAULTRET:
- case BBJ_EHFILTERRET:
- if (edge->edgeWeightMax() > bSrc->bbWeight)
- {
- // The maximum edge weight to block can't be greater than the weight of bSrc
- assignOK &= edge->setEdgeWeightMaxChecked(bSrc->bbWeight, bDst, slop, &usedSlop);
- }
- break;
-
- default:
- // We should never have an edge that starts from one of these jump kinds
- noway_assert(!"Unexpected bbKind");
- break;
- }
-
- // The maximum edge weight to block can't be greater than the weight of bDst
- if (edge->edgeWeightMax() > bDstWeight)
- {
- assignOK &= edge->setEdgeWeightMaxChecked(bDstWeight, bDst, slop, &usedSlop);
- }
-
- if (!assignOK)
- {
- // Here we have inconsistent profile data
- inconsistentProfileData = true;
- // No point in continuing
- goto EARLY_EXIT;
- }
- }
- }
-
- fgEdgeCount = numEdges;
-
- iterations = 0;
-
- do
- {
- JITDUMP("\nSolver pass %u\n", iterations);
-
- iterations++;
- goodEdgeCountPrevious = goodEdgeCountCurrent;
- goodEdgeCountCurrent = 0;
- hasIncompleteEdgeWeights = false;
-
- JITDUMP("\n -- step 1 --\n");
- for (bDst = fgFirstBB; bDst != nullptr; bDst = bDst->Next())
- {
- for (FlowEdge* const edge : bDst->PredEdges())
- {
- bool assignOK = true;
-
- // We are processing the control flow edge (bSrc -> bDst)
- bSrc = edge->getSourceBlock();
-
- slop = BasicBlock::GetSlopFraction(bSrc, bDst) + 1;
- if (bSrc->KindIs(BBJ_COND))
- {
- weight_t diff;
- FlowEdge* otherEdge;
- BasicBlock* otherDst;
- if (bSrc->FalseTargetIs(bDst))
- {
- otherEdge = bSrc->GetTrueEdge();
- }
- else
- {
- otherEdge = bSrc->GetFalseEdge();
- }
- otherDst = otherEdge->getDestinationBlock();
-
- // If we see min/max violations, just give up on the computations
- //
- const bool edgeWeightSensible = edge->edgeWeightMin() <= edge->edgeWeightMax();
- const bool otherEdgeWeightSensible = otherEdge->edgeWeightMin() <= otherEdge->edgeWeightMax();
-
- assignOK &= edgeWeightSensible && otherEdgeWeightSensible;
-
- if (assignOK)
- {
- // Adjust edge->m_edgeWeightMin up or adjust otherEdge->m_edgeWeightMax down
- diff = bSrc->bbWeight - (edge->edgeWeightMin() + otherEdge->edgeWeightMax());
- if (diff > 0)
- {
- assignOK &=
- edge->setEdgeWeightMinChecked(edge->edgeWeightMin() + diff, bDst, slop, &usedSlop);
- }
- else if (diff < 0)
- {
- assignOK &= otherEdge->setEdgeWeightMaxChecked(otherEdge->edgeWeightMax() + diff, otherDst,
- slop, &usedSlop);
- }
-
- // Adjust otherEdge->m_edgeWeightMin up or adjust edge->m_edgeWeightMax down
- diff = bSrc->bbWeight - (otherEdge->edgeWeightMin() + edge->edgeWeightMax());
- if (diff > 0)
- {
- assignOK &= otherEdge->setEdgeWeightMinChecked(otherEdge->edgeWeightMin() + diff, otherDst,
- slop, &usedSlop);
- }
- else if (diff < 0)
- {
- assignOK &=
- edge->setEdgeWeightMaxChecked(edge->edgeWeightMax() + diff, bDst, slop, &usedSlop);
- }
- }
-
- if (!assignOK)
- {
- // Here we have inconsistent profile data
- inconsistentProfileData = true;
- // No point in continuing
- goto EARLY_EXIT;
- }
-#ifdef DEBUG
- // Now edge->m_edgeWeightMin and otherEdge->m_edgeWeightMax) should add up to bSrc->bbWeight
- diff = bSrc->bbWeight - (edge->edgeWeightMin() + otherEdge->edgeWeightMax());
-
- if (!((-slop) <= diff) && (diff <= slop))
- {
- JITDUMP("Edge weight discrepancy: " FMT_BB "[" FMT_WT "] -> {" FMT_BB "[min:" FMT_WT
- "], " FMT_BB "[max: " FMT_WT "]} diff " FMT_WT " exceeds slop " FMT_WT "\n",
- bSrc->bbNum, bSrc->bbWeight, bDst->bbNum, edge->edgeWeightMin(), otherDst->bbNum,
- otherEdge->edgeWeightMax(), diff, slop);
- }
-
- // Now otherEdge->m_edgeWeightMin and edge->m_edgeWeightMax) should add up to bSrc->bbWeight
- diff = bSrc->bbWeight - (otherEdge->edgeWeightMin() + edge->edgeWeightMax());
- if (!((-slop) <= diff) && (diff <= slop))
- {
- JITDUMP("Edge weight discrepancy: " FMT_BB "[" FMT_WT "] -> {" FMT_BB "[max:" FMT_WT
- "], " FMT_BB "[min: " FMT_WT "]} diff " FMT_WT " exceeds slop " FMT_WT "\n",
- bSrc->bbNum, bSrc->bbWeight, bDst->bbNum, edge->edgeWeightMax(), otherDst->bbNum,
- otherEdge->edgeWeightMin(), diff, slop);
- }
-#endif // DEBUG
- }
- }
- }
-
- JITDUMP("\n -- step 2 --\n");
-
- for (bDst = fgFirstBB; bDst != nullptr; bDst = bDst->Next())
- {
- weight_t bDstWeight = bDst->bbWeight;
-
- if (bDstWeight == BB_MAX_WEIGHT)
- {
- inconsistentProfileData = true;
- // No point in continuing
- goto EARLY_EXIT;
- }
- else
- {
- // We subtract out the called count so that bDstWeight is
- // the sum of all edges that go into this block from this method.
- //
- if (bDst == fgFirstBB)
- {
- bDstWeight -= fgCalledCount;
- }
-
- weight_t minEdgeWeightSum = 0;
- weight_t maxEdgeWeightSum = 0;
-
- // Calculate the sums of the minimum and maximum edge weights
- for (FlowEdge* const edge : bDst->PredEdges())
- {
- maxEdgeWeightSum += edge->edgeWeightMax();
- minEdgeWeightSum += edge->edgeWeightMin();
- }
-
- // maxEdgeWeightSum is the sum of all m_edgeWeightMax values into bDst
- // minEdgeWeightSum is the sum of all m_edgeWeightMin values into bDst
-
- for (FlowEdge* const edge : bDst->PredEdges())
- {
- bool assignOK = true;
-
- // We are processing the control flow edge (bSrc -> bDst)
- bSrc = edge->getSourceBlock();
- slop = BasicBlock::GetSlopFraction(bSrc, bDst) + 1;
-
- // otherMaxEdgesWeightSum is the sum of all of the other edges m_edgeWeightMax values
- // This can be used to compute a lower bound for our minimum edge weight
- //
- weight_t const otherMaxEdgesWeightSum = maxEdgeWeightSum - edge->edgeWeightMax();
-
- if (otherMaxEdgesWeightSum >= BB_ZERO_WEIGHT)
- {
- if (bDstWeight >= otherMaxEdgesWeightSum)
- {
- // minWeightCalc is our minWeight when every other path to bDst takes it's m_edgeWeightMax
- // value
- weight_t minWeightCalc = (weight_t)(bDstWeight - otherMaxEdgesWeightSum);
- if (minWeightCalc > edge->edgeWeightMin())
- {
- assignOK &= edge->setEdgeWeightMinChecked(minWeightCalc, bDst, slop, &usedSlop);
- }
- }
- }
-
- // otherMinEdgesWeightSum is the sum of all of the other edges m_edgeWeightMin values
- // This can be used to compute an upper bound for our maximum edge weight
- //
- weight_t const otherMinEdgesWeightSum = minEdgeWeightSum - edge->edgeWeightMin();
-
- if (otherMinEdgesWeightSum >= BB_ZERO_WEIGHT)
- {
- if (bDstWeight >= otherMinEdgesWeightSum)
- {
- // maxWeightCalc is our maxWeight when every other path to bDst takes it's m_edgeWeightMin
- // value
- weight_t maxWeightCalc = (weight_t)(bDstWeight - otherMinEdgesWeightSum);
- if (maxWeightCalc < edge->edgeWeightMax())
- {
- assignOK &= edge->setEdgeWeightMaxChecked(maxWeightCalc, bDst, slop, &usedSlop);
- }
- }
- }
-
- if (!assignOK)
- {
- // Here we have inconsistent profile data
- JITDUMP("Inconsistent profile data at " FMT_BB " -> " FMT_BB ": dest weight " FMT_WT
- ", min/max into dest is " FMT_WT "/" FMT_WT ", edge " FMT_WT "/" FMT_WT "\n",
- bSrc->bbNum, bDst->bbNum, bDstWeight, minEdgeWeightSum, maxEdgeWeightSum,
- edge->edgeWeightMin(), edge->edgeWeightMax());
-
- inconsistentProfileData = true;
- // No point in continuing
- goto EARLY_EXIT;
- }
-
- // When m_edgeWeightMin equals m_edgeWeightMax we have a "good" edge weight
- if (edge->edgeWeightMin() == edge->edgeWeightMax())
- {
- // Count how many "good" edge weights we have
- // Each time through we should have more "good" weights
- // We exit the while loop when no longer find any new "good" edges
- goodEdgeCountCurrent++;
- }
- else
- {
- // Remember that we have seen at least one "Bad" edge weight
- // so that we will repeat the while loop again
- hasIncompleteEdgeWeights = true;
- }
- }
- }
- }
-
- assert(!inconsistentProfileData); // Should use EARLY_EXIT when it is false.
-
- if (numEdges == goodEdgeCountCurrent)
- {
- noway_assert(hasIncompleteEdgeWeights == false);
- break;
- }
-
- } while (hasIncompleteEdgeWeights && (goodEdgeCountCurrent > goodEdgeCountPrevious) && (iterations < 8));
-
-EARLY_EXIT:;
-
-#ifdef DEBUG
- if (verbose)
- {
- if (inconsistentProfileData)
- {
- printf("fgComputeEdgeWeights() found inconsistent profile data, not using the edge weights\n");
- }
- else
- {
- if (hasIncompleteEdgeWeights)
- {
- printf("fgComputeEdgeWeights() was able to compute exact edge weights for %3d of the %3d edges, using "
- "%d passes.\n",
- goodEdgeCountCurrent, numEdges, iterations);
- }
- else
- {
- printf("fgComputeEdgeWeights() was able to compute exact edge weights for all of the %3d edges, using "
- "%d passes.\n",
- numEdges, iterations);
- }
-
- fgPrintEdgeWeights();
- }
- }
-#endif // DEBUG
-
- fgSlopUsedInEdgeWeights = usedSlop;
- fgRangeUsedInEdgeWeights = false;
-
- // See if any edge weight are expressed in [min..max] form
-
- for (BasicBlock* const bDst : Blocks())
- {
- if (bDst->bbPreds != nullptr)
- {
- for (FlowEdge* const edge : bDst->PredEdges())
- {
- // This is the control flow edge (edge->getBlock() -> bDst)
-
- if (edge->edgeWeightMin() != edge->edgeWeightMax())
- {
- fgRangeUsedInEdgeWeights = true;
- break;
- }
- }
- if (fgRangeUsedInEdgeWeights)
- {
- break;
- }
- }
- }
-
- fgHaveValidEdgeWeights = !inconsistentProfileData;
- fgEdgeWeightsComputed = true;
-
- return PhaseStatus::MODIFIED_EVERYTHING;
-}
-
//------------------------------------------------------------------------
// fgProfileWeightsEqual: check if two profile weights are equal
// (or nearly so)
@@ -5314,14 +4660,13 @@ bool Compiler::fgDebugCheckProfileWeights(ProfileChecks checks)
// and/or
// new likelihood based weights.
//
- const bool verifyClassicWeights = fgEdgeWeightsComputed && hasFlag(checks, ProfileChecks::CHECK_CLASSIC);
- const bool verifyLikelyWeights = hasFlag(checks, ProfileChecks::CHECK_LIKELY);
- const bool verifyHasLikelihood = hasFlag(checks, ProfileChecks::CHECK_HASLIKELIHOOD);
- const bool verifyLikelihoodSum = hasFlag(checks, ProfileChecks::CHECK_LIKELIHOODSUM);
- const bool assertOnFailure = hasFlag(checks, ProfileChecks::RAISE_ASSERT) && fgPgoConsistent;
- const bool checkAllBlocks = hasFlag(checks, ProfileChecks::CHECK_ALL_BLOCKS);
+ const bool verifyLikelyWeights = hasFlag(checks, ProfileChecks::CHECK_LIKELY);
+ const bool verifyHasLikelihood = hasFlag(checks, ProfileChecks::CHECK_HASLIKELIHOOD);
+ const bool verifyLikelihoodSum = hasFlag(checks, ProfileChecks::CHECK_LIKELIHOODSUM);
+ const bool assertOnFailure = hasFlag(checks, ProfileChecks::RAISE_ASSERT) && fgPgoConsistent;
+ const bool checkAllBlocks = hasFlag(checks, ProfileChecks::CHECK_ALL_BLOCKS);
- if (!(verifyClassicWeights || verifyLikelyWeights || verifyHasLikelihood))
+ if (!verifyLikelyWeights && !verifyHasLikelihood)
{
JITDUMP("[profile weight checks disabled]\n");
return true;
@@ -5469,7 +4814,7 @@ bool Compiler::fgDebugCheckProfileWeights(ProfileChecks checks)
// Verify overall entry-exit balance.
//
- if (verifyClassicWeights || verifyLikelyWeights)
+ if (verifyLikelyWeights)
{
// If there's a try, significant weight might pass along exception edges.
// We don't model that, and it can throw off entry-exit balance.
@@ -5498,7 +4843,7 @@ bool Compiler::fgDebugCheckProfileWeights(ProfileChecks checks)
{
JITDUMP("No blocks were profiled, so nothing to check\n");
}
- else if (verifyClassicWeights || verifyLikelyWeights)
+ else if (verifyLikelyWeights)
{
JITDUMP("Profile is self-consistent (%d profiled blocks, %d unprofiled)\n", profiledBlocks,
unprofiledBlocks);
@@ -5544,18 +4889,15 @@ bool Compiler::fgDebugCheckProfileWeights(ProfileChecks checks)
//
bool Compiler::fgDebugCheckIncomingProfileData(BasicBlock* block, ProfileChecks checks)
{
- const bool verifyClassicWeights = fgEdgeWeightsComputed && hasFlag(checks, ProfileChecks::CHECK_CLASSIC);
- const bool verifyLikelyWeights = hasFlag(checks, ProfileChecks::CHECK_LIKELY);
- const bool verifyHasLikelihood = hasFlag(checks, ProfileChecks::CHECK_HASLIKELIHOOD);
+ const bool verifyLikelyWeights = hasFlag(checks, ProfileChecks::CHECK_LIKELY);
+ const bool verifyHasLikelihood = hasFlag(checks, ProfileChecks::CHECK_HASLIKELIHOOD);
- if (!(verifyClassicWeights || verifyLikelyWeights || verifyHasLikelihood))
+ if (!verifyLikelyWeights && !verifyHasLikelihood)
{
return true;
}
weight_t const blockWeight = block->bbWeight;
- weight_t incomingWeightMin = 0;
- weight_t incomingWeightMax = 0;
weight_t incomingLikelyWeight = 0;
unsigned missingLikelyWeight = 0;
bool foundPreds = false;
@@ -5563,8 +4905,6 @@ bool Compiler::fgDebugCheckIncomingProfileData(BasicBlock* block, ProfileChecks
for (FlowEdge* const predEdge : block->PredEdges())
{
- incomingWeightMin += predEdge->edgeWeightMin();
- incomingWeightMax += predEdge->edgeWeightMax();
if (predEdge->hasLikelihood())
{
if (BasicBlock::sameHndRegion(block, predEdge->getSourceBlock()))
@@ -5592,42 +4932,15 @@ bool Compiler::fgDebugCheckIncomingProfileData(BasicBlock* block, ProfileChecks
if (block->isBBCallFinallyPairTail())
{
incomingLikelyWeight = block->Prev()->bbWeight;
- incomingWeightMin = incomingLikelyWeight;
- incomingWeightMax = incomingLikelyWeight;
foundEHPreds = false;
}
- bool classicWeightsValid = true;
- bool likelyWeightsValid = true;
+ bool likelyWeightsValid = true;
// If we have EH preds we may not have consistent incoming flow.
//
if (foundPreds && !foundEHPreds)
{
- if (verifyClassicWeights)
- {
- if (!fgProfileWeightsConsistent(incomingWeightMin, incomingWeightMax))
- {
- JITDUMP(" " FMT_BB " - incoming min " FMT_WT " inconsistent with incoming max " FMT_WT "\n",
- block->bbNum, incomingWeightMin, incomingWeightMax);
- classicWeightsValid = false;
- }
-
- if (!fgProfileWeightsConsistent(blockWeight, incomingWeightMin))
- {
- JITDUMP(" " FMT_BB " - block weight " FMT_WT " inconsistent with incoming min " FMT_WT "\n",
- block->bbNum, blockWeight, incomingWeightMin);
- classicWeightsValid = false;
- }
-
- if (!fgProfileWeightsConsistent(blockWeight, incomingWeightMax))
- {
- JITDUMP(" " FMT_BB " - block weight " FMT_WT " inconsistent with incoming max " FMT_WT "\n",
- block->bbNum, blockWeight, incomingWeightMax);
- classicWeightsValid = false;
- }
- }
-
if (verifyLikelyWeights)
{
if (!fgProfileWeightsConsistentOrSmall(blockWeight, incomingLikelyWeight))
@@ -5649,7 +4962,7 @@ bool Compiler::fgDebugCheckIncomingProfileData(BasicBlock* block, ProfileChecks
}
}
- return classicWeightsValid && likelyWeightsValid;
+ return likelyWeightsValid;
}
//------------------------------------------------------------------------
@@ -5668,17 +4981,15 @@ bool Compiler::fgDebugCheckIncomingProfileData(BasicBlock* block, ProfileChecks
//
bool Compiler::fgDebugCheckOutgoingProfileData(BasicBlock* block, ProfileChecks checks)
{
- const bool verifyClassicWeights = fgEdgeWeightsComputed && hasFlag(checks, ProfileChecks::CHECK_CLASSIC);
- const bool verifyHasLikelihood = hasFlag(checks, ProfileChecks::CHECK_HASLIKELIHOOD);
- const bool verifyLikelihoodSum = hasFlag(checks, ProfileChecks::CHECK_LIKELIHOODSUM);
+ const bool verifyHasLikelihood = hasFlag(checks, ProfileChecks::CHECK_HASLIKELIHOOD);
+ const bool verifyLikelihoodSum = hasFlag(checks, ProfileChecks::CHECK_LIKELIHOODSUM);
- if (!(verifyClassicWeights || verifyHasLikelihood || verifyLikelihoodSum))
+ if (!verifyHasLikelihood && !verifyLikelihoodSum)
{
return true;
}
- bool classicWeightsValid = true;
- bool likelyWeightsValid = true;
+ bool likelyWeightsValid = true;
// We want switch targets unified, but not EH edges.
//
@@ -5687,8 +4998,6 @@ bool Compiler::fgDebugCheckOutgoingProfileData(BasicBlock* block, ProfileChecks
if ((numSuccs > 0) && !block->KindIs(BBJ_EHFINALLYRET, BBJ_EHFAULTRET, BBJ_EHFILTERRET))
{
weight_t const blockWeight = block->bbWeight;
- weight_t outgoingWeightMin = 0;
- weight_t outgoingWeightMax = 0;
weight_t outgoingLikelihood = 0;
// Walk successor edges and add up flow counts.
@@ -5701,9 +5010,6 @@ bool Compiler::fgDebugCheckOutgoingProfileData(BasicBlock* block, ProfileChecks
assert(succEdge != nullptr);
BasicBlock* succBlock = succEdge->getDestinationBlock();
- outgoingWeightMin += succEdge->edgeWeightMin();
- outgoingWeightMax += succEdge->edgeWeightMax();
-
if (succEdge->hasLikelihood())
{
outgoingLikelihood += succEdge->getLikelihood();
@@ -5718,32 +5024,7 @@ bool Compiler::fgDebugCheckOutgoingProfileData(BasicBlock* block, ProfileChecks
if (missingEdges > 0)
{
JITDUMP(" " FMT_BB " - missing %d successor edges\n", block->bbNum, missingEdges);
- classicWeightsValid = false;
- likelyWeightsValid = false;
- }
-
- if (verifyClassicWeights)
- {
- if (!fgProfileWeightsConsistent(outgoingWeightMin, outgoingWeightMax))
- {
- JITDUMP(" " FMT_BB " - outgoing min " FMT_WT " inconsistent with outgoing max " FMT_WT "\n",
- block->bbNum, outgoingWeightMin, outgoingWeightMax);
- classicWeightsValid = false;
- }
-
- if (!fgProfileWeightsConsistent(blockWeight, outgoingWeightMin))
- {
- JITDUMP(" " FMT_BB " - block weight " FMT_WT " inconsistent with outgoing min " FMT_WT "\n",
- block->bbNum, blockWeight, outgoingWeightMin);
- classicWeightsValid = false;
- }
-
- if (!fgProfileWeightsConsistent(blockWeight, outgoingWeightMax))
- {
- JITDUMP(" " FMT_BB " - block weight " FMT_WT " inconsistent with outgoing max " FMT_WT "\n",
- block->bbNum, blockWeight, outgoingWeightMax);
- classicWeightsValid = false;
- }
+ likelyWeightsValid = false;
}
if (verifyHasLikelihood)
@@ -5796,7 +5077,7 @@ bool Compiler::fgDebugCheckOutgoingProfileData(BasicBlock* block, ProfileChecks
}
}
- return classicWeightsValid && likelyWeightsValid;
+ return likelyWeightsValid;
}
#endif // DEBUG
diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp
index 7fba06f2b7b3c0..07681c75c0e95c 100644
--- a/src/coreclr/jit/importercalls.cpp
+++ b/src/coreclr/jit/importercalls.cpp
@@ -884,7 +884,21 @@ var_types Compiler::impImportCall(OPCODE opcode,
}
//-------------------------------------------------------------------------
- // The main group of arguments
+ // The main group of arguments, and the this pointer.
+
+ // 'this' is pushed on the IL stack before all call args, but if this is a
+ // constrained call 'this' is a byref that may need to be dereferenced.
+ // That dereference should happen _after_ all args, so we need to spill
+ // them if they can interfere.
+ bool hasThis;
+ hasThis = ((mflags & CORINFO_FLG_STATIC) == 0) && ((sig->callConv & CORINFO_CALLCONV_EXPLICITTHIS) == 0) &&
+ ((opcode != CEE_NEWOBJ) || (newobjThis != nullptr));
+
+ if (hasThis && (constraintCallThisTransform == CORINFO_DEREF_THIS))
+ {
+ impSpillSideEffects(false, CHECK_SPILL_ALL DEBUGARG(
+ "constrained call requires dereference for 'this' right before call"));
+ }
impPopCallArgs(sig, call->AsCall());
if (extraArg.Node != nullptr)
@@ -904,8 +918,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
//-------------------------------------------------------------------------
// The "this" pointer
- if (((mflags & CORINFO_FLG_STATIC) == 0) && ((sig->callConv & CORINFO_CALLCONV_EXPLICITTHIS) == 0) &&
- !((opcode == CEE_NEWOBJ) && (newobjThis == nullptr)))
+ if (hasThis)
{
GenTree* obj;
@@ -4717,6 +4730,14 @@ GenTree* Compiler::impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic,
ClassLayout* toLayout = nullptr;
var_types toType = TypeHandleToVarType(toTypeHnd, &toLayout);
+ if (fromType == TYP_REF || info.compCompHnd->isNullableType(fromTypeHnd) != TypeCompareState::MustNot ||
+ toType == TYP_REF || info.compCompHnd->isNullableType(toTypeHnd) != TypeCompareState::MustNot)
+ {
+ // Fallback to the software implementation to throw when the types fail a "default(T) is not null"
+ // check.
+ return nullptr;
+ }
+
unsigned fromSize = fromLayout != nullptr ? fromLayout->GetSize() : genTypeSize(fromType);
unsigned toSize = toLayout != nullptr ? toLayout->GetSize() : genTypeSize(toType);
@@ -4729,8 +4750,6 @@ GenTree* Compiler::impSRCSUnsafeIntrinsic(NamedIntrinsic intrinsic,
return nullptr;
}
- assert((fromType != TYP_REF) && (toType != TYP_REF));
-
GenTree* op1 = impPopStack().val;
op1 = impImplicitR4orR8Cast(op1, fromType);
diff --git a/src/coreclr/jit/jitconfigvalues.h b/src/coreclr/jit/jitconfigvalues.h
index 23bfec85efd5be..700cd33bd6bf2f 100644
--- a/src/coreclr/jit/jitconfigvalues.h
+++ b/src/coreclr/jit/jitconfigvalues.h
@@ -158,9 +158,13 @@ CONFIG_INTEGER(JitPrintInlinedMethodsVerbose, W("JitPrintInlinedMethodsVerboseLe
CONFIG_METHODSET(JitPrintInlinedMethods, W("JitPrintInlinedMethods"))
CONFIG_METHODSET(JitPrintDevirtualizedMethods, W("JitPrintDevirtualizedMethods"))
-
// -1: just do internal checks (CHECK_HASLIKELIHOOD | CHECK_LIKELIHOODSUM | RAISE_ASSERT)
-// Else bitflag of ProfileChecks enum.
+// Else bitflag:
+// - 0x1: check edges have likelihoods
+// - 0x2: check edge likelihoods sum to 1.0
+// - 0x4: fully check likelihoods
+// - 0x8: assert on check failure
+// - 0x10: check block profile weights
CONFIG_INTEGER(JitProfileChecks, W("JitProfileChecks"), -1)
CONFIG_INTEGER(JitRequired, W("JITRequired"), -1)
diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp
index 3f1031f6a2cccd..5eb39435a51543 100644
--- a/src/coreclr/jit/lclvars.cpp
+++ b/src/coreclr/jit/lclvars.cpp
@@ -1804,7 +1804,8 @@ void Compiler::lvaClassifyParameterABI()
}
else
#endif
-#if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_ARM)
+#if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_ARM) || \
+ defined(TARGET_RISCV64)
{
PlatformClassifier classifier(cInfo);
lvaClassifyParameterABI(classifier);
diff --git a/src/coreclr/jit/lowerarmarch.cpp b/src/coreclr/jit/lowerarmarch.cpp
index 9731331885becf..cbdc886ee2802b 100644
--- a/src/coreclr/jit/lowerarmarch.cpp
+++ b/src/coreclr/jit/lowerarmarch.cpp
@@ -295,6 +295,74 @@ bool Lowering::IsContainableUnaryOrBinaryOp(GenTree* parentNode, GenTree* childN
return false;
}
+ if (childNode->OperIs(GT_ROL, GT_ROR))
+ {
+ // Find "a op (b rotate cns)"
+
+ if (childNode->gtGetOp1()->isContained())
+ {
+ // Cannot contain if the childs op1 is already contained
+ return false;
+ }
+
+ GenTree* rotateAmountNode = childNode->gtGetOp2();
+
+ if (!rotateAmountNode->IsCnsIntOrI())
+ {
+ // Cannot contain if the childs op2 is not a constant
+ return false;
+ }
+
+ const ssize_t wrapAmount = (static_cast(genTypeSize(parentNode)) * BITS_PER_BYTE);
+ assert((wrapAmount == 32) || (wrapAmount == 64));
+
+ // Rotation is circular, so normalize to [0, wrapAmount - 1]
+ ssize_t rotateAmount = rotateAmountNode->AsIntCon()->IconValue() % wrapAmount;
+ assert((rotateAmount >= 0) && (rotateAmount <= (wrapAmount - 1)));
+
+ if (childNode->OperIs(GT_ROL))
+ {
+ // The actual instructions only encode rotate right but
+ // since rotating left by 1 is equivalen to rotating
+ // right by (rotateAmount - 1), we can fix things here.
+
+ childNode->SetOper(GT_ROR);
+ rotateAmount = wrapAmount - rotateAmount;
+ }
+
+ rotateAmountNode->AsIntCon()->SetIconValue(rotateAmount);
+ assert(childNode->OperIs(GT_ROR));
+
+ if (parentNode->OperIs(GT_AND))
+ {
+ // These operations can still report flags
+
+ if (IsInvariantInRange(childNode, parentNode))
+ {
+ assert(rotateAmountNode->isContained());
+ return true;
+ }
+ }
+
+ if ((parentNode->gtFlags & GTF_SET_FLAGS) != 0)
+ {
+ // Cannot contain if the parent operation needs to set flags
+ return false;
+ }
+
+ if (parentNode->OperIs(GT_OR, GT_XOR))
+ {
+ if (IsInvariantInRange(childNode, parentNode))
+ {
+ assert(rotateAmountNode->isContained());
+ return true;
+ }
+ }
+
+ // TODO: Handle BIC/BICS, EON, MVN, ORN, TST
+ return false;
+ }
+
if (childNode->OperIs(GT_NEG))
{
// If we have a contained LSH, RSH or RSZ, we can still contain NEG if the parent is a EQ or NE.
diff --git a/src/coreclr/jit/lsrabuild.cpp b/src/coreclr/jit/lsrabuild.cpp
index d1825f44696611..3ee0f88ee2214f 100644
--- a/src/coreclr/jit/lsrabuild.cpp
+++ b/src/coreclr/jit/lsrabuild.cpp
@@ -3511,11 +3511,11 @@ int LinearScan::BuildOperandUses(GenTree* node, regMaskTP candidates)
// ANDs may be contained in a chain.
return BuildBinaryUses(node->AsOp(), candidates);
}
- if (node->OperIs(GT_NEG, GT_CAST, GT_LSH, GT_RSH, GT_RSZ))
+ if (node->OperIs(GT_NEG, GT_CAST, GT_LSH, GT_RSH, GT_RSZ, GT_ROR))
{
// NEG can be contained for mneg on arm64
// CAST and LSH for ADD with sign/zero extension
- // LSH, RSH, and RSZ for various "shifted register" instructions on arm64
+ // LSH, RSH, RSZ, and ROR for various "shifted register" instructions on arm64
return BuildOperandUses(node->gtGetOp1(), candidates);
}
#endif
diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp
index fd06ede79cb946..c8b08540276384 100644
--- a/src/coreclr/jit/morph.cpp
+++ b/src/coreclr/jit/morph.cpp
@@ -13213,80 +13213,28 @@ Compiler::FoldResult Compiler::fgFoldConditional(BasicBlock* block)
block->SetKindAndTargetEdge(BBJ_ALWAYS, block->GetFalseEdge());
}
- if (fgHaveValidEdgeWeights)
+ // We examine the taken edge (block -> bTaken)
+ // if block has valid profile weight and bTaken does not we try to adjust bTaken's weight
+ // else if bTaken has valid profile weight and block does not we try to adjust block's weight
+ // We can only adjust the block weights when (the edge block -> bTaken) is the only edge into bTaken
+ //
+ if (block->hasProfileWeight())
{
- // We are removing an edge from block to bNotTaken
- // and we have already computed the edge weights, so
- // we will try to adjust some of the weights
- //
- BasicBlock* bUpdated = nullptr; // non-NULL if we updated the weight of an internal block
-
- // We examine the taken edge (block -> bTaken)
- // if block has valid profile weight and bTaken does not we try to adjust bTaken's weight
- // else if bTaken has valid profile weight and block does not we try to adjust block's weight
- // We can only adjust the block weights when (the edge block -> bTaken) is the only edge into bTaken
- //
- if (block->hasProfileWeight())
- {
- // The edge weights for (block -> bTaken) are 100% of block's weight
-
- edgeTaken->setEdgeWeights(block->bbWeight, block->bbWeight, bTaken);
-
- if (!bTaken->hasProfileWeight())
- {
- if ((bTaken->countOfInEdges() == 1) || (bTaken->bbWeight < block->bbWeight))
- {
- // Update the weight of bTaken
- bTaken->inheritWeight(block);
- bUpdated = bTaken;
- }
- }
- }
- else if (bTaken->hasProfileWeight())
+ if (!bTaken->hasProfileWeight())
{
- if (bTaken->countOfInEdges() == 1)
+ if ((bTaken->countOfInEdges() == 1) || (bTaken->bbWeight < block->bbWeight))
{
- // There is only one in edge to bTaken
- edgeTaken->setEdgeWeights(bTaken->bbWeight, bTaken->bbWeight, bTaken);
-
- // Update the weight of block
- block->inheritWeight(bTaken);
- bUpdated = block;
+ // Update the weight of bTaken
+ bTaken->inheritWeight(block);
}
}
-
- if (bUpdated != nullptr)
+ }
+ else if (bTaken->hasProfileWeight())
+ {
+ if (bTaken->countOfInEdges() == 1)
{
- weight_t newMinWeight;
- weight_t newMaxWeight;
-
- FlowEdge* edge;
- // Now fix the weights of the edges out of 'bUpdated'
- switch (bUpdated->GetKind())
- {
- case BBJ_COND:
- edge = bUpdated->GetFalseEdge();
- newMaxWeight = bUpdated->bbWeight;
- newMinWeight = min(edge->edgeWeightMin(), newMaxWeight);
- edge->setEdgeWeights(newMinWeight, newMaxWeight, bUpdated->GetFalseTarget());
-
- edge = bUpdated->GetTrueEdge();
- newMaxWeight = bUpdated->bbWeight;
- newMinWeight = min(edge->edgeWeightMin(), newMaxWeight);
- edge->setEdgeWeights(newMinWeight, newMaxWeight, bUpdated->GetFalseTarget());
- break;
-
- case BBJ_ALWAYS:
- edge = bUpdated->GetTargetEdge();
- newMaxWeight = bUpdated->bbWeight;
- newMinWeight = min(edge->edgeWeightMin(), newMaxWeight);
- edge->setEdgeWeights(newMinWeight, newMaxWeight, bUpdated->Next());
- break;
-
- default:
- // We don't handle BBJ_SWITCH
- break;
- }
+ // Update the weight of block
+ block->inheritWeight(bTaken);
}
}
diff --git a/src/coreclr/jit/optimizebools.cpp b/src/coreclr/jit/optimizebools.cpp
index 07da4731252ff6..0524fc5d2022c6 100644
--- a/src/coreclr/jit/optimizebools.cpp
+++ b/src/coreclr/jit/optimizebools.cpp
@@ -1348,11 +1348,9 @@ void OptBoolsDsc::optOptimizeBoolsUpdateTrees()
(1.0 - origB1TrueLikelihood) + origB1TrueLikelihood * origB2FalseEdge->getLikelihood();
}
- // Fix B1 true edge likelihood and min/max weights
+ // Fix B1 true edge likelihood
//
origB1TrueEdge->setLikelihood(newB1TrueLikelihood);
- weight_t const newB1TrueWeight = m_b1->bbWeight * newB1TrueLikelihood;
- origB1TrueEdge->setEdgeWeights(newB1TrueWeight, newB1TrueWeight, m_b1->GetTrueTarget());
assert(m_b1->KindIs(BBJ_COND));
assert(m_b2->KindIs(BBJ_COND));
@@ -1367,11 +1365,9 @@ void OptBoolsDsc::optOptimizeBoolsUpdateTrees()
FlowEdge* const newB1FalseEdge = origB2FalseEdge;
m_b1->SetFalseEdge(newB1FalseEdge);
- // Fix B1 false edge likelihood and min/max weights.
+ // Fix B1 false edge likelihood
//
newB1FalseEdge->setLikelihood(1.0 - newB1TrueLikelihood);
- weight_t const newB1FalseWeight = m_b1->bbWeight * (1.0 - newB1TrueLikelihood);
- newB1FalseEdge->setEdgeWeights(newB1FalseWeight, newB1FalseWeight, m_b1->GetTrueTarget());
}
// Get rid of the second block
diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp
index 09921b2d3aebe8..f2de86fcdef21f 100644
--- a/src/coreclr/jit/optimizer.cpp
+++ b/src/coreclr/jit/optimizer.cpp
@@ -2315,54 +2315,6 @@ bool Compiler::optInvertWhileLoop(BasicBlock* block)
weightTop);
bTest->inheritWeight(bTop);
- // Determine the new edge weights.
- //
- // We project the next/jump ratio for block and bTest by using
- // the original likelihoods out of bTest.
- //
- // Note "next" is the loop top block, not bTest's bbNext,
- // we'll call this latter block "after".
- //
- weight_t const testToNextLikelihood = min(1.0, weightTop / weightTest);
- weight_t const testToAfterLikelihood = 1.0 - testToNextLikelihood;
-
- // Adjust edges out of bTest (which now has weight weightTop)
- //
- weight_t const testToNextWeight = weightTop * testToNextLikelihood;
- weight_t const testToAfterWeight = weightTop * testToAfterLikelihood;
-
- FlowEdge* const edgeTestToNext = bTest->GetTrueEdge();
- FlowEdge* const edgeTestToAfter = bTest->GetFalseEdge();
-
- JITDUMP("Setting weight of " FMT_BB " -> " FMT_BB " to " FMT_WT " (iterate loop)\n", bTest->bbNum, bTop->bbNum,
- testToNextWeight);
- JITDUMP("Setting weight of " FMT_BB " -> " FMT_BB " to " FMT_WT " (exit loop)\n", bTest->bbNum,
- bTest->Next()->bbNum, testToAfterWeight);
-
- edgeTestToNext->setEdgeWeights(testToNextWeight, testToNextWeight, bTop);
- edgeTestToAfter->setEdgeWeights(testToAfterWeight, testToAfterWeight, bTest->GetFalseTarget());
-
- // Adjust edges out of block, using the same distribution.
- //
- JITDUMP("Profile weight of " FMT_BB " remains unchanged at " FMT_WT "\n", block->bbNum, weightBlock);
-
- weight_t const blockToNextLikelihood = testToNextLikelihood;
- weight_t const blockToAfterLikelihood = testToAfterLikelihood;
-
- weight_t const blockToNextWeight = weightBlock * blockToNextLikelihood;
- weight_t const blockToAfterWeight = weightBlock * blockToAfterLikelihood;
-
- FlowEdge* const edgeBlockToNext = bNewCond->GetFalseEdge();
- FlowEdge* const edgeBlockToAfter = bNewCond->GetTrueEdge();
-
- JITDUMP("Setting weight of " FMT_BB " -> " FMT_BB " to " FMT_WT " (enter loop)\n", bNewCond->bbNum,
- bNewCond->GetFalseTarget()->bbNum, blockToNextWeight);
- JITDUMP("Setting weight of " FMT_BB " -> " FMT_BB " to " FMT_WT " (avoid loop)\n", bNewCond->bbNum,
- bNewCond->GetTrueTarget()->bbNum, blockToAfterWeight);
-
- edgeBlockToNext->setEdgeWeights(blockToNextWeight, blockToNextWeight, bNewCond->GetFalseTarget());
- edgeBlockToAfter->setEdgeWeights(blockToAfterWeight, blockToAfterWeight, bNewCond->GetTrueTarget());
-
#ifdef DEBUG
// If we're checking profile data, see if profile for the two target blocks is consistent.
//
@@ -3232,91 +3184,6 @@ bool Compiler::optCanonicalizeExit(FlowGraphNaturalLoop* loop, BasicBlock* exit)
return true;
}
-//-----------------------------------------------------------------------------
-// optEstimateEdgeLikelihood: Given a block "from" that may transfer control to
-// "to", estimate the likelihood that this will happen taking profile into
-// account if available.
-//
-// Parameters:
-// from - From block
-// to - To block
-// fromProfile - [out] Whether or not the estimate is based on profile data
-//
-// Returns:
-// Estimated likelihood of the edge being taken.
-//
-weight_t Compiler::optEstimateEdgeLikelihood(BasicBlock* from, BasicBlock* to, bool* fromProfile)
-{
- *fromProfile = (from->HasFlag(BBF_PROF_WEIGHT) != BBF_EMPTY) && (to->HasFlag(BBF_PROF_WEIGHT) != BBF_EMPTY);
- if (!fgIsUsingProfileWeights() || !from->HasFlag(BBF_PROF_WEIGHT) || !to->HasFlag(BBF_PROF_WEIGHT) ||
- from->KindIs(BBJ_ALWAYS))
- {
- return 1.0 / from->NumSucc(this);
- }
-
- bool useEdgeWeights = fgHaveValidEdgeWeights;
-
- weight_t takenCount = 0;
- weight_t notTakenCount = 0;
-
- if (useEdgeWeights)
- {
- from->VisitRegularSuccs(this, [&, to](BasicBlock* succ) {
- *fromProfile &= succ->hasProfileWeight();
- FlowEdge* edge = fgGetPredForBlock(succ, from);
- weight_t edgeWeight = (edge->edgeWeightMin() + edge->edgeWeightMax()) / 2.0;
-
- if (succ == to)
- {
- takenCount += edgeWeight;
- }
- else
- {
- notTakenCount += edgeWeight;
- }
- return BasicBlockVisit::Continue;
- });
-
- // Watch out for cases where edge weights were not properly maintained
- // so that it appears no profile flow goes to 'to'.
- //
- useEdgeWeights = !fgProfileWeightsConsistent(takenCount, BB_ZERO_WEIGHT);
- }
-
- if (!useEdgeWeights)
- {
- takenCount = 0;
- notTakenCount = 0;
-
- from->VisitRegularSuccs(this, [&, to](BasicBlock* succ) {
- *fromProfile &= succ->hasProfileWeight();
- if (succ == to)
- {
- takenCount += succ->bbWeight;
- }
- else
- {
- notTakenCount += succ->bbWeight;
- }
-
- return BasicBlockVisit::Continue;
- });
- }
-
- if (!*fromProfile)
- {
- return 1.0 / from->NumSucc(this);
- }
-
- if (fgProfileWeightsConsistent(takenCount, BB_ZERO_WEIGHT))
- {
- return 0;
- }
-
- weight_t likelihood = takenCount / (takenCount + notTakenCount);
- return likelihood;
-}
-
//-----------------------------------------------------------------------------
// optSetWeightForPreheaderOrExit: Set the weight of a newly created preheader
// or exit, after it has been added to the flowgraph.
@@ -3327,52 +3194,34 @@ weight_t Compiler::optEstimateEdgeLikelihood(BasicBlock* from, BasicBlock* to, b
//
void Compiler::optSetWeightForPreheaderOrExit(FlowGraphNaturalLoop* loop, BasicBlock* block)
{
- bool hasProfWeight = true;
-
- assert(block->GetUniqueSucc() != nullptr);
- // Inherit first estimate from the target target; optEstimateEdgeLikelihood
- // may use it in its estimate if we do not have edge weights to estimate
- // from (we also assume the edges into 'block' already inherited their edge
- // weights from the previous edge).
- block->inheritWeight(block->GetTarget());
+ bool hasProfWeight = true;
+ weight_t newWeight = BB_ZERO_WEIGHT;
- weight_t newWeight = BB_ZERO_WEIGHT;
- for (FlowEdge* edge : block->PredEdges())
+ for (FlowEdge* const edge : block->PredEdges())
{
- BasicBlock* predBlock = edge->getSourceBlock();
-
- bool fromProfile = false;
- weight_t likelihood = optEstimateEdgeLikelihood(predBlock, block, &fromProfile);
- hasProfWeight &= fromProfile;
-
- weight_t contribution = predBlock->bbWeight * likelihood;
- JITDUMP(" Estimated likelihood " FMT_BB " -> " FMT_BB " to be " FMT_WT " (contribution: " FMT_WT ")\n",
- predBlock->bbNum, block->bbNum, likelihood, contribution);
-
- newWeight += contribution;
-
- // Normalize pred -> new block weight
- edge->setEdgeWeights(contribution, contribution, block);
+ newWeight += edge->getLikelyWeight();
+ hasProfWeight &= edge->getSourceBlock()->hasProfileWeight();
}
- block->RemoveFlags(BBF_PROF_WEIGHT | BBF_RUN_RARELY);
-
block->bbWeight = newWeight;
+
if (hasProfWeight)
{
block->SetFlags(BBF_PROF_WEIGHT);
}
+ else
+ {
+ block->RemoveFlags(BBF_PROF_WEIGHT);
+ }
if (newWeight == BB_ZERO_WEIGHT)
{
block->SetFlags(BBF_RUN_RARELY);
- return;
}
-
- // Normalize block -> target weight
- FlowEdge* const edgeFromBlock = block->GetTargetEdge();
- assert(edgeFromBlock != nullptr);
- edgeFromBlock->setEdgeWeights(block->bbWeight, block->bbWeight, block->GetTarget());
+ else
+ {
+ block->RemoveFlags(BBF_RUN_RARELY);
+ }
}
/*****************************************************************************
diff --git a/src/coreclr/jit/rangecheck.cpp b/src/coreclr/jit/rangecheck.cpp
index 2328dba7d63688..e1046de8b99863 100644
--- a/src/coreclr/jit/rangecheck.cpp
+++ b/src/coreclr/jit/rangecheck.cpp
@@ -353,7 +353,7 @@ void RangeCheck::OptimizeRangeCheck(BasicBlock* block, Statement* stmt, GenTree*
return;
}
- if (DoesOverflow(block, treeIndex))
+ if (DoesOverflow(block, treeIndex, range))
{
JITDUMP("Method determined to overflow.\n");
return;
@@ -773,6 +773,22 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
isConstantAssertion = true;
}
+ // Current assertion asserts a bounds check does not throw
+ else if (curAssertion->IsBoundsCheckNoThrow())
+ {
+ ValueNum indexVN = curAssertion->op1.bnd.vnIdx;
+ ValueNum lenVN = curAssertion->op1.bnd.vnLen;
+ if (normalLclVN == indexVN)
+ {
+ isUnsigned = true;
+ cmpOper = GT_LT;
+ limit = Limit(Limit::keBinOpArray, lenVN, 0);
+ }
+ else
+ {
+ continue;
+ }
+ }
// Current assertion is not supported, ignore it
else
{
@@ -782,7 +798,8 @@ void RangeCheck::MergeEdgeAssertions(ValueNum normalLclVN, ASSERT_VALARG_TP asse
assert(limit.IsBinOpArray() || limit.IsConstant());
// Make sure the assertion is of the form != 0 or == 0 if it isn't a constant assertion.
- if (!isConstantAssertion && (curAssertion->op2.vn != m_pCompiler->vnStore->VNZeroForType(TYP_INT)))
+ if (!isConstantAssertion && (curAssertion->assertionKind != Compiler::OAK_NO_THROW) &&
+ (curAssertion->op2.vn != m_pCompiler->vnStore->VNZeroForType(TYP_INT)))
{
continue;
}
@@ -1235,17 +1252,17 @@ bool RangeCheck::MultiplyOverflows(Limit& limit1, Limit& limit2)
}
// Does the bin operation overflow.
-bool RangeCheck::DoesBinOpOverflow(BasicBlock* block, GenTreeOp* binop)
+bool RangeCheck::DoesBinOpOverflow(BasicBlock* block, GenTreeOp* binop, const Range& range)
{
GenTree* op1 = binop->gtGetOp1();
GenTree* op2 = binop->gtGetOp2();
- if (!m_pSearchPath->Lookup(op1) && DoesOverflow(block, op1))
+ if (!m_pSearchPath->Lookup(op1) && DoesOverflow(block, op1, range))
{
return true;
}
- if (!m_pSearchPath->Lookup(op2) && DoesOverflow(block, op2))
+ if (!m_pSearchPath->Lookup(op2) && DoesOverflow(block, op2, range))
{
return true;
}
@@ -1279,7 +1296,7 @@ bool RangeCheck::DoesBinOpOverflow(BasicBlock* block, GenTreeOp* binop)
}
// Check if the var definition the rhs involves arithmetic that overflows.
-bool RangeCheck::DoesVarDefOverflow(GenTreeLclVarCommon* lcl)
+bool RangeCheck::DoesVarDefOverflow(BasicBlock* block, GenTreeLclVarCommon* lcl, const Range& range)
{
LclSsaVarDsc* ssaDef = GetSsaDefStore(lcl);
if (ssaDef == nullptr)
@@ -1291,10 +1308,25 @@ bool RangeCheck::DoesVarDefOverflow(GenTreeLclVarCommon* lcl)
}
return true;
}
- return DoesOverflow(ssaDef->GetBlock(), ssaDef->GetDefNode()->Data());
+
+ // We can use intermediate assertions about the local to prove that any
+ // overflow on this path does not matter for the range computed.
+ Range assertionRange = Range(Limit(Limit::keUnknown));
+ MergeAssertion(block, lcl, &assertionRange DEBUGARG(0));
+
+ // But only if the range from the assertion is more strict than the global
+ // range computed; otherwise we might still have used the def's value to
+ // tighten the range of the global range.
+ Range merged = RangeOps::Merge(range, assertionRange, false);
+ if (merged.LowerLimit().Equals(range.LowerLimit()) && merged.UpperLimit().Equals(range.UpperLimit()))
+ {
+ return false;
+ }
+
+ return DoesOverflow(ssaDef->GetBlock(), ssaDef->GetDefNode()->Data(), range);
}
-bool RangeCheck::DoesPhiOverflow(BasicBlock* block, GenTree* expr)
+bool RangeCheck::DoesPhiOverflow(BasicBlock* block, GenTree* expr, const Range& range)
{
for (GenTreePhi::Use& use : expr->AsPhi()->Uses())
{
@@ -1303,7 +1335,7 @@ bool RangeCheck::DoesPhiOverflow(BasicBlock* block, GenTree* expr)
{
continue;
}
- if (DoesOverflow(block, arg))
+ if (DoesOverflow(block, arg, range))
{
return true;
}
@@ -1311,17 +1343,30 @@ bool RangeCheck::DoesPhiOverflow(BasicBlock* block, GenTree* expr)
return false;
}
-bool RangeCheck::DoesOverflow(BasicBlock* block, GenTree* expr)
+//------------------------------------------------------------------------
+// DoesOverflow: Check if the computation of "expr" may have overflowed.
+//
+// Arguments:
+// block - the block that contains `expr`
+// expr - expression to check overflow of
+// range - range that we believe "expr" to be in without accounting for
+// overflow; used to ignore potential overflow on paths where
+// we can prove the value is in this range regardless.
+//
+// Return value:
+// True if the computation may have involved an impactful overflow.
+//
+bool RangeCheck::DoesOverflow(BasicBlock* block, GenTree* expr, const Range& range)
{
bool overflows = false;
if (!GetOverflowMap()->Lookup(expr, &overflows))
{
- overflows = ComputeDoesOverflow(block, expr);
+ overflows = ComputeDoesOverflow(block, expr, range);
}
return overflows;
}
-bool RangeCheck::ComputeDoesOverflow(BasicBlock* block, GenTree* expr)
+bool RangeCheck::ComputeDoesOverflow(BasicBlock* block, GenTree* expr, const Range& range)
{
JITDUMP("Does overflow [%06d]?\n", Compiler::dspTreeID(expr));
m_pSearchPath->Set(expr, block, SearchPath::Overwrite);
@@ -1343,17 +1388,17 @@ bool RangeCheck::ComputeDoesOverflow(BasicBlock* block, GenTree* expr)
}
else if (expr->OperIs(GT_COMMA))
{
- overflows = ComputeDoesOverflow(block, expr->gtEffectiveVal());
+ overflows = ComputeDoesOverflow(block, expr->gtEffectiveVal(), range);
}
// Check if the var def has rhs involving arithmetic that overflows.
else if (expr->IsLocal())
{
- overflows = DoesVarDefOverflow(expr->AsLclVarCommon());
+ overflows = DoesVarDefOverflow(block, expr->AsLclVarCommon(), range);
}
// Check if add overflows.
else if (expr->OperIs(GT_ADD, GT_MUL))
{
- overflows = DoesBinOpOverflow(block, expr->AsOp());
+ overflows = DoesBinOpOverflow(block, expr->AsOp(), range);
}
// These operators don't overflow.
// Actually, GT_LSH can overflow so it depends on the analysis done in ComputeRangeForBinOp
@@ -1364,11 +1409,11 @@ bool RangeCheck::ComputeDoesOverflow(BasicBlock* block, GenTree* expr)
// Walk through phi arguments to check if phi arguments involve arithmetic that overflows.
else if (expr->OperIs(GT_PHI))
{
- overflows = DoesPhiOverflow(block, expr);
+ overflows = DoesPhiOverflow(block, expr, range);
}
else if (expr->OperIs(GT_CAST))
{
- overflows = ComputeDoesOverflow(block, expr->gtGetOp1());
+ overflows = ComputeDoesOverflow(block, expr->gtGetOp1(), range);
}
GetOverflowMap()->Set(expr, overflows, OverflowMap::Overwrite);
m_pSearchPath->Remove(expr);
diff --git a/src/coreclr/jit/rangecheck.h b/src/coreclr/jit/rangecheck.h
index 9d7b064387174a..de44b88d3ae52d 100644
--- a/src/coreclr/jit/rangecheck.h
+++ b/src/coreclr/jit/rangecheck.h
@@ -199,7 +199,7 @@ struct Limit
return false;
}
- bool Equals(Limit& l)
+ bool Equals(const Limit& l) const
{
switch (type)
{
@@ -262,11 +262,21 @@ struct Range
{
}
+ const Limit& UpperLimit() const
+ {
+ return uLimit;
+ }
+
Limit& UpperLimit()
{
return uLimit;
}
+ const Limit& LowerLimit() const
+ {
+ return lLimit;
+ }
+
Limit& LowerLimit()
{
return lLimit;
@@ -440,12 +450,12 @@ struct RangeOps
// Given two ranges "r1" and "r2", do a Phi merge. If "monIncreasing" is true,
// then ignore the dependent variables for the lower bound but not for the upper bound.
- static Range Merge(Range& r1, Range& r2, bool monIncreasing)
+ static Range Merge(const Range& r1, const Range& r2, bool monIncreasing)
{
- Limit& r1lo = r1.LowerLimit();
- Limit& r1hi = r1.UpperLimit();
- Limit& r2lo = r2.LowerLimit();
- Limit& r2hi = r2.UpperLimit();
+ const Limit& r1lo = r1.LowerLimit();
+ const Limit& r1hi = r1.UpperLimit();
+ const Limit& r2lo = r2.LowerLimit();
+ const Limit& r2hi = r2.UpperLimit();
// Take care of lo part.
Range result = Limit(Limit::keUnknown);
@@ -689,19 +699,19 @@ class RangeCheck
bool MultiplyOverflows(Limit& limit1, Limit& limit2);
// Does the binary operation between the operands overflow? Check recursively.
- bool DoesBinOpOverflow(BasicBlock* block, GenTreeOp* binop);
+ bool DoesBinOpOverflow(BasicBlock* block, GenTreeOp* binop, const Range& range);
// Do the phi operands involve a definition that could overflow?
- bool DoesPhiOverflow(BasicBlock* block, GenTree* expr);
+ bool DoesPhiOverflow(BasicBlock* block, GenTree* expr, const Range& range);
// Find the def of the "expr" local and recurse on the arguments if any of them involve a
// calculation that overflows.
- bool DoesVarDefOverflow(GenTreeLclVarCommon* lcl);
+ bool DoesVarDefOverflow(BasicBlock* block, GenTreeLclVarCommon* lcl, const Range& range);
- bool ComputeDoesOverflow(BasicBlock* block, GenTree* expr);
+ bool ComputeDoesOverflow(BasicBlock* block, GenTree* expr, const Range& range);
- // Does the current "expr" which is a use involve a definition, that overflows.
- bool DoesOverflow(BasicBlock* block, GenTree* tree);
+ // Does the current "expr", which is a use, involve a definition that overflows.
+ bool DoesOverflow(BasicBlock* block, GenTree* tree, const Range& range);
// Widen the range by first checking if the induction variable is monotonically increasing.
// Requires "pRange" to be partially computed.
diff --git a/src/coreclr/jit/targetriscv64.cpp b/src/coreclr/jit/targetriscv64.cpp
index 5c51f66f83c402..29f71dc76d8fa2 100644
--- a/src/coreclr/jit/targetriscv64.cpp
+++ b/src/coreclr/jit/targetriscv64.cpp
@@ -24,4 +24,154 @@ const regNumber fltArgRegs [] = {REG_FLTARG_0, REG_FLTARG_1, REG_FLTARG_2, REG_F
const regMaskTP fltArgMasks[] = {RBM_FLTARG_0, RBM_FLTARG_1, RBM_FLTARG_2, RBM_FLTARG_3, RBM_FLTARG_4, RBM_FLTARG_5, RBM_FLTARG_6, RBM_FLTARG_7 };
// clang-format on
+//-----------------------------------------------------------------------------
+// RiscV64Classifier:
+// Construct a new instance of the RISC-V 64 ABI classifier.
+//
+// Parameters:
+// info - Info about the method being classified.
+//
+RiscV64Classifier::RiscV64Classifier(const ClassifierInfo& info)
+ : m_info(info)
+ , m_intRegs(intArgRegs, ArrLen(intArgRegs))
+ , m_floatRegs(fltArgRegs, ArrLen(fltArgRegs))
+{
+}
+
+//-----------------------------------------------------------------------------
+// Classify:
+// Classify a parameter for the RISC-V 64 ABI.
+//
+// Parameters:
+// comp - Compiler instance
+// type - The type of the parameter
+// structLayout - The layout of the struct. Expected to be non-null if
+// varTypeIsStruct(type) is true.
+// wellKnownParam - Well known type of the parameter (if it may affect its ABI classification)
+//
+// Returns:
+// Classification information for the parameter.
+//
+ABIPassingInformation RiscV64Classifier::Classify(Compiler* comp,
+ var_types type,
+ ClassLayout* structLayout,
+ WellKnownArg /*wellKnownParam*/)
+{
+ assert(!m_info.IsVarArgs); // TODO: varargs currently not supported on RISC-V
+
+ StructFloatFieldInfoFlags flags = STRUCT_NO_FLOAT_FIELD;
+ unsigned intFields = 0, floatFields = 0;
+ unsigned passedSize;
+
+ if (varTypeIsStruct(type))
+ {
+ passedSize = structLayout->GetSize();
+ if (passedSize > MAX_PASS_MULTIREG_BYTES)
+ {
+ passedSize = TARGET_POINTER_SIZE; // pass by reference
+ }
+ else if (!structLayout->IsBlockLayout())
+ {
+ flags = (StructFloatFieldInfoFlags)comp->info.compCompHnd->getRISCV64PassStructInRegisterFlags(
+ structLayout->GetClassHandle());
+
+ if ((flags & STRUCT_FLOAT_FIELD_ONLY_ONE) != 0)
+ {
+ floatFields = 1;
+ }
+ else if ((flags & STRUCT_FLOAT_FIELD_ONLY_TWO) != 0)
+ {
+ floatFields = 2;
+ }
+ else if (flags != STRUCT_NO_FLOAT_FIELD)
+ {
+ assert((flags & (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_SECOND)) != 0);
+ floatFields = 1;
+ intFields = 1;
+ }
+ }
+ }
+ else
+ {
+ assert(genTypeSize(type) <= TARGET_POINTER_SIZE);
+
+ if (varTypeIsFloating(type))
+ floatFields = 1;
+
+ passedSize = genTypeSize(type);
+ }
+
+ assert((floatFields > 0) || (intFields == 0));
+
+ auto PassSlot = [this](bool inFloatReg, unsigned offset, unsigned size) -> ABIPassingSegment {
+ assert(size > 0);
+ assert(size <= TARGET_POINTER_SIZE);
+ if (inFloatReg)
+ {
+ return ABIPassingSegment::InRegister(m_floatRegs.Dequeue(), offset, size);
+ }
+ else if (m_intRegs.Count() > 0)
+ {
+ return ABIPassingSegment::InRegister(m_intRegs.Dequeue(), offset, size);
+ }
+ else
+ {
+ assert((m_stackArgSize % TARGET_POINTER_SIZE) == 0);
+ ABIPassingSegment seg = ABIPassingSegment::OnStack(m_stackArgSize, offset, size);
+ m_stackArgSize += TARGET_POINTER_SIZE;
+ return seg;
+ }
+ };
+
+ if ((floatFields > 0) && (m_floatRegs.Count() >= floatFields) && (m_intRegs.Count() >= intFields))
+ {
+ // Hardware floating-point calling convention
+ if ((floatFields == 1) && (intFields == 0))
+ {
+ if (flags == STRUCT_NO_FLOAT_FIELD)
+ assert(varTypeIsFloating(type)); // standalone floating-point real
+ else
+ assert((flags & STRUCT_FLOAT_FIELD_ONLY_ONE) != 0); // struct containing just one FP real
+
+ return ABIPassingInformation::FromSegment(comp, ABIPassingSegment::InRegister(m_floatRegs.Dequeue(), 0,
+ passedSize));
+ }
+ else
+ {
+ assert(varTypeIsStruct(type));
+ assert((floatFields + intFields) == 2);
+ assert(flags != STRUCT_NO_FLOAT_FIELD);
+ assert((flags & STRUCT_FLOAT_FIELD_ONLY_ONE) == 0);
+
+ unsigned firstSize = ((flags & STRUCT_FIRST_FIELD_SIZE_IS8) != 0) ? 8 : 4;
+ unsigned secondSize = ((flags & STRUCT_SECOND_FIELD_SIZE_IS8) != 0) ? 8 : 4;
+ unsigned offset = max(firstSize, secondSize); // TODO: cover empty fields and custom offsets / alignments
+
+ bool isFirstFloat = (flags & (STRUCT_FLOAT_FIELD_ONLY_TWO | STRUCT_FLOAT_FIELD_FIRST)) != 0;
+ bool isSecondFloat = (flags & (STRUCT_FLOAT_FIELD_ONLY_TWO | STRUCT_FLOAT_FIELD_SECOND)) != 0;
+ assert(isFirstFloat || isSecondFloat);
+
+ return {2, new (comp, CMK_ABI) ABIPassingSegment[]{PassSlot(isFirstFloat, 0, firstSize),
+ PassSlot(isSecondFloat, offset, secondSize)}};
+ }
+ }
+ else
+ {
+ // Integer calling convention
+ if (passedSize <= TARGET_POINTER_SIZE)
+ {
+ return ABIPassingInformation::FromSegment(comp, PassSlot(false, 0, passedSize));
+ }
+ else
+ {
+ assert(varTypeIsStruct(type));
+ return {2, new (comp, CMK_ABI)
+ ABIPassingSegment[]{PassSlot(false, 0, TARGET_POINTER_SIZE),
+ PassSlot(false, TARGET_POINTER_SIZE, passedSize - TARGET_POINTER_SIZE)}};
+ }
+ }
+
+ unreached();
+}
+
#endif // TARGET_RISCV64
diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp
index 1fd85a96840d9b..0808d9d9711178 100644
--- a/src/coreclr/jit/valuenum.cpp
+++ b/src/coreclr/jit/valuenum.cpp
@@ -13169,10 +13169,101 @@ bool Compiler::fgValueNumberHelperCall(GenTreeCall* call)
// InvalidCastExc for these is set in VNForCast
break;
+ case CORINFO_HELP_READYTORUN_CHKCAST:
+ {
+ // This helper casts to a class determined by the entry point.
+ ssize_t addrValue = (ssize_t)call->gtEntryPoint.addr;
+ ValueNum callAddrVN = vnStore->VNForHandle(addrValue, GTF_ICON_FTN_ADDR);
+ vnpExc = vnStore->VNPExcSetSingleton(
+ vnStore->VNPairForFunc(TYP_REF, VNF_R2RInvalidCastExc,
+ vnStore->VNPNormalPair(
+ call->gtArgs.GetUserArgByIndex(0)->GetNode()->gtVNPair),
+ ValueNumPair(callAddrVN, callAddrVN)));
+ break;
+ }
+
+ case CORINFO_HELP_GETSHARED_GCSTATIC_BASE:
+ case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE:
+ case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS:
+ case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS:
+ case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE:
+ case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE:
+ case CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS:
+ case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS:
+ case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS:
+ // These all take (Module*, class ID) as parameters.
+ //
+ // Strictly speaking the exact possible exception thrown by the
+ // static constructor depends on heap state too, but given that
+ // the constructor is only invoked once we can model that for
+ // the same class the same exceptions are thrown. Downstream
+ // code like CSE/copy prop that makes use VNs innately need to
+ // establish some form of dominance around the individual trees
+ // that makes this ok.
+ //
+ vnpExc = vnStore->VNPExcSetSingleton(
+ vnStore->VNPairForFunc(TYP_REF, VNF_ClassInitExc,
+ vnStore->VNPNormalPair(
+ call->gtArgs.GetUserArgByIndex(0)->GetNode()->gtVNPair),
+ vnStore->VNPNormalPair(
+ call->gtArgs.GetUserArgByIndex(1)->GetNode()->gtVNPair)));
+ break;
+
+#ifdef FEATURE_READYTORUN
+ case CORINFO_HELP_READYTORUN_GCSTATIC_BASE:
+ case CORINFO_HELP_READYTORUN_NONGCSTATIC_BASE:
+ case CORINFO_HELP_READYTORUN_THREADSTATIC_BASE:
+ case CORINFO_HELP_READYTORUN_NONGCTHREADSTATIC_BASE:
+ case CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE:
+ {
+ // These are uniquely determined by the entry point.
+ ssize_t addrValue = (ssize_t)call->gtEntryPoint.addr;
+ ValueNum callAddrVN = vnStore->VNForHandle(addrValue, GTF_ICON_FTN_ADDR);
+ vnpExc = vnStore->VNPExcSetSingleton(
+ vnStore->VNPairForFunc(TYP_REF, VNF_R2RClassInitExc, ValueNumPair(callAddrVN, callAddrVN)));
+ break;
+ }
+#endif
+
+ case CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE:
+ case CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE:
+ case CORINFO_HELP_GETGENERICS_GCSTATIC_BASE:
+ case CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE:
+ // These take class handles as parameters.
+ vnpExc = vnStore->VNPExcSetSingleton(
+ vnStore->VNPairForFunc(TYP_REF, VNF_ClassInitGenericExc,
+ vnStore->VNPNormalPair(
+ call->gtArgs.GetUserArgByIndex(0)->GetNode()->gtVNPair)));
+ break;
+
+ case CORINFO_HELP_DIV:
+ case CORINFO_HELP_LDIV:
+ vnpExc = fgValueNumberDivisionExceptions(GT_DIV, call->gtArgs.GetUserArgByIndex(0)->GetNode(),
+ call->gtArgs.GetUserArgByIndex(1)->GetNode());
+ break;
+ case CORINFO_HELP_MOD:
+ case CORINFO_HELP_LMOD:
+ vnpExc = fgValueNumberDivisionExceptions(GT_MOD, call->gtArgs.GetUserArgByIndex(0)->GetNode(),
+ call->gtArgs.GetUserArgByIndex(1)->GetNode());
+ break;
+ case CORINFO_HELP_UDIV:
+ case CORINFO_HELP_ULDIV:
+ vnpExc = fgValueNumberDivisionExceptions(GT_UDIV, call->gtArgs.GetUserArgByIndex(0)->GetNode(),
+ call->gtArgs.GetUserArgByIndex(1)->GetNode());
+ break;
+ case CORINFO_HELP_UMOD:
+ case CORINFO_HELP_ULMOD:
+ vnpExc = fgValueNumberDivisionExceptions(GT_UMOD, call->gtArgs.GetUserArgByIndex(0)->GetNode(),
+ call->gtArgs.GetUserArgByIndex(1)->GetNode());
+ break;
+
default:
// Setup vnpExc with the information that multiple different exceptions
- // could be generated by this helper
- vnpExc = vnStore->VNPExcSetSingleton(vnStore->VNPairForFunc(TYP_REF, VNF_HelperMultipleExc));
+ // could be generated by this helper, in an opaque way
+ vnpExc =
+ vnStore->VNPExcSetSingleton(vnStore->VNPairForFunc(TYP_REF, VNF_HelperOpaqueExc,
+ vnStore->VNPairForExpr(compCurBB, TYP_I_IMPL)));
+ break;
}
}
@@ -13350,10 +13441,31 @@ void Compiler::fgValueNumberAddExceptionSetForIndirection(GenTree* tree, GenTree
//
void Compiler::fgValueNumberAddExceptionSetForDivision(GenTree* tree)
{
- genTreeOps oper = tree->OperGet();
+ ValueNumPair exceptions = fgValueNumberDivisionExceptions(tree->OperGet(), tree->gtGetOp1(), tree->gtGetOp2());
+ // Unpack, Norm,Exc for the tree's VN
+ ValueNumPair vnpTreeNorm;
+ ValueNumPair vnpTreeExc;
+ vnStore->VNPUnpackExc(tree->gtVNPair, &vnpTreeNorm, &vnpTreeExc);
+ ValueNumPair newExcSet = vnStore->VNPExcSetUnion(vnpTreeExc, exceptions);
+ tree->gtVNPair = vnStore->VNPWithExc(vnpTreeNorm, newExcSet);
+}
+
+//--------------------------------------------------------------------------------
+// fgValueNumberDivisionExceptions
+// Compute exception set for a division operation
+//
+// Arguments:
+// oper - Division operation (signed/unsigned division/modulo)
+// dividend - Tree representing dividend
+// divisor - Tree representing divisor
+//
+// Return Value:
+// VNP representing exception set
+//
+ValueNumPair Compiler::fgValueNumberDivisionExceptions(genTreeOps oper, GenTree* dividend, GenTree* divisor)
+{
// A Divide By Zero exception may be possible.
- // The divisor is held in tree->AsOp()->gtOp2
//
bool isUnsignedOper = (oper == GT_UDIV) || (oper == GT_UMOD);
bool needDivideByZeroExcLib = true;
@@ -13362,19 +13474,19 @@ void Compiler::fgValueNumberAddExceptionSetForDivision(GenTree* tree)
bool needArithmeticExcCon = !isUnsignedOper;
// Determine if we have a 32-bit or 64-bit divide operation
- var_types typ = genActualType(tree->TypeGet());
+ var_types typ = genActualType(dividend);
assert((typ == TYP_INT) || (typ == TYP_LONG));
- // Retrieve the Norm VN for op2 to use it for the DivideByZeroExc
- ValueNumPair vnpOp2Norm = vnStore->VNPNormalPair(tree->AsOp()->gtOp2->gtVNPair);
- ValueNum vnOp2NormLib = vnpOp2Norm.GetLiberal();
- ValueNum vnOp2NormCon = vnpOp2Norm.GetConservative();
+ // Retrieve the Norm VN for divisor to use it for the DivideByZeroExc
+ ValueNumPair vnpDisivorNorm = vnStore->VNPNormalPair(divisor->gtVNPair);
+ ValueNum vnDivisorNormLib = vnpDisivorNorm.GetLiberal();
+ ValueNum vnDivisorNormCon = vnpDisivorNorm.GetConservative();
if (typ == TYP_INT)
{
- if (vnStore->IsVNConstant(vnOp2NormLib))
+ if (vnStore->IsVNConstant(vnDivisorNormLib))
{
- INT32 kVal = vnStore->ConstantValue(vnOp2NormLib);
+ INT32 kVal = vnStore->ConstantValue(vnDivisorNormLib);
if (kVal != 0)
{
needDivideByZeroExcLib = false;
@@ -13384,9 +13496,9 @@ void Compiler::fgValueNumberAddExceptionSetForDivision(GenTree* tree)
needArithmeticExcLib = false;
}
}
- if (vnStore->IsVNConstant(vnOp2NormCon))
+ if (vnStore->IsVNConstant(vnDivisorNormCon))
{
- INT32 kVal = vnStore->ConstantValue(vnOp2NormCon);
+ INT32 kVal = vnStore->ConstantValue(vnDivisorNormCon);
if (kVal != 0)
{
needDivideByZeroExcCon = false;
@@ -13399,9 +13511,9 @@ void Compiler::fgValueNumberAddExceptionSetForDivision(GenTree* tree)
}
else // (typ == TYP_LONG)
{
- if (vnStore->IsVNConstant(vnOp2NormLib))
+ if (vnStore->IsVNConstant(vnDivisorNormLib))
{
- INT64 kVal = vnStore->ConstantValue(vnOp2NormLib);
+ INT64 kVal = vnStore->ConstantValue(vnDivisorNormLib);
if (kVal != 0)
{
needDivideByZeroExcLib = false;
@@ -13411,9 +13523,9 @@ void Compiler::fgValueNumberAddExceptionSetForDivision(GenTree* tree)
needArithmeticExcLib = false;
}
}
- if (vnStore->IsVNConstant(vnOp2NormCon))
+ if (vnStore->IsVNConstant(vnDivisorNormCon))
{
- INT64 kVal = vnStore->ConstantValue(vnOp2NormCon);
+ INT64 kVal = vnStore->ConstantValue(vnDivisorNormCon);
if (kVal != 0)
{
needDivideByZeroExcCon = false;
@@ -13426,26 +13538,26 @@ void Compiler::fgValueNumberAddExceptionSetForDivision(GenTree* tree)
}
// Retrieve the Norm VN for op1 to use it for the ArithmeticExc
- ValueNumPair vnpOp1Norm = vnStore->VNPNormalPair(tree->AsOp()->gtOp1->gtVNPair);
- ValueNum vnOp1NormLib = vnpOp1Norm.GetLiberal();
- ValueNum vnOp1NormCon = vnpOp1Norm.GetConservative();
+ ValueNumPair vnpDividendNorm = vnStore->VNPNormalPair(dividend->gtVNPair);
+ ValueNum vnDividendNormLib = vnpDividendNorm.GetLiberal();
+ ValueNum vnDividendNormCon = vnpDividendNorm.GetConservative();
if (needArithmeticExcLib || needArithmeticExcCon)
{
if (typ == TYP_INT)
{
- if (vnStore->IsVNConstant(vnOp1NormLib))
+ if (vnStore->IsVNConstant(vnDividendNormLib))
{
- INT32 kVal = vnStore->ConstantValue(vnOp1NormLib);
+ INT32 kVal = vnStore->ConstantValue(vnDividendNormLib);
if (!isUnsignedOper && (kVal != INT32_MIN))
{
needArithmeticExcLib = false;
}
}
- if (vnStore->IsVNConstant(vnOp1NormCon))
+ if (vnStore->IsVNConstant(vnDividendNormCon))
{
- INT32 kVal = vnStore->ConstantValue(vnOp1NormCon);
+ INT32 kVal = vnStore->ConstantValue(vnDividendNormCon);
if (!isUnsignedOper && (kVal != INT32_MIN))
{
@@ -13455,18 +13567,18 @@ void Compiler::fgValueNumberAddExceptionSetForDivision(GenTree* tree)
}
else // (typ == TYP_LONG)
{
- if (vnStore->IsVNConstant(vnOp1NormLib))
+ if (vnStore->IsVNConstant(vnDividendNormLib))
{
- INT64 kVal = vnStore->ConstantValue(vnOp1NormLib);
+ INT64 kVal = vnStore->ConstantValue(vnDividendNormLib);
if (!isUnsignedOper && (kVal != INT64_MIN))
{
needArithmeticExcLib = false;
}
}
- if (vnStore->IsVNConstant(vnOp1NormCon))
+ if (vnStore->IsVNConstant(vnDividendNormCon))
{
- INT64 kVal = vnStore->ConstantValue(vnOp1NormCon);
+ INT64 kVal = vnStore->ConstantValue(vnDividendNormCon);
if (!isUnsignedOper && (kVal != INT64_MIN))
{
@@ -13477,41 +13589,31 @@ void Compiler::fgValueNumberAddExceptionSetForDivision(GenTree* tree)
}
// Unpack, Norm,Exc for the tree's VN
- ValueNumPair vnpTreeNorm;
- ValueNumPair vnpTreeExc;
ValueNumPair vnpDivZeroExc = ValueNumStore::VNPForEmptyExcSet();
ValueNumPair vnpArithmExc = ValueNumStore::VNPForEmptyExcSet();
- vnStore->VNPUnpackExc(tree->gtVNPair, &vnpTreeNorm, &vnpTreeExc);
-
if (needDivideByZeroExcLib)
{
vnpDivZeroExc.SetLiberal(
- vnStore->VNExcSetSingleton(vnStore->VNForFunc(TYP_REF, VNF_DivideByZeroExc, vnOp2NormLib)));
+ vnStore->VNExcSetSingleton(vnStore->VNForFunc(TYP_REF, VNF_DivideByZeroExc, vnDivisorNormLib)));
}
if (needDivideByZeroExcCon)
{
vnpDivZeroExc.SetConservative(
- vnStore->VNExcSetSingleton(vnStore->VNForFunc(TYP_REF, VNF_DivideByZeroExc, vnOp2NormCon)));
+ vnStore->VNExcSetSingleton(vnStore->VNForFunc(TYP_REF, VNF_DivideByZeroExc, vnDivisorNormCon)));
}
if (needArithmeticExcLib)
{
vnpArithmExc.SetLiberal(vnStore->VNExcSetSingleton(
- vnStore->VNForFuncNoFolding(TYP_REF, VNF_ArithmeticExc, vnOp1NormLib, vnOp2NormLib)));
+ vnStore->VNForFuncNoFolding(TYP_REF, VNF_ArithmeticExc, vnDividendNormLib, vnDivisorNormLib)));
}
if (needArithmeticExcCon)
{
vnpArithmExc.SetConservative(vnStore->VNExcSetSingleton(
- vnStore->VNForFuncNoFolding(TYP_REF, VNF_ArithmeticExc, vnOp1NormLib, vnOp2NormCon)));
+ vnStore->VNForFuncNoFolding(TYP_REF, VNF_ArithmeticExc, vnDividendNormLib, vnDivisorNormCon)));
}
- // Combine vnpDivZeroExc with the exception set of tree
- ValueNumPair newExcSet = vnStore->VNPExcSetUnion(vnpTreeExc, vnpDivZeroExc);
- // Combine vnpArithmExc with the newExcSet
- newExcSet = vnStore->VNPExcSetUnion(newExcSet, vnpArithmExc);
-
- // Updated VN for tree, it now includes DivideByZeroExc and/or ArithmeticExc
- tree->gtVNPair = vnStore->VNPWithExc(vnpTreeNorm, newExcSet);
+ return vnStore->VNPExcSetUnion(vnpDivZeroExc, vnpArithmExc);
}
//--------------------------------------------------------------------------------
diff --git a/src/coreclr/jit/valuenumfuncs.h b/src/coreclr/jit/valuenumfuncs.h
index 128935847defdc..392cd58611e6e1 100644
--- a/src/coreclr/jit/valuenumfuncs.h
+++ b/src/coreclr/jit/valuenumfuncs.h
@@ -65,9 +65,14 @@ ValueNumFuncDef(ConvOverflowExc, 2, false, false, false, false) // Cast conve
// - (shifted left one bit; low bit encode whether source is unsigned.)
ValueNumFuncDef(DivideByZeroExc, 1, false, false, false, false) // Division by zero check. Args: 0: divisor value, throws when it is zero
ValueNumFuncDef(IndexOutOfRangeExc, 2, false, false, false, false) // Array bounds check, Args: 0: array length; 1: index value, throws when the bounds check fails.
-ValueNumFuncDef(InvalidCastExc, 2, false, false, false, false) // CastClass check, Args: 0: ref value being cast; 1: handle of type being cast to, throws when the cast fails.
+ValueNumFuncDef(InvalidCastExc, 2, false, false, false, false) // CastClass check, Args: 0: ref value being cast; 1: handle of type being cast to
+ValueNumFuncDef(R2RInvalidCastExc, 2, false, false, false, false) // CastClass check, Args: 0: ref value being cast; 1: entry point of R2R cast helper
ValueNumFuncDef(NewArrOverflowExc, 1, false, false, false, false) // Raises Integer overflow when Arg 0 is negative
-ValueNumFuncDef(HelperMultipleExc, 0, false, false, false, false) // Represents one or more different exceptions that could be thrown by a Jit Helper method
+ValueNumFuncDef(ClassInitExc, 2, false, false, false, false) // Represents exceptions thrown by static constructor for class. Args: 0: VN of module, 1: VN of class ID
+ValueNumFuncDef(R2RClassInitExc, 1, false, false, false, false) // Represents exceptions thrown by static constructor for class. Args: 0: VN of R2R entry point
+ValueNumFuncDef(ClassInitGenericExc, 2, false, false, false, false)// Represents exceptions thrown by static constructor for generic class. Args: 0: VN of class handle
+ValueNumFuncDef(HelperOpaqueExc, 1, false, false, false, false) // Represents opaque exceptions could be thrown by a JIT helper.
+ // Args: 0: Input to helper that uniquely determines exceptions thrown.
ValueNumFuncDef(Abs, 1, false, false, false, false)
ValueNumFuncDef(Acos, 1, false, false, false, false)
diff --git a/src/coreclr/nativeaot/Directory.Build.props b/src/coreclr/nativeaot/Directory.Build.props
index 42e6f968e0e1e9..d3277aa58ece73 100644
--- a/src/coreclr/nativeaot/Directory.Build.props
+++ b/src/coreclr/nativeaot/Directory.Build.props
@@ -21,6 +21,7 @@
$(TargetArchitecture)
arm
+ AnyCPU
true
false
@@ -78,20 +79,15 @@
- x64
- false
TARGET_64BIT;TARGET_AMD64;$(DefineConstants)
- x86
TARGET_32BIT;TARGET_X86;$(DefineConstants)
- arm
TARGET_32BIT;TARGET_ARM;$(DefineConstants)
- AnyCPU
TARGET_64BIT;TARGET_ARM64;$(DefineConstants)
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/CompatibilitySuppressions.xml b/src/coreclr/nativeaot/System.Private.CoreLib/src/CompatibilitySuppressions.xml
index 9d09ab7e105928..770514a671adfc 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/CompatibilitySuppressions.xml
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/CompatibilitySuppressions.xml
@@ -55,11 +55,11 @@
CP0001
- T:Internal.Metadata.NativeFormat.ConstantBoxedEnumValue
+ T:Internal.Metadata.NativeFormat.ConstantEnumValue
CP0001
- T:Internal.Metadata.NativeFormat.ConstantBoxedEnumValueHandle
+ T:Internal.Metadata.NativeFormat.ConstantEnumValueHandle
CP0001
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs
index eb4289695020ec..e5f82238f0b51e 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/MetadataReaderExtensions.NativeFormat.cs
@@ -141,9 +141,9 @@ public static bool IsConstructor(ref Method method, MetadataReader reader)
return nameHandle.StringEquals(ConstructorInfo.ConstructorName, reader) || nameHandle.StringEquals(ConstructorInfo.TypeConstructorName, reader);
}
- private static Exception ParseBoxedEnumConstantValue(this ConstantBoxedEnumValueHandle handle, MetadataReader reader, out object value)
+ private static Exception ParseEnumConstantValue(this ConstantEnumValueHandle handle, MetadataReader reader, out object value)
{
- ConstantBoxedEnumValue record = handle.GetConstantBoxedEnumValue(reader);
+ ConstantEnumValue record = handle.GetConstantEnumValue(reader);
Exception? exception = null;
Type? enumType = record.Type.TryResolve(reader, new TypeContext(null, null), ref exception)?.ToType();
@@ -317,9 +317,9 @@ public static Exception TryParseConstantValue(this Handle handle, MetadataReader
case HandleType.ConstantReferenceValue:
value = null;
return null;
- case HandleType.ConstantBoxedEnumValue:
+ case HandleType.ConstantEnumValue:
{
- return handle.ToConstantBoxedEnumValueHandle(reader).ParseBoxedEnumConstantValue(reader, out value);
+ return handle.ToConstantEnumValueHandle(reader).ParseEnumConstantValue(reader, out value);
}
default:
{
diff --git a/src/coreclr/pal/prebuilt/corerror/mscorurt.rc b/src/coreclr/pal/prebuilt/corerror/mscorurt.rc
index 67c5f9d48fec1d..df0e680abdd4fb 100644
--- a/src/coreclr/pal/prebuilt/corerror/mscorurt.rc
+++ b/src/coreclr/pal/prebuilt/corerror/mscorurt.rc
@@ -14,7 +14,6 @@ BEGIN
MSG_FOR_URT_HR(HOST_E_INVALIDOPERATION) "Invalid operation."
MSG_FOR_URT_HR(HOST_E_CLRNOTAVAILABLE) "CLR has been disabled due to unrecoverable error."
MSG_FOR_URT_HR(FUSION_E_REF_DEF_MISMATCH) "The located assembly's manifest definition does not match the assembly reference."
- MSG_FOR_URT_HR(FUSION_E_PRIVATE_ASM_DISALLOWED) "A strongly-named assembly is required."
MSG_FOR_URT_HR(FUSION_E_INVALID_NAME) "The given assembly name was invalid."
MSG_FOR_URT_HR(FUSION_E_APP_DOMAIN_LOCKED) "The requested assembly version conflicts with what is already bound in the app domain or specified in the manifest."
MSG_FOR_URT_HR(COR_E_LOADING_REFERENCE_ASSEMBLY) "Reference assemblies cannot be loaded for execution."
diff --git a/src/coreclr/pal/prebuilt/inc/corerror.h b/src/coreclr/pal/prebuilt/inc/corerror.h
index 12d3490aaf09d8..0b475679050fdd 100644
--- a/src/coreclr/pal/prebuilt/inc/corerror.h
+++ b/src/coreclr/pal/prebuilt/inc/corerror.h
@@ -41,7 +41,6 @@
#define HOST_E_INVALIDOPERATION EMAKEHR(0x1022)
#define HOST_E_CLRNOTAVAILABLE EMAKEHR(0x1023)
#define FUSION_E_REF_DEF_MISMATCH EMAKEHR(0x1040)
-#define FUSION_E_PRIVATE_ASM_DISALLOWED EMAKEHR(0x1044)
#define FUSION_E_INVALID_NAME EMAKEHR(0x1047)
#define FUSION_E_APP_DOMAIN_LOCKED EMAKEHR(0x1053)
#define COR_E_LOADING_REFERENCE_ASSEMBLY EMAKEHR(0x1058)
diff --git a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/SchemaDef.cs b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/SchemaDef.cs
index daea57e6e4a1b2..371b9488a7d396 100644
--- a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/SchemaDef.cs
+++ b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/Generator/SchemaDef.cs
@@ -315,6 +315,13 @@ from primitiveType in PrimitiveTypes
members: new MemberDef[] {
new MemberDef(name: "Value", typeName: "string")
}
+ ),
+ new RecordDef(
+ name: "ConstantEnumValue",
+ members: new MemberDef[] {
+ new MemberDef("Value", EnumConstantValue, MemberDefFlags.RecordRef | MemberDefFlags.Child),
+ new MemberDef("Type", TypeDefOrRefOrSpec, MemberDefFlags.RecordRef)
+ }
)
}
)
@@ -630,13 +637,6 @@ from primitiveType in PrimitiveTypes
new MemberDef("Value", TypeDefOrRefOrSpecOrConstant, MemberDefFlags.RecordRef),
}
),
- new RecordDef(
- name: "ConstantBoxedEnumValue",
- members: new MemberDef[] {
- new MemberDef("Value", EnumConstantValue, MemberDefFlags.RecordRef | MemberDefFlags.Child),
- new MemberDef("Type", TypeDefOrRefOrSpec, MemberDefFlags.RecordRef)
- }
- ),
new RecordDef(
name: "GenericParameter",
members: new MemberDef[] {
diff --git a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/MdBinaryReaderGen.cs b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/MdBinaryReaderGen.cs
index bbac55d7083047..6f0d97a9c38834 100644
--- a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/MdBinaryReaderGen.cs
+++ b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/MdBinaryReaderGen.cs
@@ -300,15 +300,6 @@ public static uint Read(this NativeReader reader, uint offset, out ConstantBoole
return offset;
} // Read
- public static uint Read(this NativeReader reader, uint offset, out ConstantBoxedEnumValueHandle handle)
- {
- uint value;
- offset = reader.DecodeUnsigned(offset, out value);
- handle = new ConstantBoxedEnumValueHandle((int)value);
- handle._Validate();
- return offset;
- } // Read
-
public static uint Read(this NativeReader reader, uint offset, out ConstantByteArrayHandle handle)
{
uint value;
@@ -372,6 +363,15 @@ public static uint Read(this NativeReader reader, uint offset, out ConstantEnumA
return offset;
} // Read
+ public static uint Read(this NativeReader reader, uint offset, out ConstantEnumValueHandle handle)
+ {
+ uint value;
+ offset = reader.DecodeUnsigned(offset, out value);
+ handle = new ConstantEnumValueHandle((int)value);
+ handle._Validate();
+ return offset;
+ } // Read
+
public static uint Read(this NativeReader reader, uint offset, out ConstantHandleArrayHandle handle)
{
uint value;
diff --git a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderCommonGen.cs b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderCommonGen.cs
index bb7fefd7816ced..a9359f373de576 100644
--- a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderCommonGen.cs
+++ b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderCommonGen.cs
@@ -94,14 +94,14 @@ public enum HandleType : byte
ByReferenceSignature = 0x2,
ConstantBooleanArray = 0x3,
ConstantBooleanValue = 0x4,
- ConstantBoxedEnumValue = 0x5,
- ConstantByteArray = 0x6,
- ConstantByteValue = 0x7,
- ConstantCharArray = 0x8,
- ConstantCharValue = 0x9,
- ConstantDoubleArray = 0xa,
- ConstantDoubleValue = 0xb,
- ConstantEnumArray = 0xc,
+ ConstantByteArray = 0x5,
+ ConstantByteValue = 0x6,
+ ConstantCharArray = 0x7,
+ ConstantCharValue = 0x8,
+ ConstantDoubleArray = 0x9,
+ ConstantDoubleValue = 0xa,
+ ConstantEnumArray = 0xb,
+ ConstantEnumValue = 0xc,
ConstantHandleArray = 0xd,
ConstantInt16Array = 0xe,
ConstantInt16Value = 0xf,
diff --git a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderGen.cs b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderGen.cs
index 7bf0d91f44e556..3fe7c55c0c2b9c 100644
--- a/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderGen.cs
+++ b/src/coreclr/tools/Common/Internal/Metadata/NativeFormat/NativeFormatReaderGen.cs
@@ -501,130 +501,6 @@ public override string ToString()
} // ToString
} // ConstantBooleanValueHandle
-#if SYSTEM_PRIVATE_CORELIB
- [CLSCompliant(false)]
-#endif
- public partial struct ConstantBoxedEnumValue
- {
- internal MetadataReader _reader;
- internal ConstantBoxedEnumValueHandle _handle;
-
- public ConstantBoxedEnumValueHandle Handle
- {
- get
- {
- return _handle;
- }
- } // Handle
- /// One of: ConstantByteValue, ConstantSByteValue, ConstantInt16Value, ConstantUInt16Value, ConstantInt32Value, ConstantUInt32Value, ConstantInt64Value, ConstantUInt64Value
-
- public Handle Value
- {
- get
- {
- return _value;
- }
- } // Value
-
- internal Handle _value;
- /// One of: TypeDefinition, TypeReference, TypeSpecification
-
- public Handle Type
- {
- get
- {
- return _type;
- }
- } // Type
-
- internal Handle _type;
- } // ConstantBoxedEnumValue
-
-#if SYSTEM_PRIVATE_CORELIB
- [CLSCompliant(false)]
-#endif
- public partial struct ConstantBoxedEnumValueHandle
- {
- public override bool Equals(object obj)
- {
- if (obj is ConstantBoxedEnumValueHandle)
- return _value == ((ConstantBoxedEnumValueHandle)obj)._value;
- else if (obj is Handle)
- return _value == ((Handle)obj)._value;
- else
- return false;
- } // Equals
-
- public bool Equals(ConstantBoxedEnumValueHandle handle)
- {
- return _value == handle._value;
- } // Equals
-
- public bool Equals(Handle handle)
- {
- return _value == handle._value;
- } // Equals
-
- public override int GetHashCode()
- {
- return (int)_value;
- } // GetHashCode
-
- internal int _value;
-
- internal ConstantBoxedEnumValueHandle(Handle handle) : this(handle._value)
- {
- }
-
- internal ConstantBoxedEnumValueHandle(int value)
- {
- HandleType hType = (HandleType)(value >> 24);
- Debug.Assert(hType == 0 || hType == HandleType.ConstantBoxedEnumValue || hType == HandleType.Null);
- _value = (value & 0x00FFFFFF) | (((int)HandleType.ConstantBoxedEnumValue) << 24);
- _Validate();
- }
-
- public static implicit operator Handle(ConstantBoxedEnumValueHandle handle)
- {
- return new Handle(handle._value);
- } // Handle
-
- internal int Offset
- {
- get
- {
- return (this._value & 0x00FFFFFF);
- }
- } // Offset
-
- public ConstantBoxedEnumValue GetConstantBoxedEnumValue(MetadataReader reader)
- {
- return reader.GetConstantBoxedEnumValue(this);
- } // GetConstantBoxedEnumValue
-
- public bool IsNull(MetadataReader reader)
- {
- return reader.IsNull(this);
- } // IsNull
-
- public Handle ToHandle(MetadataReader reader)
- {
- return reader.ToHandle(this);
- } // ToHandle
-
- [System.Diagnostics.Conditional("DEBUG")]
- internal void _Validate()
- {
- if ((HandleType)((_value & 0xFF000000) >> 24) != HandleType.ConstantBoxedEnumValue)
- throw new ArgumentException();
- } // _Validate
-
- public override string ToString()
- {
- return string.Format("{0:X8}", _value);
- } // ToString
- } // ConstantBoxedEnumValueHandle
-
#if SYSTEM_PRIVATE_CORELIB
[CLSCompliant(false)]
#endif
@@ -1419,6 +1295,128 @@ public override string ToString()
} // ToString
} // ConstantEnumArrayHandle
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+#endif
+ public partial struct ConstantEnumValue
+ {
+ internal MetadataReader _reader;
+ internal ConstantEnumValueHandle _handle;
+
+ public ConstantEnumValueHandle Handle
+ {
+ get
+ {
+ return _handle;
+ }
+ } // Handle
+
+ public Handle Value
+ {
+ get
+ {
+ return _value;
+ }
+ } // Value
+
+ internal Handle _value;
+
+ public Handle Type
+ {
+ get
+ {
+ return _type;
+ }
+ } // Type
+
+ internal Handle _type;
+ } // ConstantEnumValue
+
+#if SYSTEM_PRIVATE_CORELIB
+ [CLSCompliant(false)]
+#endif
+ public partial struct ConstantEnumValueHandle
+ {
+ public override bool Equals(object obj)
+ {
+ if (obj is ConstantEnumValueHandle)
+ return _value == ((ConstantEnumValueHandle)obj)._value;
+ else if (obj is Handle)
+ return _value == ((Handle)obj)._value;
+ else
+ return false;
+ } // Equals
+
+ public bool Equals(ConstantEnumValueHandle handle)
+ {
+ return _value == handle._value;
+ } // Equals
+
+ public bool Equals(Handle handle)
+ {
+ return _value == handle._value;
+ } // Equals
+
+ public override int GetHashCode()
+ {
+ return (int)_value;
+ } // GetHashCode
+
+ internal int _value;
+
+ internal ConstantEnumValueHandle(Handle handle) : this(handle._value)
+ {
+ }
+
+ internal ConstantEnumValueHandle(int value)
+ {
+ HandleType hType = (HandleType)(value >> 24);
+ Debug.Assert(hType == 0 || hType == HandleType.ConstantEnumValue || hType == HandleType.Null);
+ _value = (value & 0x00FFFFFF) | (((int)HandleType.ConstantEnumValue) << 24);
+ _Validate();
+ }
+
+ public static implicit operator Handle(ConstantEnumValueHandle handle)
+ {
+ return new Handle(handle._value);
+ } // Handle
+
+ internal int Offset
+ {
+ get
+ {
+ return (this._value & 0x00FFFFFF);
+ }
+ } // Offset
+
+ public ConstantEnumValue GetConstantEnumValue(MetadataReader reader)
+ {
+ return reader.GetConstantEnumValue(this);
+ } // GetConstantEnumValue
+
+ public bool IsNull(MetadataReader reader)
+ {
+ return reader.IsNull(this);
+ } // IsNull
+
+ public Handle ToHandle(MetadataReader reader)
+ {
+ return reader.ToHandle(this);
+ } // ToHandle
+
+ [System.Diagnostics.Conditional("DEBUG")]
+ internal void _Validate()
+ {
+ if ((HandleType)((_value & 0xFF000000) >> 24) != HandleType.ConstantEnumValue)
+ throw new ArgumentException();
+ } // _Validate
+
+ public override string ToString()
+ {
+ return string.Format("{0:X8}", _value);
+ } // ToString
+ } // ConstantEnumValueHandle
+
#if SYSTEM_PRIVATE_CORELIB
[CLSCompliant(false)]
#endif
@@ -3676,7 +3674,7 @@ public Handle Constructor
} // Constructor
internal Handle _constructor;
- /// One of: TypeDefinition, TypeReference, TypeSpecification, ConstantBooleanArray, ConstantBooleanValue, ConstantByteArray, ConstantByteValue, ConstantCharArray, ConstantCharValue, ConstantDoubleArray, ConstantDoubleValue, ConstantEnumArray, ConstantHandleArray, ConstantInt16Array, ConstantInt16Value, ConstantInt32Array, ConstantInt32Value, ConstantInt64Array, ConstantInt64Value, ConstantReferenceValue, ConstantSByteArray, ConstantSByteValue, ConstantSingleArray, ConstantSingleValue, ConstantStringArray, ConstantStringValue, ConstantUInt16Array, ConstantUInt16Value, ConstantUInt32Array, ConstantUInt32Value, ConstantUInt64Array, ConstantUInt64Value
+ /// One of: TypeDefinition, TypeReference, TypeSpecification, ConstantBooleanArray, ConstantBooleanValue, ConstantByteArray, ConstantByteValue, ConstantCharArray, ConstantCharValue, ConstantDoubleArray, ConstantDoubleValue, ConstantEnumArray, ConstantEnumValue, ConstantHandleArray, ConstantInt16Array, ConstantInt16Value, ConstantInt32Array, ConstantInt32Value, ConstantInt64Array, ConstantInt64Value, ConstantReferenceValue, ConstantSByteArray, ConstantSByteValue, ConstantSingleArray, ConstantSingleValue, ConstantStringArray, ConstantStringValue, ConstantUInt16Array, ConstantUInt16Value, ConstantUInt32Array, ConstantUInt32Value, ConstantUInt64Array, ConstantUInt64Value
public HandleCollection FixedArguments
{
@@ -3982,7 +3980,7 @@ public FieldSignatureHandle Signature
} // Signature
internal FieldSignatureHandle _signature;
- /// One of: TypeDefinition, TypeReference, TypeSpecification, ConstantBooleanArray, ConstantBooleanValue, ConstantByteArray, ConstantByteValue, ConstantCharArray, ConstantCharValue, ConstantDoubleArray, ConstantDoubleValue, ConstantEnumArray, ConstantHandleArray, ConstantInt16Array, ConstantInt16Value, ConstantInt32Array, ConstantInt32Value, ConstantInt64Array, ConstantInt64Value, ConstantReferenceValue, ConstantSByteArray, ConstantSByteValue, ConstantSingleArray, ConstantSingleValue, ConstantStringArray, ConstantStringValue, ConstantUInt16Array, ConstantUInt16Value, ConstantUInt32Array, ConstantUInt32Value, ConstantUInt64Array, ConstantUInt64Value
+ /// One of: TypeDefinition, TypeReference, TypeSpecification, ConstantBooleanArray, ConstantBooleanValue, ConstantByteArray, ConstantByteValue, ConstantCharArray, ConstantCharValue, ConstantDoubleArray, ConstantDoubleValue, ConstantEnumArray, ConstantEnumValue, ConstantHandleArray, ConstantInt16Array, ConstantInt16Value, ConstantInt32Array, ConstantInt32Value, ConstantInt64Array, ConstantInt64Value, ConstantReferenceValue, ConstantSByteArray, ConstantSByteValue, ConstantSingleArray, ConstantSingleValue, ConstantStringArray, ConstantStringValue, ConstantUInt16Array, ConstantUInt16Value, ConstantUInt32Array, ConstantUInt32Value, ConstantUInt64Array, ConstantUInt64Value
public Handle DefaultValue
{
@@ -5487,7 +5485,7 @@ public Handle Type
} // Type
internal Handle _type;
- /// One of: TypeDefinition, TypeReference, TypeSpecification, ConstantBooleanArray, ConstantBooleanValue, ConstantByteArray, ConstantByteValue, ConstantCharArray, ConstantCharValue, ConstantDoubleArray, ConstantDoubleValue, ConstantEnumArray, ConstantHandleArray, ConstantInt16Array, ConstantInt16Value, ConstantInt32Array, ConstantInt32Value, ConstantInt64Array, ConstantInt64Value, ConstantReferenceValue, ConstantSByteArray, ConstantSByteValue, ConstantSingleArray, ConstantSingleValue, ConstantStringArray, ConstantStringValue, ConstantUInt16Array, ConstantUInt16Value, ConstantUInt32Array, ConstantUInt32Value, ConstantUInt64Array, ConstantUInt64Value
+ /// One of: TypeDefinition, TypeReference, TypeSpecification, ConstantBooleanArray, ConstantBooleanValue, ConstantByteArray, ConstantByteValue, ConstantCharArray, ConstantCharValue, ConstantDoubleArray, ConstantDoubleValue, ConstantEnumArray, ConstantEnumValue, ConstantHandleArray, ConstantInt16Array, ConstantInt16Value, ConstantInt32Array, ConstantInt32Value, ConstantInt64Array, ConstantInt64Value, ConstantReferenceValue, ConstantSByteArray, ConstantSByteValue, ConstantSingleArray, ConstantSingleValue, ConstantStringArray, ConstantStringValue, ConstantUInt16Array, ConstantUInt16Value, ConstantUInt32Array, ConstantUInt32Value, ConstantUInt64Array, ConstantUInt64Value
public Handle Value
{
@@ -5906,7 +5904,7 @@ public ConstantStringValueHandle Name
} // Name
internal ConstantStringValueHandle _name;
- /// One of: TypeDefinition, TypeReference, TypeSpecification, ConstantBooleanArray, ConstantBooleanValue, ConstantByteArray, ConstantByteValue, ConstantCharArray, ConstantCharValue, ConstantDoubleArray, ConstantDoubleValue, ConstantEnumArray, ConstantHandleArray, ConstantInt16Array, ConstantInt16Value, ConstantInt32Array, ConstantInt32Value, ConstantInt64Array, ConstantInt64Value, ConstantReferenceValue, ConstantSByteArray, ConstantSByteValue, ConstantSingleArray, ConstantSingleValue, ConstantStringArray, ConstantStringValue, ConstantUInt16Array, ConstantUInt16Value, ConstantUInt32Array, ConstantUInt32Value, ConstantUInt64Array, ConstantUInt64Value
+ /// One of: TypeDefinition, TypeReference, TypeSpecification, ConstantBooleanArray, ConstantBooleanValue, ConstantByteArray, ConstantByteValue, ConstantCharArray, ConstantCharValue, ConstantDoubleArray, ConstantDoubleValue, ConstantEnumArray, ConstantEnumValue, ConstantHandleArray, ConstantInt16Array, ConstantInt16Value, ConstantInt32Array, ConstantInt32Value, ConstantInt64Array, ConstantInt64Value, ConstantReferenceValue, ConstantSByteArray, ConstantSByteValue, ConstantSingleArray, ConstantSingleValue, ConstantStringArray, ConstantStringValue, ConstantUInt16Array, ConstantUInt16Value, ConstantUInt32Array, ConstantUInt32Value, ConstantUInt64Array, ConstantUInt64Value
public Handle DefaultValue
{
@@ -6182,7 +6180,7 @@ public MethodSemanticsHandleCollection MethodSemantics
} // MethodSemantics
internal MethodSemanticsHandleCollection _methodSemantics;
- /// One of: TypeDefinition, TypeReference, TypeSpecification, ConstantBooleanArray, ConstantBooleanValue, ConstantByteArray, ConstantByteValue, ConstantCharArray, ConstantCharValue, ConstantDoubleArray, ConstantDoubleValue, ConstantEnumArray, ConstantHandleArray, ConstantInt16Array, ConstantInt16Value, ConstantInt32Array, ConstantInt32Value, ConstantInt64Array, ConstantInt64Value, ConstantReferenceValue, ConstantSByteArray, ConstantSByteValue, ConstantSingleArray, ConstantSingleValue, ConstantStringArray, ConstantStringValue, ConstantUInt16Array, ConstantUInt16Value, ConstantUInt32Array, ConstantUInt32Value, ConstantUInt64Array, ConstantUInt64Value
+ /// One of: TypeDefinition, TypeReference, TypeSpecification, ConstantBooleanArray, ConstantBooleanValue, ConstantByteArray, ConstantByteValue, ConstantCharArray, ConstantCharValue, ConstantDoubleArray, ConstantDoubleValue, ConstantEnumArray, ConstantEnumValue, ConstantHandleArray, ConstantInt16Array, ConstantInt16Value, ConstantInt32Array, ConstantInt32Value, ConstantInt64Array, ConstantInt64Value, ConstantReferenceValue, ConstantSByteArray, ConstantSByteValue, ConstantSingleArray, ConstantSingleValue, ConstantStringArray, ConstantStringValue, ConstantUInt16Array, ConstantUInt16Value, ConstantUInt32Array, ConstantUInt32Value, ConstantUInt64Array, ConstantUInt64Value
public Handle DefaultValue
{
@@ -9833,11 +9831,6 @@ public ConstantBooleanValueHandle ToConstantBooleanValueHandle(MetadataReader re
return new ConstantBooleanValueHandle(this);
} // ToConstantBooleanValueHandle
- public ConstantBoxedEnumValueHandle ToConstantBoxedEnumValueHandle(MetadataReader reader)
- {
- return new ConstantBoxedEnumValueHandle(this);
- } // ToConstantBoxedEnumValueHandle
-
public ConstantByteArrayHandle ToConstantByteArrayHandle(MetadataReader reader)
{
return new ConstantByteArrayHandle(this);
@@ -9873,6 +9866,11 @@ public ConstantEnumArrayHandle ToConstantEnumArrayHandle(MetadataReader reader)
return new ConstantEnumArrayHandle(this);
} // ToConstantEnumArrayHandle
+ public ConstantEnumValueHandle ToConstantEnumValueHandle(MetadataReader reader)
+ {
+ return new ConstantEnumValueHandle(this);
+ } // ToConstantEnumValueHandle
+
public ConstantHandleArrayHandle ToConstantHandleArrayHandle(MetadataReader reader)
{
return new ConstantHandleArrayHandle(this);
@@ -10246,17 +10244,6 @@ public ConstantBooleanValue GetConstantBooleanValue(ConstantBooleanValueHandle h
return record;
} // GetConstantBooleanValue
- public ConstantBoxedEnumValue GetConstantBoxedEnumValue(ConstantBoxedEnumValueHandle handle)
- {
- ConstantBoxedEnumValue record;
- record._reader = this;
- record._handle = handle;
- var offset = (uint)handle.Offset;
- offset = _streamReader.Read(offset, out record._value);
- offset = _streamReader.Read(offset, out record._type);
- return record;
- } // GetConstantBoxedEnumValue
-
public ConstantByteArray GetConstantByteArray(ConstantByteArrayHandle handle)
{
ConstantByteArray record;
@@ -10328,6 +10315,17 @@ public ConstantEnumArray GetConstantEnumArray(ConstantEnumArrayHandle handle)
return record;
} // GetConstantEnumArray
+ public ConstantEnumValue GetConstantEnumValue(ConstantEnumValueHandle handle)
+ {
+ ConstantEnumValue record;
+ record._reader = this;
+ record._handle = handle;
+ var offset = (uint)handle.Offset;
+ offset = _streamReader.Read(offset, out record._value);
+ offset = _streamReader.Read(offset, out record._type);
+ return record;
+ } // GetConstantEnumValue
+
public ConstantHandleArray GetConstantHandleArray(ConstantHandleArrayHandle handle)
{
ConstantHandleArray record;
@@ -10952,11 +10950,6 @@ internal Handle ToHandle(ConstantBooleanValueHandle handle)
return new Handle(handle._value);
} // ToHandle
- internal Handle ToHandle(ConstantBoxedEnumValueHandle handle)
- {
- return new Handle(handle._value);
- } // ToHandle
-
internal Handle ToHandle(ConstantByteArrayHandle handle)
{
return new Handle(handle._value);
@@ -10992,6 +10985,11 @@ internal Handle ToHandle(ConstantEnumArrayHandle handle)
return new Handle(handle._value);
} // ToHandle
+ internal Handle ToHandle(ConstantEnumValueHandle handle)
+ {
+ return new Handle(handle._value);
+ } // ToHandle
+
internal Handle ToHandle(ConstantHandleArrayHandle handle)
{
return new Handle(handle._value);
@@ -11267,11 +11265,6 @@ internal ConstantBooleanValueHandle ToConstantBooleanValueHandle(Handle handle)
return new ConstantBooleanValueHandle(handle._value);
} // ToConstantBooleanValueHandle
- internal ConstantBoxedEnumValueHandle ToConstantBoxedEnumValueHandle(Handle handle)
- {
- return new ConstantBoxedEnumValueHandle(handle._value);
- } // ToConstantBoxedEnumValueHandle
-
internal ConstantByteArrayHandle ToConstantByteArrayHandle(Handle handle)
{
return new ConstantByteArrayHandle(handle._value);
@@ -11307,6 +11300,11 @@ internal ConstantEnumArrayHandle ToConstantEnumArrayHandle(Handle handle)
return new ConstantEnumArrayHandle(handle._value);
} // ToConstantEnumArrayHandle
+ internal ConstantEnumValueHandle ToConstantEnumValueHandle(Handle handle)
+ {
+ return new ConstantEnumValueHandle(handle._value);
+ } // ToConstantEnumValueHandle
+
internal ConstantHandleArrayHandle ToConstantHandleArrayHandle(Handle handle)
{
return new ConstantHandleArrayHandle(handle._value);
@@ -11582,11 +11580,6 @@ internal bool IsNull(ConstantBooleanValueHandle handle)
return (handle._value & 0x00FFFFFF) == 0;
} // IsNull
- internal bool IsNull(ConstantBoxedEnumValueHandle handle)
- {
- return (handle._value & 0x00FFFFFF) == 0;
- } // IsNull
-
internal bool IsNull(ConstantByteArrayHandle handle)
{
return (handle._value & 0x00FFFFFF) == 0;
@@ -11622,6 +11615,11 @@ internal bool IsNull(ConstantEnumArrayHandle handle)
return (handle._value & 0x00FFFFFF) == 0;
} // IsNull
+ internal bool IsNull(ConstantEnumValueHandle handle)
+ {
+ return (handle._value & 0x00FFFFFF) == 0;
+ } // IsNull
+
internal bool IsNull(ConstantHandleArrayHandle handle)
{
return (handle._value & 0x00FFFFFF) == 0;
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 9366e1aa65b6d3..7719b39aa7e852 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -2941,6 +2941,14 @@ private bool isExactType(CORINFO_CLASS_STRUCT_* cls)
return _compilation.IsEffectivelySealed(type);
}
+ private TypeCompareState isNullableType(CORINFO_CLASS_STRUCT_* cls)
+ {
+ TypeDesc type = HandleToObject(cls);
+ Debug.Assert(!type.IsGenericParameter);
+
+ return type.IsNullable ? TypeCompareState.Must : TypeCompareState.MustNot;
+ }
+
private TypeCompareState isEnum(CORINFO_CLASS_STRUCT_* cls, CORINFO_CLASS_STRUCT_** underlyingType)
{
Debug.Assert(cls != null);
@@ -2951,11 +2959,7 @@ private TypeCompareState isEnum(CORINFO_CLASS_STRUCT_* cls, CORINFO_CLASS_STRUCT
}
TypeDesc type = HandleToObject(cls);
-
- if (type.IsGenericParameter)
- {
- return TypeCompareState.May;
- }
+ Debug.Assert(!type.IsGenericParameter);
if (type.IsEnum)
{
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs
index 09ea54f989fde5..481c22864356c1 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs
@@ -1210,6 +1210,21 @@ private static byte _isExactType(IntPtr thisHandle, IntPtr* ppException, CORINFO
}
}
+ [UnmanagedCallersOnly]
+ private static TypeCompareState _isNullableType(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls)
+ {
+ var _this = GetThis(thisHandle);
+ try
+ {
+ return _this.isNullableType(cls);
+ }
+ catch (Exception ex)
+ {
+ *ppException = _this.AllocException(ex);
+ return default;
+ }
+ }
+
[UnmanagedCallersOnly]
private static TypeCompareState _isEnum(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, CORINFO_CLASS_STRUCT_** underlyingType)
{
@@ -2579,7 +2594,7 @@ private static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_
private static IntPtr GetUnmanagedCallbacks()
{
- void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 174);
+ void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 175);
callbacks[0] = (delegate* unmanaged)&_isIntrinsic;
callbacks[1] = (delegate* unmanaged)&_notifyMethodInfoUsage;
@@ -2662,99 +2677,100 @@ private static IntPtr GetUnmanagedCallbacks()
callbacks[78] = (delegate* unmanaged)&_compareTypesForEquality;
callbacks[79] = (delegate* unmanaged)&_isMoreSpecificType;
callbacks[80] = (delegate* unmanaged)&_isExactType;
- callbacks[81] = (delegate* unmanaged)&_isEnum;
- callbacks[82] = (delegate* unmanaged)&_getParentType;
- callbacks[83] = (delegate* unmanaged)&_getChildType;
- callbacks[84] = (delegate* unmanaged)&_isSDArray;
- callbacks[85] = (delegate* unmanaged)&_getArrayRank;
- callbacks[86] = (delegate* unmanaged)&_getArrayIntrinsicID;
- callbacks[87] = (delegate* unmanaged)&_getArrayInitializationData;
- callbacks[88] = (delegate* unmanaged)&_canAccessClass;
- callbacks[89] = (delegate* unmanaged)&_printFieldName;
- callbacks[90] = (delegate* unmanaged)&_getFieldClass;
- callbacks[91] = (delegate* unmanaged)&_getFieldType;
- callbacks[92] = (delegate* unmanaged)&_getFieldOffset;
- callbacks[93] = (delegate* unmanaged)&_getFieldInfo;
- callbacks[94] = (delegate* unmanaged)&_getThreadLocalFieldInfo;
- callbacks[95] = (delegate* unmanaged)&_getThreadLocalStaticBlocksInfo;
- callbacks[96] = (delegate* unmanaged)&_getThreadLocalStaticInfo_NativeAOT;
- callbacks[97] = (delegate* unmanaged)&_isFieldStatic;
- callbacks[98] = (delegate* unmanaged)&_getArrayOrStringLength;
- callbacks[99] = (delegate* unmanaged)&_getBoundaries;
- callbacks[100] = (delegate* unmanaged)&_setBoundaries;
- callbacks[101] = (delegate* unmanaged)&_getVars;
- callbacks[102] = (delegate* unmanaged)&_setVars;
- callbacks[103] = (delegate* unmanaged)&_reportRichMappings;
- callbacks[104] = (delegate* unmanaged)&_reportMetadata;
- callbacks[105] = (delegate* unmanaged)&_allocateArray;
- callbacks[106] = (delegate* unmanaged)&_freeArray;
- callbacks[107] = (delegate* unmanaged)&_getArgNext;
- callbacks[108] = (delegate* unmanaged)&_getArgType;
- callbacks[109] = (delegate* unmanaged)&_getExactClasses;
- callbacks[110] = (delegate* unmanaged)&_getArgClass;
- callbacks[111] = (delegate* unmanaged)&_getHFAType;
- callbacks[112] = (delegate* unmanaged)&_runWithErrorTrap;
- callbacks[113] = (delegate* unmanaged)&_runWithSPMIErrorTrap;
- callbacks[114] = (delegate* unmanaged)&_getEEInfo;
- callbacks[115] = (delegate* unmanaged)&_getJitTimeLogFilename;
- callbacks[116] = (delegate* unmanaged)&_getMethodDefFromMethod;
- callbacks[117] = (delegate* unmanaged)&_printMethodName;
- callbacks[118] = (delegate* unmanaged)&_getMethodNameFromMetadata;
- callbacks[119] = (delegate* unmanaged)&_getMethodHash;
- callbacks[120] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor;
- callbacks[121] = (delegate* unmanaged)&_getSwiftLowering;
- callbacks[122] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags;
- callbacks[123] = (delegate* unmanaged)&_getRISCV64PassStructInRegisterFlags;
- callbacks[124] = (delegate* unmanaged)&_getThreadTLSIndex;
- callbacks[125] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal;
- callbacks[126] = (delegate* unmanaged)&_getHelperFtn;
- callbacks[127] = (delegate* unmanaged)&_getFunctionEntryPoint;
- callbacks[128] = (delegate* unmanaged)&_getFunctionFixedEntryPoint;
- callbacks[129] = (delegate* unmanaged)&_getMethodSync;
- callbacks[130] = (delegate* unmanaged)&_getLazyStringLiteralHelper;
- callbacks[131] = (delegate* unmanaged)&_embedModuleHandle;
- callbacks[132] = (delegate* unmanaged)&_embedClassHandle;
- callbacks[133] = (delegate* unmanaged)&_embedMethodHandle;
- callbacks[134] = (delegate* unmanaged)&_embedFieldHandle;
- callbacks[135] = (delegate* unmanaged)&_embedGenericHandle;
- callbacks[136] = (delegate* unmanaged)&_getLocationOfThisType;
- callbacks[137] = (delegate* unmanaged)&_getAddressOfPInvokeTarget;
- callbacks[138] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig;
- callbacks[139] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig;
- callbacks[140] = (delegate* unmanaged)&_getJustMyCodeHandle;
- callbacks[141] = (delegate* unmanaged)&_GetProfilingHandle;
- callbacks[142] = (delegate* unmanaged)&_getCallInfo;
- callbacks[143] = (delegate* unmanaged)&_getClassDomainID;
- callbacks[144] = (delegate* unmanaged)&_getStaticFieldContent;
- callbacks[145] = (delegate* unmanaged)&_getObjectContent;
- callbacks[146] = (delegate* unmanaged)&_getStaticFieldCurrentClass;
- callbacks[147] = (delegate* unmanaged)&_getVarArgsHandle;
- callbacks[148] = (delegate* unmanaged)&_canGetVarArgsHandle;
- callbacks[149] = (delegate* unmanaged)&_constructStringLiteral;
- callbacks[150] = (delegate* unmanaged)&_emptyStringLiteral;
- callbacks[151] = (delegate* unmanaged)&_getFieldThreadLocalStoreID;
- callbacks[152] = (delegate* unmanaged)&_GetDelegateCtor;
- callbacks[153] = (delegate* unmanaged)&_MethodCompileComplete;
- callbacks[154] = (delegate* unmanaged)&_getTailCallHelpers;
- callbacks[155] = (delegate* unmanaged)&_convertPInvokeCalliToCall;
- callbacks[156] = (delegate* unmanaged)&_notifyInstructionSetUsage;
- callbacks[157] = (delegate* unmanaged)&_updateEntryPointForTailCall;
- callbacks[158] = (delegate* unmanaged)&_allocMem;
- callbacks[159] = (delegate* unmanaged)&_reserveUnwindInfo;
- callbacks[160] = (delegate* unmanaged)&_allocUnwindInfo;
- callbacks[161] = (delegate* unmanaged)&_allocGCInfo;
- callbacks[162] = (delegate* unmanaged)&_setEHcount;
- callbacks[163] = (delegate* unmanaged)&_setEHinfo;
- callbacks[164] = (delegate* unmanaged)&_logMsg;
- callbacks[165] = (delegate* unmanaged)&_doAssert;
- callbacks[166] = (delegate* unmanaged)&_reportFatalError;
- callbacks[167] = (delegate* unmanaged)&_getPgoInstrumentationResults;
- callbacks[168] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema;
- callbacks[169] = (delegate* unmanaged)&_recordCallSite;
- callbacks[170] = (delegate* unmanaged)&_recordRelocation;
- callbacks[171] = (delegate* unmanaged)&_getRelocTypeHint;
- callbacks[172] = (delegate* unmanaged)&_getExpectedTargetArchitecture;
- callbacks[173] = (delegate* unmanaged)&_getJitFlags;
+ callbacks[81] = (delegate* unmanaged)&_isNullableType;
+ callbacks[82] = (delegate* unmanaged)&_isEnum;
+ callbacks[83] = (delegate* unmanaged)&_getParentType;
+ callbacks[84] = (delegate* unmanaged)&_getChildType;
+ callbacks[85] = (delegate* unmanaged)&_isSDArray;
+ callbacks[86] = (delegate* unmanaged)&_getArrayRank;
+ callbacks[87] = (delegate* unmanaged)&_getArrayIntrinsicID;
+ callbacks[88] = (delegate* unmanaged)&_getArrayInitializationData;
+ callbacks[89] = (delegate* unmanaged)&_canAccessClass;
+ callbacks[90] = (delegate* unmanaged)&_printFieldName;
+ callbacks[91] = (delegate* unmanaged)&_getFieldClass;
+ callbacks[92] = (delegate* unmanaged)&_getFieldType;
+ callbacks[93] = (delegate* unmanaged)&_getFieldOffset;
+ callbacks[94] = (delegate* unmanaged)&_getFieldInfo;
+ callbacks[95] = (delegate* unmanaged)&_getThreadLocalFieldInfo;
+ callbacks[96] = (delegate* unmanaged)&_getThreadLocalStaticBlocksInfo;
+ callbacks[97] = (delegate* unmanaged)&_getThreadLocalStaticInfo_NativeAOT;
+ callbacks[98] = (delegate* unmanaged)&_isFieldStatic;
+ callbacks[99] = (delegate* unmanaged)&_getArrayOrStringLength;
+ callbacks[100] = (delegate* unmanaged)&_getBoundaries;
+ callbacks[101] = (delegate* unmanaged)&_setBoundaries;
+ callbacks[102] = (delegate* unmanaged)&_getVars;
+ callbacks[103] = (delegate* unmanaged)&_setVars;
+ callbacks[104] = (delegate* unmanaged)&_reportRichMappings;
+ callbacks[105] = (delegate* unmanaged)&_reportMetadata;
+ callbacks[106] = (delegate* unmanaged)&_allocateArray;
+ callbacks[107] = (delegate* unmanaged)&_freeArray;
+ callbacks[108] = (delegate* unmanaged)&_getArgNext;
+ callbacks[109] = (delegate* unmanaged)&_getArgType;
+ callbacks[110] = (delegate* unmanaged)&_getExactClasses;
+ callbacks[111] = (delegate* unmanaged)&_getArgClass;
+ callbacks[112] = (delegate* unmanaged)&_getHFAType;
+ callbacks[113] = (delegate* unmanaged)&_runWithErrorTrap;
+ callbacks[114] = (delegate* unmanaged)&_runWithSPMIErrorTrap;
+ callbacks[115] = (delegate* unmanaged)&_getEEInfo;
+ callbacks[116] = (delegate* unmanaged)&_getJitTimeLogFilename;
+ callbacks[117] = (delegate* unmanaged)&_getMethodDefFromMethod;
+ callbacks[118] = (delegate* unmanaged)&_printMethodName;
+ callbacks[119] = (delegate* unmanaged)&_getMethodNameFromMetadata;
+ callbacks[120] = (delegate* unmanaged)&_getMethodHash;
+ callbacks[121] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor;
+ callbacks[122] = (delegate* unmanaged)&_getSwiftLowering;
+ callbacks[123] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags;
+ callbacks[124] = (delegate* unmanaged)&_getRISCV64PassStructInRegisterFlags;
+ callbacks[125] = (delegate* unmanaged)&_getThreadTLSIndex;
+ callbacks[126] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal;
+ callbacks[127] = (delegate* unmanaged)&_getHelperFtn;
+ callbacks[128] = (delegate* unmanaged)&_getFunctionEntryPoint;
+ callbacks[129] = (delegate* unmanaged)&_getFunctionFixedEntryPoint;
+ callbacks[130] = (delegate* unmanaged)&_getMethodSync;
+ callbacks[131] = (delegate* unmanaged)&_getLazyStringLiteralHelper;
+ callbacks[132] = (delegate* unmanaged)&_embedModuleHandle;
+ callbacks[133] = (delegate* unmanaged)&_embedClassHandle;
+ callbacks[134] = (delegate* unmanaged)&_embedMethodHandle;
+ callbacks[135] = (delegate* unmanaged)&_embedFieldHandle;
+ callbacks[136] = (delegate* unmanaged)&_embedGenericHandle;
+ callbacks[137] = (delegate* unmanaged)&_getLocationOfThisType;
+ callbacks[138] = (delegate* unmanaged)&_getAddressOfPInvokeTarget;
+ callbacks[139] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig;
+ callbacks[140] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig;
+ callbacks[141] = (delegate* unmanaged)&_getJustMyCodeHandle;
+ callbacks[142] = (delegate* unmanaged)&_GetProfilingHandle;
+ callbacks[143] = (delegate* unmanaged)&_getCallInfo;
+ callbacks[144] = (delegate* unmanaged)&_getClassDomainID;
+ callbacks[145] = (delegate* unmanaged)&_getStaticFieldContent;
+ callbacks[146] = (delegate* unmanaged)&_getObjectContent;
+ callbacks[147] = (delegate* unmanaged)&_getStaticFieldCurrentClass;
+ callbacks[148] = (delegate* unmanaged)&_getVarArgsHandle;
+ callbacks[149] = (delegate* unmanaged)&_canGetVarArgsHandle;
+ callbacks[150] = (delegate* unmanaged)&_constructStringLiteral;
+ callbacks[151] = (delegate* unmanaged)&_emptyStringLiteral;
+ callbacks[152] = (delegate* unmanaged)&_getFieldThreadLocalStoreID;
+ callbacks[153] = (delegate* unmanaged)&_GetDelegateCtor;
+ callbacks[154] = (delegate* unmanaged)&_MethodCompileComplete;
+ callbacks[155] = (delegate* unmanaged)&_getTailCallHelpers;
+ callbacks[156] = (delegate* unmanaged)&_convertPInvokeCalliToCall;
+ callbacks[157] = (delegate* unmanaged)&_notifyInstructionSetUsage;
+ callbacks[158] = (delegate* unmanaged)&_updateEntryPointForTailCall;
+ callbacks[159] = (delegate* unmanaged)&_allocMem;
+ callbacks[160] = (delegate* unmanaged)&_reserveUnwindInfo;
+ callbacks[161] = (delegate* unmanaged)&_allocUnwindInfo;
+ callbacks[162] = (delegate* unmanaged)&_allocGCInfo;
+ callbacks[163] = (delegate* unmanaged)&_setEHcount;
+ callbacks[164] = (delegate* unmanaged)&_setEHinfo;
+ callbacks[165] = (delegate* unmanaged)&_logMsg;
+ callbacks[166] = (delegate* unmanaged)&_doAssert;
+ callbacks[167] = (delegate* unmanaged)&_reportFatalError;
+ callbacks[168] = (delegate* unmanaged)&_getPgoInstrumentationResults;
+ callbacks[169] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema;
+ callbacks[170] = (delegate* unmanaged)&_recordCallSite;
+ callbacks[171] = (delegate* unmanaged)&_recordRelocation;
+ callbacks[172] = (delegate* unmanaged)&_getRelocTypeHint;
+ callbacks[173] = (delegate* unmanaged)&_getExpectedTargetArchitecture;
+ callbacks[174] = (delegate* unmanaged)&_getJitFlags;
return (IntPtr)callbacks;
}
diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt
index 8d6ecabaa77c57..86674ab2b59244 100644
--- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt
+++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt
@@ -244,6 +244,7 @@ FUNCTIONS
TypeCompareState compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
bool isMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
bool isExactType(CORINFO_CLASS_HANDLE cls)
+ TypeCompareState isNullableType(CORINFO_CLASS_HANDLE cls)
TypeCompareState isEnum(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE* underlyingType)
CORINFO_CLASS_HANDLE getParentType(CORINFO_CLASS_HANDLE cls)
CorInfoType getChildType(CORINFO_CLASS_HANDLE clsHnd, CORINFO_CLASS_HANDLE* clsRet)
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs
index 1340d8669ca08a..ad84c511393d69 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs
@@ -536,7 +536,7 @@ public static bool HandleCall(
{
// We could try to analyze if the type is known, but for now making sure this works for canonical arrays is enough.
TypeDesc canonArrayType = reflectionMarker.Factory.TypeSystemContext.CanonType.MakeArrayType();
- reflectionMarker.Dependencies.Add(reflectionMarker.Factory.NativeLayout.TemplateTypeLayout(canonArrayType), "Array.CreateInstance was called");
+ reflectionMarker.MarkType(diagnosticContext.Origin, canonArrayType, "Array.CreateInstance was called");
goto case IntrinsicId.None;
}
@@ -656,6 +656,12 @@ public static bool HandleCall(
if (Intrinsics.GetIntrinsicIdForMethod(callingMethodDefinition) == IntrinsicId.RuntimeReflectionExtensions_GetMethodInfo)
break;
+ if (param.IsEmpty())
+ {
+ // The static value is unknown and the below `foreach` won't execute
+ reflectionMarker.Dependencies.Add(reflectionMarker.Factory.ReflectedDelegate(null), "Delegate.Method access on unknown delegate type");
+ }
+
foreach (var valueNode in param.AsEnumerable())
{
TypeDesc? staticType = (valueNode as IValueWithStaticType)?.StaticType?.Type;
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/CustomAttributeBasedDependencyAlgorithm.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/CustomAttributeBasedDependencyAlgorithm.cs
index 68e8b5f6f0c39b..a18251e401fc03 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/CustomAttributeBasedDependencyAlgorithm.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/CustomAttributeBasedDependencyAlgorithm.cs
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Reflection.Metadata;
@@ -151,6 +152,12 @@ private static void AddDependenciesDueToCustomAttributes(ref DependencyList depe
// worth the hassle: the input was invalid. The most important thing is that we
// don't crash the compilation.
}
+ catch (BadImageFormatException)
+ {
+ // System.Reflection.Metadata will throw BadImageFormatException if the blob is malformed.
+ // This can happen if e.g. underlying type of an enum changes between versions and
+ // we can no longer decode the custom attribute blob.
+ }
}
}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ReflectedTypeNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ReflectedTypeNode.cs
index fa37372f4c6dff..0a6327db7e545d 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ReflectedTypeNode.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ReflectedTypeNode.cs
@@ -34,10 +34,17 @@ public ReflectedTypeNode(TypeDesc type)
public override IEnumerable GetStaticDependencies(NodeFactory factory)
{
- return new DependencyListEntry[]
- {
- new DependencyListEntry(factory.MaximallyConstructableType(_type), "Reflection target"),
- };
+ var result = new DependencyList
+ {
+ new DependencyListEntry(factory.MaximallyConstructableType(_type), "Reflection target"),
+ };
+
+ if (_type.IsCanonicalSubtype(CanonicalFormKind.Any))
+ {
+ GenericTypesTemplateMap.GetTemplateTypeDependencies(ref result, factory, _type);
+ }
+
+ return result;
}
protected override string GetName(NodeFactory factory)
{
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/MetadataManager.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/MetadataManager.cs
index 19952d1209b659..bd70b1660db3f5 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/MetadataManager.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/MetadataManager.cs
@@ -1030,7 +1030,12 @@ public bool IsReflectionBlocked(TypeDesc type)
case TypeFlags.Array:
case TypeFlags.Pointer:
case TypeFlags.ByRef:
- return IsReflectionBlocked(((ParameterizedType)type).ParameterType);
+ TypeDesc parameterType = ((ParameterizedType)type).ParameterType;
+
+ if (parameterType.IsCanonicalDefinitionType(CanonicalFormKind.Any))
+ return false;
+
+ return IsReflectionBlocked(parameterType);
case TypeFlags.FunctionPointer:
MethodSignature pointerSignature = ((FunctionPointerType)type).Signature;
diff --git a/src/coreclr/tools/aot/ILCompiler.MetadataTransform/ILCompiler/Metadata/Transform.CustomAttribute.cs b/src/coreclr/tools/aot/ILCompiler.MetadataTransform/ILCompiler/Metadata/Transform.CustomAttribute.cs
index 60f74b9402bb80..311d19d6f73c27 100644
--- a/src/coreclr/tools/aot/ILCompiler.MetadataTransform/ILCompiler/Metadata/Transform.CustomAttribute.cs
+++ b/src/coreclr/tools/aot/ILCompiler.MetadataTransform/ILCompiler/Metadata/Transform.CustomAttribute.cs
@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
-using System.Collections.Immutable;
using Internal.Metadata.NativeFormat.Writer;
@@ -11,6 +10,7 @@
using Debug = System.Diagnostics.Debug;
using NamedArgumentMemberKind = Internal.Metadata.NativeFormat.NamedArgumentMemberKind;
+using UnreachableException = System.Diagnostics.UnreachableException;
namespace ILCompiler.Metadata
{
@@ -20,52 +20,60 @@ private List HandleCustomAttributes(Cts.Ecma.EcmaModule module,
{
List customAttributes = new List(attributes.Count);
- var attributeTypeProvider = new Cts.Ecma.CustomAttributeTypeProvider(module);
-
- Ecma.MetadataReader reader = module.MetadataReader;
-
foreach (var attributeHandle in attributes)
{
if (!_policy.GeneratesMetadata(module, attributeHandle))
continue;
- Ecma.CustomAttribute attribute = reader.GetCustomAttribute(attributeHandle);
-
// TODO-NICE: We can intern the attributes based on the CA constructor and blob bytes
-
- Cts.MethodDesc constructor = module.GetMethod(attribute.Constructor);
- var decodedValue = attribute.DecodeValue(attributeTypeProvider);
-
- customAttributes.Add(HandleCustomAttribute(constructor, decodedValue));
+ customAttributes.Add(HandleCustomAttribute(module, attributeHandle));
}
return customAttributes;
}
- private CustomAttribute HandleCustomAttribute(Cts.MethodDesc constructor, Ecma.CustomAttributeValue decodedValue)
+ private CustomAttribute HandleCustomAttribute(Cts.Ecma.EcmaModule module, Ecma.CustomAttributeHandle attributeHandle)
{
+ Ecma.MetadataReader reader = module.MetadataReader;
+ Ecma.CustomAttribute attribute = reader.GetCustomAttribute(attributeHandle);
+
+ Cts.MethodDesc constructor = module.GetMethod(attribute.Constructor);
+
CustomAttribute result = new CustomAttribute
{
Constructor = HandleQualifiedMethod(constructor),
};
- result.FixedArguments.Capacity = decodedValue.FixedArguments.Length;
- foreach (var decodedArgument in decodedValue.FixedArguments)
+ Ecma.BlobReader valueReader = reader.GetBlobReader(attribute.Value);
+
+ ushort prolog = valueReader.ReadUInt16(); // Version
+ Debug.Assert(prolog == 1);
+
+ Cts.MethodSignature sig = constructor.Signature;
+ result.FixedArguments.Capacity = sig.Length;
+ foreach (Cts.TypeDesc paramType in sig)
{
- var fixedArgument = HandleCustomAttributeConstantValue(decodedArgument.Type, decodedArgument.Value);
+ var fixedArgument = paramType.IsArray ?
+ HandleCustomAttributeConstantArray(module, TypeDescToSerializationTypeCode(((Cts.ArrayType)paramType).ElementType), ref valueReader) :
+ HandleCustomAttributeConstantValue(module, TypeDescToSerializationTypeCode(paramType), ref valueReader);
result.FixedArguments.Add(fixedArgument);
}
- result.NamedArguments.Capacity = decodedValue.NamedArguments.Length;
- foreach (var decodedArgument in decodedValue.NamedArguments)
+ ushort numNamed = valueReader.ReadUInt16();
+ result.NamedArguments.Capacity = numNamed;
+ for (int i = 0; i < numNamed; i++)
{
+ byte flag = valueReader.ReadByte();
+ Cts.TypeDesc type = SerializationTypeToType(module, ref valueReader);
var namedArgument = new NamedArgument
{
- Flags = decodedArgument.Kind == Ecma.CustomAttributeNamedArgumentKind.Field ?
+ Flags = flag == (byte)Ecma.CustomAttributeNamedArgumentKind.Field ?
NamedArgumentMemberKind.Field : NamedArgumentMemberKind.Property,
- Name = HandleString(decodedArgument.Name),
- Type = HandleType(decodedArgument.Type),
- Value = HandleCustomAttributeConstantValue(decodedArgument.Type, decodedArgument.Value)
+ Type = HandleType(type),
+ Name = HandleString(valueReader.ReadSerializedString()),
+ Value = type.IsArray ?
+ HandleCustomAttributeConstantArray(module, TypeDescToSerializationTypeCode(((Cts.ArrayType)type).ElementType), ref valueReader) :
+ HandleCustomAttributeConstantValue(module, TypeDescToSerializationTypeCode(type), ref valueReader)
};
result.NamedArguments.Add(namedArgument);
}
@@ -73,142 +81,186 @@ private CustomAttribute HandleCustomAttribute(Cts.MethodDesc constructor, Ecma.C
return result;
}
- private MetadataRecord HandleCustomAttributeConstantValue(Cts.TypeDesc type, object value)
+ private static Ecma.SerializationTypeCode TypeDescToSerializationTypeCode(Cts.TypeDesc type)
{
+ Debug.Assert((int)Cts.TypeFlags.Boolean == (int)Ecma.SerializationTypeCode.Boolean);
+
switch (type.UnderlyingType.Category)
{
- case Cts.TypeFlags.Boolean:
- return new ConstantBooleanValue { Value = (bool)value };
- case Cts.TypeFlags.Byte:
- return new ConstantByteValue { Value = (byte)value };
- case Cts.TypeFlags.Char:
- return new ConstantCharValue { Value = (char)value };
- case Cts.TypeFlags.Double:
- return new ConstantDoubleValue { Value = (double)value };
- case Cts.TypeFlags.Int16:
- return new ConstantInt16Value { Value = (short)value };
- case Cts.TypeFlags.Int32:
- return new ConstantInt32Value { Value = (int)value };
- case Cts.TypeFlags.Int64:
- return new ConstantInt64Value { Value = (long)value };
- case Cts.TypeFlags.SByte:
- return new ConstantSByteValue { Value = (sbyte)value };
- case Cts.TypeFlags.Single:
- return new ConstantSingleValue { Value = (float)value };
- case Cts.TypeFlags.UInt16:
- return new ConstantUInt16Value { Value = (ushort)value };
- case Cts.TypeFlags.UInt32:
- return new ConstantUInt32Value { Value = (uint)value };
- case Cts.TypeFlags.UInt64:
- return new ConstantUInt64Value { Value = (ulong)value };
+ case Cts.TypeFlags.Single: return Ecma.SerializationTypeCode.Single;
+ case Cts.TypeFlags.Double: return Ecma.SerializationTypeCode.Double;
+ case <= Cts.TypeFlags.UInt64: return (Ecma.SerializationTypeCode)type.UnderlyingType.Category;
+ default:
+ if (type.IsObject)
+ return Ecma.SerializationTypeCode.TaggedObject;
+
+ if (type.IsString)
+ return Ecma.SerializationTypeCode.String;
+
+ if (type is not Cts.MetadataType { Name: "Type", Namespace: "System" })
+ throw new UnreachableException();
+
+ return Ecma.SerializationTypeCode.Type;
}
+ }
+
+ private static Cts.TypeDesc SerializationTypeToType(Cts.Ecma.EcmaModule module, ref Ecma.BlobReader valueReader)
+ {
+ Ecma.SerializationTypeCode typeCode = valueReader.ReadSerializationTypeCode();
- if (value == null)
+ switch (typeCode)
{
- return new ConstantReferenceValue();
+ case Ecma.SerializationTypeCode.Type: return module.Context.SystemModule.GetType("System", "Type");
+ case Ecma.SerializationTypeCode.SZArray: return module.Context.GetArrayType(SerializationTypeToType(module, ref valueReader));
+ case Ecma.SerializationTypeCode.Enum: return Cts.CustomAttributeTypeNameParser.GetTypeByCustomAttributeTypeName(module, valueReader.ReadSerializedString());
+ case Ecma.SerializationTypeCode.String: return module.Context.GetWellKnownType(Cts.WellKnownType.String);
+ case Ecma.SerializationTypeCode.TaggedObject: return module.Context.GetWellKnownType(Cts.WellKnownType.Object);
+ case Ecma.SerializationTypeCode.Single: return module.Context.GetWellKnownType(Cts.WellKnownType.Single);
+ case Ecma.SerializationTypeCode.Double: return module.Context.GetWellKnownType(Cts.WellKnownType.Double);
+ case <= Ecma.SerializationTypeCode.UInt64: return module.Context.GetWellKnownType((Cts.WellKnownType)typeCode);
}
- if (type.IsString)
+ Cts.ThrowHelper.ThrowBadImageFormatException();
+ return null; // unreached
+ }
+
+ private MetadataRecord HandleCustomAttributeConstantValue(Cts.Ecma.EcmaModule module, Ecma.SerializationTypeCode typeCode, ref Ecma.BlobReader valueReader)
+ {
+ if (typeCode == Ecma.SerializationTypeCode.TaggedObject)
{
- return HandleString((string)value);
+ typeCode = valueReader.ReadSerializationTypeCode();
}
- if (type.IsSzArray)
+ if (typeCode == Ecma.SerializationTypeCode.Enum)
{
- return HandleCustomAttributeConstantArray(
- (Cts.ArrayType)type,
- (ImmutableArray>)value);
+ Cts.TypeDesc enumType = Cts.CustomAttributeTypeNameParser.GetTypeByCustomAttributeTypeName(module, valueReader.ReadSerializedString());
+ return new ConstantEnumValue
+ {
+ Value = HandleCustomAttributeConstantValue(module, TypeDescToSerializationTypeCode(enumType), ref valueReader),
+ Type = HandleType(enumType)
+ };
}
- Debug.Assert(value is Cts.TypeDesc);
- Debug.Assert(type is Cts.MetadataType
- && ((Cts.MetadataType)type).Name == "Type"
- && ((Cts.MetadataType)type).Namespace == "System");
+ if (typeCode == Ecma.SerializationTypeCode.String)
+ {
+ string s = valueReader.ReadSerializedString();
+ return s == null ? new ConstantReferenceValue() : HandleString(s);
+ }
+
+ if (typeCode == Ecma.SerializationTypeCode.Type)
+ {
+ string s = valueReader.ReadSerializedString();
+ return s == null ? new ConstantReferenceValue() : HandleType(Cts.CustomAttributeTypeNameParser.GetTypeByCustomAttributeTypeName(module, s));
+ }
- return HandleType((Cts.TypeDesc)value);
+ return typeCode switch
+ {
+ Ecma.SerializationTypeCode.Boolean => new ConstantBooleanValue { Value = valueReader.ReadBoolean() },
+ Ecma.SerializationTypeCode.Char => new ConstantCharValue { Value = valueReader.ReadChar() },
+ Ecma.SerializationTypeCode.Byte => new ConstantByteValue { Value = valueReader.ReadByte() },
+ Ecma.SerializationTypeCode.SByte => new ConstantSByteValue { Value = valueReader.ReadSByte() },
+ Ecma.SerializationTypeCode.Int16 => new ConstantInt16Value { Value = valueReader.ReadInt16() },
+ Ecma.SerializationTypeCode.UInt16 => new ConstantUInt16Value { Value = valueReader.ReadUInt16() },
+ Ecma.SerializationTypeCode.Int32 => new ConstantInt32Value { Value = valueReader.ReadInt32() },
+ Ecma.SerializationTypeCode.UInt32 => new ConstantUInt32Value { Value = valueReader.ReadUInt32() },
+ Ecma.SerializationTypeCode.Int64 => new ConstantInt64Value { Value = valueReader.ReadInt64() },
+ Ecma.SerializationTypeCode.UInt64 => new ConstantUInt64Value { Value = valueReader.ReadUInt64() },
+ Ecma.SerializationTypeCode.Single => new ConstantSingleValue { Value = valueReader.ReadSingle() },
+ Ecma.SerializationTypeCode.Double => new ConstantDoubleValue { Value = valueReader.ReadDouble() },
+ Ecma.SerializationTypeCode.SZArray => HandleCustomAttributeConstantArray(module, valueReader.ReadSerializationTypeCode(), ref valueReader),
+ _ => throw new UnreachableException()
+ };
}
- private MetadataRecord HandleCustomAttributeConstantArray(
- Cts.ArrayType type, ImmutableArray> value)
+ private MetadataRecord HandleCustomAttributeConstantArray(Cts.Ecma.EcmaModule module, Ecma.SerializationTypeCode elementTypeCode, ref Ecma.BlobReader valueReader)
{
- Cts.TypeDesc elementType = type.ElementType;
-
- if (elementType.IsEnum)
+ if (elementTypeCode == Ecma.SerializationTypeCode.Enum)
{
- Cts.TypeSystemContext context = type.Context;
+ Cts.TypeDesc enumType = Cts.CustomAttributeTypeNameParser.GetTypeByCustomAttributeTypeName(module, valueReader.ReadSerializedString());
return new ConstantEnumArray
{
- ElementType = HandleType(elementType),
- Value = HandleCustomAttributeConstantArray(context.GetArrayType(elementType.UnderlyingType), value),
+ ElementType = HandleType(enumType),
+ Value = HandleCustomAttributeConstantArray(module, TypeDescToSerializationTypeCode(enumType), ref valueReader),
};
}
- switch (elementType.Category)
- {
- case Cts.TypeFlags.Boolean:
- return new ConstantBooleanArray { Value = GetCustomAttributeConstantArrayElements(value) };
- case Cts.TypeFlags.Byte:
- return new ConstantByteArray { Value = GetCustomAttributeConstantArrayElements(value) };
- case Cts.TypeFlags.Char:
- return new ConstantCharArray { Value = GetCustomAttributeConstantArrayElements(value) };
- case Cts.TypeFlags.Double:
- return new ConstantDoubleArray { Value = GetCustomAttributeConstantArrayElements(value) };
- case Cts.TypeFlags.Int16:
- return new ConstantInt16Array { Value = GetCustomAttributeConstantArrayElements(value) };
- case Cts.TypeFlags.Int32:
- return new ConstantInt32Array { Value = GetCustomAttributeConstantArrayElements(value) };
- case Cts.TypeFlags.Int64:
- return new ConstantInt64Array { Value = GetCustomAttributeConstantArrayElements(value) };
- case Cts.TypeFlags.SByte:
- return new ConstantSByteArray { Value = GetCustomAttributeConstantArrayElements(value) };
- case Cts.TypeFlags.Single:
- return new ConstantSingleArray { Value = GetCustomAttributeConstantArrayElements(value) };
- case Cts.TypeFlags.UInt16:
- return new ConstantUInt16Array { Value = GetCustomAttributeConstantArrayElements(value) };
- case Cts.TypeFlags.UInt32:
- return new ConstantUInt32Array { Value = GetCustomAttributeConstantArrayElements(value) };
- case Cts.TypeFlags.UInt64:
- return new ConstantUInt64Array { Value = GetCustomAttributeConstantArrayElements(value) };
+ int count = valueReader.ReadInt32();
+ if (count == -1)
+ {
+ return new ConstantReferenceValue();
}
- if (elementType.IsString)
+ if (elementTypeCode is Ecma.SerializationTypeCode.String)
{
- var record = new ConstantStringArray();
- record.Value.Capacity = value.Length;
- foreach (var element in value)
+ var handleArray = new ConstantStringArray();
+ handleArray.Value.Capacity = count;
+ for (int i = 0; i < count; i++)
{
- MetadataRecord elementRecord = element.Value == null ?
- (MetadataRecord)new ConstantReferenceValue() : HandleString((string)element.Value);
- record.Value.Add(elementRecord);
+ string val = valueReader.ReadSerializedString();
+ handleArray.Value.Add(val == null ? new ConstantReferenceValue() : HandleString(val));
}
- return record;
+ return handleArray;
}
- var result = new ConstantHandleArray();
- result.Value.Capacity = value.Length;
- for (int i = 0; i < value.Length; i++)
+ if (elementTypeCode is Ecma.SerializationTypeCode.TaggedObject or Ecma.SerializationTypeCode.Type)
{
- MetadataRecord elementRecord = HandleCustomAttributeConstantValue(value[i].Type, value[i].Value);
- if (value[i].Type.IsEnum)
+ var handleArray = new ConstantHandleArray();
+ handleArray.Value.Capacity = count;
+ for (int i = 0; i < count; i++)
{
- elementRecord = new ConstantBoxedEnumValue
- {
- Value = elementRecord,
- Type = HandleType(value[i].Type)
- };
+ Ecma.SerializationTypeCode typecode = elementTypeCode == Ecma.SerializationTypeCode.Type ? Ecma.SerializationTypeCode.Type : valueReader.ReadSerializationTypeCode();
+ handleArray.Value.Add(HandleCustomAttributeConstantValue(module, typecode, ref valueReader));
}
- result.Value.Add(elementRecord);
+ return handleArray;
}
- return result;
+ return elementTypeCode switch
+ {
+ Ecma.SerializationTypeCode.Boolean => new ConstantBooleanArray { Value = GetCustomAttributeConstantArrayElements(ref valueReader, count) },
+ Ecma.SerializationTypeCode.Char => new ConstantCharArray { Value = GetCustomAttributeConstantArrayElements(ref valueReader, count) },
+ Ecma.SerializationTypeCode.SByte => new ConstantSByteArray { Value = GetCustomAttributeConstantArrayElements(ref valueReader, count) },
+ Ecma.SerializationTypeCode.Byte => new ConstantByteArray { Value = GetCustomAttributeConstantArrayElements(ref valueReader, count) },
+ Ecma.SerializationTypeCode.Int16 => new ConstantInt16Array { Value = GetCustomAttributeConstantArrayElements(ref valueReader, count) },
+ Ecma.SerializationTypeCode.UInt16 => new ConstantUInt16Array { Value = GetCustomAttributeConstantArrayElements(ref valueReader, count) },
+ Ecma.SerializationTypeCode.Int32 => new ConstantInt32Array { Value = GetCustomAttributeConstantArrayElements(ref valueReader, count) },
+ Ecma.SerializationTypeCode.UInt32 => new ConstantUInt32Array { Value = GetCustomAttributeConstantArrayElements(ref valueReader, count) },
+ Ecma.SerializationTypeCode.Int64 => new ConstantInt64Array { Value = GetCustomAttributeConstantArrayElements(ref valueReader, count) },
+ Ecma.SerializationTypeCode.UInt64 => new ConstantUInt64Array { Value = GetCustomAttributeConstantArrayElements(ref valueReader, count) },
+ Ecma.SerializationTypeCode.Single => new ConstantSingleArray { Value = GetCustomAttributeConstantArrayElements