diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
index 5a697ac088194..d76e325e8b6ca 100644
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -25,4 +25,5 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
libssl-dev \
libkrb5-dev \
zlib1g-dev \
- ninja-build
+ ninja-build \
+ tzdata
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index b042cebfc6b92..ecc2cc3d3867c 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -21,7 +21,7 @@
/src/mono @marek-safar
-/src/mono/llvm @vargaz @SamMonoRT
+/src/mono/llvm @vargaz @steveisok
/src/mono/mono/arch @vargaz
/src/mono/mono/eglib @vargaz @lambdageek
@@ -36,7 +36,7 @@
/src/mono/mono/eventpipe @lateralusX @lambdageek
-/src/mono/mono/mini @vargaz @lambdageek @SamMonoRT
+/src/mono/mono/mini @vargaz @lambdageek @steveisok
/src/mono/mono/mini/*cfgdump* @vargaz
/src/mono/mono/mini/*exceptions* @vargaz @BrzVlad
/src/mono/mono/mini/*llvm* @vargaz @fanyang-mono
@@ -50,7 +50,7 @@
/src/mono/mono/mini/*simd* @fanyang-mono
/src/mono/mono/profiler @BrzVlad @lambdageek
-/src/mono/mono/sgen @BrzVlad @lambdageek @SamMonoRT
+/src/mono/mono/sgen @BrzVlad @lambdageek
/src/mono/mono/utils @vargaz @lambdageek
/src/mono/mono/utils/*-win* @lateralusX @lambdageek
diff --git a/.github/ISSUE_TEMPLATE/05_blank_issue.md b/.github/ISSUE_TEMPLATE/04_blank_issue.md
similarity index 100%
rename from .github/ISSUE_TEMPLATE/05_blank_issue.md
rename to .github/ISSUE_TEMPLATE/04_blank_issue.md
diff --git a/.github/ISSUE_TEMPLATE/04_ci_known_issue.yml b/.github/ISSUE_TEMPLATE/04_ci_known_issue.yml
deleted file mode 100644
index 17ec4e5e5ec93..0000000000000
--- a/.github/ISSUE_TEMPLATE/04_ci_known_issue.yml
+++ /dev/null
@@ -1,32 +0,0 @@
-name: CI Known Issue Report
-description: Create a known issue directly
-labels: ["blocking-clean-ci","Known Build Error"]
-body:
- - type: markdown
- attributes:
- value: |
- Use this template to report issues currently affecting PR stability, be it build or test failures.
- - type: textarea
- id: background
- attributes:
- label: Error Blob
- description: Please identify a clear error string that can help identify future instances of this issue. For more information on how to fill this check our issue triage guidelines at [Failure Analysis](/dotnet/runtime/blob/main/docs/workflow/ci/failure-analysis.md#what-to-do-if-you-determine-the-failure-is-unrelated)
- value: |
- ```json
- {
- "ErrorMessage": "",
- "BuildRetry": false,
- "ErrorPattern": "",
- "ExcludeConsoleLog": true
- }
- ```
- validations:
- required: true
- - type: textarea
- id: repro-steps
- attributes:
- label: Reproduction Steps
- description: |
- If possible describe where you observe the issue with links and any other relevant details.
- validations:
- required: false
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 54d8c5740bad6..b14edd954edee 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -18,3 +18,6 @@ contact_links:
- name: Issue with WPF
url: https://github.com/dotnet/wpf/issues/new/choose
about: Please open issues relating to WPF in dotnet/wpf.
+ - name: CI Known Issue Report
+ url: https://helix.dot.net/BuildAnalysis/CreateKnownIssues
+ about: Use the helper to create a Known Issue in CI if failures in your runs are unrelated to your change. See [Failure Analysis](https://github.com/dotnet/runtime/blob/main/docs/workflow/ci/failure-analysis.md#what-to-do-if-you-determine-the-failure-is-unrelated) for triage instructions.
diff --git a/Directory.Build.props b/Directory.Build.props
index 26e112fab56e1..1969e3e16a2a9 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -313,6 +313,8 @@
'$(OfficialBuildId)' == ''">true
true
+
+ ClrFullNativeBuild;ClrRuntimeSubset;ClrJitSubset;ClrPalTestsSubset;ClrAllJitsSubset;ClrILToolsSubset;ClrNativeAotSubset;ClrSpmiSubset;ClrCrossComponentsSubset;ClrDebugSubset;HostArchitecture;PgoInstrument;NativeOptimizationDataSupported;CMakeArgs
diff --git a/docs/area-owners.md b/docs/area-owners.md
index 52cb16d8d8d72..6795bebb817f3 100644
--- a/docs/area-owners.md
+++ b/docs/area-owners.md
@@ -73,9 +73,9 @@ Note: Editing this file doesn't update the mapping used by `@msftbot` for area-s
| area-System.Composition | @ericstj | @dotnet/area-system-composition | |
| area-System.Configuration | @ericstj | @dotnet/area-system-configuration | |
| area-System.Console | @jeffhandley | @dotnet/area-system-console | |
-| area-System.Data | @ajcvickers | @ajcvickers @davoudeshtehari @david-engel @roji |
- Odbc, OleDb - @saurabh500
|
-| area-System.Data.Odbc | @ajcvickers | @ajcvickers @roji | |
-| area-System.Data.OleDB | @ajcvickers | @ajcvickers @roji | |
+| area-System.Data | @sammonort | @ajcvickers @davoudeshtehari @david-engel @roji | - Odbc, OleDb - @saurabh500
|
+| area-System.Data.Odbc | @sammonort | @ajcvickers @roji | |
+| area-System.Data.OleDB | @sammonort | @ajcvickers @roji | |
| area-System.Data.SqlClient | @David-Engel | @davoudeshtehari @david-engel @jrahnama | Archived component - limited churn/contributions (see https://devblogs.microsoft.com/dotnet/introducing-the-new-microsoftdatasqlclient/) |
| area-System.DateTime | @ericstj | @dotnet/area-system-datetime | System namespace APIs related to dates and times, including DateOnly, DateTime, DateTimeKind, DateTimeOffset, DayOfWeek, TimeOnly, TimeSpan, TimeZone, and TimeZoneInfo |
| area-System.Diagnostics | @tommcdon | @dotnet/area-system-diagnostics | |
@@ -135,7 +135,7 @@ Note: Editing this file doesn't update the mapping used by `@msftbot` for area-s
| area-System.Threading.Channels | @ericstj | @dotnet/area-system-threading-channels | Consultants: @stephentoub |
| area-System.Threading.RateLimiting | @rafikiassumani-msft | @BrennanConroy @halter73 | |
| area-System.Threading.Tasks | @ericstj | @dotnet/area-system-threading-tasks | Consultants: @stephentoub |
-| area-System.Transactions | @ajcvickers | @roji | |
+| area-System.Transactions | @sammonort | @roji | |
| area-System.Xml | @jeffhandley | @dotnet/area-system-xml | |
| area-TieredCompilation-coreclr | @mangod9 | @kouvel | |
| area-Tools-ILLink | @agocke | @dotnet/illink | |
diff --git a/docs/design/coreclr/jit/first-class-structs.md b/docs/design/coreclr/jit/first-class-structs.md
index dc017aee75f2e..4211f75ff745f 100644
--- a/docs/design/coreclr/jit/first-class-structs.md
+++ b/docs/design/coreclr/jit/first-class-structs.md
@@ -94,10 +94,6 @@ encountered by most phases of the JIT:
[#21705](https://github.com/dotnet/coreclr/pull/21705) they are no longer large nodes.
* `GT_STORE_OBJ` and `GT_STORE_BLK` have the same structure as `GT_OBJ` and `GT_BLK`, respectively
* `Data()` is op2
- * `GT_STORE_DYN_BLK` (GenTreeStoreDynBlk extends GenTreeBlk)
- * Additional child `gtDynamicSize`
- * Note that these aren't really struct stores; they represent dynamically sized blocks
- of arbitrary data.
* For `GT_LCL_FLD` nodes, we store a pointer to `ClassLayout` in the node.
* For `GT_LCL_VAR` nodes, the `ClassLayout` is obtained from the `LclVarDsc`.
diff --git a/docs/design/coreclr/jit/ryujit-overview.md b/docs/design/coreclr/jit/ryujit-overview.md
index cdb17002ee197..5e63d38e98f66 100644
--- a/docs/design/coreclr/jit/ryujit-overview.md
+++ b/docs/design/coreclr/jit/ryujit-overview.md
@@ -222,6 +222,7 @@ The top-level function of interest is `Compiler::compCompile`. It invokes the fo
| [Common Subexpression Elimination (CSE)](#cse) | Elimination of redundant subexressions based on value numbers. |
| [Assertion Propagation](#assertion-propagation) | Utilizes value numbers to propagate and transform based on properties such as non-nullness. |
| [Range analysis](#range-analysis) | Eliminate array index range checks based on value numbers and assertions |
+| [Induction variable optimization](#iv-opts) | Optimize induction variables used inside natural loops based on scalar evolution analysis |
| [VN-based dead store elimination](#vn-based-dead-store-elimination) | Eliminate stores that do not change the value of a local. |
| [If conversion](#if-conversion) | Transform conditional definitions into `GT_SELECT` operators. |
| [Rationalization](#rationalization) | Flowgraph order changes from `FGOrderTree` to `FGOrderLinear`. All `GT_COMMA` nodes are transformed. |
@@ -347,6 +348,11 @@ reused.
Utilizes value numbers to propagate and transform based on properties such as non-nullness.
+### Induction variable optimization
+
+Performs scalar evolution analysis and utilized it to optimize induction variables inside loops.
+Currently this entails IV widening which is done on x64 only.
+
### Range analysis
Optimize array index range checks based on value numbers and assertions.
diff --git a/docs/design/coreclr/jit/ryujit-tutorial.md b/docs/design/coreclr/jit/ryujit-tutorial.md
index 34466e45afbcd..ec900ccc8cd93 100644
--- a/docs/design/coreclr/jit/ryujit-tutorial.md
+++ b/docs/design/coreclr/jit/ryujit-tutorial.md
@@ -447,6 +447,10 @@ This is the same diagram as before, but with additional links to indicate execut
- Determine initial value for dependent phis
- Eliminate checks where the range of the index is within the check range
+### Induction Variable Optimization
+- Perform scalar evolution analysis to describe values of IR nodes inside loops
+- Perform IV widening on x64 to avoid unnecessary zero extensions for array/span indexing
+
## RyuJIT Back-End
### Rationalization
diff --git a/docs/workflow/ci/failure-analysis.md b/docs/workflow/ci/failure-analysis.md
index 57917c841316a..58a11c06bdfa4 100644
--- a/docs/workflow/ci/failure-analysis.md
+++ b/docs/workflow/ci/failure-analysis.md
@@ -12,6 +12,19 @@
## Triaging errors seen in CI
+## Summary
+
+**Passing Build Analysis is required to merge into the runtime repo**.
+
+To resolve failures, do the following, in order:
+
+1. Fix the problem if your PR is the cause.
+2. For all failures not in the "Known test errors" section, [try to file a Known Build Error issue](#what-to-do-if-you-determine-the-failure-is-unrelated).
+3. If all else fails, perform a [manual bypass](#bypassing-build-analysis).
+
+
+## Details
+
In case of failure, any PR on the runtime will have a failed GitHub check - PR Build Analysis - which has a summary of all failures, including a list of matching known issues as well as any regressions introduced to the build or the tests. This tab should be your first stop for analyzing the PR failures.
![Build analysis check](analysis-check.png)
@@ -78,6 +91,7 @@ If you have considered all the diagnostic artifacts and determined the failure i
````
It already contains most of the essential information, but *it is very important that you fill out the json blob*.
+ - You can now use the [Build Analysis Known Issue Helper](https://helix.dot.net/BuildAnalysis/CreateKnownIssues) to create an issue. It assists in adding the right set of labels, fill the necessary paths in the json blob, and it will validate that it matches the text presented for the issue found in the logs.
- You can add into the `ErrorMessage` field the string that you found uniquely identifies the issue. In case you need to use a regex, use the `ErrorPattern` field instead. This is a limited to a single-line, non-backtracking regex as described [here](https://github.com/dotnet/arcade/blob/main/Documentation/Projects/Build%20Analysis/KnownIssues.md#regex-matching). This regex also needs to be appropriately escaped. Check the [arcade known issues](https://github.com/dotnet/arcade/blob/main/Documentation/Projects/Build%20Analysis/KnownIssues.md#filling-out-known-issues-json-blob) documentation for a good guide on proper regex and JSON escaping.
- The field `ExcludeConsoleLog` describes if the execution logs should be considered on top of the individual test results. **For most cases, this should be set to `true` as the failure will happen within a single test**. Setting it to `false` will mean all failures within an xUnit set of tests will also get attributed to this particular error, since there's one log describing all the problems. Due to limitations in Known Issues around rate limiting and xUnit resiliency, setting `ExcludeConsoleLog=false` is necessary in two scenarios:
+ Nested tests as reported to Azure DevOps. Essentially this means theory failures, which look like this when reported in Azure DevOps: ![xUnit theory seen in azure devops](theory-azdo.png).
@@ -95,6 +109,16 @@ After you do this, if the failure is occurring frequently as per the data captur
There are plenty of intermittent failures that won't manifest again on a retry. Therefore these steps should be followed for every iteration of the PR build, e.g. before retrying/rebuilding.
+### Bypassing build analysis
+
+To unconditionally bypass the build analysis check (turn it green), you can add a comment to your PR with the following text:
+
+```
+/ba-g
+```
+
+For more information, see https://github.com/dotnet/arcade/blob/main/Documentation/Projects/Build%20Analysis/EscapeMechanismforBuildAnalysis.md
+
### Examples of Build Analysis
#### Good usage examples
diff --git a/eng/DotNetBuild.props b/eng/DotNetBuild.props
index 53d03c7f4dd1d..a6350c7fea93f 100644
--- a/eng/DotNetBuild.props
+++ b/eng/DotNetBuild.props
@@ -21,6 +21,10 @@
<_hostArch>$(_hostRid.Substring($(_hostRidPlatformIndex)).TrimStart('-'))
minimal
+
+
+ true
diff --git a/eng/Subsets.props b/eng/Subsets.props
index dd284ea6d9977..29d7467e6b43e 100644
--- a/eng/Subsets.props
+++ b/eng/Subsets.props
@@ -255,7 +255,7 @@
-
+
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 3ee91b259e46d..327d959b892e8 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -1,8 +1,8 @@
-
+
https://github.com/dotnet/icu
- c15a038f408fef6814e5f9c0bf8882bcdf53a290
+ 9c4c9995bc756a01597b5efb0e452ef879a76d99
https://github.com/dotnet/msquic
@@ -12,9 +12,9 @@
https://github.com/dotnet/wcf
7f504aabb1988e9a093c1e74d8040bd52feb2f01
-
+
https://github.com/dotnet/emsdk
- 2d3f1fe4807a21879cedba9d3fde8cd329fb17f2
+ 0f3e462442af5fe65271e3185d5b645ad40a6041
https://github.com/dotnet/llvm-project
@@ -90,121 +90,121 @@
a045dd54a4c44723c215d992288160eb1401bb7f
-
+
https://github.com/dotnet/cecil
- 61250b0ed403b3f9b69a33f7d8f66f311338d6a1
+ 0d0bc8e0f47fdae9834e1eac678f364c50946133
-
+
https://github.com/dotnet/cecil
- 61250b0ed403b3f9b69a33f7d8f66f311338d6a1
+ 0d0bc8e0f47fdae9834e1eac678f364c50946133
-
+
https://github.com/dotnet/emsdk
- 2d3f1fe4807a21879cedba9d3fde8cd329fb17f2
+ 0f3e462442af5fe65271e3185d5b645ad40a6041
-
+
https://github.com/dotnet/emsdk
- 2d3f1fe4807a21879cedba9d3fde8cd329fb17f2
+ 0f3e462442af5fe65271e3185d5b645ad40a6041
-
+
https://github.com/dotnet/source-build-reference-packages
- 2f79f97b7a6a0cf2ca3297a8fa526e6f4ea98ce2
+ 62fb9a85e5c4af657b0014fd6d6588c139d0bb4f
-
+
https://github.com/dotnet/source-build-externals
- ddfb60463c966af55fd0e222c2266170e83d1324
+ 88f13afba58a6c455039d71bbdd2cff3d847b236
-
+
https://github.com/dotnet/arcade
- c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb
+ 9aa3f2e68b30ac51823dd444e8cb962e058c5699
-
+
https://github.com/dotnet/arcade
- c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb
+ 9aa3f2e68b30ac51823dd444e8cb962e058c5699
-
+
https://github.com/dotnet/arcade
- c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb
+ 9aa3f2e68b30ac51823dd444e8cb962e058c5699
-
+
https://github.com/dotnet/arcade
- c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb
+ 9aa3f2e68b30ac51823dd444e8cb962e058c5699
-
+
https://github.com/dotnet/arcade
- c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb
+ 9aa3f2e68b30ac51823dd444e8cb962e058c5699
-
+
https://github.com/dotnet/arcade
- c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb
+ 9aa3f2e68b30ac51823dd444e8cb962e058c5699
-
+
https://github.com/dotnet/arcade
- c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb
+ 9aa3f2e68b30ac51823dd444e8cb962e058c5699
-
+
https://github.com/dotnet/arcade
- c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb
+ 9aa3f2e68b30ac51823dd444e8cb962e058c5699
-
+
https://github.com/dotnet/arcade
- c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb
+ 9aa3f2e68b30ac51823dd444e8cb962e058c5699
-
+
https://github.com/dotnet/arcade
- c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb
+ 9aa3f2e68b30ac51823dd444e8cb962e058c5699
-
+
https://github.com/dotnet/arcade
- c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb
+ 9aa3f2e68b30ac51823dd444e8cb962e058c5699
-
+
https://github.com/dotnet/arcade
- c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb
+ 9aa3f2e68b30ac51823dd444e8cb962e058c5699
-
+
https://github.com/dotnet/arcade
- c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb
+ 9aa3f2e68b30ac51823dd444e8cb962e058c5699
-
+
https://github.com/dotnet/arcade
- c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb
+ 9aa3f2e68b30ac51823dd444e8cb962e058c5699
-
+
https://github.com/dotnet/arcade
- c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb
+ 9aa3f2e68b30ac51823dd444e8cb962e058c5699
-
+
https://github.com/dotnet/arcade
- c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb
+ 9aa3f2e68b30ac51823dd444e8cb962e058c5699
-
+
https://github.com/dotnet/arcade
- c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb
+ 9aa3f2e68b30ac51823dd444e8cb962e058c5699
-
+
https://github.com/dotnet/arcade
- c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb
+ 9aa3f2e68b30ac51823dd444e8cb962e058c5699
-
+
https://github.com/dotnet/arcade
- c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb
+ 9aa3f2e68b30ac51823dd444e8cb962e058c5699
-
+
https://github.com/dotnet/arcade
- c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb
+ 9aa3f2e68b30ac51823dd444e8cb962e058c5699
https://github.com/dotnet/runtime-assets
@@ -314,43 +314,43 @@
https://github.com/dotnet/llvm-project
9885e5aecc176ca701fc3527877d608bf7ccfb7d
-
+
https://github.com/dotnet/runtime
- d972a19c077e899d0b3fff97d955968e50906396
+ c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4
-
+
https://github.com/dotnet/runtime
- d972a19c077e899d0b3fff97d955968e50906396
+ c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4
-
+
https://github.com/dotnet/runtime
- d972a19c077e899d0b3fff97d955968e50906396
+ c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4
-
+
https://github.com/dotnet/runtime
- d972a19c077e899d0b3fff97d955968e50906396
+ c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4
-
+
https://github.com/dotnet/runtime
- d972a19c077e899d0b3fff97d955968e50906396
+ c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4
-
+
https://github.com/dotnet/runtime
- d972a19c077e899d0b3fff97d955968e50906396
+ c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4
-
+
https://github.com/dotnet/runtime
- d972a19c077e899d0b3fff97d955968e50906396
+ c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4
-
+
https://github.com/dotnet/runtime
- d972a19c077e899d0b3fff97d955968e50906396
+ c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4
-
+
https://github.com/dotnet/runtime
- d972a19c077e899d0b3fff97d955968e50906396
+ c55c4d50793c878cc73ae6ca3335f2b6b3ccc8a4
https://github.com/dotnet/xharness
@@ -364,9 +364,9 @@
https://github.com/dotnet/xharness
8aa2a4cb80000ebb46ee61cd6ac29b2e63ebe87c
-
+
https://github.com/dotnet/arcade
- c3f5cbfb2829795294f5c2d9fa5a0522f47e91fb
+ 9aa3f2e68b30ac51823dd444e8cb962e058c5699
https://dev.azure.com/dnceng/internal/_git/dotnet-optimization
@@ -384,9 +384,9 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-optimization
db9f1c2362565f3ef41c8e8feb5ed49ab11a6459
-
+
https://github.com/dotnet/hotreload-utils
- ec73ebf54c4ae98ac1450fcf95998180d4160f31
+ 81cdd6568c7360cf337b1ab6a2dcf2ce84530a7f
https://github.com/dotnet/runtime-assets
@@ -399,19 +399,18 @@
https://github.com/dotnet/roslyn
77372c66fd54927312b5b0a2e399e192f74445c9
-
https://github.com/dotnet/roslyn
77372c66fd54927312b5b0a2e399e192f74445c9
-
+
https://github.com/dotnet/roslyn-analyzers
- 4195460a822168a75aa3d31b4a8d0fa88c42855c
+ ba8b7f2c3ae092d0301f0c5e49bd30340af553c8
-
+
https://github.com/dotnet/roslyn-analyzers
- 4195460a822168a75aa3d31b4a8d0fa88c42855c
+ ba8b7f2c3ae092d0301f0c5e49bd30340af553c8
@@ -419,14 +418,14 @@
77372c66fd54927312b5b0a2e399e192f74445c9
-
+
https://github.com/dotnet/sdk
- b834bb25bdf308c4971d00cef6b726dfaa828c66
+ 7900db19bd7d1a384490909f085cec371ec696d2
-
+
https://github.com/dotnet/sdk
- b834bb25bdf308c4971d00cef6b726dfaa828c66
+ 7900db19bd7d1a384490909f085cec371ec696d2
@@ -443,9 +442,9 @@
https://github.com/NuGet/NuGet.Client
8fef55f5a55a3b4f2c96cd1a9b5ddc51d4b927f8
-
+
https://github.com/dotnet/installer
- e6b3ff2dff85b43bd3a323e7c0bac4f1f58ccd62
+ d070660282eb5f78497310f77093638744112e03
diff --git a/eng/Versions.props b/eng/Versions.props
index 5c7aeded43391..256e6e83a22f8 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -11,7 +11,7 @@
7.0.$([MSBuild]::Add($([System.Version]::Parse('$(PackageVersionNet8)').Build),14))
6.0.$([MSBuild]::Add($([System.Version]::Parse('$(PackageVersionNet7)').Build),11))
preview
- 2
+ 3
false
release
@@ -34,8 +34,8 @@
- 3.11.0-beta1.24121.1
- 9.0.0-preview.24121.1
+ 3.11.0-beta1.24122.2
+ 9.0.0-preview.24122.2
- 9.0.100-preview.2.24118.3
+ 9.0.100-preview.3.24126.1
- 9.0.0-beta.24112.1
- 9.0.0-beta.24112.1
- 9.0.0-beta.24112.1
- 9.0.0-beta.24112.1
- 2.6.7-beta.24112.1
- 9.0.0-beta.24112.1
- 2.6.7-beta.24112.1
- 9.0.0-beta.24112.1
- 9.0.0-beta.24112.1
- 9.0.0-beta.24112.1
- 9.0.0-beta.24112.1
- 9.0.0-beta.24112.1
- 9.0.0-beta.24112.1
- 9.0.0-beta.24112.1
- 9.0.0-beta.24112.1
- 9.0.0-beta.24112.1
+ 9.0.0-beta.24127.4
+ 9.0.0-beta.24127.4
+ 9.0.0-beta.24127.4
+ 9.0.0-beta.24127.4
+ 2.6.7-beta.24127.4
+ 9.0.0-beta.24127.4
+ 2.6.7-beta.24127.4
+ 9.0.0-beta.24127.4
+ 9.0.0-beta.24127.4
+ 9.0.0-beta.24127.4
+ 9.0.0-beta.24127.4
+ 9.0.0-beta.24127.4
+ 9.0.0-beta.24127.4
+ 9.0.0-beta.24127.4
+ 9.0.0-beta.24127.4
+ 9.0.0-beta.24127.4
1.4.0
6.0.0-preview.1.102
- 9.0.0-preview.2.24116.2
+ 9.0.0-preview.3.24126.1
6.0.0
- 9.0.0-preview.2.24116.2
+ 9.0.0-preview.3.24126.1
16.0.5-alpha.1.24112.1
16.0.5-alpha.1.24112.1
@@ -128,19 +128,19 @@
8.0.0
5.0.0
4.5.5
- 9.0.0-preview.2.24116.2
- 9.0.0-preview.2.24116.2
+ 9.0.0-preview.3.24126.1
+ 9.0.0-preview.3.24126.1
6.0.0
5.0.0
5.0.0
5.0.0
7.0.0
- 9.0.0-preview.2.24116.2
+ 9.0.0-preview.3.24126.1
6.0.0
7.0.0
4.5.4
4.5.0
- 9.0.0-preview.2.24116.2
+ 9.0.0-preview.3.24126.1
8.0.0
8.0.0
@@ -190,7 +190,7 @@
9.0.0-prerelease.24119.1
9.0.0-prerelease.24119.1
9.0.0-prerelease.24119.1
- 9.0.0-alpha.0.24119.1
+ 9.0.0-alpha.0.24120.1
3.12.0
4.5.0
6.0.0
@@ -216,11 +216,11 @@
8.0.0-preview-20230918.1
- 0.11.4-alpha.24119.1
+ 0.11.4-alpha.24120.1
- 9.0.0-preview.2.24116.2
+ 9.0.0-preview.3.24126.1
- 9.0.0-preview.2.24119.1
+ 9.0.0-preview.3.24123.1
2.2.3
9.0.0-alpha.1.24067.1
@@ -243,9 +243,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.2.24121.1
+ 9.0.0-preview.3.24126.1
$(MicrosoftNETWorkloadEmscriptenCurrentManifest90100TransportVersion)
- 9.0.0-preview.2.24121.1
+ 9.0.0-preview.3.24126.1
1.1.87-gba258badda
1.0.0-v3.14.0.5722
@@ -262,7 +262,7 @@
3.1.7
1.0.406601
- 9.0.100-preview.2.24116.21
+ 9.0.100-preview.3.24126.2
$(MicrosoftDotnetSdkInternalVersion)
diff --git a/eng/build.ps1 b/eng/build.ps1
index db18267f33e1c..be88dcb263e8d 100644
--- a/eng/build.ps1
+++ b/eng/build.ps1
@@ -325,6 +325,9 @@ if ($env:TreatWarningsAsErrors -eq 'false') {
$arguments += " -warnAsError 0"
}
+# disable terminal logger for now: https://github.com/dotnet/runtime/issues/97211
+$arguments += " /tl:false"
+
# Disable targeting pack caching as we reference a partially constructed targeting pack and update it later.
# The later changes are ignored when using the cache.
$env:DOTNETSDK_ALLOW_TARGETING_PACK_CACHING=0
diff --git a/eng/build.sh b/eng/build.sh
index 67f3cfeea4727..75fe2cdc39c5d 100755
--- a/eng/build.sh
+++ b/eng/build.sh
@@ -553,6 +553,9 @@ if [[ "${TreatWarningsAsErrors:-}" == "false" ]]; then
arguments="$arguments -warnAsError 0"
fi
+# disable terminal logger for now: https://github.com/dotnet/runtime/issues/97211
+arguments="$arguments -tl:false"
+
initDistroRid "$os" "$arch" "$crossBuild"
# Disable targeting pack caching as we reference a partially constructed targeting pack and update it later.
diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1
index 7d8dc89b919bc..269fdb9420da9 100644
--- a/eng/common/tools.ps1
+++ b/eng/common/tools.ps1
@@ -65,6 +65,9 @@ $ErrorActionPreference = 'Stop'
# Base-64 encoded SAS token that has permission to storage container described by $runtimeSourceFeed
[string]$runtimeSourceFeedKey = if (Test-Path variable:runtimeSourceFeedKey) { $runtimeSourceFeedKey } else { $null }
+# True if the build is a product build
+[bool]$productBuild = if (Test-Path variable:productBuild) { $productBuild } else { $false }
+
function Create-Directory ([string[]] $path) {
New-Item -Path $path -Force -ItemType 'Directory' | Out-Null
}
@@ -850,7 +853,8 @@ function MSBuild-Core() {
}
# When running on Azure Pipelines, override the returned exit code to avoid double logging.
- if ($ci -and $env:SYSTEM_TEAMPROJECT -ne $null) {
+ # Skip this when the build is a child of the VMR orchestrator build.
+ if ($ci -and $env:SYSTEM_TEAMPROJECT -ne $null -and !$productBuild -and $properties -notlike "*DotNetBuildRepo=true*") {
Write-PipelineSetResult -Result "Failed" -Message "msbuild execution failed."
# Exiting with an exit code causes the azure pipelines task to log yet another "noise" error
# The above Write-PipelineSetResult will cause the task to be marked as failure without adding yet another error
diff --git a/eng/common/tools.sh b/eng/common/tools.sh
index ece4b73079536..6f0141e7d513f 100755
--- a/eng/common/tools.sh
+++ b/eng/common/tools.sh
@@ -68,6 +68,9 @@ fi
runtime_source_feed=${runtime_source_feed:-''}
runtime_source_feed_key=${runtime_source_feed_key:-''}
+# True if the build is a product build
+product_build=${product_build:-false}
+
# Resolve any symlinks in the given path.
function ResolvePath {
local path=$1
@@ -141,7 +144,7 @@ function InitializeDotNetCli {
if [[ $global_json_has_runtimes == false && -n "${DOTNET_INSTALL_DIR:-}" && -d "$DOTNET_INSTALL_DIR/sdk/$dotnet_sdk_version" ]]; then
dotnet_root="$DOTNET_INSTALL_DIR"
else
- dotnet_root="$repo_root/.dotnet"
+ dotnet_root="${repo_root}.dotnet"
export DOTNET_INSTALL_DIR="$dotnet_root"
@@ -503,7 +506,8 @@ function MSBuild-Core {
echo "Build failed with exit code $exit_code. Check errors above."
# When running on Azure Pipelines, override the returned exit code to avoid double logging.
- if [[ "$ci" == "true" && -n ${SYSTEM_TEAMPROJECT:-} ]]; then
+ # Skip this when the build is a child of the VMR orchestrator build.
+ if [[ "$ci" == true && -n ${SYSTEM_TEAMPROJECT:-} && "$product_build" != true && $properties != *"DotNetBuildRepo=true"* ]]; then
Write-PipelineSetResult -result "Failed" -message "msbuild execution failed."
# Exiting with an exit code causes the azure pipelines task to log yet another "noise" error
# The above Write-PipelineSetResult will cause the task to be marked as failure without adding yet another error
diff --git a/eng/pipelines/common/xplat-setup.yml b/eng/pipelines/common/xplat-setup.yml
index c66fec22bead5..dfb8952b423e4 100644
--- a/eng/pipelines/common/xplat-setup.yml
+++ b/eng/pipelines/common/xplat-setup.yml
@@ -171,9 +171,13 @@ jobs:
demands: ImageOverride -equals Build.Ubuntu.2204.Amd64
# OSX Build Pool (we don't have on-prem OSX BuildPool).
- ${{ if in(parameters.osGroup, 'osx', 'maccatalyst', 'ios', 'iossimulator', 'tvos', 'tvossimulator') }}:
+ ${{ if and(in(parameters.osGroup, 'osx', 'maccatalyst', 'ios', 'iossimulator', 'tvos', 'tvossimulator'), eq(variables['System.TeamProject'], 'public')) }}:
vmImage: 'macos-12'
+ # Official build OSX pool
+ ${{ if and(in(parameters.osGroup, 'osx', 'maccatalyst', 'ios', 'iossimulator', 'tvos', 'tvossimulator'), ne(variables['System.TeamProject'], 'public')) }}:
+ vmImage: 'macos-13-arm64'
+
# Official Build Windows Pool
${{ if and(or(eq(parameters.osGroup, 'windows'), eq(parameters.jobParameters.hostedOs, 'windows')), ne(variables['System.TeamProject'], 'public')) }}:
name: $(DncEngInternalBuildPool)
diff --git a/eng/pipelines/coreclr/runtime-nativeaot-outerloop.yml b/eng/pipelines/coreclr/runtime-nativeaot-outerloop.yml
index b348c636ffb2e..de23519f9c62e 100644
--- a/eng/pipelines/coreclr/runtime-nativeaot-outerloop.yml
+++ b/eng/pipelines/coreclr/runtime-nativeaot-outerloop.yml
@@ -68,7 +68,7 @@ extends:
testGroup: innerloop
isSingleFile: true
nameSuffix: NativeAOT_Libs
- buildArgs: -s clr.aot+host.native+libs+libs.tests -c $(_BuildConfig) /p:TestNativeAot=true /p:ArchiveTests=true /p:IlcUseServerGc=false
+ buildArgs: -s clr.aot+host.native+libs+libs.tests -c $(_BuildConfig) /p:TestNativeAot=true /p:ArchiveTests=true /p:IlcUseServerGc=false /p:RunAnalyzers=false
timeoutInMinutes: 300 # doesn't normally take this long, but I've seen Helix queues backed up for 160 minutes
includeAllPlatforms: true
# extra steps, run tests
@@ -94,7 +94,7 @@ extends:
testGroup: innerloop
isSingleFile: true
nameSuffix: NativeAOT_Checked_Libs
- buildArgs: -s clr.aot+host.native+libs+libs.tests -c $(_BuildConfig) -rc Checked /p:TestNativeAot=true /p:ArchiveTests=true /p:IlcUseServerGc=false
+ buildArgs: -s clr.aot+host.native+libs+libs.tests -c $(_BuildConfig) -rc Checked /p:TestNativeAot=true /p:ArchiveTests=true /p:IlcUseServerGc=false /p:RunAnalyzers=false
timeoutInMinutes: 360
# extra steps, run tests
postBuildSteps:
@@ -119,7 +119,7 @@ extends:
testGroup: innerloop
isSingleFile: true
nameSuffix: NativeAOT_Checked_Libs_SizeOpt
- buildArgs: -s clr.aot+host.native+libs+libs.tests -c $(_BuildConfig) -rc Checked /p:TestNativeAot=true /p:ArchiveTests=true /p:OptimizationPreference=Size /p:IlcUseServerGc=false
+ buildArgs: -s clr.aot+host.native+libs+libs.tests -c $(_BuildConfig) -rc Checked /p:TestNativeAot=true /p:ArchiveTests=true /p:OptimizationPreference=Size /p:IlcUseServerGc=false /p:RunAnalyzers=false
timeoutInMinutes: 240
# extra steps, run tests
postBuildSteps:
@@ -144,7 +144,7 @@ extends:
testGroup: innerloop
isSingleFile: true
nameSuffix: NativeAOT_Checked_Libs_SpeedOpt
- buildArgs: -s clr.aot+host.native+libs+libs.tests -c $(_BuildConfig) -rc Checked /p:TestNativeAot=true /p:ArchiveTests=true /p:OptimizationPreference=Speed /p:IlcUseServerGc=false
+ buildArgs: -s clr.aot+host.native+libs+libs.tests -c $(_BuildConfig) -rc Checked /p:TestNativeAot=true /p:ArchiveTests=true /p:OptimizationPreference=Speed /p:IlcUseServerGc=false /p:RunAnalyzers=false
timeoutInMinutes: 240
# extra steps, run tests
postBuildSteps:
@@ -174,7 +174,7 @@ extends:
jobParameters:
timeoutInMinutes: 240
nameSuffix: NativeAOT_Pri0
- buildArgs: -s clr.aot+host.native+libs -rc $(_BuildConfig) -lc Release -hc Release
+ buildArgs: -s clr.aot+host.native+libs -rc $(_BuildConfig) -lc Release -hc Release /p:RunAnalyzers=false
postBuildSteps:
- template: /eng/pipelines/coreclr/nativeaot-post-build-steps.yml
parameters:
diff --git a/eng/pipelines/coreclr/templates/helix-queues-setup.yml b/eng/pipelines/coreclr/templates/helix-queues-setup.yml
index 7b4ce6c6c7f43..9339194111448 100644
--- a/eng/pipelines/coreclr/templates/helix-queues-setup.yml
+++ b/eng/pipelines/coreclr/templates/helix-queues-setup.yml
@@ -86,9 +86,9 @@ jobs:
# Linux musl arm32
- ${{ if eq(parameters.platform, 'linux_musl_arm') }}:
- ${{ if eq(variables['System.TeamProject'], 'public') }}:
- - (Alpine.316.Arm32.Open)Ubuntu.2004.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.16-helix-arm32v7
+ - (Alpine.316.Arm32.Open)Ubuntu.2004.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.17-helix-arm32v7
- ${{ if eq(variables['System.TeamProject'], 'internal') }}:
- - (Alpine.316.Arm32)Ubuntu.2004.ArmArch@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.16-helix-arm32v7
+ - (Alpine.316.Arm32)Ubuntu.2004.ArmArch@mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.17-helix-arm32v7
# Linux musl arm64
- ${{ if eq(parameters.platform, 'linux_musl_arm64') }}:
diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml
index be2870611e617..d7a1f1847eb11 100644
--- a/eng/pipelines/runtime.yml
+++ b/eng/pipelines/runtime.yml
@@ -254,7 +254,7 @@ extends:
jobParameters:
timeoutInMinutes: 120
nameSuffix: NativeAOT
- buildArgs: -s clr.aot+host.native+libs -rc $(_BuildConfig) -lc Release -hc Release
+ buildArgs: -s clr.aot+host.native+libs -rc $(_BuildConfig) -lc Release -hc Release /p:RunAnalyzers=false
postBuildSteps:
- template: /eng/pipelines/coreclr/nativeaot-post-build-steps.yml
parameters:
@@ -293,7 +293,7 @@ extends:
jobParameters:
timeoutInMinutes: 180
nameSuffix: NativeAOT
- buildArgs: -s clr.aot+host.native+libs.native+libs.sfx -rc $(_BuildConfig) -lc Release -hc Release
+ buildArgs: -s clr.aot+host.native+libs.native+libs.sfx -rc $(_BuildConfig) -lc Release -hc Release /p:RunAnalyzers=false
postBuildSteps:
- template: /eng/pipelines/coreclr/nativeaot-post-build-steps.yml
parameters:
@@ -338,7 +338,7 @@ extends:
testGroup: innerloop
timeoutInMinutes: 120
nameSuffix: NativeAOT
- buildArgs: -s clr.aot+host.native+libs+tools.illink -c $(_BuildConfig) -rc $(_BuildConfig) -lc Release -hc Release
+ buildArgs: -s clr.aot+host.native+libs+tools.illink -c $(_BuildConfig) -rc $(_BuildConfig) -lc Release -hc Release /p:RunAnalyzers=false
postBuildSteps:
- template: /eng/pipelines/coreclr/nativeaot-post-build-steps.yml
parameters:
@@ -375,7 +375,7 @@ extends:
testGroup: innerloop
isSingleFile: true
nameSuffix: NativeAOT_Libraries
- buildArgs: -s clr.aot+host.native+libs+libs.tests -c $(_BuildConfig) /p:TestNativeAot=true /p:RunSmokeTestsOnly=true /p:ArchiveTests=true
+ buildArgs: -s clr.aot+host.native+libs+libs.tests -c $(_BuildConfig) /p:TestNativeAot=true /p:RunSmokeTestsOnly=true /p:ArchiveTests=true /p:RunAnalyzers=false
timeoutInMinutes: 240 # Doesn't actually take long, but we've seen the ARM64 Helix queue often get backlogged for 2+ hours
# extra steps, run tests
postBuildSteps:
diff --git a/eng/testing/ChromeVersions.props b/eng/testing/ChromeVersions.props
index 8549c7646a516..ecf01665114dd 100644
--- a/eng/testing/ChromeVersions.props
+++ b/eng/testing/ChromeVersions.props
@@ -1,12 +1,12 @@
- 121.0.6167.184
- 1233107
- https://storage.googleapis.com/chromium-browser-snapshots/Linux_x64/1233114
- 12.1.285
- 121.0.6167.185
- 1233107
- https://storage.googleapis.com/chromium-browser-snapshots/Win_x64/1233136
- 12.1.285
+ 122.0.6261.69
+ 1250580
+ https://storage.googleapis.com/chromium-browser-snapshots/Linux_x64/1250580
+ 12.2.281
+ 122.0.6261.69
+ 1250580
+ https://storage.googleapis.com/chromium-browser-snapshots/Win_x64/1250586
+ 12.2.281
\ No newline at end of file
diff --git a/global.json b/global.json
index 1e159da9c5464..6fe08725d44cf 100644
--- a/global.json
+++ b/global.json
@@ -1,18 +1,18 @@
{
"sdk": {
- "version": "9.0.100-alpha.1.23615.4",
+ "version": "9.0.100-preview.1.24101.2",
"allowPrerelease": true,
"rollForward": "major"
},
"tools": {
- "dotnet": "9.0.100-alpha.1.23615.4"
+ "dotnet": "9.0.100-preview.1.24101.2"
},
"msbuild-sdks": {
- "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.24112.1",
- "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.24112.1",
- "Microsoft.DotNet.SharedFramework.Sdk": "9.0.0-beta.24112.1",
+ "Microsoft.DotNet.Arcade.Sdk": "9.0.0-beta.24127.4",
+ "Microsoft.DotNet.Helix.Sdk": "9.0.0-beta.24127.4",
+ "Microsoft.DotNet.SharedFramework.Sdk": "9.0.0-beta.24127.4",
"Microsoft.Build.NoTargets": "3.7.0",
"Microsoft.Build.Traversal": "3.4.0",
- "Microsoft.NET.Sdk.IL": "9.0.0-preview.2.24116.2"
+ "Microsoft.NET.Sdk.IL": "9.0.0-preview.3.24126.1"
}
}
diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
index 6b3ddff0cc868..d005341dae6b1 100644
--- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -203,7 +203,6 @@
-
@@ -231,7 +230,6 @@
-
diff --git a/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs b/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs
index db8d4ead4659b..77f64abd1b42c 100644
--- a/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs
+++ b/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs
@@ -203,7 +203,6 @@ private static void ClassRegistrationScenarioForType(ComActivationContext cxt, b
// Finally validate signature
ReadOnlySpan methParams = method.GetParametersAsSpan();
if (method.ReturnType != typeof(void)
- || methParams == null
|| methParams.Length != 1
|| (methParams[0].ParameterType != typeof(string) && methParams[0].ParameterType != typeof(Type)))
{
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Object.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Object.CoreCLR.cs
index 88c929dbe74cb..940d1622bad18 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Object.CoreCLR.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Object.CoreCLR.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.Diagnostics;
using System.Runtime.CompilerServices;
namespace System
@@ -19,7 +20,9 @@ public partial class Object
[Intrinsic]
protected internal unsafe object MemberwiseClone()
{
- object clone = RuntimeHelpers.AllocateUninitializedClone(this);
+ object clone = this;
+ RuntimeHelpers.AllocateUninitializedClone(ObjectHandleOnStack.Create(ref clone));
+ Debug.Assert(clone != this);
// copy contents of "this" to the clone
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs
index 2b695f1baf5b0..327113c63f9a3 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs
@@ -417,7 +417,7 @@ private int GetMemberRefToken(MethodInfo methodInfo, Type[]? optionalParameterTy
throw new ArgumentException(SR.Argument_MustBeRuntimeMethodInfo, nameof(methodInfo));
ReadOnlySpan paramInfo = methodInfo.GetParametersAsSpan();
- if (paramInfo != null && paramInfo.Length != 0)
+ if (paramInfo.Length != 0)
{
parameterTypes = new Type[paramInfo.Length];
requiredCustomModifiers = new Type[parameterTypes.Length][];
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs
index b5cff2f1e42ec..53f2690948df4 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs
@@ -645,27 +645,29 @@ public override Assembly GetSatelliteAssembly(CultureInfo culture, Version? vers
{
ArgumentNullException.ThrowIfNull(culture);
- return InternalGetSatelliteAssembly(culture, version, throwOnFileNotFound: true)!;
+ return InternalGetSatelliteAssembly(this, culture, version, throwOnFileNotFound: true)!;
}
[DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
- internal Assembly? InternalGetSatelliteAssembly(CultureInfo culture,
+ internal static Assembly? InternalGetSatelliteAssembly(Assembly assembly,
+ CultureInfo culture,
Version? version,
bool throwOnFileNotFound)
{
var an = new AssemblyName();
- an.SetPublicKey(GetPublicKey());
- an.Flags = GetFlags() | AssemblyNameFlags.PublicKey;
- an.Version = version ?? GetVersion();
+ RuntimeAssembly runtimeAssembly = (RuntimeAssembly)assembly;
+ an.SetPublicKey(runtimeAssembly.GetPublicKey());
+ an.Flags = runtimeAssembly.GetFlags() | AssemblyNameFlags.PublicKey;
+ an.Version = version ?? runtimeAssembly.GetVersion();
an.CultureInfo = culture;
- an.Name = GetSimpleName() + ".resources";
+ an.Name = runtimeAssembly.GetSimpleName() + ".resources";
// This stack crawl mark is never used because the requesting assembly is explicitly specified,
// so the value could be anything.
StackCrawlMark unused = default;
- RuntimeAssembly? retAssembly = InternalLoad(an, ref unused, requestingAssembly: this, throwOnFileNotFound: throwOnFileNotFound);
+ RuntimeAssembly? retAssembly = InternalLoad(an, ref unused, requestingAssembly: runtimeAssembly, throwOnFileNotFound: throwOnFileNotFound);
- if (retAssembly == this)
+ if (retAssembly == runtimeAssembly)
{
retAssembly = null;
}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Resources/ManifestBasedResourceGroveler.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Resources/ManifestBasedResourceGroveler.CoreCLR.cs
deleted file mode 100644
index 05805072cd7cf..0000000000000
--- a/src/coreclr/System.Private.CoreLib/src/System/Resources/ManifestBasedResourceGroveler.CoreCLR.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Globalization;
-using System.Reflection;
-
-namespace System.Resources
-{
- internal sealed partial class ManifestBasedResourceGroveler
- {
- // Internal version of GetSatelliteAssembly that avoids throwing FileNotFoundException
- private static Assembly? InternalGetSatelliteAssembly(Assembly mainAssembly,
- CultureInfo culture,
- Version? version)
- {
- return ((RuntimeAssembly)mainAssembly).InternalGetSatelliteAssembly(culture, version, throwOnFileNotFound: false);
- }
- }
-}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs
index 02ecf96568927..733e3a664bcc5 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs
@@ -139,8 +139,32 @@ public static unsafe void PrepareMethod(RuntimeMethodHandle method, RuntimeTypeH
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern int TryGetHashCode(object o);
+ public static new unsafe bool Equals(object? o1, object? o2)
+ {
+ // Compare by ref for normal classes, by value for value types.
+
+ if (ReferenceEquals(o1, o2))
+ return true;
+
+ if (o1 is null || o2 is null)
+ return false;
+
+ MethodTable* pMT = GetMethodTable(o1);
+
+ // If it's not a value class, don't compare by value
+ if (!pMT->IsValueType)
+ return false;
+
+ // Make sure they are the same type.
+ if (pMT != GetMethodTable(o2))
+ return false;
+
+ // Compare the contents
+ return ContentEquals(o1, o2);
+ }
+
[MethodImpl(MethodImplOptions.InternalCall)]
- public static extern new bool Equals(object? o1, object? o2);
+ private static extern unsafe bool ContentEquals(object o1, object o2);
[Obsolete("OffsetToStringData has been deprecated. Use string.GetPinnableReference() instead.")]
public static int OffsetToStringData
@@ -194,8 +218,8 @@ public static object GetUninitializedObject(
return rt.GetUninitializedObject();
}
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern object AllocateUninitializedClone(object obj);
+ [LibraryImport(QCall, EntryPoint = "ObjectNative_AllocateUninitializedClone")]
+ internal static partial void AllocateUninitializedClone(ObjectHandleOnStack objHandle);
/// true if given type is reference type or value type that contains references
[Intrinsic]
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/ExceptionServices/InternalCalls.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/ExceptionServices/InternalCalls.cs
index 4ae608fc17d23..228f58c0ea4d0 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/ExceptionServices/InternalCalls.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/ExceptionServices/InternalCalls.cs
@@ -42,7 +42,7 @@ internal static unsafe partial bool RhpCallFilterFunclet(
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "EHEnumInitFromStackFrameIterator")]
[return: MarshalAs(UnmanagedType.Bool)]
- internal static unsafe partial bool RhpEHEnumInitFromStackFrameIterator(ref StackFrameIterator pFrameIter, byte** pMethodStartAddress, void* pEHEnum);
+ internal static unsafe partial bool RhpEHEnumInitFromStackFrameIterator(ref StackFrameIterator pFrameIter, out EH.MethodRegionInfo pMethodRegionInfo, void* pEHEnum);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "EHEnumNext")]
[return: MarshalAs(UnmanagedType.Bool)]
diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs
index c74d76388b91a..00a8d78685d4d 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs
@@ -2757,7 +2757,12 @@ public override InterfaceMapping GetInterfaceMap([DynamicallyAccessedMembers(Dyn
MethodBase? rtTypeMethodBase = GetMethodBase(reflectedType, classRtMethodHandle);
// a class may not implement all the methods of an interface (abstract class) so null is a valid value
Debug.Assert(rtTypeMethodBase is null || rtTypeMethodBase is RuntimeMethodInfo);
- im.TargetMethods[i] = (MethodInfo)rtTypeMethodBase!;
+ RuntimeMethodInfo? targetMethod = (RuntimeMethodInfo?)rtTypeMethodBase;
+ // the TargetMethod provided to us by runtime internals may be a generic method instance,
+ // potentially with invalid arguments. TargetMethods in the InterfaceMap should never be
+ // instances, only definitions.
+ im.TargetMethods[i] = (targetMethod is { IsGenericMethod: true, IsGenericMethodDefinition: false })
+ ? targetMethod.GetGenericMethodDefinition() : targetMethod!;
}
return im;
diff --git a/src/coreclr/System.Private.CoreLib/src/System/ValueType.cs b/src/coreclr/System.Private.CoreLib/src/System/ValueType.cs
index 78301866c36dc..f4c3acb31adf8 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/ValueType.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/ValueType.cs
@@ -120,7 +120,7 @@ public override unsafe int GetHashCode()
else
{
object thisRef = this;
- switch (GetHashCodeStrategy(pMT, ObjectHandleOnStack.Create(ref thisRef), out uint fieldOffset, out uint fieldSize))
+ switch (GetHashCodeStrategy(pMT, ObjectHandleOnStack.Create(ref thisRef), out uint fieldOffset, out uint fieldSize, out MethodTable* fieldMT))
{
case ValueTypeHashCodeStrategy.ReferenceField:
hashCode.Add(Unsafe.As(ref Unsafe.AddByteOffset(ref rawData, fieldOffset)).GetHashCode());
@@ -138,6 +138,12 @@ public override unsafe int GetHashCode()
Debug.Assert(fieldSize != 0);
hashCode.AddBytes(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AddByteOffset(ref rawData, fieldOffset), (int)fieldSize));
break;
+
+ case ValueTypeHashCodeStrategy.ValueTypeOverride:
+ Debug.Assert(fieldMT != null);
+ // Box the field to handle complicated cases like mutable method and shared generic
+ hashCode.Add(RuntimeHelpers.Box(fieldMT, ref Unsafe.AddByteOffset(ref rawData, fieldOffset))?.GetHashCode() ?? 0);
+ break;
}
}
@@ -152,11 +158,12 @@ private enum ValueTypeHashCodeStrategy
DoubleField,
SingleField,
FastGetHashCode,
+ ValueTypeOverride,
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ValueType_GetHashCodeStrategy")]
private static unsafe partial ValueTypeHashCodeStrategy GetHashCodeStrategy(
- MethodTable* pMT, ObjectHandleOnStack objHandle, out uint fieldOffset, out uint fieldSize);
+ MethodTable* pMT, ObjectHandleOnStack objHandle, out uint fieldOffset, out uint fieldSize, out MethodTable* fieldMT);
public override string? ToString()
{
diff --git a/src/coreclr/classlibnative/bcltype/objectnative.cpp b/src/coreclr/classlibnative/bcltype/objectnative.cpp
index 4622955b44adf..afbda5fad9916 100644
--- a/src/coreclr/classlibnative/bcltype/objectnative.cpp
+++ b/src/coreclr/classlibnative/bcltype/objectnative.cpp
@@ -123,48 +123,22 @@ FCIMPL1(INT32, ObjectNative::TryGetHashCode, Object* obj) {
}
FCIMPLEND
-//
-// Compare by ref for normal classes, by value for value types.
-//
-// @todo: it would be nice to customize this method based on the
-// defining class rather than doing a runtime check whether it is
-// a value type.
-//
-
-FCIMPL2(FC_BOOL_RET, ObjectNative::Equals, Object *pThisRef, Object *pCompareRef)
+FCIMPL2(FC_BOOL_RET, ObjectNative::ContentEquals, Object *pThisRef, Object *pCompareRef)
{
- CONTRACTL
- {
- FCALL_CHECK;
- INJECT_FAULT(FCThrow(kOutOfMemoryException););
- }
- CONTRACTL_END;
-
- if (pThisRef == pCompareRef)
- FC_RETURN_BOOL(TRUE);
+ FCALL_CONTRACT;
- // Since we are in FCALL, we must handle NULL specially.
- if (pThisRef == NULL || pCompareRef == NULL)
- FC_RETURN_BOOL(FALSE);
+ // Should be ensured by caller
+ _ASSERTE(pThisRef != NULL);
+ _ASSERTE(pCompareRef != NULL);
+ _ASSERTE(pThisRef->GetMethodTable() == pCompareRef->GetMethodTable());
MethodTable *pThisMT = pThisRef->GetMethodTable();
- // If it's not a value class, don't compare by value
- if (!pThisMT->IsValueType())
- FC_RETURN_BOOL(FALSE);
-
- // Make sure they are the same type.
- if (pThisMT != pCompareRef->GetMethodTable())
- FC_RETURN_BOOL(FALSE);
-
- // Compare the contents (size - vtable - sync block index).
- DWORD dwBaseSize = pThisMT->GetBaseSize();
- if(pThisMT == g_pStringClass)
- dwBaseSize -= sizeof(WCHAR);
+ // Compare the contents
BOOL ret = memcmp(
- (void *) (pThisRef+1),
- (void *) (pCompareRef+1),
- dwBaseSize - sizeof(Object) - sizeof(int)) == 0;
+ pThisRef->GetData(),
+ pCompareRef->GetData(),
+ pThisMT->GetNumInstanceFieldBytes()) == 0;
FC_GC_POLL_RET();
@@ -215,36 +189,34 @@ FCIMPL1(Object*, ObjectNative::GetClass, Object* pThis)
}
FCIMPLEND
-FCIMPL1(Object*, ObjectNative::AllocateUninitializedClone, Object* pObjUNSAFE)
+extern "C" void QCALLTYPE ObjectNative_AllocateUninitializedClone(QCall::ObjectHandleOnStack objHandle)
{
- FCALL_CONTRACT;
-
- // Delegate error handling to managed side (it will throw NullReferenceException)
- if (pObjUNSAFE == NULL)
- return NULL;
+ QCALL_CONTRACT;
- OBJECTREF refClone = ObjectToOBJECTREF(pObjUNSAFE);
+ BEGIN_QCALL;
- HELPER_METHOD_FRAME_BEGIN_RET_1(refClone);
+ GCX_COOP();
+ OBJECTREF refClone = objHandle.Get();
+ _ASSERTE(refClone != NULL); // Should be handled at managed side
MethodTable* pMT = refClone->GetMethodTable();
-
+
// assert that String has overloaded the Clone() method
_ASSERTE(pMT != g_pStringClass);
-
- if (pMT->IsArray()) {
- refClone = DupArrayForCloning((BASEARRAYREF)refClone);
- } else {
+
+ if (pMT->IsArray())
+ {
+ objHandle.Set(DupArrayForCloning((BASEARRAYREF)refClone));
+ }
+ else
+ {
// We don't need to call the because we know
// that it has been called....(It was called before this was created)
- refClone = AllocateObject(pMT);
+ objHandle.Set(AllocateObject(pMT));
}
- HELPER_METHOD_FRAME_END();
-
- return OBJECTREFToObject(refClone);
+ END_QCALL;
}
-FCIMPLEND
extern "C" BOOL QCALLTYPE Monitor_Wait(QCall::ObjectHandleOnStack pThis, INT32 Timeout)
{
diff --git a/src/coreclr/classlibnative/bcltype/objectnative.h b/src/coreclr/classlibnative/bcltype/objectnative.h
index d8948922dd0b7..418fd2561d7cc 100644
--- a/src/coreclr/classlibnative/bcltype/objectnative.h
+++ b/src/coreclr/classlibnative/bcltype/objectnative.h
@@ -27,12 +27,12 @@ class ObjectNative
static FCDECL1(INT32, GetHashCode, Object* vThisRef);
static FCDECL1(INT32, TryGetHashCode, Object* vThisRef);
- static FCDECL2(FC_BOOL_RET, Equals, Object *pThisRef, Object *pCompareRef);
- static FCDECL1(Object*, AllocateUninitializedClone, Object* pObjUNSAFE);
+ static FCDECL2(FC_BOOL_RET, ContentEquals, Object *pThisRef, Object *pCompareRef);
static FCDECL1(Object*, GetClass, Object* pThis);
static FCDECL1(FC_BOOL_RET, IsLockHeld, Object* pThisUNSAFE);
};
+extern "C" void QCALLTYPE ObjectNative_AllocateUninitializedClone(QCall::ObjectHandleOnStack objHandle);
extern "C" BOOL QCALLTYPE Monitor_Wait(QCall::ObjectHandleOnStack pThis, INT32 Timeout);
extern "C" void QCALLTYPE Monitor_Pulse(QCall::ObjectHandleOnStack pThis);
extern "C" void QCALLTYPE Monitor_PulseAll(QCall::ObjectHandleOnStack pThis);
diff --git a/src/coreclr/classlibnative/bcltype/system.cpp b/src/coreclr/classlibnative/bcltype/system.cpp
index ef02743b36696..6e9a9a9ee956a 100644
--- a/src/coreclr/classlibnative/bcltype/system.cpp
+++ b/src/coreclr/classlibnative/bcltype/system.cpp
@@ -145,7 +145,7 @@ WCHAR *g_pFailFastBuffer = g_szFailFastBuffer;
// This is the common code for FailFast processing that is wrapped by the two
// FailFast FCalls below.
-void SystemNative::GenericFailFast(STRINGREF refMesgString, EXCEPTIONREF refExceptionForWatsonBucketing, UINT_PTR retAddress, UINT exitCode, STRINGREF refErrorSourceString)
+void SystemNative::GenericFailFast(STRINGREF refMesgString, EXCEPTIONREF refExceptionForWatsonBucketing, UINT_PTR retAddress, STRINGREF refErrorSourceString)
{
CONTRACTL
{
@@ -282,7 +282,7 @@ void SystemNative::GenericFailFast(STRINGREF refMesgString, EXCEPTIONREF refExce
if (gc.refExceptionForWatsonBucketing != NULL)
pThread->SetLastThrownObject(gc.refExceptionForWatsonBucketing);
- EEPolicy::HandleFatalError(exitCode, retAddress, pszMessage, NULL, errorSourceString, argExceptionString);
+ EEPolicy::HandleFatalError(COR_E_FAILFAST, retAddress, pszMessage, NULL, errorSourceString, argExceptionString);
GCPROTECT_END();
}
@@ -301,25 +301,7 @@ FCIMPL1(VOID, SystemNative::FailFast, StringObject* refMessageUNSAFE)
UINT_PTR retaddr = HELPER_METHOD_FRAME_GET_RETURN_ADDRESS();
// Call the actual worker to perform failfast
- GenericFailFast(refMessage, NULL, retaddr, COR_E_FAILFAST, NULL);
-
- HELPER_METHOD_FRAME_END();
-}
-FCIMPLEND
-
-FCIMPL2(VOID, SystemNative::FailFastWithExitCode, StringObject* refMessageUNSAFE, UINT exitCode)
-{
- FCALL_CONTRACT;
-
- STRINGREF refMessage = (STRINGREF)refMessageUNSAFE;
-
- HELPER_METHOD_FRAME_BEGIN_1(refMessage);
-
- // The HelperMethodFrame knows how to get the return address.
- UINT_PTR retaddr = HELPER_METHOD_FRAME_GET_RETURN_ADDRESS();
-
- // Call the actual worker to perform failfast
- GenericFailFast(refMessage, NULL, retaddr, exitCode, NULL);
+ GenericFailFast(refMessage, NULL, retaddr, NULL);
HELPER_METHOD_FRAME_END();
}
@@ -338,7 +320,7 @@ FCIMPL2(VOID, SystemNative::FailFastWithException, StringObject* refMessageUNSAF
UINT_PTR retaddr = HELPER_METHOD_FRAME_GET_RETURN_ADDRESS();
// Call the actual worker to perform failfast
- GenericFailFast(refMessage, refException, retaddr, COR_E_FAILFAST, NULL);
+ GenericFailFast(refMessage, refException, retaddr, NULL);
HELPER_METHOD_FRAME_END();
}
@@ -358,7 +340,7 @@ FCIMPL3(VOID, SystemNative::FailFastWithExceptionAndSource, StringObject* refMes
UINT_PTR retaddr = HELPER_METHOD_FRAME_GET_RETURN_ADDRESS();
// Call the actual worker to perform failfast
- GenericFailFast(refMessage, refException, retaddr, COR_E_FAILFAST, errorSource);
+ GenericFailFast(refMessage, refException, retaddr, errorSource);
HELPER_METHOD_FRAME_END();
}
diff --git a/src/coreclr/classlibnative/bcltype/system.h b/src/coreclr/classlibnative/bcltype/system.h
index b4a773a847c39..e440f1fa8b067 100644
--- a/src/coreclr/classlibnative/bcltype/system.h
+++ b/src/coreclr/classlibnative/bcltype/system.h
@@ -44,7 +44,6 @@ class SystemNative
static FCDECL0(INT32, GetExitCode);
static FCDECL1(VOID, FailFast, StringObject* refMessageUNSAFE);
- static FCDECL2(VOID, FailFastWithExitCode, StringObject* refMessageUNSAFE, UINT exitCode);
static FCDECL2(VOID, FailFastWithException, StringObject* refMessageUNSAFE, ExceptionObject* refExceptionUNSAFE);
static FCDECL3(VOID, FailFastWithExceptionAndSource, StringObject* refMessageUNSAFE, ExceptionObject* refExceptionUNSAFE, StringObject* errorSourceUNSAFE);
@@ -55,7 +54,7 @@ class SystemNative
private:
// Common processing code for FailFast
- static void GenericFailFast(STRINGREF refMesgString, EXCEPTIONREF refExceptionForWatsonBucketing, UINT_PTR retAddress, UINT exitCode, STRINGREF errorSource);
+ static void GenericFailFast(STRINGREF refMesgString, EXCEPTIONREF refExceptionForWatsonBucketing, UINT_PTR retAddress, STRINGREF errorSource);
};
extern "C" void QCALLTYPE Environment_Exit(INT32 exitcode);
diff --git a/src/coreclr/clrdefinitions.cmake b/src/coreclr/clrdefinitions.cmake
index fb8d095b5606d..2097ef5360ef0 100644
--- a/src/coreclr/clrdefinitions.cmake
+++ b/src/coreclr/clrdefinitions.cmake
@@ -258,7 +258,7 @@ function(set_target_definitions_to_custom_os_and_arch)
if (TARGETDETAILS_OS STREQUAL "unix_anyos")
target_compile_definitions(${TARGETDETAILS_TARGET} PRIVATE TARGET_UNIX_ANYOS)
endif()
- elseif (TARGETDETAILS_OS STREQUAL "win")
+ elseif (TARGETDETAILS_OS MATCHES "^win")
target_compile_definitions(${TARGETDETAILS_TARGET} PRIVATE TARGET_WINDOWS)
endif((TARGETDETAILS_OS MATCHES "^unix"))
@@ -287,7 +287,7 @@ function(set_target_definitions_to_custom_os_and_arch)
target_compile_definitions(${TARGETDETAILS_TARGET} PRIVATE ARM_SOFTFP)
endif()
- if (NOT (TARGETDETAILS_ARCH STREQUAL "x86") OR (TARGETDETAILS_OS MATCHES "^unix"))
+ if (NOT (TARGETDETAILS_ARCH STREQUAL "x86") OR (TARGETDETAILS_OS MATCHES "^unix") OR (TARGETDETAILS_OS MATCHES "win_aot"))
target_compile_definitions(${TARGETDETAILS_TARGET} PRIVATE FEATURE_EH_FUNCLETS)
- endif (NOT (TARGETDETAILS_ARCH STREQUAL "x86") OR (TARGETDETAILS_OS MATCHES "^unix"))
+ endif (NOT (TARGETDETAILS_ARCH STREQUAL "x86") OR (TARGETDETAILS_OS MATCHES "^unix") OR (TARGETDETAILS_OS MATCHES "win_aot"))
endfunction()
diff --git a/src/coreclr/crosscomponents.cmake b/src/coreclr/crosscomponents.cmake
index 11e923805a6ea..b06b706070489 100644
--- a/src/coreclr/crosscomponents.cmake
+++ b/src/coreclr/crosscomponents.cmake
@@ -25,6 +25,13 @@ if (CLR_CMAKE_HOST_OS STREQUAL CLR_CMAKE_TARGET_OS OR CLR_CMAKE_TARGET_IOS OR CL
DESTINATIONS .
COMPONENT crosscomponents
)
+ if (CLR_CMAKE_TARGET_ARCH_I386)
+ install_clr (TARGETS
+ clrjit_win_aot_${ARCH_TARGET_NAME}_${ARCH_HOST_NAME}
+ DESTINATIONS .
+ COMPONENT crosscomponents
+ )
+ endif()
endif()
endif()
endif()
diff --git a/src/coreclr/inc/clrconfigvalues.h b/src/coreclr/inc/clrconfigvalues.h
index 45674a77c3539..d9571f0776456 100644
--- a/src/coreclr/inc/clrconfigvalues.h
+++ b/src/coreclr/inc/clrconfigvalues.h
@@ -259,7 +259,7 @@ RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_legacyCorruptedStateExceptionsPolicy, W("le
CONFIG_DWORD_INFO(INTERNAL_SuppressLostExceptionTypeAssert, W("SuppressLostExceptionTypeAssert"), 0, "")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_UseEntryPointFilter, W("UseEntryPointFilter"), 0, "")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_Corhost_Swallow_Uncaught_Exceptions, W("Corhost_Swallow_Uncaught_Exceptions"), 0, "")
-RETAIL_CONFIG_DWORD_INFO(EXTERNAL_LegacyExceptionHandling, W("LegacyExceptionHandling"), 0, "Enable legacy exception handling.");
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_LegacyExceptionHandling, W("LegacyExceptionHandling"), 1, "Enable legacy exception handling.");
///
diff --git a/src/coreclr/inc/clrnt.h b/src/coreclr/inc/clrnt.h
index 56245ea46f25e..1373753862804 100644
--- a/src/coreclr/inc/clrnt.h
+++ b/src/coreclr/inc/clrnt.h
@@ -184,12 +184,17 @@ RtlVirtualUnwind_Unsafe(
#ifdef HOST_X86
typedef struct _RUNTIME_FUNCTION {
DWORD BeginAddress;
+ // NOTE: R2R doesn't include EndAddress (see docs/design/coreclr/botr/readytorun-format.md).
+ // NativeAOT does include the EndAddress because the Microsoft linker expects it. In NativeAOT
+ // the info is generated in the managed ObjectWriter, so the structures don't have to match.
+ // DWORD EndAddress;
DWORD UnwindData;
} RUNTIME_FUNCTION, *PRUNTIME_FUNCTION;
typedef struct _DISPATCHER_CONTEXT {
_EXCEPTION_REGISTRATION_RECORD* RegistrationPointer;
} DISPATCHER_CONTEXT, *PDISPATCHER_CONTEXT;
+
#endif // HOST_X86
#endif // !HOST_UNIX
@@ -207,7 +212,7 @@ RtlpGetFunctionEndAddress (
_In_ TADDR ImageBase
)
{
- PTR_UNWIND_INFO pUnwindInfo = (PTR_UNWIND_INFO)(ImageBase + FunctionEntry->UnwindData);
+ PUNWIND_INFO pUnwindInfo = (PUNWIND_INFO)(ImageBase + FunctionEntry->UnwindData);
return FunctionEntry->BeginAddress + pUnwindInfo->FunctionLength;
}
diff --git a/src/coreclr/jit/CMakeLists.txt b/src/coreclr/jit/CMakeLists.txt
index ae08a27e4c00a..5ba50306d1b72 100644
--- a/src/coreclr/jit/CMakeLists.txt
+++ b/src/coreclr/jit/CMakeLists.txt
@@ -23,6 +23,8 @@ function(create_standalone_jit)
if(TARGETDETAILS_OS STREQUAL "unix_osx" OR TARGETDETAILS_OS STREQUAL "unix_anyos")
set(JIT_ARCH_LINK_LIBRARIES gcinfo_unix_${TARGETDETAILS_ARCH})
+ elseif(TARGETDETAILS_OS STREQUAL "win_aot")
+ set(JIT_ARCH_LINK_LIBRARIES gcinfo_win_${TARGETDETAILS_ARCH})
else()
set(JIT_ARCH_LINK_LIBRARIES gcinfo_${TARGETDETAILS_OS}_${TARGETDETAILS_ARCH})
endif()
@@ -94,7 +96,6 @@ set( JIT_SOURCES
bitset.cpp
block.cpp
buildstring.cpp
- layout.cpp
codegencommon.cpp
codegenlinear.cpp
compiler.cpp
@@ -123,14 +124,15 @@ set( JIT_SOURCES
gentree.cpp
gschecks.cpp
hashbv.cpp
- hwintrinsic.cpp
+ helperexpansion.cpp
hostallocator.cpp
+ hwintrinsic.cpp
ifconversion.cpp
- helperexpansion.cpp
- indirectcalltransformer.cpp
- importercalls.cpp
importer.cpp
+ importercalls.cpp
importervectorization.cpp
+ indirectcalltransformer.cpp
+ inductionvariableopts.cpp
inline.cpp
inlinepolicy.cpp
instr.cpp
@@ -138,6 +140,7 @@ set( JIT_SOURCES
jiteh.cpp
jithashtable.cpp
jitmetadata.cpp
+ layout.cpp
lclmorph.cpp
lclvars.cpp
likelyclass.cpp
@@ -152,7 +155,6 @@ set( JIT_SOURCES
objectalloc.cpp
optcse.cpp
optimizebools.cpp
- switchrecognition.cpp
optimizer.cpp
patchpoint.cpp
phase.cpp
@@ -165,6 +167,7 @@ set( JIT_SOURCES
regalloc.cpp
registerargconvention.cpp
regset.cpp
+ scev.cpp
scopeinfo.cpp
sideeffects.cpp
sm.cpp
@@ -173,6 +176,7 @@ set( JIT_SOURCES
ssabuilder.cpp
ssarenamestate.cpp
stacklevelsetter.cpp
+ switchrecognition.cpp
treelifeupdater.cpp
unwind.cpp
utils.cpp
@@ -359,6 +363,7 @@ set( JIT_HEADERS
registerargconvention.h
register.h
regset.h
+ scev.h
sideeffects.h
simd.h
simdashwintrinsic.h
@@ -649,6 +654,7 @@ else()
create_standalone_jit(TARGET clrjit_universal_arm_${ARCH_HOST_NAME} OS universal ARCH arm DESTINATIONS .)
target_compile_definitions(clrjit_universal_arm_${ARCH_HOST_NAME} PRIVATE ARM_SOFTFP CONFIGURABLE_ARM_ABI)
create_standalone_jit(TARGET clrjit_win_x86_${ARCH_HOST_NAME} OS win ARCH x86 DESTINATIONS .)
+ create_standalone_jit(TARGET clrjit_win_aot_x86_${ARCH_HOST_NAME} OS win_aot ARCH x86 DESTINATIONS .)
endif (CLR_CMAKE_TARGET_ARCH_RISCV64)
if (CLR_CMAKE_TARGET_ARCH_I386 AND CLR_CMAKE_TARGET_UNIX)
diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp
index ba25a60af8edb..5d69c8d1bdd94 100644
--- a/src/coreclr/jit/assertionprop.cpp
+++ b/src/coreclr/jit/assertionprop.cpp
@@ -5493,7 +5493,6 @@ GenTree* Compiler::optAssertionProp(ASSERT_VALARG_TP assertions, GenTree* tree,
case GT_IND:
case GT_STOREIND:
case GT_NULLCHECK:
- case GT_STORE_DYN_BLK:
return optAssertionProp_Ind(assertions, tree, stmt);
case GT_BOUNDS_CHECK:
@@ -6147,7 +6146,7 @@ ASSERT_TP* Compiler::optComputeAssertionGen()
AssertionIndex valueAssertionIndex;
AssertionIndex jumpDestAssertionIndex;
- if (info.IsNextEdgeAssertion())
+ if (info.AssertionHoldsOnFalseEdge())
{
valueAssertionIndex = info.GetAssertionIndex();
jumpDestAssertionIndex = optFindComplementary(info.GetAssertionIndex());
diff --git a/src/coreclr/jit/block.cpp b/src/coreclr/jit/block.cpp
index 273c6f045123d..bd9abbe7fef30 100644
--- a/src/coreclr/jit/block.cpp
+++ b/src/coreclr/jit/block.cpp
@@ -68,6 +68,24 @@ unsigned SsaStressHashHelper()
}
#endif
+//------------------------------------------------------------------------
+// setLikelihood: set the likelihood of aflow edge
+//
+// Arguments:
+// likelihood -- value in range [0.0, 1.0] indicating how likely
+// the source block is to transfer control along this edge.
+//
+void FlowEdge::setLikelihood(weight_t likelihood)
+{
+ assert(likelihood >= 0.0);
+ assert(likelihood <= 1.0);
+ m_likelihoodSet = true;
+ m_likelihood = likelihood;
+
+ JITDUMP("setting likelihood of " FMT_BB " -> " FMT_BB " to " FMT_WT "\n", m_sourceBlock->bbNum, m_destBlock->bbNum,
+ m_likelihood);
+}
+
//------------------------------------------------------------------------
// AllSuccessorEnumerator: Construct an instance of the enumerator.
//
@@ -676,11 +694,11 @@ void BasicBlock::dspKind() const
break;
case BBJ_EHFILTERRET:
- printf(" -> %s (fltret)", dspBlockNum(bbTarget));
+ printf(" -> %s (fltret)", dspBlockNum(GetTarget()));
break;
case BBJ_EHCATCHRET:
- printf(" -> %s (cret)", dspBlockNum(bbTarget));
+ printf(" -> %s (cret)", dspBlockNum(GetTarget()));
break;
case BBJ_THROW:
@@ -694,28 +712,28 @@ void BasicBlock::dspKind() const
case BBJ_ALWAYS:
if (HasFlag(BBF_KEEP_BBJ_ALWAYS))
{
- printf(" -> %s (ALWAYS)", dspBlockNum(bbTarget));
+ printf(" -> %s (ALWAYS)", dspBlockNum(GetTarget()));
}
else
{
- printf(" -> %s (always)", dspBlockNum(bbTarget));
+ printf(" -> %s (always)", dspBlockNum(GetTarget()));
}
break;
case BBJ_LEAVE:
- printf(" -> %s (leave)", dspBlockNum(bbTarget));
+ printf(" -> %s (leave)", dspBlockNum(GetTarget()));
break;
case BBJ_CALLFINALLY:
- printf(" -> %s (callf)", dspBlockNum(bbTarget));
+ printf(" -> %s (callf)", dspBlockNum(GetTarget()));
break;
case BBJ_CALLFINALLYRET:
- printf(" -> %s (callfr)", dspBlockNum(bbTarget));
+ printf(" -> %s (callfr)", dspBlockNum(GetTarget()));
break;
case BBJ_COND:
- printf(" -> %s,%s (cond)", dspBlockNum(bbTrueTarget), dspBlockNum(bbFalseTarget));
+ printf(" -> %s,%s (cond)", dspBlockNum(GetTrueTarget()), dspBlockNum(GetFalseTarget()));
break;
case BBJ_SWITCH:
@@ -857,11 +875,16 @@ void BasicBlock::TransferTarget(BasicBlock* from)
SetEhf(from->GetEhfTargets());
from->bbEhfTargets = nullptr; // Make sure nobody uses the descriptor after this.
break;
+
+ // TransferTarget may be called after setting the source block of `from`'s
+ // successor edges to this block.
+ // This means calling GetTarget/GetTrueTarget/GetFalseTarget would trigger asserts.
+ // Avoid this by accessing the edges directly.
case BBJ_COND:
- SetCond(from->GetTrueTarget(), from->GetFalseTarget());
+ SetCond(from->bbTrueEdge, from->bbFalseEdge);
break;
case BBJ_ALWAYS:
- SetKindAndTarget(from->GetKind(), from->GetTarget());
+ SetKindAndTargetEdge(BBJ_ALWAYS, from->bbTargetEdge);
CopyFlags(from, BBF_NONE_QUIRK);
break;
case BBJ_CALLFINALLY:
@@ -869,10 +892,10 @@ void BasicBlock::TransferTarget(BasicBlock* from)
case BBJ_EHCATCHRET:
case BBJ_EHFILTERRET:
case BBJ_LEAVE:
- SetKindAndTarget(from->GetKind(), from->GetTarget());
+ SetKindAndTargetEdge(from->GetKind(), from->bbTargetEdge);
break;
default:
- SetKindAndTarget(from->GetKind()); // Clear the target
+ SetKindAndTargetEdge(from->GetKind()); // Clear the target
break;
}
assert(KindIs(from->GetKind()));
@@ -985,7 +1008,7 @@ BasicBlock* BasicBlock::GetUniquePred(Compiler* compiler) const
//
BasicBlock* BasicBlock::GetUniqueSucc() const
{
- return KindIs(BBJ_ALWAYS) ? bbTarget : nullptr;
+ return KindIs(BBJ_ALWAYS) ? GetTarget() : nullptr;
}
// Static vars.
@@ -1145,7 +1168,7 @@ unsigned BasicBlock::NumSucc() const
return 1;
case BBJ_COND:
- if (bbTrueTarget == bbFalseTarget)
+ if (bbTrueEdge == bbFalseEdge)
{
return 1;
}
@@ -1180,15 +1203,15 @@ unsigned BasicBlock::NumSucc() const
}
//------------------------------------------------------------------------
-// GetSucc: Returns the requested block successor. See the declaration comment for details.
+// GetSucc: Returns the requested successor edge. See the declaration comment for details.
//
// Arguments:
// i - index of successor to return. 0 <= i <= NumSucc().
//
// Return Value:
-// Requested successor block
+// Requested successor edge
//
-BasicBlock* BasicBlock::GetSucc(unsigned i) const
+FlowEdge* BasicBlock::GetSuccEdge(unsigned i) const
{
assert(i < NumSucc()); // Index bounds check.
switch (bbKind)
@@ -1199,31 +1222,45 @@ BasicBlock* BasicBlock::GetSucc(unsigned i) const
case BBJ_EHCATCHRET:
case BBJ_EHFILTERRET:
case BBJ_LEAVE:
- return bbTarget;
+ return GetTargetEdge();
case BBJ_COND:
if (i == 0)
{
- return bbFalseTarget;
+ return GetFalseEdge();
}
else
{
assert(i == 1);
- assert(bbFalseTarget != bbTrueTarget);
- return bbTrueTarget;
+ assert(bbTrueEdge != bbFalseEdge);
+ return GetTrueEdge();
}
case BBJ_EHFINALLYRET:
- return bbEhfTargets->bbeSuccs[i]->getDestinationBlock();
+ return bbEhfTargets->bbeSuccs[i];
case BBJ_SWITCH:
- return bbSwtTargets->bbsDstTab[i]->getDestinationBlock();
+ return bbSwtTargets->bbsDstTab[i];
default:
unreached();
}
}
+//------------------------------------------------------------------------
+// GetSucc: Returns the requested block successor. See the declaration comment for details.
+//
+// Arguments:
+// i - index of successor to return. 0 <= i <= NumSucc().
+//
+// Return Value:
+// Requested successor block
+//
+BasicBlock* BasicBlock::GetSucc(unsigned i) const
+{
+ return GetSuccEdge(i)->getDestinationBlock();
+}
+
//------------------------------------------------------------------------
// NumSucc: Returns the count of block successors. See the declaration comment for details.
//
@@ -1270,7 +1307,7 @@ unsigned BasicBlock::NumSucc(Compiler* comp)
return 1;
case BBJ_COND:
- if (bbTrueTarget == bbFalseTarget)
+ if (bbTrueEdge == bbFalseEdge)
{
return 1;
}
@@ -1291,16 +1328,16 @@ unsigned BasicBlock::NumSucc(Compiler* comp)
}
//------------------------------------------------------------------------
-// GetSucc: Returns the requested block successor. See the declaration comment for details.
+// GetSucc: Returns the requested successor edge. See the declaration comment for details.
//
// Arguments:
// i - index of successor to return. 0 <= i <= NumSucc(comp).
// comp - Compiler instance
//
// Return Value:
-// Requested successor block
+// Requested successor edge
//
-BasicBlock* BasicBlock::GetSucc(unsigned i, Compiler* comp)
+FlowEdge* BasicBlock::GetSuccEdge(unsigned i, Compiler* comp)
{
assert(comp != nullptr);
@@ -1309,31 +1346,31 @@ BasicBlock* BasicBlock::GetSucc(unsigned i, Compiler* comp)
{
case BBJ_EHFILTERRET:
// Handler is the (sole) normal successor of the filter.
- assert(comp->fgFirstBlockOfHandler(this) == bbTarget);
- return bbTarget;
+ assert(comp->fgFirstBlockOfHandler(this) == GetTarget());
+ return GetTargetEdge();
case BBJ_EHFINALLYRET:
assert(bbEhfTargets != nullptr);
assert(i < bbEhfTargets->bbeCount);
- return bbEhfTargets->bbeSuccs[i]->getDestinationBlock();
+ return bbEhfTargets->bbeSuccs[i];
case BBJ_CALLFINALLY:
case BBJ_CALLFINALLYRET:
case BBJ_ALWAYS:
case BBJ_EHCATCHRET:
case BBJ_LEAVE:
- return bbTarget;
+ return GetTargetEdge();
case BBJ_COND:
if (i == 0)
{
- return bbFalseTarget;
+ return GetFalseEdge();
}
else
{
assert(i == 1);
- assert(bbFalseTarget != bbTrueTarget);
- return bbTrueTarget;
+ assert(bbTrueEdge != bbFalseEdge);
+ return GetTrueEdge();
}
case BBJ_SWITCH:
@@ -1348,6 +1385,21 @@ BasicBlock* BasicBlock::GetSucc(unsigned i, Compiler* comp)
}
}
+//------------------------------------------------------------------------
+// GetSucc: Returns the requested block successor. See the declaration comment for details.
+//
+// Arguments:
+// i - index of successor to return. 0 <= i <= NumSucc(comp).
+// comp - Compiler instance
+//
+// Return Value:
+// Requested successor block
+//
+BasicBlock* BasicBlock::GetSucc(unsigned i, Compiler* comp)
+{
+ return GetSuccEdge(i, comp)->getDestinationBlock();
+}
+
void BasicBlock::InitVarSets(Compiler* comp)
{
VarSetOps::AssignNoCopy(comp, bbVarUse, VarSetOps::MakeEmpty(comp));
@@ -1585,15 +1637,10 @@ BasicBlock* BasicBlock::New(Compiler* compiler)
return block;
}
-BasicBlock* BasicBlock::New(Compiler* compiler, BBKinds kind, BasicBlock* target /* = nullptr */)
+BasicBlock* BasicBlock::New(Compiler* compiler, BBKinds kind)
{
BasicBlock* block = BasicBlock::New(compiler);
-
- // In some cases, we don't know a block's jump target during initialization, so don't check the jump kind/target
- // yet.
- // The checks will be done any time the jump kind/target is read or written to after initialization.
- block->bbKind = kind;
- block->bbTarget = target;
+ block->bbKind = kind;
if (block->KindIs(BBJ_THROW))
{
diff --git a/src/coreclr/jit/block.h b/src/coreclr/jit/block.h
index 208eb07e583fa..e4b6b9d0daacd 100644
--- a/src/coreclr/jit/block.h
+++ b/src/coreclr/jit/block.h
@@ -307,29 +307,17 @@ class PredBlockList
}
};
-// BBArrayIterator: forward iterator for an array of BasicBlock*, such as the BBswtDesc->bbsDstTab.
+// BBArrayIterator: forward iterator for an array of BasicBlock*.
// It is an error (with assert) to yield a nullptr BasicBlock* in this array.
-// `m_bbEntry` can be nullptr, but it only makes sense if both the begin and end of an iteration range are nullptr
+// `m_edgeEntry` can be nullptr, but it only makes sense if both the begin and end of an iteration range are nullptr
// (meaning, no actual iteration will happen).
//
class BBArrayIterator
{
- // Quirk: Some BasicBlock kinds refer to their successors with BasicBlock pointers,
- // while others use FlowEdge pointers. Eventually, every type will use FlowEdge pointers.
- // For now, support iterating with both types.
- union {
- BasicBlock* const* m_bbEntry;
- FlowEdge* const* m_edgeEntry;
- };
-
- bool iterateEdges;
+ FlowEdge* const* m_edgeEntry;
public:
- BBArrayIterator(BasicBlock* const* bbEntry) : m_bbEntry(bbEntry), iterateEdges(false)
- {
- }
-
- BBArrayIterator(FlowEdge* const* edgeEntry) : m_edgeEntry(edgeEntry), iterateEdges(true)
+ BBArrayIterator(FlowEdge* const* edgeEntry) : m_edgeEntry(edgeEntry)
{
}
@@ -337,14 +325,49 @@ class BBArrayIterator
BBArrayIterator& operator++()
{
- assert(m_bbEntry != nullptr);
- ++m_bbEntry;
+ assert(m_edgeEntry != nullptr);
+ ++m_edgeEntry;
return *this;
}
bool operator!=(const BBArrayIterator& i) const
{
- return m_bbEntry != i.m_bbEntry;
+ return m_edgeEntry != i.m_edgeEntry;
+ }
+};
+
+// FlowEdgeArrayIterator: forward iterator for an array of FlowEdge*, such as the BBswtDesc->bbsDstTab.
+// It is an error (with assert) to yield a nullptr FlowEdge* in this array.
+// `m_edgeEntry` can be nullptr, but it only makes sense if both the begin and end of an iteration range are nullptr
+// (meaning, no actual iteration will happen).
+//
+class FlowEdgeArrayIterator
+{
+ FlowEdge* const* m_edgeEntry;
+
+public:
+ FlowEdgeArrayIterator(FlowEdge* const* edgeEntry) : m_edgeEntry(edgeEntry)
+ {
+ }
+
+ FlowEdge* operator*() const
+ {
+ assert(m_edgeEntry != nullptr);
+ FlowEdge* const edge = *m_edgeEntry;
+ assert(edge != nullptr);
+ return edge;
+ }
+
+ FlowEdgeArrayIterator& operator++()
+ {
+ assert(m_edgeEntry != nullptr);
+ ++m_edgeEntry;
+ return *this;
+ }
+
+ bool operator!=(const FlowEdgeArrayIterator& i) const
+ {
+ return m_edgeEntry != i.m_edgeEntry;
}
};
@@ -506,6 +529,179 @@ enum class BasicBlockVisit
// clang-format on
+//-------------------------------------------------------------------------
+// FlowEdge -- control flow edge
+//
+// In compiler terminology the control flow between two BasicBlocks
+// is typically referred to as an "edge". Most well known are the
+// backward branches for loops, which are often called "back-edges".
+//
+// "struct FlowEdge" is the type that represents our control flow edges.
+// This type is a linked list of zero or more "edges".
+// (The list of zero edges is represented by NULL.)
+// Every BasicBlock has a field called bbPreds of this type. This field
+// represents the list of "edges" that flow into this BasicBlock.
+// The FlowEdge type only stores the BasicBlock* of the source for the
+// control flow edge. The destination block for the control flow edge
+// is implied to be the block which contained the bbPreds field.
+//
+// For a switch branch target there may be multiple "edges" that have
+// the same source block (and destination block). We need to count the
+// number of these edges so that during optimization we will know when
+// we have zero of them. Rather than have extra FlowEdge entries we
+// track this via the DupCount property.
+//
+// When we have Profile weight for the BasicBlocks we can usually compute
+// the number of times each edge was executed by examining the adjacent
+// BasicBlock weights. As we are doing for BasicBlocks, we call the number
+// of times that a control flow edge was executed the "edge weight".
+// In order to compute the edge weights we need to use a bounded range
+// for every edge weight. These two fields, 'flEdgeWeightMin' and 'flEdgeWeightMax'
+// are used to hold a bounded range. Most often these will converge such
+// that both values are the same and that value is the exact edge weight.
+// Sometimes we are left with a rage of possible values between [Min..Max]
+// which represents an inexact edge weight.
+//
+// The bbPreds list is initially created by Compiler::fgLinkBasicBlocks()
+// and is incrementally kept up to date.
+//
+// The edge weight are computed by Compiler::fgComputeEdgeWeights()
+// the edge weights are used to straighten conditional branches
+// by Compiler::fgReorderBlocks()
+//
+struct FlowEdge
+{
+private:
+ // The next predecessor edge in the list, nullptr for end of list.
+ FlowEdge* m_nextPredEdge;
+
+ // The source of the control flow
+ BasicBlock* m_sourceBlock;
+
+ // 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;
+
+ // The count of duplicate "edges" (used for switch stmts or degenerate branches)
+ unsigned m_dupCount;
+
+ // True if likelihood has been set
+ bool m_likelihoodSet;
+
+public:
+ FlowEdge(BasicBlock* sourceBlock, BasicBlock* destBlock, FlowEdge* rest)
+ : m_nextPredEdge(rest)
+ , m_sourceBlock(sourceBlock)
+ , m_destBlock(destBlock)
+ , m_edgeWeightMin(0)
+ , m_edgeWeightMax(0)
+ , m_likelihood(0)
+ , m_dupCount(0)
+ , m_likelihoodSet(false)
+ {
+ }
+
+ FlowEdge* getNextPredEdge() const
+ {
+ return m_nextPredEdge;
+ }
+
+ FlowEdge** getNextPredEdgeRef()
+ {
+ return &m_nextPredEdge;
+ }
+
+ void setNextPredEdge(FlowEdge* newEdge)
+ {
+ m_nextPredEdge = newEdge;
+ }
+
+ BasicBlock* getSourceBlock() const
+ {
+ assert(m_sourceBlock != nullptr);
+ return m_sourceBlock;
+ }
+
+ void setSourceBlock(BasicBlock* newBlock)
+ {
+ assert(newBlock != nullptr);
+ m_sourceBlock = newBlock;
+ }
+
+ BasicBlock* getDestinationBlock() const
+ {
+ assert(m_destBlock != nullptr);
+ return m_destBlock;
+ }
+
+ void setDestinationBlock(BasicBlock* newBlock)
+ {
+ assert(newBlock != nullptr);
+ 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
+ {
+ return m_likelihood;
+ }
+
+ void setLikelihood(weight_t likelihood);
+
+ void clearLikelihood()
+ {
+ m_likelihood = 0.0;
+ m_likelihoodSet = false;
+ }
+
+ bool hasLikelihood() const
+ {
+ return m_likelihoodSet;
+ }
+
+ weight_t getLikelyWeight() const;
+
+ unsigned getDupCount() const
+ {
+ return m_dupCount;
+ }
+
+ void incrementDupCount()
+ {
+ m_dupCount++;
+ }
+
+ void decrementDupCount()
+ {
+ assert(m_dupCount >= 1);
+ m_dupCount--;
+ }
+};
+
//------------------------------------------------------------------------
// BasicBlock: describes a basic block in the flowgraph.
//
@@ -525,19 +721,19 @@ struct BasicBlock : private LIR::Range
/* The following union describes the jump target(s) of this block */
union {
- unsigned bbTargetOffs; // PC offset (temporary only)
- BasicBlock* bbTarget; // basic block
- BasicBlock* bbTrueTarget; // BBJ_COND jump target when its condition is true (alias for bbTarget)
- BBswtDesc* bbSwtTargets; // switch descriptor
- BBehfDesc* bbEhfTargets; // BBJ_EHFINALLYRET descriptor
+ unsigned bbTargetOffs; // PC offset (temporary only)
+ FlowEdge* bbTargetEdge; // successor edge for block kinds with only one successor (BBJ_ALWAYS, etc)
+ FlowEdge* bbTrueEdge; // BBJ_COND successor edge when its condition is true (alias for bbTargetEdge)
+ BBswtDesc* bbSwtTargets; // switch descriptor
+ BBehfDesc* bbEhfTargets; // BBJ_EHFINALLYRET descriptor
};
- // Points to the successor of a BBJ_COND block if bbTrueTarget is not taken
- BasicBlock* bbFalseTarget;
+ // Successor edge of a BBJ_COND block if bbTrueEdge is not taken
+ FlowEdge* bbFalseEdge;
public:
static BasicBlock* New(Compiler* compiler);
- static BasicBlock* New(Compiler* compiler, BBKinds kind, BasicBlock* target = nullptr);
+ static BasicBlock* New(Compiler* compiler, BBKinds kind);
static BasicBlock* New(Compiler* compiler, BBehfDesc* ehfTargets);
static BasicBlock* New(Compiler* compiler, BBswtDesc* swtTargets);
static BasicBlock* New(Compiler* compiler, BBKinds kind, unsigned targetOffs);
@@ -623,100 +819,135 @@ struct BasicBlock : private LIR::Range
return bbTargetOffs;
}
- void SetKindAndTarget(BBKinds kind, unsigned targetOffs)
- {
- bbKind = kind;
- bbTargetOffs = targetOffs;
- assert(KindIs(BBJ_ALWAYS, BBJ_COND, BBJ_LEAVE));
- }
-
bool HasTarget() const
{
- // These block types should always have bbTarget set
+ // These block types should always have bbTargetEdge set
return KindIs(BBJ_ALWAYS, BBJ_CALLFINALLY, BBJ_CALLFINALLYRET, BBJ_EHCATCHRET, BBJ_EHFILTERRET, BBJ_LEAVE);
}
BasicBlock* GetTarget() const
{
- // Only block kinds that use `bbTarget` can access it, and it must be non-null.
+ return GetTargetEdge()->getDestinationBlock();
+ }
+
+ FlowEdge* GetTargetEdge() const
+ {
+ // Only block kinds that use `bbTargetEdge` can access it, and it must be non-null.
assert(HasInitializedTarget());
- return bbTarget;
+ assert(bbTargetEdge->getSourceBlock() == this);
+ assert(bbTargetEdge->getDestinationBlock() != nullptr);
+ return bbTargetEdge;
}
- void SetTarget(BasicBlock* target)
+ void SetTargetEdge(FlowEdge* targetEdge)
{
// SetKindAndTarget() nulls target for non-jump kinds,
- // so don't use SetTarget() to null bbTarget without updating bbKind.
- bbTarget = target;
+ // so don't use SetTargetEdge() to null bbTargetEdge without updating bbKind.
+ bbTargetEdge = targetEdge;
assert(HasInitializedTarget());
+ assert(bbTargetEdge->getSourceBlock() == this);
+ assert(bbTargetEdge->getDestinationBlock() != nullptr);
}
BasicBlock* GetTrueTarget() const
+ {
+ return GetTrueEdge()->getDestinationBlock();
+ }
+
+ FlowEdge* GetTrueEdge() const
{
assert(KindIs(BBJ_COND));
- assert(bbTrueTarget != nullptr);
- return bbTrueTarget;
+ assert(bbTrueEdge != nullptr);
+ assert(bbTrueEdge->getSourceBlock() == this);
+ assert(bbTrueEdge->getDestinationBlock() != nullptr);
+ return bbTrueEdge;
}
- void SetTrueTarget(BasicBlock* target)
+ void SetTrueEdge(FlowEdge* trueEdge)
{
assert(KindIs(BBJ_COND));
- assert(target != nullptr);
- bbTrueTarget = target;
+ bbTrueEdge = trueEdge;
+ assert(bbTrueEdge != nullptr);
+ assert(bbTrueEdge->getSourceBlock() == this);
+ assert(bbTrueEdge->getDestinationBlock() != nullptr);
}
bool TrueTargetIs(const BasicBlock* target) const
{
- assert(KindIs(BBJ_COND));
- assert(bbTrueTarget != nullptr);
- return (bbTrueTarget == target);
+ return (GetTrueTarget() == target);
+ }
+
+ bool TrueEdgeIs(const FlowEdge* targetEdge) const
+ {
+ return (GetTrueEdge() == targetEdge);
}
BasicBlock* GetFalseTarget() const
+ {
+ return GetFalseEdge()->getDestinationBlock();
+ }
+
+ FlowEdge* GetFalseEdge() const
{
assert(KindIs(BBJ_COND));
- assert(bbFalseTarget != nullptr);
- return bbFalseTarget;
+ assert(bbFalseEdge != nullptr);
+ assert(bbFalseEdge->getSourceBlock() == this);
+ assert(bbFalseEdge->getDestinationBlock() != nullptr);
+ return bbFalseEdge;
}
- void SetFalseTarget(BasicBlock* target)
+ void SetFalseEdge(FlowEdge* falseEdge)
{
assert(KindIs(BBJ_COND));
- assert(target != nullptr);
- bbFalseTarget = target;
+ bbFalseEdge = falseEdge;
+ assert(bbFalseEdge != nullptr);
+ assert(bbFalseEdge->getSourceBlock() == this);
+ assert(bbFalseEdge->getDestinationBlock() != nullptr);
}
bool FalseTargetIs(const BasicBlock* target) const
{
- assert(KindIs(BBJ_COND));
- assert(bbFalseTarget != nullptr);
- return (bbFalseTarget == target);
+ return (GetFalseTarget() == target);
}
- void SetCond(BasicBlock* trueTarget, BasicBlock* falseTarget)
+ bool FalseEdgeIs(const FlowEdge* targetEdge) const
{
- assert(trueTarget != nullptr);
- bbKind = BBJ_COND;
- bbTrueTarget = trueTarget;
- bbFalseTarget = falseTarget;
+ return (GetFalseEdge() == targetEdge);
}
- // Set both the block kind and target. This can clear `bbTarget` when setting
- // block kinds that don't use `bbTarget`.
- void SetKindAndTarget(BBKinds kind, BasicBlock* target = nullptr)
+ void SetCond(FlowEdge* trueEdge, FlowEdge* falseEdge)
{
- bbKind = kind;
- bbTarget = target;
+ bbKind = BBJ_COND;
+ SetTrueEdge(trueEdge);
+ SetFalseEdge(falseEdge);
+ }
+
+ // In most cases, a block's true and false targets are known by the time SetCond is called.
+ // To simplify the few cases where the false target isn't available until later,
+ // overload SetCond to initialize only the true target.
+ // This simplifies, for example, lowering switch blocks into jump sequences.
+ void SetCond(FlowEdge* trueEdge)
+ {
+ bbKind = BBJ_COND;
+ SetTrueEdge(trueEdge);
+ }
- // If bbKind indicates this block has a jump, bbTarget cannot be null.
+ // Set both the block kind and target edge. This can clear `bbTargetEdge` when setting
+ // block kinds that don't use `bbTargetEdge`.
+ void SetKindAndTargetEdge(BBKinds kind, FlowEdge* targetEdge = nullptr)
+ {
+ bbKind = kind;
+ bbTargetEdge = targetEdge;
+
+ // If bbKind indicates this block has a jump, bbTargetEdge cannot be null.
// You shouldn't use this to set a BBJ_COND, BBJ_SWITCH, or BBJ_EHFINALLYRET.
- assert(HasTarget() ? HasInitializedTarget() : (bbTarget == nullptr));
+ assert(HasTarget() ? HasInitializedTarget() : (bbTargetEdge == nullptr));
}
bool HasInitializedTarget() const
{
assert(HasTarget());
- return (bbTarget != nullptr);
+ return (bbTargetEdge != nullptr);
}
bool TargetIs(const BasicBlock* target) const
@@ -762,19 +993,13 @@ struct BasicBlock : private LIR::Range
bbEhfTargets = ehfTarget;
}
- // BBJ_CALLFINALLYRET uses the `bbTarget` field. However, also treat it specially:
+ // BBJ_CALLFINALLYRET uses the `bbTargetEdge` field. However, also treat it specially:
// for callers that know they want a continuation, use this function instead of the
// general `GetTarget()` to allow asserting on the block kind.
BasicBlock* GetFinallyContinuation() const
{
assert(KindIs(BBJ_CALLFINALLYRET));
- return bbTarget;
- }
-
- void SetFinallyContinuation(BasicBlock* finallyContinuation)
- {
- assert(KindIs(BBJ_CALLFINALLYRET));
- bbTarget = finallyContinuation;
+ return GetTarget();
}
#ifdef DEBUG
@@ -783,21 +1008,21 @@ struct BasicBlock : private LIR::Range
BasicBlock* GetTargetRaw() const
{
assert(HasTarget());
- return bbTarget;
+ return (bbTargetEdge == nullptr) ? nullptr : bbTargetEdge->getDestinationBlock();
}
// Return the BBJ_COND true target; it might be null. Only used during dumping.
BasicBlock* GetTrueTargetRaw() const
{
assert(KindIs(BBJ_COND));
- return bbTrueTarget;
+ return (bbTrueEdge == nullptr) ? nullptr : bbTrueEdge->getDestinationBlock();
}
// Return the BBJ_COND false target; it might be null. Only used during dumping.
BasicBlock* GetFalseTargetRaw() const
{
assert(KindIs(BBJ_COND));
- return bbFalseTarget;
+ return (bbFalseEdge == nullptr) ? nullptr : bbFalseEdge->getDestinationBlock();
}
#endif // DEBUG
@@ -1087,7 +1312,11 @@ struct BasicBlock : private LIR::Range
unsigned NumSucc() const;
unsigned NumSucc(Compiler* comp);
- // GetSucc: Returns the "i"th successor. Requires (0 <= i < NumSucc()).
+ // GetSuccEdge: Returns the "i"th successor edge. Requires (0 <= i < NumSucc()).
+ FlowEdge* GetSuccEdge(unsigned i) const;
+ FlowEdge* GetSuccEdge(unsigned i, Compiler* comp);
+
+ // GetSucc: Returns the "i"th successor block. Requires (0 <= i < NumSucc()).
BasicBlock* GetSucc(unsigned i) const;
BasicBlock* GetSucc(unsigned i, Compiler* comp);
@@ -1566,37 +1795,64 @@ struct BasicBlock : private LIR::Range
bool HasPotentialEHSuccs(Compiler* comp);
- // BBSuccList: adapter class for forward iteration of block successors, using range-based `for`,
- // normally used via BasicBlock::Succs(), e.g.:
- // for (BasicBlock* const target : block->Succs()) ...
+ // Base class for Successor block/edge iterators.
//
- class BBSuccList
+ class SuccList
{
+ protected:
// For one or two successors, pre-compute and stash the successors inline, in m_succs[], so we don't
// need to call a function or execute another `switch` to get them. Also, pre-compute the begin and end
// points of the iteration, for use by BBArrayIterator. `m_begin` and `m_end` will either point at
// `m_succs` or at the switch table successor array.
- BasicBlock* m_succs[2];
-
- // Quirk: Some BasicBlock kinds refer to their successors with BasicBlock pointers,
- // while others use FlowEdge pointers. Eventually, every type will use FlowEdge pointers.
- // For now, support iterating with both types.
- union {
- BasicBlock* const* m_begin;
- FlowEdge* const* m_beginEdge;
- };
+ FlowEdge* m_succs[2];
+ FlowEdge* const* m_begin;
+ FlowEdge* const* m_end;
- union {
- BasicBlock* const* m_end;
- FlowEdge* const* m_endEdge;
- };
+ SuccList(const BasicBlock* block);
+ };
- bool iterateEdges;
+ // BBSuccList: adapter class for forward iteration of block successors, using range-based `for`,
+ // normally used via BasicBlock::Succs(), e.g.:
+ // for (BasicBlock* const target : block->Succs()) ...
+ //
+ class BBSuccList : private SuccList
+ {
+ public:
+ BBSuccList(const BasicBlock* block) : SuccList(block)
+ {
+ }
+ BBArrayIterator begin() const
+ {
+ return BBArrayIterator(m_begin);
+ }
+
+ BBArrayIterator end() const
+ {
+ return BBArrayIterator(m_end);
+ }
+ };
+
+ // BBSuccEdgeList: adapter class for forward iteration of block successors edges, using range-based `for`,
+ // normally used via BasicBlock::SuccEdges(), e.g.:
+ // for (FlowEdge* const succEdge : block->SuccEdges()) ...
+ //
+ class BBSuccEdgeList : private SuccList
+ {
public:
- BBSuccList(const BasicBlock* block);
- BBArrayIterator begin() const;
- BBArrayIterator end() const;
+ BBSuccEdgeList(const BasicBlock* block) : SuccList(block)
+ {
+ }
+
+ FlowEdgeArrayIterator begin() const
+ {
+ return FlowEdgeArrayIterator(m_begin);
+ }
+
+ FlowEdgeArrayIterator end() const
+ {
+ return FlowEdgeArrayIterator(m_end);
+ }
};
// BBCompilerSuccList: adapter class for forward iteration of block successors, using range-based `for`,
@@ -1610,7 +1866,7 @@ struct BasicBlock : private LIR::Range
Compiler* m_comp;
BasicBlock* m_block;
- // iterator: forward iterator for an array of BasicBlock*, such as the BBswtDesc->bbsDstTab.
+ // iterator: forward iterator for an array of BasicBlock*
//
class iterator
{
@@ -1660,6 +1916,67 @@ struct BasicBlock : private LIR::Range
}
};
+ // BBCompilerSuccEdgeList: adapter class for forward iteration of block successors edges, using range-based `for`,
+ // normally used via BasicBlock::SuccEdges(), e.g.:
+ // for (FlowEdge* const succEdge : block->SuccEdges(compiler)) ...
+ //
+ // This version uses NumSucc(Compiler*)/GetSucc(Compiler*). See the documentation there for the explanation
+ // of the implications of this versus the version that does not take `Compiler*`.
+ class BBCompilerSuccEdgeList
+ {
+ Compiler* m_comp;
+ BasicBlock* m_block;
+
+ // iterator: forward iterator for an array of BasicBlock*
+ //
+ class iterator
+ {
+ Compiler* m_comp;
+ BasicBlock* m_block;
+ unsigned m_succNum;
+
+ public:
+ iterator(Compiler* comp, BasicBlock* block, unsigned succNum)
+ : m_comp(comp), m_block(block), m_succNum(succNum)
+ {
+ }
+
+ FlowEdge* operator*() const
+ {
+ assert(m_block != nullptr);
+ FlowEdge* succEdge = m_block->GetSuccEdge(m_succNum, m_comp);
+ assert(succEdge != nullptr);
+ return succEdge;
+ }
+
+ iterator& operator++()
+ {
+ ++m_succNum;
+ return *this;
+ }
+
+ bool operator!=(const iterator& i) const
+ {
+ return m_succNum != i.m_succNum;
+ }
+ };
+
+ public:
+ BBCompilerSuccEdgeList(Compiler* comp, BasicBlock* block) : m_comp(comp), m_block(block)
+ {
+ }
+
+ iterator begin() const
+ {
+ return iterator(m_comp, m_block, 0);
+ }
+
+ iterator end() const
+ {
+ return iterator(m_comp, m_block, m_block->NumSucc(m_comp));
+ }
+ };
+
// Succs: convenience methods for enabling range-based `for` iteration over a block's successors, e.g.:
// for (BasicBlock* const succ : block->Succs()) ...
//
@@ -1676,6 +1993,16 @@ struct BasicBlock : private LIR::Range
return BBCompilerSuccList(comp, this);
}
+ BBSuccEdgeList SuccEdges()
+ {
+ return BBSuccEdgeList(this);
+ }
+
+ BBCompilerSuccEdgeList SuccEdges(Compiler* comp)
+ {
+ return BBCompilerSuccEdgeList(comp, this);
+ }
+
// Clone block state and statements from `from` block to `to` block (which must be new/empty)
static void CloneBlockState(Compiler* compiler, BasicBlock* to, const BasicBlock* from);
@@ -1927,12 +2254,11 @@ inline BBArrayIterator BBEhfSuccList::end() const
return BBArrayIterator(m_bbeDesc->bbeSuccs + m_bbeDesc->bbeCount);
}
-// BBSuccList out-of-class-declaration implementations
+// SuccList out-of-class-declaration implementations
//
-inline BasicBlock::BBSuccList::BBSuccList(const BasicBlock* block)
+inline BasicBlock::SuccList::SuccList(const BasicBlock* block)
{
assert(block != nullptr);
- iterateEdges = false;
switch (block->bbKind)
{
@@ -1950,24 +2276,24 @@ inline BasicBlock::BBSuccList::BBSuccList(const BasicBlock* block)
case BBJ_EHCATCHRET:
case BBJ_EHFILTERRET:
case BBJ_LEAVE:
- m_succs[0] = block->bbTarget;
+ m_succs[0] = block->GetTargetEdge();
m_begin = &m_succs[0];
m_end = &m_succs[1];
break;
case BBJ_COND:
- m_succs[0] = block->bbFalseTarget;
+ m_succs[0] = block->GetFalseEdge();
m_begin = &m_succs[0];
// If both fall-through and branch successors are identical, then only include
// them once in the iteration (this is the same behavior as NumSucc()/GetSucc()).
- if (block->TrueTargetIs(block->GetFalseTarget()))
+ if (block->TrueEdgeIs(block->GetFalseEdge()))
{
m_end = &m_succs[1];
}
else
{
- m_succs[1] = block->bbTrueTarget;
+ m_succs[1] = block->GetTrueEdge();
m_end = &m_succs[2];
}
break;
@@ -1978,26 +2304,22 @@ inline BasicBlock::BBSuccList::BBSuccList(const BasicBlock* block)
// been computed.
if (block->GetEhfTargets() == nullptr)
{
- m_beginEdge = nullptr;
- m_endEdge = nullptr;
+ m_begin = nullptr;
+ m_end = nullptr;
}
else
{
- m_beginEdge = block->GetEhfTargets()->bbeSuccs;
- m_endEdge = block->GetEhfTargets()->bbeSuccs + block->GetEhfTargets()->bbeCount;
+ m_begin = block->GetEhfTargets()->bbeSuccs;
+ m_end = block->GetEhfTargets()->bbeSuccs + block->GetEhfTargets()->bbeCount;
}
-
- iterateEdges = true;
break;
case BBJ_SWITCH:
// We don't use the m_succs in-line data for switches; use the existing jump table in the block.
assert(block->bbSwtTargets != nullptr);
assert(block->bbSwtTargets->bbsDstTab != nullptr);
- m_beginEdge = block->bbSwtTargets->bbsDstTab;
- m_endEdge = block->bbSwtTargets->bbsDstTab + block->bbSwtTargets->bbsCount;
-
- iterateEdges = true;
+ m_begin = block->bbSwtTargets->bbsDstTab;
+ m_end = block->bbSwtTargets->bbsDstTab + block->bbSwtTargets->bbsCount;
break;
default:
@@ -2007,16 +2329,6 @@ inline BasicBlock::BBSuccList::BBSuccList(const BasicBlock* block)
assert(m_end >= m_begin);
}
-inline BBArrayIterator BasicBlock::BBSuccList::begin() const
-{
- return (iterateEdges ? BBArrayIterator(m_beginEdge) : BBArrayIterator(m_begin));
-}
-
-inline BBArrayIterator BasicBlock::BBSuccList::end() const
-{
- return (iterateEdges ? BBArrayIterator(m_endEdge) : BBArrayIterator(m_end));
-}
-
// We have a simpler struct, BasicBlockList, which is simply a singly-linked
// list of blocks.
@@ -2034,206 +2346,23 @@ struct BasicBlockList
}
};
-//-------------------------------------------------------------------------
-// FlowEdge -- control flow edge
-//
-// In compiler terminology the control flow between two BasicBlocks
-// is typically referred to as an "edge". Most well known are the
-// backward branches for loops, which are often called "back-edges".
-//
-// "struct FlowEdge" is the type that represents our control flow edges.
-// This type is a linked list of zero or more "edges".
-// (The list of zero edges is represented by NULL.)
-// Every BasicBlock has a field called bbPreds of this type. This field
-// represents the list of "edges" that flow into this BasicBlock.
-// The FlowEdge type only stores the BasicBlock* of the source for the
-// control flow edge. The destination block for the control flow edge
-// is implied to be the block which contained the bbPreds field.
-//
-// For a switch branch target there may be multiple "edges" that have
-// the same source block (and destination block). We need to count the
-// number of these edges so that during optimization we will know when
-// we have zero of them. Rather than have extra FlowEdge entries we
-// track this via the DupCount property.
-//
-// When we have Profile weight for the BasicBlocks we can usually compute
-// the number of times each edge was executed by examining the adjacent
-// BasicBlock weights. As we are doing for BasicBlocks, we call the number
-// of times that a control flow edge was executed the "edge weight".
-// In order to compute the edge weights we need to use a bounded range
-// for every edge weight. These two fields, 'flEdgeWeightMin' and 'flEdgeWeightMax'
-// are used to hold a bounded range. Most often these will converge such
-// that both values are the same and that value is the exact edge weight.
-// Sometimes we are left with a rage of possible values between [Min..Max]
-// which represents an inexact edge weight.
-//
-// The bbPreds list is initially created by Compiler::fgLinkBasicBlocks()
-// and is incrementally kept up to date.
-//
-// The edge weight are computed by Compiler::fgComputeEdgeWeights()
-// the edge weights are used to straighten conditional branches
-// by Compiler::fgReorderBlocks()
-//
-struct FlowEdge
-{
-private:
- // The next predecessor edge in the list, nullptr for end of list.
- FlowEdge* m_nextPredEdge;
-
- // The source of the control flow
- BasicBlock* m_sourceBlock;
-
- // 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;
-
- // The count of duplicate "edges" (used for switch stmts or degenerate branches)
- unsigned m_dupCount;
-
- // True if likelihood has been set
- bool m_likelihoodSet;
-
-public:
- FlowEdge(BasicBlock* sourceBlock, BasicBlock* destBlock, FlowEdge* rest)
- : m_nextPredEdge(rest)
- , m_sourceBlock(sourceBlock)
- , m_destBlock(destBlock)
- , m_edgeWeightMin(0)
- , m_edgeWeightMax(0)
- , m_likelihood(0)
- , m_dupCount(0)
- , m_likelihoodSet(false)
- {
- }
-
- FlowEdge* getNextPredEdge() const
- {
- return m_nextPredEdge;
- }
-
- FlowEdge** getNextPredEdgeRef()
- {
- return &m_nextPredEdge;
- }
-
- void setNextPredEdge(FlowEdge* newEdge)
- {
- m_nextPredEdge = newEdge;
- }
-
- BasicBlock* getSourceBlock() const
- {
- assert(m_sourceBlock != nullptr);
- return m_sourceBlock;
- }
-
- void setSourceBlock(BasicBlock* newBlock)
- {
- assert(newBlock != nullptr);
- m_sourceBlock = newBlock;
- }
-
- BasicBlock* getDestinationBlock() const
- {
- assert(m_destBlock != nullptr);
- return m_destBlock;
- }
-
- void setDestinationBlock(BasicBlock* newBlock)
- {
- assert(newBlock != nullptr);
- 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
- {
- return m_likelihood;
- }
-
- void setLikelihood(weight_t likelihood)
- {
- assert(likelihood >= 0.0);
- assert(likelihood <= 1.0);
- m_likelihoodSet = true;
- m_likelihood = likelihood;
- }
+// FlowEdge implementations (that are required to be defined after the declaration of BasicBlock)
- void clearLikelihood()
- {
- m_likelihood = 0.0;
- m_likelihoodSet = false;
- }
-
- bool hasLikelihood() const
- {
- return m_likelihoodSet;
- }
-
- weight_t getLikelyWeight() const
- {
- assert(m_likelihoodSet);
- return m_likelihood * m_sourceBlock->bbWeight;
- }
-
- unsigned getDupCount() const
- {
- return m_dupCount;
- }
-
- void incrementDupCount()
- {
- m_dupCount++;
- }
-
- void decrementDupCount()
- {
- assert(m_dupCount >= 1);
- m_dupCount--;
- }
-};
+inline weight_t FlowEdge::getLikelyWeight() const
+{
+ assert(m_likelihoodSet);
+ return m_likelihood * m_sourceBlock->bbWeight;
+}
// BasicBlock iterator implementations (that are required to be defined after the declaration of FlowEdge)
inline BasicBlock* BBArrayIterator::operator*() const
{
- if (iterateEdges)
- {
- assert(m_edgeEntry != nullptr);
- FlowEdge* edgeTarget = *m_edgeEntry;
- assert(edgeTarget != nullptr);
- assert(edgeTarget->getDestinationBlock() != nullptr);
- return edgeTarget->getDestinationBlock();
- }
-
- assert(m_bbEntry != nullptr);
- BasicBlock* bTarget = *m_bbEntry;
- assert(bTarget != nullptr);
- return bTarget;
+ assert(m_edgeEntry != nullptr);
+ FlowEdge* edgeTarget = *m_edgeEntry;
+ assert(edgeTarget != nullptr);
+ assert(edgeTarget->getDestinationBlock() != nullptr);
+ return edgeTarget->getDestinationBlock();
}
// Pred list iterator implementations (that are required to be defined after the declaration of BasicBlock and FlowEdge)
diff --git a/src/coreclr/jit/clrjit.natvis b/src/coreclr/jit/clrjit.natvis
index 95dd3dc305689..e8ac7e8f7c4a3 100644
--- a/src/coreclr/jit/clrjit.natvis
+++ b/src/coreclr/jit/clrjit.natvis
@@ -21,7 +21,7 @@ Documentation for VS debugger format specifiers: https://docs.microsoft.com/en-u
- BB{bbNum,d}->BB{bbTarget->bbNum,d}; {bbKind,en}
+ BB{bbNum,d}->BB{bbTargetEdge->m_destBlock->bbNum,d}; {bbKind,en}
BB{bbNum,d}; {bbKind,en}; {bbSwtTargets->bbsCount} cases
BB{bbNum,d}; {bbKind,en}; {bbEhfTargets->bbeCount} succs
BB{bbNum,d}; {bbKind,en}
@@ -86,6 +86,11 @@ Documentation for VS debugger format specifiers: https://docs.microsoft.com/en-u
{gtTreeID, d}: [{gtOper,en}, {gtType,en} V{((GenTreeLclFld*)this)->_gtLclNum,u}[+{((GenTreeLclFld*)this)->m_lclOffs,u}]]
+
+
+ [{Oper,en}, {Type,en}]
+
+
LinearScan
diff --git a/src/coreclr/jit/codegen.h b/src/coreclr/jit/codegen.h
index c36a6776a8cd9..4d17e291d0c8a 100644
--- a/src/coreclr/jit/codegen.h
+++ b/src/coreclr/jit/codegen.h
@@ -1183,6 +1183,9 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void genCodeForCpBlkRepMovs(GenTreeBlk* cpBlkNode);
void genCodeForCpBlkUnroll(GenTreeBlk* cpBlkNode);
void genCodeForPhysReg(GenTreePhysReg* tree);
+#ifdef SWIFT_SUPPORT
+ void genCodeForSwiftErrorReg(GenTree* tree);
+#endif // SWIFT_SUPPORT
void genCodeForNullCheck(GenTreeIndir* tree);
void genCodeForCmpXchg(GenTreeCmpXchg* tree);
void genCodeForReuseVal(GenTree* treeNode);
diff --git a/src/coreclr/jit/codegenarm64test.cpp b/src/coreclr/jit/codegenarm64test.cpp
index 1a7ae0ef7d032..ae5c6b0487c67 100644
--- a/src/coreclr/jit/codegenarm64test.cpp
+++ b/src/coreclr/jit/codegenarm64test.cpp
@@ -4581,6 +4581,14 @@ void CodeGen::genArm64EmitterUnitTestsSve()
theEmitter->emitIns_R_R_R(INS_sve_subr, EA_SCALABLE, REG_V2, REG_P0, REG_V13,
INS_OPTS_SCALABLE_S); // SUBR ., /M, ., .
+#ifdef ALL_ARM64_EMITTER_UNIT_TESTS_SVE_UNSUPPORTED
+ // IF_SVE_AB_3B
+ theEmitter->emitIns_R_R_R(INS_sve_addpt, EA_SCALABLE, REG_V0, REG_P1, REG_V2,
+ INS_OPTS_SCALABLE_D); // ADDPT .D, /M, .D, .D
+ theEmitter->emitIns_R_R_R(INS_sve_subpt, EA_SCALABLE, REG_V0, REG_P1, REG_V2,
+ INS_OPTS_SCALABLE_D); // SUBPT .D, /M, .D, .D
+#endif // ALL_ARM64_EMITTER_UNIT_TESTS_SVE_UNSUPPORTED
+
// IF_SVE_AC_3A
theEmitter->emitIns_R_R_R(INS_sve_sdiv, EA_SCALABLE, REG_V3, REG_P2, REG_V9,
INS_OPTS_SCALABLE_S); // SDIV ., /M, ., .
@@ -4725,6 +4733,54 @@ void CodeGen::genArm64EmitterUnitTestsSve()
theEmitter->emitIns_R_R_R(INS_sve_lsr, EA_SCALABLE, REG_V0, REG_P0, REG_V0, INS_OPTS_SCALABLE_S,
INS_SCALABLE_OPTS_WIDE); // LSR ., /M, ., .D
+ // IF_SVE_CE_2A
+ theEmitter->emitIns_R_R(INS_sve_pmov, EA_SCALABLE, REG_P2, REG_V12, INS_OPTS_SCALABLE_B,
+ INS_SCALABLE_OPTS_TO_PREDICATE); // PMOV .B,
+ theEmitter->emitIns_R_R(INS_sve_pmov, EA_SCALABLE, REG_P7, REG_V2, INS_OPTS_SCALABLE_H,
+ INS_SCALABLE_OPTS_TO_PREDICATE); // PMOV .H, [0]
+
+ // IF_SVE_CE_2B
+ theEmitter->emitIns_R_R_I(INS_sve_pmov, EA_SCALABLE, REG_P15, REG_V7, 7, INS_OPTS_SCALABLE_D,
+ INS_SCALABLE_OPTS_TO_PREDICATE); // PMOV .D, []
+ theEmitter->emitIns_R_R_I(INS_sve_pmov, EA_SCALABLE, REG_P7, REG_V16, 0, INS_OPTS_SCALABLE_D,
+ INS_SCALABLE_OPTS_TO_PREDICATE); // PMOV .D, []
+
+ // IF_SVE_CE_2C
+ theEmitter->emitIns_R_R_I(INS_sve_pmov, EA_SCALABLE, REG_P0, REG_V31, 1, INS_OPTS_SCALABLE_H,
+ INS_SCALABLE_OPTS_TO_PREDICATE); // PMOV .H, []
+ theEmitter->emitIns_R_R_I(INS_sve_pmov, EA_SCALABLE, REG_V1, REG_P1, 0, INS_OPTS_SCALABLE_H,
+ INS_SCALABLE_OPTS_TO_PREDICATE); // PMOV .H, []
+
+ // IF_SVE_CE_2D
+ theEmitter->emitIns_R_R_I(INS_sve_pmov, EA_SCALABLE, REG_P3, REG_V9, 3, INS_OPTS_SCALABLE_S,
+ INS_SCALABLE_OPTS_TO_PREDICATE); // PMOV .S, []
+ theEmitter->emitIns_R_R_I(INS_sve_pmov, EA_SCALABLE, REG_P10, REG_V4, 0, INS_OPTS_SCALABLE_S,
+ INS_SCALABLE_OPTS_TO_PREDICATE); // PMOV .S, []
+
+ // IF_SVE_CF_2A
+ theEmitter->emitIns_R_R(INS_sve_pmov, EA_SCALABLE, REG_V11, REG_P12, INS_OPTS_SCALABLE_B,
+ INS_SCALABLE_OPTS_TO_VECTOR); // PMOV , .B
+ theEmitter->emitIns_R_R(INS_sve_pmov, EA_SCALABLE, REG_V2, REG_P7, INS_OPTS_SCALABLE_S,
+ INS_SCALABLE_OPTS_TO_VECTOR); // PMOV [0], .S
+
+ // IF_SVE_CF_2B
+ theEmitter->emitIns_R_R_I(INS_sve_pmov, EA_SCALABLE, REG_V6, REG_P8, 7, INS_OPTS_SCALABLE_D,
+ INS_SCALABLE_OPTS_TO_VECTOR); // PMOV [], .D
+ theEmitter->emitIns_R_R_I(INS_sve_pmov, EA_SCALABLE, REG_V9, REG_P7, 0, INS_OPTS_SCALABLE_D,
+ INS_SCALABLE_OPTS_TO_VECTOR); // PMOV [], .D
+
+ // IF_SVE_CF_2C
+ theEmitter->emitIns_R_R_I(INS_sve_pmov, EA_SCALABLE, REG_V8, REG_P4, 1, INS_OPTS_SCALABLE_H,
+ INS_SCALABLE_OPTS_TO_VECTOR); // PMOV [], .H
+ theEmitter->emitIns_R_R_I(INS_sve_pmov, EA_SCALABLE, REG_V5, REG_P9, 0, INS_OPTS_SCALABLE_H,
+ INS_SCALABLE_OPTS_TO_VECTOR); // PMOV [], .H
+
+ // IF_SVE_CF_2D
+ theEmitter->emitIns_R_R_I(INS_sve_pmov, EA_SCALABLE, REG_V14, REG_P2, 3, INS_OPTS_SCALABLE_S,
+ INS_SCALABLE_OPTS_TO_VECTOR); // PMOV [], .S
+ theEmitter->emitIns_R_R_I(INS_sve_pmov, EA_SCALABLE, REG_V3, REG_P15, 0, INS_OPTS_SCALABLE_S,
+ INS_SCALABLE_OPTS_TO_VECTOR); // PMOV [], .S
+
// IF_SVE_CJ_2A
theEmitter->emitIns_R_R(INS_sve_rev, EA_SCALABLE, REG_P1, REG_P2,
INS_OPTS_SCALABLE_B); // REV ., .
@@ -5101,6 +5157,22 @@ void CodeGen::genArm64EmitterUnitTestsSve()
theEmitter->emitIns_R_R_R(INS_sve_fsubr, EA_SCALABLE, REG_V6, REG_P4, REG_V29,
INS_OPTS_SCALABLE_D); // FSUBR ., /M, ., .
+ // IF_SVE_HL_3B
+ theEmitter->emitIns_R_R_R(INS_sve_bfadd, EA_SCALABLE, REG_V0, REG_P0, REG_V1,
+ INS_OPTS_SCALABLE_H); // BFADD .H, /M, .H, .H
+ theEmitter->emitIns_R_R_R(INS_sve_bfmax, EA_SCALABLE, REG_V2, REG_P1, REG_V3,
+ INS_OPTS_SCALABLE_H); // BFMAX .H, /M, .H, .H
+ theEmitter->emitIns_R_R_R(INS_sve_bfmaxnm, EA_SCALABLE, REG_V4, REG_P2, REG_V5,
+ INS_OPTS_SCALABLE_H); // BFMAXNM .H, /M, .H, .H
+ theEmitter->emitIns_R_R_R(INS_sve_bfmin, EA_SCALABLE, REG_V6, REG_P3, REG_V7,
+ INS_OPTS_SCALABLE_H); // BFMIN .H, /M, .H, .H
+ theEmitter->emitIns_R_R_R(INS_sve_bfminnm, EA_SCALABLE, REG_V8, REG_P4, REG_V9,
+ INS_OPTS_SCALABLE_H); // BFMINNM .H, /M, .H, .H
+ theEmitter->emitIns_R_R_R(INS_sve_bfmul, EA_SCALABLE, REG_V10, REG_P5, REG_V11,
+ INS_OPTS_SCALABLE_H); // BFMUL .H, /M, .H, .H
+ theEmitter->emitIns_R_R_R(INS_sve_bfsub, EA_SCALABLE, REG_V12, REG_P6, REG_V13,
+ INS_OPTS_SCALABLE_H); // BFSUB .H, /M, .H, .H
+
// IF_SVE_HT_4A
theEmitter->emitIns_R_R_R_R(INS_sve_facge, EA_SCALABLE, REG_P0, REG_P0, REG_V10, REG_V31,
INS_OPTS_SCALABLE_H); // FACGE ., /Z, ., .
@@ -5125,6 +5197,16 @@ void CodeGen::genArm64EmitterUnitTestsSve()
theEmitter->emitIns_R_R_R_R(INS_sve_fcmuo, EA_SCALABLE, REG_P5, REG_P2, REG_V31, REG_V20,
INS_OPTS_SCALABLE_S); // FCMUO ., /Z, ., .
+ // IF_SVE_HU_4A
+ theEmitter->emitIns_R_R_R_R(INS_sve_fmla, EA_SCALABLE, REG_V0, REG_P0, REG_V1, REG_V2,
+ INS_OPTS_SCALABLE_H); // FMLA ., /M, ., .
+ theEmitter->emitIns_R_R_R_R(INS_sve_fmls, EA_SCALABLE, REG_V3, REG_P2, REG_V4, REG_V5,
+ INS_OPTS_SCALABLE_S); // FMLS ., /M, ., .
+ theEmitter->emitIns_R_R_R_R(INS_sve_fnmla, EA_SCALABLE, REG_V6, REG_P4, REG_V7, REG_V8,
+ INS_OPTS_SCALABLE_D); // FNMLA ., /M, ., .
+ theEmitter->emitIns_R_R_R_R(INS_sve_fnmls, EA_SCALABLE, REG_V9, REG_P6, REG_V10, REG_V11,
+ INS_OPTS_SCALABLE_H); // FNMLS ., /M, ., .
+
// IF_SVE_AF_3A
theEmitter->emitIns_R_R_R(INS_sve_andv, EA_1BYTE, REG_V0, REG_P0, REG_V0,
INS_OPTS_SCALABLE_B); // ANDV , , .
@@ -5269,6 +5351,10 @@ void CodeGen::genArm64EmitterUnitTestsSve()
theEmitter->emitIns_R_R_R(INS_sve_umulh, EA_SCALABLE, REG_V31, REG_V5, REG_V0, INS_OPTS_SCALABLE_D,
INS_SCALABLE_OPTS_UNPREDICATED); // UMULH ., ., .
+ // IF_SVE_BD_3B
+ theEmitter->emitIns_R_R_R(INS_sve_pmul, EA_SCALABLE, REG_V0, REG_V1, REG_V2,
+ INS_OPTS_SCALABLE_B); // PMUL .B, .B, .B
+
// IF_SVE_BE_3A
theEmitter->emitIns_R_R_R(INS_sve_sqdmulh, EA_SCALABLE, REG_V7, REG_V28, REG_V0,
INS_OPTS_SCALABLE_B); // SQDMULH ., ., .
@@ -5283,6 +5369,24 @@ void CodeGen::genArm64EmitterUnitTestsSve()
theEmitter->emitIns_R_R_R(INS_sve_lsr, EA_SCALABLE, REG_V29, REG_V10, REG_V22, INS_OPTS_SCALABLE_S,
INS_SCALABLE_OPTS_UNPREDICATED_WIDE); // LSR ., ., .D
+ // IF_SVE_BH_3A
+ theEmitter->emitInsSve_R_R_R_I(INS_sve_adr, EA_SCALABLE, REG_V4, REG_V2, REG_V0, 0, INS_OPTS_SCALABLE_D,
+ INS_SCALABLE_OPTS_LSL_N); // ADR ., [., .{, }]
+ theEmitter->emitInsSve_R_R_R_I(INS_sve_adr, EA_SCALABLE, REG_V29, REG_V1, REG_V10, 1, INS_OPTS_SCALABLE_S,
+ INS_SCALABLE_OPTS_LSL_N); // ADR ., [., .{, }]
+
+ // IF_SVE_BH_3B
+ theEmitter->emitInsSve_R_R_R_I(INS_sve_adr, EA_SCALABLE, REG_V9, REG_V7, REG_V9, 0,
+ INS_OPTS_SCALABLE_D_SXTW); // ADR .D, [.D, .D, SXTW{}]
+ theEmitter->emitInsSve_R_R_R_I(INS_sve_adr, EA_SCALABLE, REG_V12, REG_V3, REG_V5, 2,
+ INS_OPTS_SCALABLE_D_SXTW); // ADR .D, [.D, .D, SXTW{}]
+
+ // IF_SVE_BH_3B_A
+ theEmitter->emitInsSve_R_R_R_I(INS_sve_adr, EA_SCALABLE, REG_V9, REG_V10, REG_V14, 0,
+ INS_OPTS_SCALABLE_D_UXTW); // ADR .D, [.D, .D, UXTW{}]
+ theEmitter->emitInsSve_R_R_R_I(INS_sve_adr, EA_SCALABLE, REG_V3, REG_V15, REG_V11, 3,
+ INS_OPTS_SCALABLE_D_UXTW); // ADR .D, [.D, .D, UXTW{}]
+
// IF_SVE_BK_3A
theEmitter->emitIns_R_R_R(INS_sve_ftssel, EA_SCALABLE, REG_V17, REG_V16, REG_V15,
INS_OPTS_SCALABLE_D); // FTSSEL ., ., .
@@ -5559,6 +5663,111 @@ void CodeGen::genArm64EmitterUnitTestsSve()
theEmitter->emitIns_R_R_R(INS_sve_uabalt, EA_SCALABLE, REG_V9, REG_V10, REG_V11,
INS_OPTS_SCALABLE_H); // UABALT ., ., .
+#ifdef ALL_ARM64_EMITTER_UNIT_TESTS_SVE_UNSUPPORTED
+ // IF_SVE_GC_3A
+ theEmitter->emitIns_R_R_R(INS_sve_addhnb, EA_SCALABLE, REG_V0, REG_V1, REG_V2,
+ INS_OPTS_SCALABLE_B); // ADDHNB ., ., .
+ theEmitter->emitIns_R_R_R(INS_sve_addhnt, EA_SCALABLE, REG_V3, REG_V4, REG_V5,
+ INS_OPTS_SCALABLE_H); // ADDHNT ., ., .
+ theEmitter->emitIns_R_R_R(INS_sve_raddhnb, EA_SCALABLE, REG_V6, REG_V7, REG_V8,
+ INS_OPTS_SCALABLE_S); // RADDHNB ., ., .
+ theEmitter->emitIns_R_R_R(INS_sve_raddhnt, EA_SCALABLE, REG_V9, REG_V10, REG_V11,
+ INS_OPTS_SCALABLE_B); // RADDHNT ., ., .
+ theEmitter->emitIns_R_R_R(INS_sve_rsubhnb, EA_SCALABLE, REG_V12, REG_V13, REG_V14,
+ INS_OPTS_SCALABLE_H); // RSUBHNB .