diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index d64902048b60..28a90bad92d3 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -15,7 +15,7 @@
]
},
"microsoft.dotnet.xharness.cli": {
- "version": "1.0.0-prerelease.21175.2",
+ "version": "1.0.0-prerelease.21180.1",
"commands": [
"xharness"
]
diff --git a/README.md b/README.md
index 13c4ff4a9af4..fa5b7db77835 100644
--- a/README.md
+++ b/README.md
@@ -23,8 +23,8 @@ This project is successor of RyuJIT CodeGen from [CoreRT](https://github.com/dot
---
# .NET Runtime
-
[![Build Status](https://dnceng.visualstudio.com/public/_apis/build/status/dotnet/runtime/runtime?branchName=main)](https://dnceng.visualstudio.com/public/_build/latest?definitionId=686&branchName=main)
+[![Help Wanted](https://img.shields.io/github/issues/dotnet/runtime/up-for-grabs?style=flat-square&color=%232EA043&label=help%20wanted)](https://github.com/dotnet/runtime/issues?q=is%3Aissue+is%3Aopen+label%3A%22up-for-grabs%22)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/dotnet/runtime)
[![Discord](https://img.shields.io/discord/732297728826277939?style=flat-square&label=Discord&logo=discord&logoColor=white&color=7289DA)](https://aka.ms/dotnet-discord)
diff --git a/docs/coding-guidelines/project-guidelines.md b/docs/coding-guidelines/project-guidelines.md
index 556c9ac6d9ae..c0a79248d01c 100644
--- a/docs/coding-guidelines/project-guidelines.md
+++ b/docs/coding-guidelines/project-guidelines.md
@@ -142,6 +142,9 @@ All libraries should use `` for all their references
Other target frameworks than .NETCoreApp latest (i.e. `netstandard2.0`, `net461`, `netcoreapp3.0`) should use ProjectReference items to reference dependencies.
+### src\ILLink
+Contains the files used to direct the trimming tool. See [ILLink files](../workflow/trimming/ILLink-files.md).
+
### src output
All src outputs are under
diff --git a/docs/workflow/testing/libraries/testing-android.md b/docs/workflow/testing/libraries/testing-android.md
index 596d7851f1a8..08ad7316814b 100644
--- a/docs/workflow/testing/libraries/testing-android.md
+++ b/docs/workflow/testing/libraries/testing-android.md
@@ -45,6 +45,7 @@ curl https://dl.google.com/android/repository/commandlinetools-${HOST_OS_SHORT}-
mkdir ${ANDROID_SDK_ROOT} && unzip ~/asdk.zip -d ${ANDROID_SDK_ROOT}/cmdline-tools && rm -rf ~/asdk.zip
yes | ${ANDROID_SDK_ROOT}/cmdline-tools/tools/bin/sdkmanager --sdk_root=${ANDROID_SDK_ROOT} --licenses
${ANDROID_SDK_ROOT}/cmdline-tools/tools/bin/sdkmanager --sdk_root=${ANDROID_SDK_ROOT} "platform-tools" "platforms;android-${SDK_API_LEVEL}" "build-tools;${SDK_BUILD_TOOLS}"
+```
## Building Libs and Tests for Android
diff --git a/docs/workflow/trimming/ILLink-files.md b/docs/workflow/trimming/ILLink-files.md
new file mode 100644
index 000000000000..bbce56daa43a
--- /dev/null
+++ b/docs/workflow/trimming/ILLink-files.md
@@ -0,0 +1,45 @@
+# ILLink Files
+
+There are a few `ILLink.*.xml` files under `src` folders in `dotnet/runtime`. These files are used by the trimming tool for various reasons.
+
+See https://github.com/mono/linker/blob/main/docs/data-formats.md for full documentation on these files.
+
+## ILLink.Descriptors.xml
+
+Descriptors are used to direct the trimming tool to always keep some items in the assembly, regardless of if the trimming tool can find any references to them.
+
+We try to limit the usage of descriptor files as much as possible. Since using a descriptor means the code will always be preserved, even in the final application. Typically the main scenario they are used is when non-IL code (e.g. C/C++, JavaScript, etc.) is calling into IL code. The trimming tool isn't able to see the non-IL code, so it doesn't know which IL methods are necessary.
+
+In some cases it is only necessary to preserve items only during `dotnet/runtime`'s build, but we don't want to unconditionally preserve them in an the final application. Examples of these cases are non-public methods only used by tests, or non-public methods that are called through Reflection by another assembly. To only preserve items during `dotnet/runtime`'s build, use a `ILLink.Descriptors.LibraryBuild.xml` file.
+
+In almost all cases, when using a descriptors file, add a comment justifying why it is necessary.
+
+## ILLink.Substitutions.xml
+
+Substitutions direct the trimming tool to replace specific method's body with either a throw or return constant statements.
+
+These files are mainly used to implement [feature switches](feature-switches.md).
+
+They can also be used to hard-code constants depending on the platform we are building for, typically in `System.Private.CoreLib.dll` since, at this time, that is the only assembly we build specifically for each target architecture. In those cases, there are multiple `ILLink.Substitutions.{arch}.xml` files, which get included depending on the architecture. This is possible through an MSBuild Item `@(ILLinkSubstitutionsXmls)` which can conditionally get added to, and all the .xml files are combined into a final `ILLink.Substitutions.xml`, which is embedded into the assembly.
+
+## ILLink.Suppressions.xml
+
+When we build `dotnet/runtime`, we run the trimming tool to analyze our assemblies for code that is using patterns (like Reflection) that may be broken once the application is trimmed. When the trimming tool encounters code that isn't trim compatible, it issues a warning. Because we haven't addressed all these warnings in the code, we suppress the existing warnings in `ILLink.Suppressions.xml` files, and fail the build when an unsuppressed warning is encountered. This ensures that no new code can introduce new warnings while we are addressing the existing warnings.
+
+If your new feature or bug fix is introducing new ILLink warnings, the warnings need to be addressed before your PR can be merged. No new suppressions should be added to an `ILLink.Suppressions.xml` file. To address the warnings, see [Linking the .NET Libraries](https://github.com/dotnet/designs/blob/main/accepted/2020/linking-libraries.md). Typically, either adding `[DynamicallyAccessedMembers]` or `[RequiresUnreferencedCode]` attributes are acceptable ways of addressing the warnings. If the warning is a false-positive (meaning it is trim compatible, but the trimming tool wasn't able to tell), it can be suppressed in code using an `[UnconditionalSuppressMessage]`.
+
+ILLink warnings that are suppressed by the `ILLink.Suppressions.xml` file will still be emitted when the final application is published. This allows developers to see where their application might be broken when it is trimmed. Warnings that are suppressed by `[UnconditionalSuppressMessage]` attributes in `dotnet/runtime` code will never be emitted, during the `dotnet/runtime` build nor in the final application.
+
+Sometimes it is beneficial to leave an ILLink warning as unsuppressed so the final application's developer sees the warning. An examples of this is using the [`Startup Hooks`](../../design/features/host-startup-hook.md) feature in .NET. By default this feature is disabled when trimming a .NET application. However, the application can re-enable the feature. When they do, an ILLInk warning is emitted when the application is trimmed telling them the feature may not work after trimming.
+
+To suppress a warning only in the `dotnet/runtime` build, but keep emitting it in the final application, add the warning to a `ILLink.Suppressions.LibraryBuild.xml` file, and include a justification why this approach was taken.
+
+## ILLink.LinkAttributes.xml
+
+Attribute annotations direct the trimming tool to behave as if the specified item has the specified attribute.
+
+This is mainly used to tell the trimming tool which attributes to remove from the trimmed application. This is useful because some attributes are only needed at development time. They aren't necessary at runtime. Trimming unnecessary attributes can make the application smaller.
+
+Under the covers, the way this works is that the `ILLink.LinkAttributes.xml` tells the trimming tool to act like a `[RemoveAttributeInstances]` attribute is applied to the attribute type we want to remove. The trimming tool removes any instantiations of the attribute in all the assemblies of the application. However, if the trimming tool encounters code that is trying to read the attribute at runtime, it doesn't trim the attribute instances. For example, if runtime code is reading the `ObsoleteAttribute`, `ObsoleteAttribute` instances won't be trimmed even if it was asked to be removed through this file.
+
+This is also how the above `ILLink.Suppressions.xml` file works under the covers. It injects `[UnconditionalSuppressMessage]` attributes to tell the trimming tool to act as if there was a suppress attribute in code.
\ No newline at end of file
diff --git a/docs/workflow/trimming/feature-switches.md b/docs/workflow/trimming/feature-switches.md
index 40971d1fdb9d..36ac156f4f86 100644
--- a/docs/workflow/trimming/feature-switches.md
+++ b/docs/workflow/trimming/feature-switches.md
@@ -19,6 +19,7 @@ configurations but their defaults might vary as any SDK can set the defaults dif
| StartupHookSupport | System.StartupHookProvider.IsSupported | Startup hooks are disabled when set to false. Startup hook related functionality can be trimmed. |
| TBD | System.Threading.ThreadPool.EnableDispatchAutoreleasePool | When set to true, creates an NSAutoreleasePool around each thread pool work item on applicable platforms. |
| CustomResourceTypesSupport | System.Resources.ResourceManager.AllowCustomResourceTypes | Use of custom resource types is disabled when set to false. ResourceManager code paths that use reflection for custom types can be trimmed. |
+| EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization | System.ComponentModel.TypeConverter.EnableUnsafeBinaryFormatterInDesigntimeLicenseContextSerialization | BinaryFormatter serialization support is trimmed when set to false. |
Any feature-switch which defines property can be set in csproj file or
on the command line as any other MSBuild property. Those without predefined property name
diff --git a/eng/Subsets.props b/eng/Subsets.props
index 0afab2529a53..3d44846fa54c 100644
--- a/eng/Subsets.props
+++ b/eng/Subsets.props
@@ -226,7 +226,7 @@
$(CoreClrProjectRoot)crossgen-corelib.proj" Category="clr" />
-
+
@@ -316,7 +316,7 @@
-
+
@@ -342,10 +342,10 @@
-
+
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 3dc5e6869fbc..34bcbbe46e0e 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -1,74 +1,74 @@
-
+ https://github.com/dotnet/icu
- 370a34dfa95ba6f071aa315ee85749b21a263a96
+ 29647ace51f6bb8085326ff137525f7a6d89d726
-
+ https://github.com/dotnet/arcade
- 12a2bc501ce756c9522588d88583c0256297bd70
+ fd5f55c64d48b7894516cc841fba1253b2e79ffd
-
+ https://github.com/dotnet/arcade
- 12a2bc501ce756c9522588d88583c0256297bd70
+ fd5f55c64d48b7894516cc841fba1253b2e79ffd
-
+ https://github.com/dotnet/arcade
- 12a2bc501ce756c9522588d88583c0256297bd70
+ fd5f55c64d48b7894516cc841fba1253b2e79ffd
-
+ https://github.com/dotnet/arcade
- 12a2bc501ce756c9522588d88583c0256297bd70
+ fd5f55c64d48b7894516cc841fba1253b2e79ffd
-
+ https://github.com/dotnet/arcade
- 12a2bc501ce756c9522588d88583c0256297bd70
+ fd5f55c64d48b7894516cc841fba1253b2e79ffd
-
+ https://github.com/dotnet/arcade
- 12a2bc501ce756c9522588d88583c0256297bd70
+ fd5f55c64d48b7894516cc841fba1253b2e79ffd
-
+ https://github.com/dotnet/arcade
- 12a2bc501ce756c9522588d88583c0256297bd70
+ fd5f55c64d48b7894516cc841fba1253b2e79ffd
-
+ https://github.com/dotnet/arcade
- 12a2bc501ce756c9522588d88583c0256297bd70
+ fd5f55c64d48b7894516cc841fba1253b2e79ffd
-
+ https://github.com/dotnet/arcade
- 12a2bc501ce756c9522588d88583c0256297bd70
+ fd5f55c64d48b7894516cc841fba1253b2e79ffd
-
+ https://github.com/dotnet/arcade
- 12a2bc501ce756c9522588d88583c0256297bd70
+ fd5f55c64d48b7894516cc841fba1253b2e79ffd
-
+ https://github.com/dotnet/arcade
- 12a2bc501ce756c9522588d88583c0256297bd70
+ fd5f55c64d48b7894516cc841fba1253b2e79ffd
-
+ https://github.com/dotnet/arcade
- 12a2bc501ce756c9522588d88583c0256297bd70
+ fd5f55c64d48b7894516cc841fba1253b2e79ffd
-
+ https://github.com/dotnet/arcade
- 12a2bc501ce756c9522588d88583c0256297bd70
+ fd5f55c64d48b7894516cc841fba1253b2e79ffd
-
+ https://github.com/dotnet/arcade
- 12a2bc501ce756c9522588d88583c0256297bd70
+ fd5f55c64d48b7894516cc841fba1253b2e79ffd
-
+ https://github.com/dotnet/arcade
- 12a2bc501ce756c9522588d88583c0256297bd70
+ fd5f55c64d48b7894516cc841fba1253b2e79ffd
-
+ https://github.com/dotnet/arcade
- 12a2bc501ce756c9522588d88583c0256297bd70
+ fd5f55c64d48b7894516cc841fba1253b2e79ffdhttps://dev.azure.com/dnceng/internal/_git/dotnet-optimization
@@ -130,85 +130,85 @@
https://github.com/dotnet/runtime-assets055ed026132a7070e41629cfb5e410f0fcbdf948
-
+ https://github.com/dotnet/llvm-project
- 53c10319be026ec370f293b342ca490026db5358
+ a2bf9755287bdd3dcf998e41042e79dfd0136c85
-
+ https://github.com/dotnet/llvm-project
- 53c10319be026ec370f293b342ca490026db5358
+ a2bf9755287bdd3dcf998e41042e79dfd0136c85
-
+ https://github.com/dotnet/llvm-project
- 53c10319be026ec370f293b342ca490026db5358
+ a2bf9755287bdd3dcf998e41042e79dfd0136c85
-
+ https://github.com/dotnet/llvm-project
- 53c10319be026ec370f293b342ca490026db5358
+ a2bf9755287bdd3dcf998e41042e79dfd0136c85
-
+ https://github.com/dotnet/llvm-project
- 53c10319be026ec370f293b342ca490026db5358
+ a2bf9755287bdd3dcf998e41042e79dfd0136c85
-
+ https://github.com/dotnet/llvm-project
- 53c10319be026ec370f293b342ca490026db5358
+ a2bf9755287bdd3dcf998e41042e79dfd0136c85
-
+ https://github.com/dotnet/llvm-project
- 53c10319be026ec370f293b342ca490026db5358
+ a2bf9755287bdd3dcf998e41042e79dfd0136c85
-
+ https://github.com/dotnet/llvm-project
- 53c10319be026ec370f293b342ca490026db5358
+ a2bf9755287bdd3dcf998e41042e79dfd0136c85https://github.com/dotnet/runtime38017c3935de95d0335bac04f4901ddfc2718656
-
+ https://github.com/dotnet/runtime
- 76954b4ed7b5cd48ace16fefb1209fe56779b247
+ 102d1e856c7e0e553abeec937783da5debed73ad
-
+ https://github.com/dotnet/runtime
- 76954b4ed7b5cd48ace16fefb1209fe56779b247
+ 102d1e856c7e0e553abeec937783da5debed73ad
-
+ https://github.com/dotnet/runtime
- 76954b4ed7b5cd48ace16fefb1209fe56779b247
+ 102d1e856c7e0e553abeec937783da5debed73ad
-
+ https://github.com/dotnet/runtime
- 76954b4ed7b5cd48ace16fefb1209fe56779b247
+ 102d1e856c7e0e553abeec937783da5debed73ad
-
+ https://github.com/dotnet/runtime
- 76954b4ed7b5cd48ace16fefb1209fe56779b247
+ 102d1e856c7e0e553abeec937783da5debed73ad
-
+ https://github.com/dotnet/runtime
- 76954b4ed7b5cd48ace16fefb1209fe56779b247
+ 102d1e856c7e0e553abeec937783da5debed73ad
-
+ https://github.com/dotnet/runtime
- 76954b4ed7b5cd48ace16fefb1209fe56779b247
+ 102d1e856c7e0e553abeec937783da5debed73ad
-
+ https://github.com/mono/linker
- 2f5594e95e1a5227103b9b7d6b92f4b2250be2d7
+ dd7d70118b7146125781c830bbff47a8cb953f39
-
+ https://github.com/dotnet/xharness
- f4d7df9189d3b8ab04c6ba9a94dc8ccff255224e
+ 5c3ac06a6a3192222857d3a3683e838f91a9751d
-
+ https://github.com/dotnet/xharness
- f4d7df9189d3b8ab04c6ba9a94dc8ccff255224e
+ 5c3ac06a6a3192222857d3a3683e838f91a9751d
-
+ https://github.com/dotnet/arcade
- 12a2bc501ce756c9522588d88583c0256297bd70
+ fd5f55c64d48b7894516cc841fba1253b2e79ffd
diff --git a/eng/Versions.props b/eng/Versions.props
index 7aa4dbc1be43..b7a3f0baba3d 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -45,32 +45,32 @@
- 6.0.0-preview3.21158.1
+ 6.0.0-preview3.21168.13.9.0-5.final3.9.0-5.final
- 6.0.0-beta.21175.1
- 6.0.0-beta.21175.1
- 6.0.0-beta.21175.1
- 6.0.0-beta.21175.1
- 6.0.0-beta.21175.1
- 6.0.0-beta.21175.1
- 2.5.1-beta.21175.1
- 6.0.0-beta.21175.1
- 6.0.0-beta.21175.1
- 6.0.0-beta.21175.1
- 6.0.0-beta.21175.1
- 6.0.0-beta.21175.1
- 6.0.0-beta.21175.1
+ 6.0.0-beta.21179.7
+ 6.0.0-beta.21179.7
+ 6.0.0-beta.21179.7
+ 6.0.0-beta.21179.7
+ 6.0.0-beta.21179.7
+ 6.0.0-beta.21179.7
+ 2.5.1-beta.21179.7
+ 6.0.0-beta.21179.7
+ 6.0.0-beta.21179.7
+ 6.0.0-beta.21179.7
+ 6.0.0-beta.21179.7
+ 6.0.0-beta.21179.7
+ 6.0.0-beta.21179.75.9.0-preview.26.0.0-alpha.1.20612.4
- 6.0.0-preview.3.21169.6
- 6.0.0-preview.3.21169.6
+ 6.0.0-preview.4.21178.6
+ 6.0.0-preview.4.21178.63.1.0
- 6.0.0-preview.3.21169.6
+ 6.0.0-preview.4.21178.61.2.0-beta.3044.5.1
@@ -98,14 +98,14 @@
4.7.04.7.04.7.0
- 6.0.0-preview.3.21169.6
- 6.0.0-preview.3.21169.6
+ 6.0.0-preview.4.21178.6
+ 6.0.0-preview.4.21178.64.3.04.5.44.5.01.1.14.3.0
- 6.0.0-preview.3.21169.6
+ 6.0.0-preview.4.21178.66.0.0-beta.21174.26.0.0-beta.21174.2
@@ -148,8 +148,8 @@
1.0.1-prerelease-0000616.9.0-preview-20201201-01
- 1.0.0-prerelease.21175.2
- 1.0.0-prerelease.21175.2
+ 1.0.0-prerelease.21180.1
+ 1.0.0-prerelease.21180.12.4.12.4.21.3.0
@@ -159,18 +159,18 @@
5.0.0-preview-20201009.2
- 6.0.100-preview.2.21172.2
+ 6.0.100-preview.2.21180.4
- 6.0.0-preview.4.21172.5
+ 6.0.0-preview.4.21179.1
- 9.0.1-alpha.1.21172.2
- 9.0.1-alpha.1.21172.2
- 9.0.1-alpha.1.21172.2
- 9.0.1-alpha.1.21172.2
- 9.0.1-alpha.1.21172.2
- 9.0.1-alpha.1.21172.2
- 9.0.1-alpha.1.21172.2
- 9.0.1-alpha.1.21172.2
+ 9.0.1-alpha.1.21179.2
+ 9.0.1-alpha.1.21179.2
+ 9.0.1-alpha.1.21179.2
+ 9.0.1-alpha.1.21179.2
+ 9.0.1-alpha.1.21179.2
+ 9.0.1-alpha.1.21179.2
+ 9.0.1-alpha.1.21179.2
+ 9.0.1-alpha.1.21179.2
diff --git a/eng/common/generate-locproject.ps1 b/eng/common/generate-locproject.ps1
index ad3e80651fe3..7225ddc66690 100644
--- a/eng/common/generate-locproject.ps1
+++ b/eng/common/generate-locproject.ps1
@@ -38,7 +38,7 @@ if ($allXlfFiles) {
$langXlfFiles = Get-ChildItem -Recurse -Path "$SourcesDirectory\*\*.$firstLangCode.xlf"
}
$langXlfFiles | ForEach-Object {
- $null = $_.Name -Match "([^.]+)\.[\w-]+\.xlf" # matches '[filename].[langcode].xlf'
+ $null = $_.Name -Match "(.+)\.[\w-]+\.xlf" # matches '[filename].[langcode].xlf
$destinationFile = "$($_.Directory.FullName)\$($Matches.1).xlf"
$xlfFiles += Copy-Item "$($_.FullName)" -Destination $destinationFile -PassThru
@@ -52,7 +52,7 @@ $locJson = @{
LanguageSet = $LanguageSet
LocItems = @(
$locFiles | ForEach-Object {
- $outputPath = "Localize\$(($_.DirectoryName | Resolve-Path -Relative) + "\")"
+ $outputPath = "$(($_.DirectoryName | Resolve-Path -Relative) + "\")"
$continue = $true
foreach ($exclusion in $exclusions.Exclusions) {
if ($outputPath.Contains($exclusion))
diff --git a/eng/common/performance/android_scenarios.proj b/eng/common/performance/android_scenarios.proj
new file mode 100644
index 000000000000..d0850eab1bc0
--- /dev/null
+++ b/eng/common/performance/android_scenarios.proj
@@ -0,0 +1,34 @@
+
+
+ python3
+ $(HelixPreCommands);chmod +x $HELIX_WORKITEM_PAYLOAD/SOD/SizeOnDisk
+
+
+
+
+ %(Identity)
+
+
+
+
+ %HELIX_CORRELATION_PAYLOAD%\performance\src\scenarios\
+
+
+ $HELIX_CORRELATION_PAYLOAD/performance/src/scenarios/
+
+
+
+
+ $(ScenarioDirectory)helloandroid
+ copy $HELIX_CORRELATION_PAYLOAD%\HelloAndroid.apk .;$(Python) pre.py
+ $(Python) test.py sod --scenario-name "%(Identity)"
+ $(Python) post.py
+
+
+ $(ScenarioDirectory)helloandroid
+ copy $HELIX_CORRELATION_PAYLOAD%\HelloAndroid.apk .;$(Python) pre.py --unzip
+ $(Python) test.py sod --scenario-name "%(Identity)"
+ $(Python) post.py
+
+
+
\ No newline at end of file
diff --git a/eng/common/performance/performance-setup.ps1 b/eng/common/performance/performance-setup.ps1
index b6324039ad37..174ceeb1b9d7 100644
--- a/eng/common/performance/performance-setup.ps1
+++ b/eng/common/performance/performance-setup.ps1
@@ -19,7 +19,8 @@ Param(
[switch] $Compare,
[string] $MonoDotnet="",
[string] $Configurations="CompilationMode=$CompilationMode RunKind=$Kind",
- [string] $LogicalMachine=""
+ [string] $LogicalMachine="",
+ [switch] $AndroidMono
)
$RunFromPerformanceRepo = ($Repository -eq "dotnet/performance") -or ($Repository -eq "dotnet-performance")
@@ -102,6 +103,15 @@ if ($UseBaselineCoreRun) {
Move-Item -Path $BaselineCoreRootDirectory -Destination $NewBaselineCoreRoot
}
+if ($AndroidMono) {
+ if(!(Test-Path $WorkItemDirectory))
+ {
+ mkdir $WorkItemDirectory
+ }
+ Copy-Item -path "$SourceDirectory\artifacts\bin\AndroidSampleApp\arm64\Release\android-arm64\publish\apk\bin\HelloAndroid.apk" $PayloadDirectory
+ $SetupArguments = $SetupArguments -replace $Architecture, 'arm64'
+}
+
$DocsDir = (Join-Path $PerformanceDirectory "docs")
robocopy $DocsDir $WorkItemDirectory
diff --git a/eng/common/templates/job/onelocbuild.yml b/eng/common/templates/job/onelocbuild.yml
index 6abc041cd1c8..928a70cda2c5 100644
--- a/eng/common/templates/job/onelocbuild.yml
+++ b/eng/common/templates/job/onelocbuild.yml
@@ -46,16 +46,19 @@ jobs:
- task: OneLocBuild@2
displayName: OneLocBuild
+ env:
+ SYSTEM_ACCESSTOKEN: $(System.AccessToken)
inputs:
locProj: Localize/LocProject.json
outDir: $(Build.ArtifactStagingDirectory)
lclSource: ${{ parameters.LclSource }}
lclPackageId: ${{ parameters.LclPackageId }}
isCreatePrSelected: ${{ parameters.CreatePr }}
- repoType: ${{ parameters.RepoType }}
- gitHubPatVariable: "${{ parameters.GithubPat }}"
packageSourceAuth: patAuth
patVariable: ${{ parameters.CeapexPat }}
+ ${{ if eq(parameters.RepoType, 'gitHub') }}:
+ repoType: ${{ parameters.RepoType }}
+ gitHubPatVariable: "${{ parameters.GithubPat }}"
condition: always()
- task: PublishBuildArtifacts@1
diff --git a/eng/pipelines/coreclr/perf.yml b/eng/pipelines/coreclr/perf.yml
index 511db7798004..ce756c81303a 100644
--- a/eng/pipelines/coreclr/perf.yml
+++ b/eng/pipelines/coreclr/perf.yml
@@ -152,6 +152,29 @@ jobs:
archiveType: tar
tarCompression: gz
+ # build mono Android scenarios
+ - template: /eng/pipelines/common/platform-matrix.yml
+ parameters:
+ jobTemplate: /eng/pipelines/common/global-build-job.yml
+ buildConfig: release
+ runtimeFlavor: mono
+ platforms:
+ - Android_arm64
+ jobParameters:
+ buildArgs: -s mono+libs+host+packs -c $(_BuildConfig)
+ nameSuffix: AndroidMono
+ isOfficialBuild: false
+ extraStepsTemplate: /eng/pipelines/coreclr/templates/build-perf-sample-apps.yml
+ extraStepsParameters:
+ rootFolder: '$(Build.SourcesDirectory)/artifacts/'
+ includeRootFolder: true
+ displayName: Android Mono Artifacts
+ artifactName: AndroidMonoarm64
+ archiveExtension: '.tar.gz'
+ archiveType: tar
+ tarCompression: gz
+
+
# build mono
- template: /eng/pipelines/common/platform-matrix.yml
parameters:
@@ -161,6 +184,22 @@ jobs:
platforms:
- Linux_x64
+ # run mono android scenarios
+ - template: /eng/pipelines/common/platform-matrix.yml
+ parameters:
+ jobTemplate: /eng/pipelines/coreclr/templates/perf-job.yml
+ buildConfig: release
+ runtimeFlavor: mono
+ platforms:
+ - Windows_x64
+ jobParameters:
+ testGroup: perf
+ runtimeType: AndroidMono
+ projectFile: android_scenarios.proj
+ runKind: android_scenarios
+ runJobTemplate: /eng/pipelines/coreclr/templates/run-scenarios-job.yml
+ logicalmachine: 'perftiger'
+
# run mono microbenchmarks perf job
- template: /eng/pipelines/common/platform-matrix.yml
parameters:
diff --git a/eng/pipelines/coreclr/templates/build-perf-sample-apps.yml b/eng/pipelines/coreclr/templates/build-perf-sample-apps.yml
new file mode 100644
index 000000000000..2b556af6d911
--- /dev/null
+++ b/eng/pipelines/coreclr/templates/build-perf-sample-apps.yml
@@ -0,0 +1,45 @@
+parameters:
+ osGroup: ''
+ osSubgroup: ''
+ archType: ''
+ buildConfig: ''
+ runtimeFlavor: ''
+ helixQueues: ''
+ targetRid: ''
+ nameSuffix: ''
+ platform: ''
+ shouldContinueOnError: ''
+ rootFolder: ''
+ includeRootFolder: ''
+ displayName: ''
+ artifactName: ''
+ archiveExtension: ''
+ archiveType: ''
+ tarCompression: ''
+
+steps:
+# Build Android sample app
+ - ${{ if eq(parameters.osGroup, 'Android') }}:
+ - script: make run MONO_ARCH=arm64 DEPLOY_AND_RUN=false
+ workingDirectory: $(Build.SourcesDirectory)/src/mono/sample/Android
+ displayName: Build HelloAndroid sample app
+
+ - template: /eng/pipelines/common/upload-artifact-step.yml
+ parameters:
+ osGroup: ${{ parameters.osGroup }}
+ osSubgroup: ${{ parameters.osSubgroup }}
+ archType: ${{ parameters.archType }}
+ buildConfig: ${{ parameters.buildConfig }}
+ runtimeFlavor: ${{ parameters.runtimeFlavor }}
+ helixQueues: ${{ parameters.helixQueues }}
+ targetRid: ${{ parameters.targetRid }}
+ nameSuffix: ${{ parameters.nameSuffix }}
+ platform: ${{ parameters.platform }}
+ shouldContinueOnError: ${{ parameters.shouldContinueOnError }}
+ rootFolder: ${{ parameters.rootFolder }}
+ includeRootFolder: ${{ parameters.includeRootFolder }}
+ displayName: ${{ parameters.displayName }}
+ artifactName: ${{ parameters.artifactName }}
+ archiveExtension: ${{ parameters.archiveExtension }}
+ archiveType: ${{ parameters.archiveType }}
+ tarCompression: ${{ parameters.tarCompression }}
\ No newline at end of file
diff --git a/eng/pipelines/coreclr/templates/perf-job.yml b/eng/pipelines/coreclr/templates/perf-job.yml
index 703e7a4645c6..d208f362fac0 100644
--- a/eng/pipelines/coreclr/templates/perf-job.yml
+++ b/eng/pipelines/coreclr/templates/perf-job.yml
@@ -11,7 +11,7 @@ parameters:
runtimeType: 'coreclr'
pool: ''
codeGenType: 'JIT'
- projetFile: ''
+ projectFile: ''
runKind: ''
runJobTemplate: '/eng/pipelines/coreclr/templates/run-performance-job.yml'
additionalSetupParameters: ''
@@ -44,7 +44,8 @@ jobs:
logicalmachine: ${{ parameters.logicalmachine }}
# Test job depends on the corresponding build job
dependsOn:
- - ${{ format('coreclr_{0}_product_build_{1}{2}_{3}_{4}', parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
+ - ${{ if ne(parameters.runtimeType, 'AndroidMono')}}:
+ - ${{ format('coreclr_{0}_product_build_{1}{2}_{3}_{4}', parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
- ${{ if ne(parameters.liveLibrariesBuildConfig, '') }}:
- ${{ format('libraries_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.liveLibrariesBuildConfig) }}
- ${{ if and(eq(parameters.runtimeType, 'mono'), ne(parameters.codeGenType, 'AOT')) }}:
@@ -53,13 +54,15 @@ jobs:
- ${{ format('build_{0}{1}_{2}_{3}_{4}', 'Browser', '', 'wasm', parameters.buildConfig, parameters.runtimeType) }}
- ${{ if eq(parameters.codeGenType, 'AOT')}}:
- ${{ format('build_{0}{1}_{2}_{3}_{4}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig, parameters.codeGenType) }}
+ - ${{ if eq(parameters.runtimeType, 'AndroidMono')}}:
+ - ${{ 'build_Android_arm64_release_AndroidMono' }}
- ${{ if eq(parameters.osGroup, 'windows') }}:
+ ${{ if and(eq(parameters.osGroup, 'windows'), ne(parameters.runtimeType, 'AndroidMono')) }}:
${{ if eq(parameters.runtimeType, 'mono') }}:
extraSetupParameters: -Architecture ${{ parameters.archType }} -MonoDotnet $(Build.SourcesDirectory)\.dotnet-mono
${{ if eq(parameters.runtimeType, 'coreclr') }}:
extraSetupParameters: -CoreRootDirectory $(Build.SourcesDirectory)\artifacts\tests\coreclr\${{ parameters.osGroup }}.${{ parameters.archType }}.Release\Tests\Core_Root -Architecture ${{ parameters.archType }}
- ${{ if ne(parameters.osGroup, 'windows') }}:
+ ${{ if and(ne(parameters.osGroup, 'windows'), ne(parameters.runtimeType, 'AndroidMono')) }}:
${{ if and(eq(parameters.runtimeType, 'mono'), ne(parameters.codeGenType, 'AOT')) }}:
extraSetupParameters: --architecture ${{ parameters.archType }} --monodotnet $(Build.SourcesDirectory)/.dotnet-mono
${{ if eq(parameters.runtimeType, 'wasm') }}:
@@ -70,7 +73,9 @@ jobs:
extraSetupParameters: --corerootdirectory $(Build.SourcesDirectory)/artifacts/tests/coreclr/${{ parameters.osGroup }}.${{ parameters.archType }}.Release/Tests/Core_Root --architecture ${{ parameters.archType }}
${{ if and(eq(parameters.runtimeType, 'coreclr'), eq(parameters.osSubGroup, '_musl')) }}:
extraSetupParameters: --corerootdirectory $(Build.SourcesDirectory)/artifacts/tests/coreclr/${{ parameters.osGroup }}.${{ parameters.archType }}.Release/Tests/Core_Root --architecture ${{ parameters.archType }} --alpine
-
+ ${{ if eq(parameters.runtimeType, 'AndroidMono') }}:
+ extraSetupParameters: -Architecture ${{ parameters.archType }} -AndroidMono
+
variables: ${{ parameters.variables }}
frameworks:
@@ -89,12 +94,13 @@ jobs:
displayName: 'live-built libraries'
# Download coreclr
- - template: /eng/pipelines/common/download-artifact-step.yml
- parameters:
- unpackFolder: $(buildProductRootFolderPath)
- artifactFileName: '$(buildProductArtifactName)$(archiveExtension)'
- artifactName: '$(buildProductArtifactName)'
- displayName: 'Coreclr product build'
+ - ${{ if ne(parameters.runtimeType, 'AndroidMono') }}:
+ - template: /eng/pipelines/common/download-artifact-step.yml
+ parameters:
+ unpackFolder: $(buildProductRootFolderPath)
+ artifactFileName: '$(buildProductArtifactName)$(archiveExtension)'
+ artifactName: '$(buildProductArtifactName)'
+ displayName: 'Coreclr product build'
# Download mono
- ${{ if and(eq(parameters.runtimeType, 'mono'), ne(parameters.codeGenType, 'AOT')) }}:
@@ -130,6 +136,17 @@ jobs:
- script: "mkdir -p $(librariesDownloadDir)/bin/aot/sgen;mkdir -p $(librariesDownloadDir)/bin/aot/pack;cp -r $(librariesDownloadDir)/LinuxMonoAOT/artifacts/obj/mono/Linux.${{ parameters.archType }}.Release/mono/* $(librariesDownloadDir)/bin/aot/sgen;cp -r $(librariesDownloadDir)/LinuxMonoAOT/artifacts/bin/microsoft.netcore.app.runtime.linux-${{ parameters.archType }}/Release/* $(librariesDownloadDir)/bin/aot/pack"
displayName: "Create aot directory (Linux)"
+ # Download AndroidMono
+ - ${{ if eq(parameters.runtimeType, 'AndroidMono')}}:
+ - template: /eng/pipelines/common/download-artifact-step.yml
+ parameters:
+ unpackFolder: $(Build.SourcesDirectory)
+ cleanUnpackFolder: false
+ artifactFileName: 'AndroidMonoarm64.tar.gz'
+ artifactName: 'AndroidMonoarm64'
+ displayName: 'Mono Android runtime'
+
+
# Create Core_Root
- script: $(Build.SourcesDirectory)/src/tests/build$(scriptExt) $(buildConfig) $(archType) generatelayoutonly $(librariesOverrideArg)
displayName: Create Core_Root
@@ -138,8 +155,8 @@ jobs:
# Copy the runtime directory into the testhost folder to include OOBs.
- script: "build.cmd -subset libs.pretest -configuration release -ci -arch $(archType) -testscope innerloop /p:RuntimeArtifactsPath=$(librariesDownloadDir)\\bin\\mono\\$(osGroup).$(archType).$(buildConfigUpper) /p:RuntimeFlavor=mono;xcopy $(Build.SourcesDirectory)\\artifacts\\bin\\runtime\\$(_Framework)-$(osGroup)-$(buildConfigUpper)-$(archType)\\* $(Build.SourcesDirectory)\\artifacts\\bin\\testhost\\$(_Framework)-$(osGroup)-$(buildConfigUpper)-$(archType)\\shared\\Microsoft.NETCore.App\\6.0.0 /E /I /Y;xcopy $(Build.SourcesDirectory)\\artifacts\\bin\\testhost\\$(_Framework)-$(osGroup)-$(buildConfigUpper)-$(archType)\\* $(Build.SourcesDirectory)\\.dotnet-mono /E /I /Y;copy $(Build.SourcesDirectory)\\artifacts\\bin\\coreclr\\$(osGroup).$(archType).$(buildConfigUpper)\\corerun.exe $(Build.SourcesDirectory)\\.dotnet-mono\\shared\\Microsoft.NETCore.App\\6.0.0\\corerun.exe"
displayName: "Create mono dotnet (Windows)"
- condition: and(and(succeeded(), eq(variables.runtimeFlavorName, 'Mono')), eq(variables.osGroup, 'windows'))
+ condition: and(and(succeeded(), eq(variables.runtimeFlavorName, 'Mono')), eq(variables.osGroup, 'windows'), ne('${{ parameters.runtimeType }}', 'AndroidMono'))
- script: "mkdir $(Build.SourcesDirectory)/.dotnet-mono;./build.sh -subset libs.pretest -configuration release -ci -arch $(archType) -testscope innerloop /p:RuntimeArtifactsPath=$(librariesDownloadDir)/bin/mono/$(osGroup).$(archType).$(buildConfigUpper) /p:RuntimeFlavor=mono;cp $(Build.SourcesDirectory)/artifacts/bin/runtime/$(_Framework)-$(osGroup)-$(buildConfigUpper)-$(archType)/* $(Build.SourcesDirectory)/artifacts/bin/testhost/$(_Framework)-$(osGroup)-$(buildConfigUpper)-$(archType)/shared/Microsoft.NETCore.App/6.0.0 -rf;cp $(Build.SourcesDirectory)/artifacts/bin/testhost/$(_Framework)-$(osGroup)-$(buildConfigUpper)-$(archType)/* $(Build.SourcesDirectory)/.dotnet-mono -r;cp $(Build.SourcesDirectory)/artifacts/bin/coreclr/$(osGroup).$(archType).$(buildConfigUpper)/corerun $(Build.SourcesDirectory)/.dotnet-mono/shared/Microsoft.NETCore.App/6.0.0/corerun"
displayName: "Create mono dotnet (Linux)"
- condition: and(and(succeeded(), eq(variables.runtimeFlavorName, 'Mono')), ne(variables.osGroup, 'windows'))
+ condition: and(and(succeeded(), eq(variables.runtimeFlavorName, 'Mono')), ne(variables.osGroup, 'windows'), ne('${{ parameters.runtimeType }}', 'AndroidMono'))
diff --git a/eng/pipelines/libraries/helix-queues-setup.yml b/eng/pipelines/libraries/helix-queues-setup.yml
index 8b0f58894cd4..90bf48d7cae1 100644
--- a/eng/pipelines/libraries/helix-queues-setup.yml
+++ b/eng/pipelines/libraries/helix-queues-setup.yml
@@ -52,7 +52,7 @@ jobs:
# Linux x64
- ${{ if eq(parameters.platform, 'Linux_x64') }}:
- - ${{ if eq(parameters.jobParameters.interpreter, '') }}:
+ - ${{ if and(eq(parameters.jobParameters.interpreter, ''), ne(parameters.jobParameters.isSingleFile, true)) }}:
- ${{ if and(eq(parameters.jobParameters.testScope, 'outerloop'), eq(parameters.jobParameters.runtimeFlavor, 'mono')) }}:
- (Centos.8.Amd64.Open)Ubuntu.1604.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:centos-8-helix-20201229003624-c1bf759
- RedHat.7.Amd64.Open
@@ -81,7 +81,7 @@ jobs:
- Ubuntu.1804.Amd64.Open
- SLES.15.Amd64.Open
- (Fedora.30.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-30-helix-20200512010621-4f8cef7
- - ${{ if eq(parameters.jobParameters.interpreter, 'true') }}:
+ - ${{ if or(eq(parameters.jobParameters.interpreter, 'true'), eq(parameters.jobParameters.isSingleFile, true)) }}:
# Limiting interp runs as we don't need as much coverage.
- Debian.9.Amd64.Open
@@ -135,7 +135,7 @@ jobs:
# .NETFramework
- ${{ if eq(parameters.jobParameters.framework, 'net48') }}:
- Windows.10.Amd64.Client19H1.Open
-
+
# AllConfigurations
- ${{ if eq(parameters.jobParameters.framework, 'allConfigurations') }}:
- Windows.10.Amd64.Server19H1.Open
diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml
index 4819accff31f..476150aad686 100644
--- a/eng/pipelines/runtime.yml
+++ b/eng/pipelines/runtime.yml
@@ -293,6 +293,7 @@ jobs:
creator: dotnet-bot
testRunNamePrefixSuffix: Mono_$(_BuildConfig)
scenarios:
+ - buildwasmapps
- normal
- wasmtestonbrowser
condition: >-
@@ -301,6 +302,28 @@ jobs:
eq(variables['monoContainsChange'], true),
eq(variables['isFullMatrix'], true))
+# Build and test libraries under single-file publishing
+- template: /eng/pipelines/common/platform-matrix.yml
+ parameters:
+ jobTemplate: /eng/pipelines/common/global-build-job.yml
+ helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml
+ buildConfig: Release
+ platforms:
+ - windows_x64
+ - Linux_x64
+ jobParameters:
+ testGroup: innerloop
+ isFullMatrix: ${{ variables.isFullMatrix }}
+ isSingleFile: true
+ nameSuffix: SingleFile
+ buildArgs: -s clr+libs+libs.tests -c $(_BuildConfig) /p:TestSingleFile=true /p:ArchiveTests=true
+ timeoutInMinutes: 120
+ # extra steps, run tests
+ extraStepsTemplate: /eng/pipelines/libraries/helix.yml
+ extraStepsParameters:
+ creator: dotnet-bot
+ testRunNamePrefixSuffix: SingleFile_$(_BuildConfig)
+
#
# Build the whole product using Mono and run runtime tests
#
diff --git a/eng/targetframeworksuffix.props b/eng/targetframeworksuffix.props
index 5926e5266de0..00d2acfd4607 100644
--- a/eng/targetframeworksuffix.props
+++ b/eng/targetframeworksuffix.props
@@ -9,6 +9,8 @@
$(TargetFrameworkSuffix)1.0$(TargetFrameworkSuffix),Version=$(TargetPlatformVersion)
+
+ 0.0
diff --git a/eng/testing/AndroidRunnerTemplate.sh b/eng/testing/AndroidRunnerTemplate.sh
index 26698577798c..3dab96f0bf3c 100644
--- a/eng/testing/AndroidRunnerTemplate.sh
+++ b/eng/testing/AndroidRunnerTemplate.sh
@@ -10,7 +10,7 @@ TEST_NAME=$4
XHARNESS_OUT="$EXECUTION_DIR/xharness-output"
if [ -n "$5" ]; then
- EXPECTED_EXIT_CODE="--expected-exit-code $5"
+ ADDITIONAL_ARGS=${@:5}
fi
cd $EXECUTION_DIR
@@ -41,7 +41,7 @@ $HARNESS_RUNNER android test \
--app="$EXECUTION_DIR/bin/$TEST_NAME.apk" \
--output-directory="$XHARNESS_OUT" \
--timeout=1800 \
- $EXPECTED_EXIT_CODE
+ $ADDITIONAL_ARGS
_exitCode=$?
diff --git a/eng/testing/AppleRunnerTemplate.sh b/eng/testing/AppleRunnerTemplate.sh
index 5ec52b36c7ee..0f2eb7f2abed 100644
--- a/eng/testing/AppleRunnerTemplate.sh
+++ b/eng/testing/AppleRunnerTemplate.sh
@@ -13,7 +13,7 @@ XCODE_PATH=$(xcode-select -p)/../..
if [ -n "$5" ]; then
XHARNESS_CMD="run"
- EXPECTED_EXIT_CODE="--expected-exit-code $5"
+ ADDITIONAL_ARGS=${@:5}
fi
if [[ "$TARGET_OS" == "MacCatalyst" ]]; then TARGET=maccatalyst; fi
@@ -62,7 +62,7 @@ $HARNESS_RUNNER apple $XHARNESS_CMD \
--targets="$TARGET" \
--xcode="$XCODE_PATH" \
--output-directory="$XHARNESS_OUT" \
- $EXPECTED_EXIT_CODE
+ $ADDITIONAL_ARGS
_exitCode=$?
diff --git a/eng/testing/linker/project.csproj.template b/eng/testing/linker/project.csproj.template
index 7ac21cbcb5b5..53576a8cc216 100644
--- a/eng/testing/linker/project.csproj.template
+++ b/eng/testing/linker/project.csproj.template
@@ -29,6 +29,7 @@
{AdditionalProjectReferences}
+ {TrimmerRootAssemblies}
+ $(AdditionalXHarnessArguments) --arg=-m=$(XUnitMethodName)
+ $(AdditionalXHarnessArguments) --arg=-c=$(XUnitClassName)
+
+
diff --git a/eng/testing/tests.singlefile.targets b/eng/testing/tests.singlefile.targets
new file mode 100644
index 000000000000..86cbc7ee5109
--- /dev/null
+++ b/eng/testing/tests.singlefile.targets
@@ -0,0 +1,62 @@
+
+
+ Exe
+
+ $([MSBuild]::NormalizeDirectory('$(OutDir)', 'publish'))
+ $([MSBuild]::NormalizePath('$(BundleDir)', '$(RunScriptOutputName)'))
+ $(PackageRID)
+
+ $(AssemblyName).exe
+ chmod +rwx $(AssemblyName) && ./$(AssemblyName)
+
+
+
+ true
+ true
+ true
+ $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'coreclr', '$(TargetOS).$(TargetArchitecture).$(Configuration)', 'corehost'))/singlefilehost
+ $(SingleFileHostSourcePath).exe
+
+
+
+
+
+
+
+
+
+
+
+
+ <__Identity>%(ResolvedFileToPublish.Identity)
+ <__FileName>%(ResolvedFileToPublish.Filename)%(ResolvedFileToPublish.Extension)
+
+
+
+ <__NewResolvedFiles Include="@(ResolvedFileToPublish)">
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/eng/testing/tests.targets b/eng/testing/tests.targets
index 1ad1ae7df0df..9fc08ddd6bcc 100644
--- a/eng/testing/tests.targets
+++ b/eng/testing/tests.targets
@@ -25,7 +25,7 @@
-
+
@@ -37,7 +37,7 @@
<_ZipSourceDirectory>$(OutDir)
- <_ZipSourceDirectory Condition="'$(TargetOS)' == 'Browser'">$(BundleDir)
+ <_ZipSourceDirectory Condition="'$(TargetOS)' == 'Browser' or '$(TestSingleFile)' == 'true'">$(BundleDir)
@@ -96,7 +96,7 @@
$(RunTestsCommand) --runtime-path "$(TestHostRootPath.TrimEnd('\/'))"$(RunTestsCommand) --rsp-file "$(TestRspFile)"
- "$(RunScriptOutputPath)" $(AssemblyName) $(TargetArchitecture) $(TargetOS) $(TestProjectName) $(ExpectedExitCode)
+ "$(RunScriptOutputPath)" $(AssemblyName) $(TargetArchitecture) $(TargetOS) $(TestProjectName) $(AdditionalXHarnessArguments)"$(RunScriptOutputPath)" $(JSEngine) $(AssemblyName).dll $(Scenario)
@@ -118,10 +118,11 @@
+
-
+
diff --git a/eng/testing/xunit/xunit.console.targets b/eng/testing/xunit/xunit.console.targets
index a88b08f61398..7710a05b5a37 100644
--- a/eng/testing/xunit/xunit.console.targets
+++ b/eng/testing/xunit/xunit.console.targets
@@ -5,7 +5,7 @@
true
-
+
<_depsFileArgument Condition="'$(GenerateDependencyFile)' == 'true'">--depsfile $(AssemblyName).deps.json
"$(RunScriptHost)" exec --runtimeconfig $(AssemblyName).runtimeconfig.json $(_depsFileArgument) xunit.console.dllxunit.console.exe
@@ -36,7 +36,7 @@
$(_withoutCategories.Replace(';', '%0dcategory='))
-
+
diff --git a/eng/testing/xunit/xunit.props b/eng/testing/xunit/xunit.props
index f63b3906fccb..3f9c4b67141a 100644
--- a/eng/testing/xunit/xunit.props
+++ b/eng/testing/xunit/xunit.props
@@ -13,7 +13,7 @@
-
+
diff --git a/eng/versioning.targets b/eng/versioning.targets
index a55fe2407ece..cf0f497a1096 100644
--- a/eng/versioning.targets
+++ b/eng/versioning.targets
@@ -47,17 +47,27 @@
-
-
-
-
+
+
+
+
+
+
+
<_unsupportedOSPlatforms Include="$(UnsupportedOSPlatforms)" />
-
+
+
<_Parameter1>%(_unsupportedOSPlatforms.Identity)
diff --git a/global.json b/global.json
index d085b22585ab..28dd3bb990da 100644
--- a/global.json
+++ b/global.json
@@ -12,12 +12,12 @@
"python3": "3.7.1"
},
"msbuild-sdks": {
- "Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk": "6.0.0-beta.21175.1",
- "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21175.1",
- "Microsoft.DotNet.Helix.Sdk": "6.0.0-beta.21175.1",
- "Microsoft.DotNet.SharedFramework.Sdk": "6.0.0-beta.21175.1",
+ "Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk": "6.0.0-beta.21179.7",
+ "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21179.7",
+ "Microsoft.DotNet.Helix.Sdk": "6.0.0-beta.21179.7",
+ "Microsoft.DotNet.SharedFramework.Sdk": "6.0.0-beta.21179.7",
"Microsoft.Build.NoTargets": "2.0.17",
"Microsoft.Build.Traversal": "2.1.1",
- "Microsoft.NET.Sdk.IL": "6.0.0-preview.3.21169.6"
+ "Microsoft.NET.Sdk.IL": "6.0.0-preview.4.21178.6"
}
}
diff --git a/src/coreclr/EmptyProps.props b/src/coreclr/EmptyProps.props
index f26de36e4f97..c062d8bc5662 100644
--- a/src/coreclr/EmptyProps.props
+++ b/src/coreclr/EmptyProps.props
@@ -5,13 +5,4 @@
in the root of the source tree. In particular this was necessary to compile DacTableGen, which is currently compiled
against .NET Framework.
-->
-
-
-
-
-
-
-
-
-
diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
index c09f3ae1ad95..61458bee3e9f 100644
--- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -50,7 +50,7 @@
enable
- CORECLR;NETCOREAPP;SYSTEM_PRIVATE_CORELIB;FEATURE_POOLASYNCVALUETASKS
+ CORECLR;NETCOREAPP;SYSTEM_PRIVATE_CORELIBtruetrue
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Exception.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Exception.CoreCLR.cs
index d6bb435387b0..ebd4660a4bc3 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Exception.CoreCLR.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Exception.CoreCLR.cs
@@ -7,7 +7,6 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
-using System.Text;
namespace System
{
@@ -15,8 +14,6 @@ public partial class Exception : ISerializable
{
partial void RestoreRemoteStackTrace(SerializationInfo info, StreamingContext context)
{
- _remoteStackTraceString = info.GetString("RemoteStackTraceString"); // Do not rename (binary serialization)
-
// Get the WatsonBuckets that were serialized - this is particularly
// done to support exceptions going across AD transitions.
//
@@ -246,8 +243,6 @@ internal void RestoreDispatchState(in DispatchState dispatchState)
// See src\inc\corexcep.h's EXCEPTION_COMPLUS definition:
private const int _COMPlusExceptionCode = unchecked((int)0xe0434352); // Win32 exception code for COM+ exceptions
- private string? SerializationRemoteStackTraceString => _remoteStackTraceString;
-
private object? SerializationWatsonBuckets => _watsonBuckets;
private string? SerializationStackTraceString
@@ -323,14 +318,16 @@ internal DispatchState CaptureDispatchState()
_remoteStackTraceString, _ipForWatsonBuckets, _watsonBuckets);
}
- [StackTraceHidden]
- internal void SetCurrentStackTrace()
+ // Returns true if setting the _remoteStackTraceString field is legal, false if not (immutable exception).
+ // A false return value means the caller should early-exit the operation.
+ // Can also throw InvalidOperationException if a stack trace is already set or if object has been thrown.
+ private bool CanSetRemoteStackTrace()
{
// If this is a preallocated singleton exception, silently skip the operation,
// regardless of the value of throwIfHasExistingStack.
if (IsImmutableAgileException(this))
{
- return;
+ return false;
}
// Check to see if the exception already has a stack set in it.
@@ -339,13 +336,7 @@ internal void SetCurrentStackTrace()
ThrowHelper.ThrowInvalidOperationException();
}
- // Store the current stack trace into the "remote" stack trace, which was originally introduced to support
- // remoting of exceptions cross app-domain boundaries, and is thus concatenated into Exception.StackTrace
- // when it's retrieved.
- var sb = new StringBuilder(256);
- new StackTrace(fNeedFileInfo: true).ToString(System.Diagnostics.StackTrace.TraceFormat.TrailingNewLine, sb);
- sb.AppendLine(SR.Exception_EndStackTraceFromPreviousThrow);
- _remoteStackTraceString = sb.ToString();
+ return true;
}
}
}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs
index 60fe3a180d24..6e99db321a05 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs
@@ -209,8 +209,13 @@ internal static bool HasElementType(RuntimeType type)
return outHandles;
}
- internal static object CreateInstanceForAnotherGenericParameter(RuntimeType type, RuntimeType genericParameter)
+ internal static object CreateInstanceForAnotherGenericParameter(
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] RuntimeType type,
+ RuntimeType genericParameter)
{
+ Debug.Assert(type.GetConstructor(Type.EmptyTypes) is ConstructorInfo c && c.IsPublic,
+ $"CreateInstanceForAnotherGenericParameter requires {nameof(type)} to have a public parameterless constructor so it can be annotated for trimming without preserving private constructors.");
+
object? instantiatedObject = null;
IntPtr typeHandle = genericParameter.GetTypeHandleInternal().Value;
@@ -224,8 +229,14 @@ internal static object CreateInstanceForAnotherGenericParameter(RuntimeType type
return instantiatedObject!;
}
- internal static object CreateInstanceForAnotherGenericParameter(RuntimeType type, RuntimeType genericParameter1, RuntimeType genericParameter2)
+ internal static object CreateInstanceForAnotherGenericParameter(
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] RuntimeType type,
+ RuntimeType genericParameter1,
+ RuntimeType genericParameter2)
{
+ Debug.Assert(type.GetConstructor(Type.EmptyTypes) is ConstructorInfo c && c.IsPublic,
+ $"CreateInstanceForAnotherGenericParameter requires {nameof(type)} to have a public parameterless constructor so it can be annotated for trimming without preserving private constructors.");
+
object? instantiatedObject = null;
IntPtr* pTypeHandles = stackalloc IntPtr[]
diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
index 51faa23a6070..7c7296b80363 100644
--- a/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
+++ b/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
@@ -2685,8 +2685,11 @@ void MethodContext::dmpGetArgNext(DWORDLONG key, DWORDLONG value)
}
CORINFO_ARG_LIST_HANDLE MethodContext::repGetArgNext(CORINFO_ARG_LIST_HANDLE args)
{
- CORINFO_ARG_LIST_HANDLE temp = (CORINFO_ARG_LIST_HANDLE)GetArgNext->Get(CastHandle(args));
- DEBUG_REP(dmpGetArgNext(CastHandle(args), CastHandle(temp)));
+ DWORDLONG key = CastHandle(args);
+ AssertCodeMsg(GetArgNext != nullptr, EXCEPTIONCODE_MC, "Didn't find %016llx", key);
+ AssertCodeMsg(GetArgNext->GetIndex(key) != -1, EXCEPTIONCODE_MC, "Didn't find %016llx", key);
+ CORINFO_ARG_LIST_HANDLE temp = (CORINFO_ARG_LIST_HANDLE)GetArgNext->Get(key);
+ DEBUG_REP(dmpGetArgNext(key, CastHandle(temp)));
return temp;
}
void MethodContext::recGetMethodSig(CORINFO_METHOD_HANDLE ftn, CORINFO_SIG_INFO* sig, CORINFO_CLASS_HANDLE memberParent)
diff --git a/src/coreclr/ToolBox/superpmi/superpmi/parallelsuperpmi.cpp b/src/coreclr/ToolBox/superpmi/superpmi/parallelsuperpmi.cpp
index ba8584617de2..1eb1a7c2f510 100644
--- a/src/coreclr/ToolBox/superpmi/superpmi/parallelsuperpmi.cpp
+++ b/src/coreclr/ToolBox/superpmi/superpmi/parallelsuperpmi.cpp
@@ -210,6 +210,7 @@ void ProcessChildStdOut(const CommandLine::Options& o,
int* jitted,
int* failed,
int* excluded,
+ int* missing,
int* diffs,
bool* usageError)
{
@@ -253,13 +254,13 @@ void ProcessChildStdOut(const CommandLine::Options& o,
}
else if (strncmp(buff, g_AllFormatStringFixedPrefix, strlen(g_AllFormatStringFixedPrefix)) == 0)
{
- int childLoaded = 0, childJitted = 0, childFailed = 0, childExcluded = 0;
+ int childLoaded = 0, childJitted = 0, childFailed = 0, childExcluded = 0, childMissing = 0;
if (o.applyDiff)
{
int childDiffs = 0;
int converted = sscanf_s(buff, g_AsmDiffsSummaryFormatString, &childLoaded, &childJitted, &childFailed,
- &childExcluded, &childDiffs);
- if (converted != 5)
+ &childExcluded, &childMissing, &childDiffs);
+ if (converted != 6)
{
LogError("Couldn't parse status message: \"%s\"", buff);
continue;
@@ -269,8 +270,8 @@ void ProcessChildStdOut(const CommandLine::Options& o,
else
{
int converted =
- sscanf_s(buff, g_SummaryFormatString, &childLoaded, &childJitted, &childFailed, &childExcluded);
- if (converted != 4)
+ sscanf_s(buff, g_SummaryFormatString, &childLoaded, &childJitted, &childFailed, &childExcluded, &childMissing);
+ if (converted != 5)
{
LogError("Couldn't parse status message: \"%s\"", buff);
continue;
@@ -281,6 +282,7 @@ void ProcessChildStdOut(const CommandLine::Options& o,
*jitted += childJitted;
*failed += childFailed;
*excluded += childExcluded;
+ *missing += childMissing;
}
}
@@ -616,14 +618,14 @@ int doParallelSuperPMI(CommandLine::Options& o)
bool usageError = false; // variable to flag if we hit a usage error in SuperPMI
- int loaded = 0, jitted = 0, failed = 0, excluded = 0, diffs = 0;
+ int loaded = 0, jitted = 0, failed = 0, excluded = 0, missing = 0, diffs = 0;
// Read the stderr files and log them as errors
// Read the stdout files and parse them for counts and log any MISSING or ISSUE errors
for (int i = 0; i < o.workerCount; i++)
{
ProcessChildStdErr(arrStdErrorPath[i]);
- ProcessChildStdOut(o, arrStdOutputPath[i], &loaded, &jitted, &failed, &excluded, &diffs, &usageError);
+ ProcessChildStdOut(o, arrStdOutputPath[i], &loaded, &jitted, &failed, &excluded, &missing, &diffs, &usageError);
if (usageError)
break;
}
@@ -644,11 +646,11 @@ int doParallelSuperPMI(CommandLine::Options& o)
{
if (o.applyDiff)
{
- LogInfo(g_AsmDiffsSummaryFormatString, loaded, jitted, failed, excluded, diffs);
+ LogInfo(g_AsmDiffsSummaryFormatString, loaded, jitted, failed, excluded, missing, diffs);
}
else
{
- LogInfo(g_SummaryFormatString, loaded, jitted, failed, excluded);
+ LogInfo(g_SummaryFormatString, loaded, jitted, failed, excluded, missing);
}
}
diff --git a/src/coreclr/ToolBox/superpmi/superpmi/superpmi.cpp b/src/coreclr/ToolBox/superpmi/superpmi/superpmi.cpp
index 2b741a45f1ee..a3fa79dbc537 100644
--- a/src/coreclr/ToolBox/superpmi/superpmi/superpmi.cpp
+++ b/src/coreclr/ToolBox/superpmi/superpmi/superpmi.cpp
@@ -25,8 +25,8 @@ extern int doParallelSuperPMI(CommandLine::Options& o);
// There must be a single, fixed prefix common to all strings, to ease the determination of when
// to parse the string fully.
const char* const g_AllFormatStringFixedPrefix = "Loaded ";
-const char* const g_SummaryFormatString = "Loaded %d Jitted %d FailedCompile %d Excluded %d";
-const char* const g_AsmDiffsSummaryFormatString = "Loaded %d Jitted %d FailedCompile %d Excluded %d Diffs %d";
+const char* const g_SummaryFormatString = "Loaded %d Jitted %d FailedCompile %d Excluded %d Missing %d";
+const char* const g_AsmDiffsSummaryFormatString = "Loaded %d Jitted %d FailedCompile %d Excluded %d Missing %d Diffs %d";
//#define SuperPMI_ChewMemory 0x7FFFFFFF //Amount of address space to consume on startup
@@ -576,11 +576,11 @@ int __cdecl main(int argc, char* argv[])
if (o.applyDiff)
{
LogInfo(g_AsmDiffsSummaryFormatString, loadedCount, jittedCount, failToReplayCount, excludedCount,
- jittedCount - failToReplayCount - matchCount);
+ missingCount, jittedCount - failToReplayCount - matchCount);
}
else
{
- LogInfo(g_SummaryFormatString, loadedCount, jittedCount, failToReplayCount, excludedCount);
+ LogInfo(g_SummaryFormatString, loadedCount, jittedCount, failToReplayCount, excludedCount, missingCount);
}
st2.Stop();
@@ -607,7 +607,7 @@ int __cdecl main(int argc, char* argv[])
{
result = SpmiResult::Error;
}
- else if (o.applyDiff && matchCount != jittedCount)
+ else if (o.applyDiff && (matchCount != jittedCount - missingCount))
{
result = SpmiResult::Diffs;
}
diff --git a/src/coreclr/debug/createdump/crashinfo.cpp b/src/coreclr/debug/createdump/crashinfo.cpp
index bccbb8553a91..4592b0d253a5 100644
--- a/src/coreclr/debug/createdump/crashinfo.cpp
+++ b/src/coreclr/debug/createdump/crashinfo.cpp
@@ -16,10 +16,8 @@ CrashInfo::CrashInfo(pid_t pid) :
m_task = 0;
#else
m_auxvValues.fill(0);
-#ifndef HAVE_PROCESS_VM_READV
m_fd = -1;
#endif
-#endif
}
CrashInfo::~CrashInfo()
diff --git a/src/coreclr/debug/createdump/crashinfo.h b/src/coreclr/debug/createdump/crashinfo.h
index 9bdf63be49e7..46b0825c0a7e 100644
--- a/src/coreclr/debug/createdump/crashinfo.h
+++ b/src/coreclr/debug/createdump/crashinfo.h
@@ -45,9 +45,8 @@ class CrashInfo : public ICLRDataEnumMemoryRegionsCallback,
#ifdef __APPLE__
vm_map_t m_task; // the mach task for the process
#else
-#ifndef HAVE_PROCESS_VM_READV
+ bool m_canUseProcVmReadSyscall;
int m_fd; // /proc//mem handle
-#endif
#endif
std::string m_coreclrPath; // the path of the coreclr module or empty if none
#ifdef __APPLE__
@@ -112,7 +111,7 @@ class CrashInfo : public ICLRDataEnumMemoryRegionsCallback,
void VisitModule(uint64_t baseAddress, std::string& moduleName);
void VisitProgramHeader(uint64_t loadbias, uint64_t baseAddress, ElfW(Phdr)* phdr);
bool EnumerateModuleMappings();
-#endif
+#endif
bool EnumerateMemoryRegionsWithDAC(MINIDUMP_TYPE minidumpType);
bool EnumerateManagedModules(IXCLRDataProcess* pClrDataProcess);
bool UnwindAllThreads(IXCLRDataProcess* pClrDataProcess);
diff --git a/src/coreclr/debug/createdump/crashinfounix.cpp b/src/coreclr/debug/createdump/crashinfounix.cpp
index d300d343d54a..93a55394a5d8 100644
--- a/src/coreclr/debug/createdump/crashinfounix.cpp
+++ b/src/coreclr/debug/createdump/crashinfounix.cpp
@@ -8,7 +8,6 @@ bool GetStatus(pid_t pid, pid_t* ppid, pid_t* tgid, std::string* name);
bool
CrashInfo::Initialize()
{
-#ifndef HAVE_PROCESS_VM_READV
char memPath[128];
_snprintf_s(memPath, sizeof(memPath), sizeof(memPath), "/proc/%lu/mem", m_pid);
@@ -18,12 +17,13 @@ CrashInfo::Initialize()
fprintf(stderr, "open(%s) FAILED %d (%s)\n", memPath, errno, strerror(errno));
return false;
}
-#endif
// Get the process info
if (!GetStatus(m_pid, &m_ppid, &m_tgid, &m_name))
{
return false;
}
+
+ m_canUseProcVmReadSyscall = true;
return true;
}
@@ -39,13 +39,11 @@ CrashInfo::CleanupAndResumeProcess()
waitpid(thread->Tid(), &waitStatus, __WALL);
}
}
-#ifndef HAVE_PROCESS_VM_READV
if (m_fd != -1)
{
close(m_fd);
m_fd = -1;
}
-#endif
}
//
@@ -253,7 +251,7 @@ CrashInfo::GetDSOInfo()
int phnum = m_auxvValues[AT_PHNUM];
assert(m_auxvValues[AT_PHENT] == sizeof(Phdr));
assert(phnum != PN_XNUM);
- return EnumerateElfInfo(phdrAddr, phnum);
+ return EnumerateElfInfo(phdrAddr, phnum);
}
//
@@ -334,17 +332,31 @@ CrashInfo::ReadProcessMemory(void* address, void* buffer, size_t size, size_t* r
{
assert(buffer != nullptr);
assert(read != nullptr);
+ *read = 0;
#ifdef HAVE_PROCESS_VM_READV
- iovec local{ buffer, size };
- iovec remote{ address, size };
- *read = process_vm_readv(m_pid, &local, 1, &remote, 1, 0);
-#else
- assert(m_fd != -1);
- *read = pread64(m_fd, buffer, size, (off64_t)address);
+ if (m_canUseProcVmReadSyscall)
+ {
+ iovec local{ buffer, size };
+ iovec remote{ address, size };
+ *read = process_vm_readv(m_pid, &local, 1, &remote, 1, 0);
+ }
+
+ if (!m_canUseProcVmReadSyscall || (*read == (size_t)-1 && errno == EPERM))
#endif
+ {
+ // If we've failed, avoid going through expensive syscalls
+ // After all, the use of process_vm_readv is largely as a
+ // performance optimization.
+ m_canUseProcVmReadSyscall = false;
+ assert(m_fd != -1);
+ *read = pread64(m_fd, buffer, size, (off64_t)address);
+ }
+
if (*read == (size_t)-1)
{
+ int readErrno = errno;
+ TRACE_VERBOSE("ReadProcessMemory FAILED, addr: %" PRIA PRIx ", size: %zu, ERRNO %d: %s\n", address, size, readErrno, strerror(readErrno));
return false;
}
return true;
diff --git a/src/coreclr/debug/daccess/daccess.cpp b/src/coreclr/debug/daccess/daccess.cpp
index 424cff1b9148..71e35abec93e 100644
--- a/src/coreclr/debug/daccess/daccess.cpp
+++ b/src/coreclr/debug/daccess/daccess.cpp
@@ -7084,7 +7084,7 @@ HRESULT ClrDataAccess::VerifyDlls()
// Note that we check this knob every time because it may be handy to turn it on in
// the environment mid-flight.
DWORD dwAssertDefault = m_fEnableDllVerificationAsserts ? 1 : 0;
- if (REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_DbgDACAssertOnMismatch, dwAssertDefault))
+ if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgDACAssertOnMismatch, dwAssertDefault))
{
// Output a nice error message that contains the timestamps in string format.
time_t actualTime = timestamp;
diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp
index d38273244086..076662042084 100644
--- a/src/coreclr/debug/daccess/dacdbiimpl.cpp
+++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp
@@ -4787,6 +4787,17 @@ VMPTR_OBJECTHANDLE DacDbiInterfaceImpl::GetThreadObject(VMPTR_Thread vmThread)
}
}
+void DacDbiInterfaceImpl::GetThreadAllocInfo(VMPTR_Thread vmThread,
+ DacThreadAllocInfo* threadAllocInfo)
+{
+ DD_ENTER_MAY_THROW;
+
+ Thread * pThread = vmThread.GetDacPtr();
+ gc_alloc_context* allocContext = pThread->GetAllocContext();
+ threadAllocInfo->m_allocBytesSOH = (ULONG)(allocContext->alloc_bytes - (allocContext->alloc_limit - allocContext->alloc_ptr));
+ threadAllocInfo->m_allocBytesUOH = (ULONG)allocContext->alloc_bytes_uoh;
+}
+
// Set and reset the TSNC_DebuggerUserSuspend bit on the state of the specified thread
// according to the CorDebugThreadState.
void DacDbiInterfaceImpl::SetDebugState(VMPTR_Thread vmThread,
diff --git a/src/coreclr/debug/daccess/dacdbiimpl.h b/src/coreclr/debug/daccess/dacdbiimpl.h
index 42028b59d46d..3088ed007a71 100644
--- a/src/coreclr/debug/daccess/dacdbiimpl.h
+++ b/src/coreclr/debug/daccess/dacdbiimpl.h
@@ -783,6 +783,9 @@ class DacDbiInterfaceImpl :
// Return the object handle for the managed Thread object corresponding to the specified thread.
VMPTR_OBJECTHANDLE GetThreadObject(VMPTR_Thread vmThread);
+ // Get the alocated bytes for this thread.
+ void GetThreadAllocInfo(VMPTR_Thread vmThread, DacThreadAllocInfo* threadAllocInfo);
+
// Set and reset the TSNC_DebuggerUserSuspend bit on the state of the specified thread
// according to the CorDebugThreadState.
void SetDebugState(VMPTR_Thread vmThread,
diff --git a/src/coreclr/debug/di/eventredirectionpipeline.cpp b/src/coreclr/debug/di/eventredirectionpipeline.cpp
index 2332ec25e39c..382319dc8fe8 100644
--- a/src/coreclr/debug/di/eventredirectionpipeline.cpp
+++ b/src/coreclr/debug/di/eventredirectionpipeline.cpp
@@ -58,10 +58,10 @@ void EventRedirectionPipeline::Delete()
void EventRedirectionPipeline::InitConfiguration()
{
// We need some config strings. See header for possible values.
- m_DebuggerCmd.Init_DontUse_(CLRConfig::EXTERNAL_DbgRedirectApplication);
- m_AttachParams.Init_DontUse_(CLRConfig::EXTERNAL_DbgRedirectAttachCmd);
- m_CreateParams.Init_DontUse_(CLRConfig::EXTERNAL_DbgRedirectCreateCmd);
- m_CommonParams.Init_DontUse_(CLRConfig::EXTERNAL_DbgRedirectCommonCmd);
+ m_DebuggerCmd = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_DbgRedirectApplication);
+ m_AttachParams = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_DbgRedirectAttachCmd);
+ m_CreateParams = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_DbgRedirectCreateCmd);
+ m_CommonParams = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_DbgRedirectCommonCmd);
}
@@ -108,11 +108,11 @@ HRESULT EventRedirectionPipeline::AttachDebuggerToTarget(LPCWSTR szOptions, DWOR
// Initialize
m_pBlock->m_versionCookie = EVENT_REDIRECTION_CURRENT_VERSION;
- s.Printf(m_CommonParams.Value(), GetCurrentProcessId(), m_pBlock, szOptions, pidTarget);
+ s.Printf(m_CommonParams, GetCurrentProcessId(), m_pBlock, szOptions, pidTarget);
lpCommandLine = s.GetUnicode();
- lpApplicationName = m_DebuggerCmd.Value(); // eg, something like L"c:\\debuggers_amd64\\windbg.exe";
+ lpApplicationName = m_DebuggerCmd; // eg, something like L"c:\\debuggers_amd64\\windbg.exe";
// Initialize events.
const BOOL kManualResetEvent = TRUE;
@@ -283,7 +283,7 @@ HRESULT EventRedirectionPipeline::CreateProcessUnderDebugger(
}
// Attach the real debugger.
- AttachDebuggerToTarget(m_CreateParams.Value(), lpProcessInformation->dwProcessId);
+ AttachDebuggerToTarget(m_CreateParams, lpProcessInformation->dwProcessId);
m_dwProcessId = lpProcessInformation->dwProcessId;
@@ -298,7 +298,7 @@ HRESULT EventRedirectionPipeline::DebugActiveProcess(MachineInfo machineInfo, co
// Use redirected pipeline
// Spin up debugger to attach to target.
- return AttachDebuggerToTarget(m_AttachParams.Value(), processDescriptor.m_Pid);
+ return AttachDebuggerToTarget(m_AttachParams, processDescriptor.m_Pid);
}
// Detach
diff --git a/src/coreclr/debug/di/eventredirectionpipeline.h b/src/coreclr/debug/di/eventredirectionpipeline.h
index e219c182980a..a8a0aeed8067 100644
--- a/src/coreclr/debug/di/eventredirectionpipeline.h
+++ b/src/coreclr/debug/di/eventredirectionpipeline.h
@@ -102,7 +102,7 @@ class EventRedirectionPipeline :
// The debugger application to launch. eg:
// c:\debuggers_amd64\windbg.exe
- ConfigStringHolder m_DebuggerCmd;
+ CLRConfigStringHolder m_DebuggerCmd;
// The common format string for the command line.
// This will get the following printf args:
@@ -113,7 +113,7 @@ class EventRedirectionPipeline :
// target debuggee (%d or %x): pid of the debuggee.
// eg (for windbg):
// -c ".load C:\vbl\ClrDbg\ndp\clr\src\Tools\strikeRS\objc\amd64\strikeRS.dll; !watch %x %p" %s -p %d
- ConfigStringHolder m_CommonParams;
+ CLRConfigStringHolder m_CommonParams;
// Command parameters for create case.
// Note that we must always physically call CreateProcess on the debuggee so that we get the proper out-parameters
@@ -128,12 +128,12 @@ class EventRedirectionPipeline :
// to not create the break-in thread (which it can't do on a pre-initialized process).
// eg:
// "-WX -pb -pr"
- ConfigStringHolder m_CreateParams;
+ CLRConfigStringHolder m_CreateParams;
// command parameters for attach. The WFDE server will send a loader breakpoint.
// eg:
// "-WX"
- ConfigStringHolder m_AttachParams;
+ CLRConfigStringHolder m_AttachParams;
DWORD m_dwProcessId;
};
diff --git a/src/coreclr/debug/di/rsmain.cpp b/src/coreclr/debug/di/rsmain.cpp
index 779a6eac56d2..ff49f2186a40 100644
--- a/src/coreclr/debug/di/rsmain.cpp
+++ b/src/coreclr/debug/di/rsmain.cpp
@@ -480,15 +480,15 @@ void CordbCommonBase::InitializeCommon()
// StressLog will turn on stress logging for the entire runtime.
// RSStressLog is only used here and only effects just the RS.
fStressLog =
- (REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_StressLog, fStressLog) != 0) ||
+ (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_StressLog, fStressLog) != 0) ||
(CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_RSStressLog) != 0);
if (fStressLog == true)
{
- unsigned facilities = REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_LogFacility, LF_ALL);
- unsigned level = REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::EXTERNAL_LogLevel, LL_INFO1000);
- unsigned bytesPerThread = REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_StressLogSize, STRESSLOG_CHUNK_SIZE * 2);
- unsigned totalBytes = REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_TotalStressLogSize, STRESSLOG_CHUNK_SIZE * 1024);
+ unsigned facilities = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_LogFacility, LF_ALL);
+ unsigned level = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_LogLevel, LL_INFO1000);
+ unsigned bytesPerThread = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_StressLogSize, STRESSLOG_CHUNK_SIZE * 2);
+ unsigned totalBytes = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_TotalStressLogSize, STRESSLOG_CHUNK_SIZE * 1024);
StressLog::Initialize(facilities, level, bytesPerThread, totalBytes, GetClrModuleBase());
}
}
diff --git a/src/coreclr/debug/di/rsthread.cpp b/src/coreclr/debug/di/rsthread.cpp
index b6870e560665..04a7fa21a1db 100644
--- a/src/coreclr/debug/di/rsthread.cpp
+++ b/src/coreclr/debug/di/rsthread.cpp
@@ -9790,6 +9790,7 @@ HRESULT CordbEval::NewParameterizedObject(ICorDebugFunction * pConstructor,
if (FAILED(hr))
{
+ delete [] pArgData;
return hr;
}
}
diff --git a/src/coreclr/debug/ee/debugger.cpp b/src/coreclr/debug/ee/debugger.cpp
index d64bb94e905a..d8791362ca72 100644
--- a/src/coreclr/debug/ee/debugger.cpp
+++ b/src/coreclr/debug/ee/debugger.cpp
@@ -1048,11 +1048,11 @@ void Debugger::InitDebugEventCounting()
memset(&g_iDbgDebuggerCounter, 0, DBG_DEBUGGER_MAX*sizeof(int));
// retrieve the possible counter for break point
- LPWSTR wstrValue = NULL;
+ CLRConfigStringHolder wstrValue = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DebuggerBreakPoint);
// The string value is of the following format
// =Count;=Count;....;
// The string must end with ;
- if ((wstrValue = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DebuggerBreakPoint)) != NULL)
+ if (wstrValue != NULL)
{
LPSTR strValue;
int cbReq;
@@ -1108,7 +1108,6 @@ void Debugger::InitDebugEventCounting()
// free the ansi buffer
delete [] strValue;
- REGUTIL::FreeConfigString(wstrValue);
}
#endif // _DEBUG
}
diff --git a/src/coreclr/debug/ee/debugger.h b/src/coreclr/debug/ee/debugger.h
index 52ed73615ba4..374f4ded1e65 100644
--- a/src/coreclr/debug/ee/debugger.h
+++ b/src/coreclr/debug/ee/debugger.h
@@ -326,16 +326,6 @@ class GCHolderEEInterface
#define GCX_PREEMP_EEINTERFACE_TOGGLE_IFTHREAD_COND(cond) \
GCHolderEEInterface __gcCoop_onlyOneAllowedPerScope((cond))
-
-
-// There are still some APIs that call new that we call from the helper thread.
-// These are unsafe operations, so we wrap them here. Each of these is a potential hang.
-inline DWORD UnsafeGetConfigDWORD_DontUse_(LPCWSTR name, DWORD defValue)
-{
- SUPPRESS_ALLOCATION_ASSERTS_IN_THIS_SCOPE;
- return REGUTIL::GetConfigDWORD_DontUse_(name, defValue);
-}
-
inline DWORD UnsafeGetConfigDWORD(const CLRConfig::ConfigDWORDInfo & info)
{
SUPPRESS_ALLOCATION_ASSERTS_IN_THIS_SCOPE;
diff --git a/src/coreclr/debug/inc/dacdbiinterface.h b/src/coreclr/debug/inc/dacdbiinterface.h
index 5ca550ae0f1f..2dc0beca1c0a 100644
--- a/src/coreclr/debug/inc/dacdbiinterface.h
+++ b/src/coreclr/debug/inc/dacdbiinterface.h
@@ -1065,6 +1065,17 @@ class IDacDbiInterface
virtual
VMPTR_OBJECTHANDLE GetThreadObject(VMPTR_Thread vmThread) = 0;
+
+ //
+ // Get the allocation info corresponding to the specified thread.
+ //
+ // Arguments:
+ // vmThread - the specified thread
+ // threadAllocInfo - the allocated bytes from SOH and UOH so far on this thread
+ //
+
+ virtual
+ void GetThreadAllocInfo(VMPTR_Thread vmThread, DacThreadAllocInfo* threadAllocInfo) = 0;
//
// Set and reset the TSNC_DebuggerUserSuspend bit on the state of the specified thread
diff --git a/src/coreclr/debug/inc/dacdbistructures.h b/src/coreclr/debug/inc/dacdbistructures.h
index b515cd7f1f38..2dabaa48e2c2 100644
--- a/src/coreclr/debug/inc/dacdbistructures.h
+++ b/src/coreclr/debug/inc/dacdbistructures.h
@@ -784,5 +784,12 @@ struct MSLAYOUT DacSharedReJitInfo
CORDB_ADDRESS m_rgInstrumentedMapEntries;
};
+// These represent the allocated bytes so far on the thread.
+struct MSLAYOUT DacThreadAllocInfo
+{
+ ULONG m_allocBytesSOH;
+ ULONG m_allocBytesUOH;
+};
+
#include "dacdbistructures.inl"
#endif // DACDBISTRUCTURES_H_
diff --git a/src/coreclr/debug/inc/dbgtransportsession.h b/src/coreclr/debug/inc/dbgtransportsession.h
index f90f4db12ca7..5c305b178187 100644
--- a/src/coreclr/debug/inc/dbgtransportsession.h
+++ b/src/coreclr/debug/inc/dbgtransportsession.h
@@ -145,8 +145,8 @@ inline void DbgTransportLog(DbgTransportLogClass eClass, const char *szFormat, .
if (s_dwLoggingEnabled == LE_Unknown)
{
- s_dwLoggingEnabled = REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_DbgTransportLog, LE_None);
- s_dwLoggingClass = REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_DbgTransportLogClass, LC_All);
+ s_dwLoggingEnabled = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgTransportLog);
+ s_dwLoggingClass = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgTransportLogClass);
}
if ((s_dwLoggingEnabled & DBG_TRANSPORT_LOG_THIS_SIDE) &&
diff --git a/src/coreclr/inc/clrconfig.h b/src/coreclr/inc/clrconfig.h
index bd5e41cdbc0a..842313df2408 100644
--- a/src/coreclr/inc/clrconfig.h
+++ b/src/coreclr/inc/clrconfig.h
@@ -6,13 +6,8 @@
//
//
-// Unified method of accessing configuration values from environment variables, registry and config file(s).
-// This class replaces all GetConfigDWORD and GetConfigString methods in EEConfig and REGUTIL. To define a
-// flag, add an entry in the table in file:CLRConfigValues.h.
-//
-//
-//
-//
+// Unified method of accessing configuration values.
+// To define a flag, add an entry in the table in file:CLRConfigValues.h.
// --------------------------------------------------------------------------------------------------
@@ -25,28 +20,18 @@
class CLRConfig
{
public:
- //
- // Types
- //
+ // Setting each option results in some change to the config value.
+ enum class LookupOptions
+ {
+ // Default options.
+ Default = 0,
- // Setting each option results in some change to the config value lookup method. Default behavior is (in
- // the following order):
- // * Look at environment variables (prepending COMPlus to the name)
- // * Look at the framework registry keys (HKCU\Software\Microsoft\.NETFramework then
- // HKLM\Software\Microsoft\.NETFramework)
- // * Look at the available config files (system, application, host and user). For details see TODO:
- // Link to BOTR documentation
- enum LookupOptions {
- // If set, don't look in environment variables.
- IgnoreEnv = 0x1,
// If set, do not prepend "COMPlus_" when doing environment variable lookup.
- DontPrependCOMPlus_ = 0x2,
+ DontPrependCOMPlus_ = 0x1,
+
// Remove any whitespace at beginning and end of value. (Only applicable for
// *string* configuration values.)
- TrimWhiteSpaceFromStringValue = 0x100,
-
- // Legacy EEConfig-style lookup.
- EEConfig_default = 0,
+ TrimWhiteSpaceFromStringValue = 0x2,
};
// Struct used to store information about where/how to find a Config DWORD.
@@ -82,14 +67,6 @@ class CLRConfig
#define RETAIL_CONFIG_STRING_INFO_EX(symbol, name, description, lookupOptions) \
static const ConfigStringInfo symbol;
- // TEMPORARY macros that declare strings. These are used for config value accesses that haven't been
- // moved over to CLRConfig yet. Once all accesses have been moved, these macros (and corresponding
- // instantiations in file:../utilcode/CLRConfig.cpp) should be removed.
- #define RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(symbol, name, description) \
- static const LPCWSTR symbol;
- #define RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(symbol, name, description) \
- static const LPCWSTR symbol;
-
//
// Debug versions of the macros
//
@@ -102,18 +79,13 @@ class CLRConfig
static const ConfigStringInfo symbol;
#define CONFIG_STRING_INFO_EX(symbol, name, description, lookupOptions) \
static const ConfigStringInfo symbol;
- #define CONFIG_DWORD_INFO_DIRECT_ACCESS(symbol, name, description) \
- static const LPCWSTR symbol;
- #define CONFIG_STRING_INFO_DIRECT_ACCESS(symbol, name, description) \
- static const LPCWSTR symbol;
#else
#define CONFIG_DWORD_INFO(symbol, name, defaultValue, description)
#define CONFIG_DWORD_INFO_EX(symbol, name, defaultValue, description, lookupOptions)
#define CONFIG_STRING_INFO(symbol, name, description)
#define CONFIG_STRING_INFO_EX(symbol, name, description, lookupOptions)
- #define CONFIG_DWORD_INFO_DIRECT_ACCESS(symbol, name, description)
- #define CONFIG_STRING_INFO_DIRECT_ACCESS(symbol, name, description)
#endif // _DEBUG
+
// Now that we have defined what what the macros in file:CLRConfigValues.h mean, include it to generate the code.
#include "clrconfigvalues.h"
@@ -121,14 +93,10 @@ class CLRConfig
#undef RETAIL_CONFIG_STRING_INFO
#undef RETAIL_CONFIG_DWORD_INFO_EX
#undef RETAIL_CONFIG_STRING_INFO_EX
- #undef RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS
- #undef RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS
#undef CONFIG_DWORD_INFO
#undef CONFIG_STRING_INFO
#undef CONFIG_DWORD_INFO_EX
#undef CONFIG_STRING_INFO_EX
- #undef CONFIG_DWORD_INFO_DIRECT_ACCESS
- #undef CONFIG_STRING_INFO_DIRECT_ACCESS
//
// Methods to do config value (DWORD and String) lookups.
@@ -139,7 +107,10 @@ class CLRConfig
static DWORD GetConfigValue(const ConfigDWORDInfo & info);
// Look up a DWORD config value.
- static DWORD GetConfigValue(const ConfigDWORDInfo & info, bool acceptExplicitDefaultFromRegutil, /* [Out] */ bool *isDefault);
+ static DWORD GetConfigValue(const ConfigDWORDInfo & info, /* [Out] */ bool *isDefault);
+
+ // Look up a DWORD config value.
+ static DWORD GetConfigValue(const ConfigDWORDInfo & info, DWORD defaultValue);
// Look up a string config value.
// You own the string that's returned.
@@ -159,39 +130,10 @@ class CLRConfig
static BOOL IsConfigOptionSpecified(LPCWSTR name);
// Free a string returned by GetConfigValue
- static void FreeConfigString(__in __in_z LPWSTR name);
-
-private:
+ static void FreeConfigString(__in __in_z LPWSTR name);
- // Helper method to translate LookupOptions to REGUTIL::CORConfigLevel
- static REGUTIL::CORConfigLevel GetConfigLevel(LookupOptions options);
-
- //
- // Helper methods.
- //
-
- // Helper method to check if a certain option is set in a ConfigDWORDInfo struct.
- static inline BOOL CheckLookupOption(const ConfigDWORDInfo & info, LookupOptions option)
- {
- LIMITED_METHOD_CONTRACT;
- return ((info.options & option) == option) ? TRUE : FALSE;
- }
-
- // Helper method to check if a certain option is set in a ConfigStringInfo struct.
- static inline BOOL CheckLookupOption(const ConfigStringInfo & info, LookupOptions option)
- {
- LIMITED_METHOD_CONTRACT;
- return ((info.options & option) == option) ? TRUE : FALSE;
- }
-
- // Helper method to check if a certain option is set in an options enum.
- static inline BOOL CheckLookupOption(LookupOptions infoOptions, LookupOptions optionToCheck)
- {
- LIMITED_METHOD_CONTRACT;
- return ((infoOptions & optionToCheck) == optionToCheck) ? TRUE : FALSE;
- }
-
- static HRESULT TrimWhiteSpace(LPCWSTR wszOrig, __deref_out_z LPWSTR * pwszTrimmed);
+ // Populate the caches with current state to improve lookup times.
+ static void InitCache();
};
inline CLRConfig::LookupOptions operator|(CLRConfig::LookupOptions lhs, CLRConfig::LookupOptions rhs)
@@ -199,6 +141,11 @@ inline CLRConfig::LookupOptions operator|(CLRConfig::LookupOptions lhs, CLRConfi
return static_cast(static_cast(lhs) | static_cast(rhs));
}
+inline CLRConfig::LookupOptions operator&(CLRConfig::LookupOptions lhs, CLRConfig::LookupOptions rhs)
+{
+ return static_cast(static_cast(lhs) & static_cast(rhs));
+}
+
typedef Wrapper CLRConfigStringHolder;
#endif //__CLRConfig_h__
diff --git a/src/coreclr/inc/clrconfigvalues.h b/src/coreclr/inc/clrconfigvalues.h
index 6051c2aabd55..46db05a29358 100644
--- a/src/coreclr/inc/clrconfigvalues.h
+++ b/src/coreclr/inc/clrconfigvalues.h
@@ -9,7 +9,7 @@
// registry and config file.
//
// Given any config knob below that looks like this example:
-// RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_LogEnable, W("LogEnable"), "Turns on the traditional CLR log.")
+// RETAIL_CONFIG_DWORD_INFO(INTERNAL_LogEnable, W("LogEnable"), 0, "Turns on the traditional CLR log.")
// ---------
// |
// --------------------
@@ -43,7 +43,7 @@
// CONFIG_DWORD_INFO(symbol, name, defaultValue, description)
// --------------------------------------------------------------------------
// Use this macro to define a basic DWORD value. CLRConfig will look in environment variables (adding
-// COMPlus_ to the name), the registry (HKLM and HKCU), and all the config files for this value. To customize
+// COMPlus_ to the name) for this value. To customize
// where CLRConfig looks, use the extended version of the macro below. IMPORTANT: please follow the
// code:#NamingConventions for the symbol and the name!
//
@@ -56,7 +56,7 @@
// of options and their descriptions, see code:CLRConfig.LookupOptions
//
// Example: CONFIG_DWORD_INFO_EX(INTERNAL_EnableInternetHREFexes, W("EnableInternetHREFexes"), 0, "",
-// (CLRConfig::LookupOptions) (CLRConfig::IgnoreEnv | CLRConfig::IgnoreHKCU))
+// (CLRConfig::LookupOptions) (CLRConfig::LookupOptions::DontPrependCOMPlus_))
//
// #Strings:
// --------------------------------------------------------------------------
@@ -112,12 +112,7 @@
///
/// AppDomain
///
-CONFIG_DWORD_INFO(INTERNAL_ADDumpSB, W("ADDumpSB"), 0, "Not used")
-CONFIG_DWORD_INFO(INTERNAL_ADForceSB, W("ADForceSB"), 0, "Forces sync block creation for all objects")
-CONFIG_DWORD_INFO(INTERNAL_ADLogMemory, W("ADLogMemory"), 0, "Superseded by test hooks")
-CONFIG_DWORD_INFO(INTERNAL_ADTakeDHSnapShot, W("ADTakeDHSnapShot"), 0, "Superseded by test hooks")
-CONFIG_DWORD_INFO(INTERNAL_ADTakeSnapShot, W("ADTakeSnapShot"), 0, "Superseded by test hooks")
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_EnableFullDebug, W("EnableFullDebug"), "Heavy-weight checking for AD boundary violations (AD leaks)")
+CONFIG_DWORD_INFO(INTERNAL_EnableFullDebug, W("EnableFullDebug"), 0, "Heavy-weight checking for AD boundary violations (AD leaks)")
///
/// Jit Pitching
@@ -133,103 +128,102 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_JitPitchMaxVal, W("JitPitchMaxVal"), (DWORD)0x
///
/// Assembly Loader
///
-CONFIG_DWORD_INFO_EX(INTERNAL_GetAssemblyIfLoadedIgnoreRidMap, W("GetAssemblyIfLoadedIgnoreRidMap"), 0, "Used to force loader to ignore assemblies cached in the rid-map", CLRConfig::EEConfig_default)
+CONFIG_DWORD_INFO(INTERNAL_GetAssemblyIfLoadedIgnoreRidMap, W("GetAssemblyIfLoadedIgnoreRidMap"), 0, "Used to force loader to ignore assemblies cached in the rid-map")
///
/// Conditional breakpoints
///
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_BreakOnBadExit, W("BreakOnBadExit"), 0, "", CLRConfig::EEConfig_default)
+RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_BreakOnBadExit, W("BreakOnBadExit"), 0, "")
CONFIG_STRING_INFO(INTERNAL_BreakOnClassBuild, W("BreakOnClassBuild"), "Very useful for debugging class layout code.")
CONFIG_STRING_INFO(INTERNAL_BreakOnClassLoad, W("BreakOnClassLoad"), "Very useful for debugging class loading code.")
CONFIG_STRING_INFO(INTERNAL_BreakOnComToClrNativeInfoInit, W("BreakOnComToClrNativeInfoInit"), "Throws an assert when native information about a COM -> CLR call are about to be gathered.")
-CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnDebugBreak, W("BreakOnDebugBreak"), 0, "Allows an assert in debug builds when a user break is hit", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnDILoad, W("BreakOnDILoad"), 0, "Allows an assert when the DI is loaded", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnDumpToken, W("BreakOnDumpToken"), 0xffffffff, "Breaks when using internal logging on a particular token value.", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_BreakOnEELoad, W("BreakOnEELoad"), 0, "", CLRConfig::EEConfig_default)
+CONFIG_DWORD_INFO(INTERNAL_BreakOnDebugBreak, W("BreakOnDebugBreak"), 0, "Allows an assert in debug builds when a user break is hit")
+CONFIG_DWORD_INFO(INTERNAL_BreakOnDILoad, W("BreakOnDILoad"), 0, "Allows an assert when the DI is loaded")
+CONFIG_DWORD_INFO(INTERNAL_BreakOnDumpToken, W("BreakOnDumpToken"), 0xffffffff, "Breaks when using internal logging on a particular token value.")
+RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_BreakOnEELoad, W("BreakOnEELoad"), 0, "")
CONFIG_DWORD_INFO(INTERNAL_BreakOnEEShutdown, W("BreakOnEEShutdown"), 0, "")
-CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnExceptionInGetThrowable, W("BreakOnExceptionInGetThrowable"), 0, "", CLRConfig::EEConfig_default)
+CONFIG_DWORD_INFO(INTERNAL_BreakOnExceptionInGetThrowable, W("BreakOnExceptionInGetThrowable"), 0, "")
CONFIG_DWORD_INFO(INTERNAL_BreakOnFindMethod, W("BreakOnFindMethod"), 0, "Breaks in findMethodInternal when it searches for the specified token.")
-CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnFirstPass, W("BreakOnFirstPass"), 0, "", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnHR, W("BreakOnHR"), 0, "Debug.cpp, IfFailxxx use this macro to stop if hr matches ", CLRConfig::EEConfig_default)
+CONFIG_DWORD_INFO(INTERNAL_BreakOnFirstPass, W("BreakOnFirstPass"), 0, "")
+CONFIG_DWORD_INFO(INTERNAL_BreakOnHR, W("BreakOnHR"), 0, "Debug.cpp, IfFailxxx use this macro to stop if hr matches ")
CONFIG_STRING_INFO(INTERNAL_BreakOnInstantiation, W("BreakOnInstantiation"), "Very useful for debugging generic class instantiation.")
CONFIG_STRING_INFO(INTERNAL_BreakOnInteropStubSetup, W("BreakOnInteropStubSetup"), "Throws an assert when marshaling stub for the given method is about to be built.")
-CONFIG_STRING_INFO_EX(INTERNAL_BreakOnInteropVTableBuild, W("BreakOnInteropVTableBuild"), "Specifies a type name for which an assert should be thrown when building interop v-table.", CLRConfig::EEConfig_default)
+CONFIG_STRING_INFO(INTERNAL_BreakOnInteropVTableBuild, W("BreakOnInteropVTableBuild"), "Specifies a type name for which an assert should be thrown when building interop v-table.")
CONFIG_STRING_INFO(INTERNAL_BreakOnMethodName, W("BreakOnMethodName"), "Very useful for debugging method override placement code.")
-CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnNotify, W("BreakOnNotify"), 0, "", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnRetailAssert, W("BreakOnRetailAssert"), 0, "Used for debugging \"retail\" asserts (fatal errors)", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnSecondPass, W("BreakOnSecondPass"), 0, "", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_BreakOnSO, W("BreakOnSO"), 0, "", CLRConfig::EEConfig_default)
+CONFIG_DWORD_INFO(INTERNAL_BreakOnNotify, W("BreakOnNotify"), 0, "")
+RETAIL_CONFIG_DWORD_INFO(INTERNAL_BreakOnRetailAssert, W("BreakOnRetailAssert"), 0, "Used for debugging \"retail\" asserts (fatal errors)")
+CONFIG_DWORD_INFO(INTERNAL_BreakOnSecondPass, W("BreakOnSecondPass"), 0, "")
+RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_BreakOnSO, W("BreakOnSO"), 0, "")
CONFIG_STRING_INFO(INTERNAL_BreakOnStructMarshalSetup, W("BreakOnStructMarshalSetup"), "Throws an assert when field marshalers for the given type with layout are about to be created.")
-CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnUEF, W("BreakOnUEF"), 0, "", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnUncaughtException, W("BreakOnUncaughtException"), 0, "", CLRConfig::EEConfig_default)
+CONFIG_DWORD_INFO(INTERNAL_BreakOnUEF, W("BreakOnUEF"), 0, "")
+CONFIG_DWORD_INFO(INTERNAL_BreakOnUncaughtException, W("BreakOnUncaughtException"), 0, "")
///
-
/// Debugger
///
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_EnableDiagnostics, W("EnableDiagnostics"), 1, "Allows the debugger, profiler, and EventPipe diagnostics to be disabled", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_D__FCE, W("D::FCE"), 0, "Allows an assert when crawling the managed stack for an exception handler", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgBreakIfLocksUnavailable, W("DbgBreakIfLocksUnavailable"), 0, "Allows an assert when the debugger can't take a lock ", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgBreakOnErr, W("DbgBreakOnErr"), 0, "Allows an assert when we get a failing hresult", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgBreakOnMapPatchToDJI, W("DbgBreakOnMapPatchToDJI"), 0, "Allows an assert when mapping a patch to an address", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgBreakOnRawInt3, W("DbgBreakOnRawInt3"), 0, "Allows an assert for test coverage for debug break or other int3 breaks", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgBreakOnSendBreakpoint, W("DbgBreakOnSendBreakpoint"), 0, "Allows an assert when sending a breakpoint to the right side", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgBreakOnSetIP, W("DbgBreakOnSetIP"), 0, "Allows an assert when setting the IP", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgCheckInt3, W("DbgCheckInt3"), 0, "Asserts if the debugger explicitly writes int3 instead of calling SetUnmanagedBreakpoint", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_DbgDACAssertOnMismatch, W("DbgDACAssertOnMismatch"), "Allows an assert when the mscordacwks and mscorwks dll versions don't match")
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgDACEnableAssert, W("DbgDACEnableAssert"), 0, "Enables extra validity checking in DAC - assumes target isn't corrupt", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_DbgDACSkipVerifyDlls, W("DbgDACSkipVerifyDlls"), 0, "Allows disabling the check to ensure mscordacwks and mscorwks dll versions match", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgDelayHelper, W("DbgDelayHelper"), 0, "Varies the wait in the helper thread startup for testing race between threads", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_DbgDisableDynamicSymsCompat, W("DbgDisableDynamicSymsCompat"), 0, "", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgDisableTargetConsistencyAsserts, W("DbgDisableTargetConsistencyAsserts"), 0, "Allows explicitly testing with corrupt targets", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_DbgEnableMixedModeDebugging, W("DbgEnableMixedModeDebuggingInternalOnly"), 0, "", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgExtraThreads, W("DbgExtraThreads"), 0, "Allows extra unmanaged threads to run and throw debug events for stress testing", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgExtraThreadsCantStop, W("DbgExtraThreadsCantStop"), 0, "Allows extra unmanaged threads in can't stop region to run and throw debug events for stress testing", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgExtraThreadsIB, W("DbgExtraThreadsIB"), 0, "Allows extra in-band unmanaged threads to run and throw debug events for stress testing", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgExtraThreadsOOB, W("DbgExtraThreadsOOB"), 0, "Allows extra out of band unmanaged threads to run and throw debug events for stress testing", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgFaultInHandleIPCEvent, W("DbgFaultInHandleIPCEvent"), 0, "Allows testing the unhandled event filter", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgInjectFEE, W("DbgInjectFEE"), 0, "Allows injecting a fatal execution error for testing Watson", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgLeakCheck, W("DbgLeakCheck"), 0, "Allows checking for leaked Cordb objects", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgNo2ndChance, W("DbgNo2ndChance"), 0, "Allows breaking on (and catching bogus) 2nd chance exceptions", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgNoDebugger, W("DbgNoDebugger"), 0, "Allows breaking if we don't want to lazily initialize the debugger", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_DbgNoForceContinue, W("DbgNoForceContinue"), 1, "Used to force a continue on longhorn", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgNoOpenMDByFile, W("DbgNoOpenMDByFile"), 0, "Allows opening MD by memory for perf testing", CLRConfig::EEConfig_default)
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableDiagnostics, W("EnableDiagnostics"), 1, "Allows the debugger, profiler, and EventPipe diagnostics to be disabled")
+CONFIG_DWORD_INFO(INTERNAL_D__FCE, W("D::FCE"), 0, "Allows an assert when crawling the managed stack for an exception handler")
+CONFIG_DWORD_INFO(INTERNAL_DbgBreakIfLocksUnavailable, W("DbgBreakIfLocksUnavailable"), 0, "Allows an assert when the debugger can't take a lock ")
+CONFIG_DWORD_INFO(INTERNAL_DbgBreakOnErr, W("DbgBreakOnErr"), 0, "Allows an assert when we get a failing hresult")
+CONFIG_DWORD_INFO(INTERNAL_DbgBreakOnMapPatchToDJI, W("DbgBreakOnMapPatchToDJI"), 0, "Allows an assert when mapping a patch to an address")
+CONFIG_DWORD_INFO(INTERNAL_DbgBreakOnRawInt3, W("DbgBreakOnRawInt3"), 0, "Allows an assert for test coverage for debug break or other int3 breaks")
+CONFIG_DWORD_INFO(INTERNAL_DbgBreakOnSendBreakpoint, W("DbgBreakOnSendBreakpoint"), 0, "Allows an assert when sending a breakpoint to the right side")
+CONFIG_DWORD_INFO(INTERNAL_DbgBreakOnSetIP, W("DbgBreakOnSetIP"), 0, "Allows an assert when setting the IP")
+CONFIG_DWORD_INFO(INTERNAL_DbgCheckInt3, W("DbgCheckInt3"), 0, "Asserts if the debugger explicitly writes int3 instead of calling SetUnmanagedBreakpoint")
+RETAIL_CONFIG_DWORD_INFO(INTERNAL_DbgForcePDBSymbols, W("DbgForcePDBSymbols"), 0, "")
+CONFIG_DWORD_INFO(INTERNAL_DbgDACAssertOnMismatch, W("DbgDACAssertOnMismatch"), 0, "Allows an assert when the mscordacwks and mscorwks dll versions don't match")
+CONFIG_DWORD_INFO(INTERNAL_DbgDACEnableAssert, W("DbgDACEnableAssert"), 0, "Enables extra validity checking in DAC - assumes target isn't corrupt")
+RETAIL_CONFIG_DWORD_INFO(INTERNAL_DbgDACSkipVerifyDlls, W("DbgDACSkipVerifyDlls"), 0, "Allows disabling the check to ensure mscordacwks and mscorwks dll versions match")
+CONFIG_DWORD_INFO(INTERNAL_DbgDelayHelper, W("DbgDelayHelper"), 0, "Varies the wait in the helper thread startup for testing race between threads")
+RETAIL_CONFIG_DWORD_INFO(INTERNAL_DbgDisableDynamicSymsCompat, W("DbgDisableDynamicSymsCompat"), 0, "")
+CONFIG_DWORD_INFO(INTERNAL_DbgDisableTargetConsistencyAsserts, W("DbgDisableTargetConsistencyAsserts"), 0, "Allows explicitly testing with corrupt targets")
+RETAIL_CONFIG_DWORD_INFO(INTERNAL_DbgEnableMixedModeDebugging, W("DbgEnableMixedModeDebuggingInternalOnly"), 0, "")
+CONFIG_DWORD_INFO(INTERNAL_DbgExtraThreads, W("DbgExtraThreads"), 0, "Allows extra unmanaged threads to run and throw debug events for stress testing")
+CONFIG_DWORD_INFO(INTERNAL_DbgExtraThreadsCantStop, W("DbgExtraThreadsCantStop"), 0, "Allows extra unmanaged threads in can't stop region to run and throw debug events for stress testing")
+CONFIG_DWORD_INFO(INTERNAL_DbgExtraThreadsIB, W("DbgExtraThreadsIB"), 0, "Allows extra in-band unmanaged threads to run and throw debug events for stress testing")
+CONFIG_DWORD_INFO(INTERNAL_DbgExtraThreadsOOB, W("DbgExtraThreadsOOB"), 0, "Allows extra out of band unmanaged threads to run and throw debug events for stress testing")
+CONFIG_DWORD_INFO(INTERNAL_DbgFaultInHandleIPCEvent, W("DbgFaultInHandleIPCEvent"), 0, "Allows testing the unhandled event filter")
+CONFIG_DWORD_INFO(INTERNAL_DbgInjectFEE, W("DbgInjectFEE"), 0, "Allows injecting a fatal execution error for testing Watson")
+CONFIG_DWORD_INFO(INTERNAL_DbgLeakCheck, W("DbgLeakCheck"), 0, "Allows checking for leaked Cordb objects")
+CONFIG_DWORD_INFO(INTERNAL_DbgNo2ndChance, W("DbgNo2ndChance"), 0, "Allows breaking on (and catching bogus) 2nd chance exceptions")
+CONFIG_DWORD_INFO(INTERNAL_DbgNoDebugger, W("DbgNoDebugger"), 0, "Allows breaking if we don't want to lazily initialize the debugger")
+RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_DbgNoForceContinue, W("DbgNoForceContinue"), 1, "Used to force a continue on longhorn")
+CONFIG_DWORD_INFO(INTERNAL_DbgNoOpenMDByFile, W("DbgNoOpenMDByFile"), 0, "Allows opening MD by memory for perf testing")
CONFIG_DWORD_INFO(INTERNAL_DbgOOBinFEEE, W("DbgOOBinFEEE"), 0, "Allows forcing oob breakpoints when a fatal error occurs")
-RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(EXTERNAL_DbgPackShimPath, W("DbgPackShimPath"), "CoreCLR path to dbgshim.dll - we are trying to figure out if we can remove this")
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgPingInterop, W("DbgPingInterop"), 0, "Allows checking for deadlocks in interop debugging", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgRace, W("DbgRace"), 0, "Allows pausing for native debug events to get hijicked", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_DbgRedirect, W("DbgRedirect"), 0, "Allows for redirecting the event pipeline", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(EXTERNAL_DbgRedirectApplication, W("DbgRedirectApplication"), "Specifies the auxiliary debugger application to launch.")
-RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(EXTERNAL_DbgRedirectAttachCmd, W("DbgRedirectAttachCmd"), "Specifies command parameters for attaching the auxiliary debugger.")
-RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(EXTERNAL_DbgRedirectCommonCmd, W("DbgRedirectCommonCmd"), "Specifies a command line format string for the auxiliary debugger.")
-RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(EXTERNAL_DbgRedirectCreateCmd, W("DbgRedirectCreateCmd"), "Specifies command parameters when creating the auxiliary debugger.")
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgShortcutCanary, W("DbgShortcutCanary"), 0, "Allows a way to force canary to fail to be able to test failure paths", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgSkipMEOnStep, W("DbgSkipMEOnStep"), 0, "Turns off MethodEnter checks", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgSkipVerCheck, W("DbgSkipVerCheck"), 0, "Allows different RS and LS versions (for servicing work)", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgTC, W("DbgTC"), 0, "Allows checking boundary compression for offset mappings", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgTransportFaultInject, W("DbgTransportFaultInject"), 0, "Allows injecting a fault for testing the debug transport", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_DbgTransportLog, W("DbgTransportLog"), "Turns on logging for the debug transport")
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_DbgTransportLogClass, W("DbgTransportLogClass"), "Mask to control what is logged in DbgTransportLog")
-RETAIL_CONFIG_STRING_INFO_EX(UNSUPPORTED_DbgTransportProxyAddress, W("DbgTransportProxyAddress"), "Allows specifying the transport proxy address", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgTrapOnSkip, W("DbgTrapOnSkip"), 0, "Allows breaking when we skip a breakpoint", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgWaitTimeout, W("DbgWaitTimeout"), 1, "Specifies the timeout value for waits", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_DbgWFDETimeout, W("DbgWFDETimeout"), 25, "Specifies the timeout value for wait when waiting for a debug event", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_RaiseExceptionOnAssert, W("RaiseExceptionOnAssert"), 0, "Raise a first chance (if set to 1) or second chance (if set to 2) exception on asserts.", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DebugBreakOnAssert, W("DebugBreakOnAssert"), 0, "If DACCESS_COMPILE is defined, break on asserts.", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_DebugBreakOnVerificationFailure, W("DebugBreakOnVerificationFailure"), 0, "Halts the jit on verification failure", CLRConfig::EEConfig_default)
-CONFIG_STRING_INFO_EX(INTERNAL_DebuggerBreakPoint, W("DebuggerBreakPoint"), "Allows counting various debug events", CLRConfig::EEConfig_default)
-CONFIG_STRING_INFO_EX(INTERNAL_DebugVerify, W("DebugVerify"), "Control for tracing in peverify", CLRConfig::EEConfig_default)
+CONFIG_DWORD_INFO(INTERNAL_DbgPingInterop, W("DbgPingInterop"), 0, "Allows checking for deadlocks in interop debugging")
+CONFIG_DWORD_INFO(INTERNAL_DbgRace, W("DbgRace"), 0, "Allows pausing for native debug events to get hijicked")
+RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_DbgRedirect, W("DbgRedirect"), 0, "Allows for redirecting the event pipeline")
+RETAIL_CONFIG_STRING_INFO(EXTERNAL_DbgRedirectApplication, W("DbgRedirectApplication"), "Specifies the auxiliary debugger application to launch.")
+RETAIL_CONFIG_STRING_INFO(EXTERNAL_DbgRedirectAttachCmd, W("DbgRedirectAttachCmd"), "Specifies command parameters for attaching the auxiliary debugger.")
+RETAIL_CONFIG_STRING_INFO(EXTERNAL_DbgRedirectCommonCmd, W("DbgRedirectCommonCmd"), "Specifies a command line format string for the auxiliary debugger.")
+RETAIL_CONFIG_STRING_INFO(EXTERNAL_DbgRedirectCreateCmd, W("DbgRedirectCreateCmd"), "Specifies command parameters when creating the auxiliary debugger.")
+CONFIG_DWORD_INFO(INTERNAL_DbgShortcutCanary, W("DbgShortcutCanary"), 0, "Allows a way to force canary to fail to be able to test failure paths")
+CONFIG_DWORD_INFO(INTERNAL_DbgSkipMEOnStep, W("DbgSkipMEOnStep"), 0, "Turns off MethodEnter checks")
+CONFIG_DWORD_INFO(INTERNAL_DbgSkipVerCheck, W("DbgSkipVerCheck"), 0, "Allows different RS and LS versions (for servicing work)")
+CONFIG_DWORD_INFO(INTERNAL_DbgTC, W("DbgTC"), 0, "Allows checking boundary compression for offset mappings")
+CONFIG_DWORD_INFO(INTERNAL_DbgTransportFaultInject, W("DbgTransportFaultInject"), 0, "Allows injecting a fault for testing the debug transport")
+CONFIG_DWORD_INFO(INTERNAL_DbgTransportLog, W("DbgTransportLog"), 0 /* LE_None */, "Turns on logging for the debug transport")
+CONFIG_DWORD_INFO(INTERNAL_DbgTransportLogClass, W("DbgTransportLogClass"), (DWORD)-1 /* LC_All */, "Mask to control what is logged in DbgTransportLog")
+RETAIL_CONFIG_STRING_INFO(UNSUPPORTED_DbgTransportProxyAddress, W("DbgTransportProxyAddress"), "Allows specifying the transport proxy address")
+CONFIG_DWORD_INFO(INTERNAL_DbgTrapOnSkip, W("DbgTrapOnSkip"), 0, "Allows breaking when we skip a breakpoint")
+CONFIG_DWORD_INFO(INTERNAL_DbgWaitTimeout, W("DbgWaitTimeout"), 1, "Specifies the timeout value for waits")
+RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_DbgWFDETimeout, W("DbgWFDETimeout"), 25, "Specifies the timeout value for wait when waiting for a debug event")
+CONFIG_DWORD_INFO(INTERNAL_RaiseExceptionOnAssert, W("RaiseExceptionOnAssert"), 0, "Raise a first chance (if set to 1) or second chance (if set to 2) exception on asserts.")
+CONFIG_DWORD_INFO(INTERNAL_DebugBreakOnAssert, W("DebugBreakOnAssert"), 0, "If DACCESS_COMPILE is defined, break on asserts.")
+CONFIG_DWORD_INFO(INTERNAL_DebugBreakOnVerificationFailure, W("DebugBreakOnVerificationFailure"), 0, "Halts the jit on verification failure")
+CONFIG_STRING_INFO(INTERNAL_DebuggerBreakPoint, W("DebuggerBreakPoint"), "Allows counting various debug events")
+CONFIG_STRING_INFO(INTERNAL_DebugVerify, W("DebugVerify"), "Control for tracing in peverify")
CONFIG_DWORD_INFO(INTERNAL_EncApplyChanges, W("EncApplyChanges"), 0, "Allows breaking when ApplyEditAndContinue is called")
-CONFIG_DWORD_INFO_EX(INTERNAL_EnCBreakOnRemapComplete, W("EnCBreakOnRemapComplete"), 0, "Allows breaking after N RemapCompletes", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_EnCBreakOnRemapOpportunity, W("EnCBreakOnRemapOpportunity"), 0, "Allows breaking after N RemapOpportunities", CLRConfig::EEConfig_default)
+CONFIG_DWORD_INFO(INTERNAL_EnCBreakOnRemapComplete, W("EnCBreakOnRemapComplete"), 0, "Allows breaking after N RemapCompletes")
+CONFIG_DWORD_INFO(INTERNAL_EnCBreakOnRemapOpportunity, W("EnCBreakOnRemapOpportunity"), 0, "Allows breaking after N RemapOpportunities")
CONFIG_DWORD_INFO(INTERNAL_EncDumpApplyChanges, W("EncDumpApplyChanges"), 0, "Allows dumping edits in delta metadata and il files")
CONFIG_DWORD_INFO(INTERNAL_EncFixupFieldBreak, W("EncFixupFieldBreak"), 0, "Unlikely that this is used anymore.")
CONFIG_DWORD_INFO(INTERNAL_EncJitUpdatedFunction, W("EncJitUpdatedFunction"), 0, "Allows breaking when an updated function is jitted")
CONFIG_DWORD_INFO(INTERNAL_EnCResolveField, W("EnCResolveField"), 0, "Allows breaking when computing the address of an EnC-added field")
CONFIG_DWORD_INFO(INTERNAL_EncResumeInUpdatedFunction, W("EncResumeInUpdatedFunction"), 0, "Allows breaking when execution resumes in a new EnC version of a function")
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgAssertOnDebuggeeDebugBreak, W("DbgAssertOnDebuggeeDebugBreak"), 0, "If non-zero causes the managed-only debugger to assert on unhandled breakpoints in the debuggee", CLRConfig::EEConfig_default)
+CONFIG_DWORD_INFO(INTERNAL_DbgAssertOnDebuggeeDebugBreak, W("DbgAssertOnDebuggeeDebugBreak"), 0, "If non-zero causes the managed-only debugger to assert on unhandled breakpoints in the debuggee")
RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_DbgDontResumeThreadsOnUnhandledException, W("UNSUPPORTED_DbgDontResumeThreadsOnUnhandledException"), 0, "If non-zero, then don't try to unsuspend threads after continuing a 2nd-chance native exception")
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_DbgSkipStackCheck, W("DbgSkipStackCheck"), 0, "Skip the stack pointer check during stackwalking", CLRConfig::EEConfig_default)
+RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_DbgSkipStackCheck, W("DbgSkipStackCheck"), 0, "Skip the stack pointer check during stackwalking")
#ifdef DACCESS_COMPILE
CONFIG_DWORD_INFO(INTERNAL_DumpGeneration_IntentionallyCorruptDataFromTarget, W("IntentionallyCorruptDataFromTarget"), 0, "Intentionally fakes bad data retrieved from target to try and break dump generation.")
#endif
@@ -240,18 +234,17 @@ CONFIG_DWORD_INFO(UNSUPPORTED_Debugging_RequiredVersion, W("UNSUPPORTED_Debuggin
RETAIL_CONFIG_DWORD_INFO(INTERNAL_MiniMdBufferCapacity, W("MiniMdBufferCapacity"), 64 * 1024, "The max size of the buffer to store mini metadata information for triage- and mini-dumps.")
#endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
-CONFIG_DWORD_INFO_EX(INTERNAL_DbgNativeCodeBpBindsAcrossVersions, W("DbgNativeCodeBpBindsAcrossVersions"), 0, "If non-zero causes native breakpoints at offset 0 to bind in all tiered compilation versions of the given method", CLRConfig::EEConfig_default)
+CONFIG_DWORD_INFO(INTERNAL_DbgNativeCodeBpBindsAcrossVersions, W("DbgNativeCodeBpBindsAcrossVersions"), 0, "If non-zero causes native breakpoints at offset 0 to bind in all tiered compilation versions of the given method")
///
/// Diagnostics (internal general-purpose)
///
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_ConditionalContracts, W("ConditionalContracts"), "If ENABLE_CONTRACTS_IMPL is defined, sets whether contracts are conditional. (?)")
+CONFIG_DWORD_INFO(INTERNAL_ConditionalContracts, W("ConditionalContracts"), 0, "If ENABLE_CONTRACTS_IMPL is defined, sets whether contracts are conditional. (?)")
CONFIG_DWORD_INFO(INTERNAL_ConsistencyCheck, W("ConsistencyCheck"), 0, "")
-CONFIG_DWORD_INFO_EX(INTERNAL_ContinueOnAssert, W("ContinueOnAssert"), 0, "If set, doesn't break on asserts.", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_disableStackOverflowProbing, W("disableStackOverflowProbing"), 0, "", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_InjectFatalError, W("InjectFatalError"), "")
-CONFIG_DWORD_INFO_EX(INTERNAL_InjectFault, W("InjectFault"), 0, "", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_SuppressChecks, W("SuppressChecks"), "")
+CONFIG_DWORD_INFO(INTERNAL_ContinueOnAssert, W("ContinueOnAssert"), 0, "If set, doesn't break on asserts.")
+CONFIG_DWORD_INFO(INTERNAL_InjectFatalError, W("InjectFatalError"), 0, "")
+CONFIG_DWORD_INFO(INTERNAL_InjectFault, W("InjectFault"), 0, "")
+CONFIG_DWORD_INFO(INTERNAL_SuppressChecks, W("SuppressChecks"),0, "")
#ifdef FEATURE_EH_FUNCLETS
CONFIG_DWORD_INFO(INTERNAL_SuppressLockViolationsOnReentryFromOS, W("SuppressLockViolationsOnReentryFromOS"), 0, "64 bit OOM tests re-enter the CLR via RtlVirtualUnwind. This indicates whether to suppress resulting locking violations.")
#endif // FEATURE_EH_FUNCLETS
@@ -259,18 +252,18 @@ CONFIG_DWORD_INFO(INTERNAL_SuppressLockViolationsOnReentryFromOS, W("SuppressLoc
///
/// Exception Handling
///
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_AssertOnFailFast, W("AssertOnFailFast"), "")
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_legacyCorruptedStateExceptionsPolicy, W("legacyCorruptedStateExceptionsPolicy"), 0, "Enabled Pre-V4 CSE behavior", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_SuppressLostExceptionTypeAssert, W("SuppressLostExceptionTypeAssert"), 0, "", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_UseEntryPointFilter, W("UseEntryPointFilter"), 0, "", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_Corhost_Swallow_Uncaught_Exceptions, W("Corhost_Swallow_Uncaught_Exceptions"), 0, "", CLRConfig::EEConfig_default)
+CONFIG_DWORD_INFO(INTERNAL_AssertOnFailFast, W("AssertOnFailFast"), 1, "")
+RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_legacyCorruptedStateExceptionsPolicy, W("legacyCorruptedStateExceptionsPolicy"), 0, "Enabled Pre-V4 CSE behavior")
+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, "")
///
/// Garbage collector
///
CONFIG_DWORD_INFO(INTERNAL_FastGCCheckStack, W("FastGCCheckStack"), 0, "")
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_FastGCStress, W("FastGCStress"), "Reduce the number of GCs done by enabling GCStress")
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_GCBreakOnOOM, W("GCBreakOnOOM"), "Does a DebugBreak at the soonest time we detect an OOM")
+CONFIG_DWORD_INFO(INTERNAL_FastGCStress, W("FastGCStress"), 0, "Reduce the number of GCs done by enabling GCStress")
+RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_GCBreakOnOOM, W("GCBreakOnOOM"), 0, "Does a DebugBreak at the soonest time we detect an OOM")
RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_gcConcurrent, W("gcConcurrent"), (DWORD)-1, "Enables/Disables concurrent GC")
#ifdef FEATURE_CONSERVATIVE_GC
@@ -283,9 +276,9 @@ RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_StatsUpdatePeriod, W("StatsUpdatePeriod"),
RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_GCRetainVM, W("GCRetainVM"), 0, "When set we put the segments that should be deleted on a standby list (instead of releasing them back to the OS) which will be considered to satisfy new segment requests (note that the same thing can be specified via API which is the supported way)")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_GCLOHThreshold, W("GCLOHThreshold"), 0, "Specifies the size that will make objects go on LOH")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_gcAllowVeryLargeObjects, W("gcAllowVeryLargeObjects"), 1, "Allow allocation of 2GB+ objects on GC heap")
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_GCStress, W("GCStress"), 0, "Trigger GCs at regular intervals", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_GcStressOnDirectCalls, W("GcStressOnDirectCalls"), 0, "Whether to trigger a GC on direct calls", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_HeapVerify, W("HeapVerify"), "When set verifies the integrity of the managed heap on entry and exit of each GC")
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_GCStress, W("GCStress"), 0, "Trigger GCs at regular intervals")
+CONFIG_DWORD_INFO(INTERNAL_GcStressOnDirectCalls, W("GcStressOnDirectCalls"), 0, "Whether to trigger a GC on direct calls")
+RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_HeapVerify, W("HeapVerify"), 0, "When set verifies the integrity of the managed heap on entry and exit of each GC")
RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_GCNumaAware, W("GCNumaAware"), 1, "Specifies if to enable GC NUMA aware")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_GCCpuGroup, W("GCCpuGroup"), 0, "Specifies if to enable GC to support CPU groups")
RETAIL_CONFIG_STRING_INFO(EXTERNAL_GCName, W("GCName"), "")
@@ -293,33 +286,32 @@ RETAIL_CONFIG_STRING_INFO(EXTERNAL_GCName, W("GCName"), "")
///
/// IBC
///
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_ConvertIbcData, W("ConvertIbcData"), 1, "Converts between v1 and v2 IBC data", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_DisableHotCold, W("DisableHotCold"), "Master hot/cold splitting switch in Jit64")
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_DisableIBC, W("DisableIBC"), 0, "Disables the use of IBC data", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_UseIBCFile, W("UseIBCFile"), 0, "", CLRConfig::EEConfig_default)
+RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_ConvertIbcData, W("ConvertIbcData"), 1, "Converts between v1 and v2 IBC data")
+RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_DisableIBC, W("DisableIBC"), 0, "Disables the use of IBC data")
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_UseIBCFile, W("UseIBCFile"), 0, "")
///
/// JIT
///
-CONFIG_DWORD_INFO_EX(INTERNAL_JitBreakEmit, W("JitBreakEmit"), (DWORD)-1, "", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_JitDebuggable, W("JitDebuggable"), "")
+CONFIG_DWORD_INFO(INTERNAL_JitBreakEmit, W("JitBreakEmit"), (DWORD)-1, "")
+CONFIG_DWORD_INFO(INTERNAL_JitDebuggable, W("JitDebuggable"), 0, "")
#if !defined(DEBUG) && !defined(_DEBUG)
#define INTERNAL_JitEnableNoWayAssert_Default 0
#else
#define INTERNAL_JitEnableNoWayAssert_Default 1
#endif
-RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_JitEnableNoWayAssert, W("JitEnableNoWayAssert"), INTERNAL_JitEnableNoWayAssert_Default, "", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_JitFramed, W("JitFramed"), "Forces EBP frames")
-CONFIG_DWORD_INFO_EX(INTERNAL_JitGCStress, W("JitGCStress"), 0, "GC stress mode for jit", CLRConfig::EEConfig_default)
+RETAIL_CONFIG_DWORD_INFO(INTERNAL_JitEnableNoWayAssert, W("JitEnableNoWayAssert"), INTERNAL_JitEnableNoWayAssert_Default, "")
+RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_JitFramed, W("JitFramed"), 0, "Forces EBP frames")
+CONFIG_DWORD_INFO(INTERNAL_JitGCStress, W("JitGCStress"), 0, "GC stress mode for jit")
CONFIG_DWORD_INFO(INTERNAL_JitHeartbeat, W("JitHeartbeat"), 0, "")
CONFIG_DWORD_INFO(INTERNAL_JitHelperLogging, W("JitHelperLogging"), 0, "")
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_JITMinOpts, W("JITMinOpts"), "Forces MinOpts")
+RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_JITMinOpts, W("JITMinOpts"), 0, "Forces MinOpts")
RETAIL_CONFIG_STRING_INFO(EXTERNAL_JitName, W("JitName"), "Primary Jit to use")
#if defined(ALLOW_SXS_JIT)
-RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_AltJitName, W("AltJitName"), "Alternative Jit to use, will fall back to primary jit.", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_AltJit, W("AltJit"), "Enables AltJit and selectively limits it to the specified methods.", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_AltJitExcludeAssemblies, W("AltJitExcludeAssemblies"), "Do not use AltJit on this semicolon-delimited list of assemblies.", CLRConfig::EEConfig_default)
+RETAIL_CONFIG_STRING_INFO(EXTERNAL_AltJitName, W("AltJitName"), "Alternative Jit to use, will fall back to primary jit.")
+RETAIL_CONFIG_STRING_INFO(EXTERNAL_AltJit, W("AltJit"), "Enables AltJit and selectively limits it to the specified methods.")
+RETAIL_CONFIG_STRING_INFO(EXTERNAL_AltJitExcludeAssemblies, W("AltJitExcludeAssemblies"), "Do not use AltJit on this semicolon-delimited list of assemblies.")
#endif // defined(ALLOW_SXS_JIT)
#if defined(FEATURE_STACK_SAMPLING)
@@ -330,21 +322,21 @@ RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_StackSamplingNumMethods, W("StackSamplingNu
#endif // defined(FEATURE_JIT_SAMPLING)
#if defined(ALLOW_SXS_JIT_NGEN)
-RETAIL_CONFIG_STRING_INFO_EX(INTERNAL_AltJitNgen, W("AltJitNgen"), "Enables AltJit for NGEN and selectively limits it to the specified methods.", CLRConfig::EEConfig_default)
+RETAIL_CONFIG_STRING_INFO(INTERNAL_AltJitNgen, W("AltJitNgen"), "Enables AltJit for NGEN and selectively limits it to the specified methods.")
#endif // defined(ALLOW_SXS_JIT_NGEN)
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_JitHostMaxSlabCache, W("JitHostMaxSlabCache"), 0x1000000, "Sets jit host max slab cache size, 16MB default")
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_JitOptimizeType, W("JitOptimizeType"), "")
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_JitPrintInlinedMethods, W("JitPrintInlinedMethods"), 0, "", CLRConfig::EEConfig_default)
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_JitOptimizeType, W("JitOptimizeType"), 0 /* OPT_DEFAULT */, "")
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_JitPrintInlinedMethods, W("JitPrintInlinedMethods"), 0, "")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_JitTelemetry, W("JitTelemetry"), 1, "If non-zero, gather JIT telemetry data")
RETAIL_CONFIG_STRING_INFO(INTERNAL_JitTimeLogFile, W("JitTimeLogFile"), "If set, gather JIT throughput data and write to this file.")
RETAIL_CONFIG_STRING_INFO(INTERNAL_JitTimeLogCsv, W("JitTimeLogCsv"), "If set, gather JIT throughput data and write to a CSV file. This mode must be used in internal retail builds.")
RETAIL_CONFIG_STRING_INFO(INTERNAL_JitFuncInfoLogFile, W("JitFuncInfoLogFile"), "If set, gather JIT function info and write to this file.")
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_JitVerificationDisable, W("JitVerificationDisable"), "")
+CONFIG_DWORD_INFO(INTERNAL_JitVerificationDisable, W("JitVerificationDisable"), 0, "")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_JitLockWrite, W("JitLockWrite"), 0, "Force all volatile writes to be 'locked'")
-CONFIG_STRING_INFO_EX(INTERNAL_TailCallMax, W("TailCallMax"), "", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_TailCallOpt, W("TailCallOpt"), "", CLRConfig::EEConfig_default)
+CONFIG_STRING_INFO(INTERNAL_TailCallMax, W("TailCallMax"), "")
+RETAIL_CONFIG_STRING_INFO(EXTERNAL_TailCallOpt, W("TailCallOpt"), "")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_TailCallLoopOpt, W("TailCallLoopOpt"), 1, "Convert recursive tail calls to loops")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_Jit_NetFx40PInvokeStackResilience, W("NetFx40_PInvokeStackResilience"), (DWORD)-1, "Makes P/Invoke resilient against mismatched signature and calling convention (significant perf penalty).")
@@ -354,10 +346,10 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_AltJitAssertOnNYI, W("AltJitAssertOnNYI"), 0,
#else
RETAIL_CONFIG_DWORD_INFO(INTERNAL_AltJitAssertOnNYI, W("AltJitAssertOnNYI"), 1, "Controls the AltJit behavior of NYI stuff")
#endif
-CONFIG_DWORD_INFO_EX(INTERNAL_JitLargeBranches, W("JitLargeBranches"), 0, "Force using the largest conditional branch format", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_JitRegisterFP, W("JitRegisterFP"), 3, "Control FP enregistration", CLRConfig::EEConfig_default)
+CONFIG_DWORD_INFO(INTERNAL_JitLargeBranches, W("JitLargeBranches"), 0, "Force using the largest conditional branch format")
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_JitRegisterFP, W("JitRegisterFP"), 3, "Control FP enregistration")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_JitELTHookEnabled, W("JitELTHookEnabled"), 0, "On ARM, setting this will emit Enter/Leave/TailCall callbacks")
-RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_JitMemStats, W("JitMemStats"), 0, "Display JIT memory usage statistics", CLRConfig::EEConfig_default)
+RETAIL_CONFIG_DWORD_INFO(INTERNAL_JitMemStats, W("JitMemStats"), 0, "Display JIT memory usage statistics")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_JitVNMapSelBudget, W("JitVNMapSelBudget"), 100, "Max # of MapSelect's considered for a particular top-level invocation.")
#if defined(TARGET_AMD64) || defined(TARGET_X86) || defined(TARGET_ARM64)
#define EXTERNAL_FeatureSIMD_Default 1
@@ -369,10 +361,10 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_JitVNMapSelBudget, W("JitVNMapSelBudget"), 100
#else // !(defined(TARGET_AMD64) || defined(TARGET_X86)
#define EXTERNAL_JitEnableAVX_Default 0
#endif // !(defined(TARGET_AMD64) || defined(TARGET_X86)
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_FeatureSIMD, W("FeatureSIMD"), EXTERNAL_FeatureSIMD_Default, "Enable SIMD intrinsics recognition in System.Numerics.dll and/or System.Numerics.Vectors.dll", CLRConfig::EEConfig_default)
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_FeatureSIMD, W("FeatureSIMD"), EXTERNAL_FeatureSIMD_Default, "Enable SIMD intrinsics recognition in System.Numerics.dll and/or System.Numerics.Vectors.dll")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_SIMD16ByteOnly, W("SIMD16ByteOnly"), 0, "Limit maximum SIMD vector length to 16 bytes (used by x64_arm64_altjit)")
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_EnableAVX, W("EnableAVX"), EXTERNAL_JitEnableAVX_Default, "Enable AVX instruction set for wide operations as default", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_TrackDynamicMethodDebugInfo, W("TrackDynamicMethodDebugInfo"), 0, "Specifies whether debug info should be generated and tracked for dynamic methods", CLRConfig::EEConfig_default)
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableAVX, W("EnableAVX"), EXTERNAL_JitEnableAVX_Default, "Enable AVX instruction set for wide operations as default")
+RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_TrackDynamicMethodDebugInfo, W("TrackDynamicMethodDebugInfo"), 0, "Specifies whether debug info should be generated and tracked for dynamic methods")
#ifdef FEATURE_MULTICOREJIT
@@ -385,18 +377,18 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_MultiCoreJitProfileWriteDelay, W("MultiCoreJit
///
/// Interpreter
///
-RETAIL_CONFIG_STRING_INFO_EX(INTERNAL_Interpret, W("Interpret"), "Selectively uses the interpreter to execute the specified methods", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_STRING_INFO_EX(INTERNAL_InterpretExclude, W("InterpretExclude"), "Excludes the specified methods from the set selected by 'Interpret'", CLRConfig::EEConfig_default)
+RETAIL_CONFIG_STRING_INFO(INTERNAL_Interpret, W("Interpret"), "Selectively uses the interpreter to execute the specified methods")
+RETAIL_CONFIG_STRING_INFO(INTERNAL_InterpretExclude, W("InterpretExclude"), "Excludes the specified methods from the set selected by 'Interpret'")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_InterpreterMethHashMin, W("InterpreterMethHashMin"), 0, "Only interpret methods selected by 'Interpret' whose hash is at least this value. or after nth")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_InterpreterMethHashMax, W("InterpreterMethHashMax"), UINT32_MAX, "If non-zero, only interpret methods selected by 'Interpret' whose hash is at most this value")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_InterpreterStubMin, W("InterpreterStubMin"), 0, "Only interpret methods selected by 'Interpret' whose stub num is at least this value.")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_InterpreterStubMax, W("InterpreterStubMax"), UINT32_MAX, "If non-zero, only interpret methods selected by 'Interpret' whose stub number is at most this value.")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_InterpreterJITThreshold, W("InterpreterJITThreshold"), 10, "The number of times a method should be interpreted before being JITted")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_InterpreterDoLoopMethods, W("InterpreterDoLoopMethods"), 0, "If set, don't check for loops, start by interpreting *all* methods")
-RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_InterpreterUseCaching, W("InterpreterUseCaching"), 1, "If non-zero, use the caching mechanism.", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_InterpreterLooseRules, W("InterpreterLooseRules"), 1, "If non-zero, allow ECMA spec violations required by managed C++.", CLRConfig::EEConfig_default)
+RETAIL_CONFIG_DWORD_INFO(INTERNAL_InterpreterUseCaching, W("InterpreterUseCaching"), 1, "If non-zero, use the caching mechanism.")
+RETAIL_CONFIG_DWORD_INFO(INTERNAL_InterpreterLooseRules, W("InterpreterLooseRules"), 1, "If non-zero, allow ECMA spec violations required by managed C++.")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_InterpreterPrintPostMortem, W("InterpreterPrintPostMortem"), 0, "Prints summary information about the execution to the console")
-RETAIL_CONFIG_STRING_INFO_EX(INTERNAL_InterpreterLogFile, W("InterpreterLogFile"), "If non-null, append interpreter logging to this file, else use stdout", CLRConfig::EEConfig_default)
+RETAIL_CONFIG_STRING_INFO(INTERNAL_InterpreterLogFile, W("InterpreterLogFile"), "If non-null, append interpreter logging to this file, else use stdout")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_DumpInterpreterStubs, W("DumpInterpreterStubs"), 0, "Prints all interpreter stubs that are created to the console")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_TraceInterpreterEntries, W("TraceInterpreterEntries"), 0, "Logs entries to interpreted methods to the console")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_TraceInterpreterIL, W("TraceInterpreterIL"), 0, "Logs individual instructions of interpreted methods to the console")
@@ -416,7 +408,7 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_InterpreterFallback, W("InterpreterFallback"),
///
/// Loader heap
///
-CONFIG_DWORD_INFO_EX(INTERNAL_LoaderHeapCallTracing, W("LoaderHeapCallTracing"), 0, "Loader heap troubleshooting", CLRConfig::EEConfig_default)
+CONFIG_DWORD_INFO(INTERNAL_LoaderHeapCallTracing, W("LoaderHeapCallTracing"), 0, "Loader heap troubleshooting")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_CodeHeapReserveForJumpStubs, W("CodeHeapReserveForJumpStubs"), 1, "Percentage of code heap to reserve for jump stubs")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_NGenReserveForJumpStubs, W("NGenReserveForJumpStubs"), 0, "Percentage of ngen image size to reserve for jump stubs")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_BreakOnOutOfMemoryWithinRange, W("BreakOnOutOfMemoryWithinRange"), 0, "Break before out of memory within range exception is thrown")
@@ -424,48 +416,48 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_BreakOnOutOfMemoryWithinRange, W("BreakOnOutOf
///
/// Log
///
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_LogEnable, W("LogEnable"), "Turns on the traditional CLR log.")
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_LogFacility, W("LogFacility"), "Specifies a facility mask for CLR log. (See 'loglf.h'; VM interprets string value as hex number.) Also used by stresslog.")
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_LogFacility2, W("LogFacility2"), "Specifies a facility mask for CLR log. (See 'loglf.h'; VM interprets string value as hex number.) Also used by stresslog.")
+RETAIL_CONFIG_DWORD_INFO(INTERNAL_LogEnable, W("LogEnable"), 0, "Turns on the traditional CLR log.")
+RETAIL_CONFIG_DWORD_INFO(INTERNAL_LogFacility, W("LogFacility"), 0, "Specifies a facility mask for CLR log. (See 'loglf.h'; VM interprets string value as hex number.) Also used by stresslog.")
+RETAIL_CONFIG_DWORD_INFO(INTERNAL_LogFacility2, W("LogFacility2"), 0, "Specifies a facility mask for CLR log. (See 'loglf.h'; VM interprets string value as hex number.) Also used by stresslog.")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_logFatalError, W("logFatalError"), 1, "Specifies whether EventReporter logs fatal errors in the Windows event log.")
-CONFIG_STRING_INFO_EX(INTERNAL_LogFile, W("LogFile"), "Specifies a file name for the CLR log.", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_LogFileAppend, W("LogFileAppend"), "Specifies whether to append to or replace the CLR log file.")
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_LogFlushFile, W("LogFlushFile"), "Specifies whether to flush the CLR log file on each write.")
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_LogLevel, W("LogLevel"), "4=10 msgs, 9=1000000, 10=everything")
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_LogToConsole, W("LogToConsole"), "Writes the CLR log to console.")
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_LogToDebugger, W("LogToDebugger"), "Writes the CLR log to debugger (OutputDebugStringA).")
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_LogToFile, W("LogToFile"), "Writes the CLR log to a file.")
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_LogWithPid, W("LogWithPid"), "Appends pid to filename for the CLR log.")
+CONFIG_STRING_INFO(INTERNAL_LogFile, W("LogFile"), "Specifies a file name for the CLR log.")
+CONFIG_DWORD_INFO(INTERNAL_LogFileAppend, W("LogFileAppend"), 0 , "Specifies whether to append to or replace the CLR log file.")
+CONFIG_DWORD_INFO(INTERNAL_LogFlushFile, W("LogFlushFile"), 0 , "Specifies whether to flush the CLR log file on each write.")
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_LogLevel, W("LogLevel"), 0 , "4=10 msgs, 9=1000000, 10=everything")
+RETAIL_CONFIG_DWORD_INFO(INTERNAL_LogToConsole, W("LogToConsole"), 0 , "Writes the CLR log to console.")
+CONFIG_DWORD_INFO(INTERNAL_LogToDebugger, W("LogToDebugger"), 0 , "Writes the CLR log to debugger (OutputDebugStringA).")
+CONFIG_DWORD_INFO(INTERNAL_LogToFile, W("LogToFile"), 0 , "Writes the CLR log to a file.")
+CONFIG_DWORD_INFO(INTERNAL_LogWithPid, W("LogWithPid"), FALSE, "Appends pid to filename for the CLR log.")
///
/// MetaData
///
-CONFIG_DWORD_INFO_EX(INTERNAL_MD_ApplyDeltaBreak, W("MD_ApplyDeltaBreak"), 0, "ASSERT when applying EnC", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_AssertOnBadImageFormat, W("AssertOnBadImageFormat"), "ASSERT when invalid MD read")
-RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_MD_DeltaCheck, W("MD_DeltaCheck"), 1, "Some checks of GUID when applying EnC (?)", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_MD_EncDelta, W("MD_EncDelta"), 0, "Forces EnC Delta format in MD (?)", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_MD_ForceNoColDesSharing, W("MD_ForceNoColDesSharing"), 0, "Don't know - the only usage I could find is #if 0 (?)", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_MD_KeepKnownCA, W("MD_KeepKnownCA"), 0, "Something with known CAs (?)", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_MD_MiniMDBreak, W("MD_MiniMDBreak"), 0, "ASSERT when creating CMiniMdRw class", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_MD_PreSaveBreak, W("MD_PreSaveBreak"), 0, "ASSERT when calling CMiniMdRw::PreSave", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_MD_RegMetaBreak, W("MD_RegMetaBreak"), 0, "ASSERT when creating RegMeta class", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_MD_RegMetaDump, W("MD_RegMetaDump"), 0, "Dump MD in 4 functions (?)", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_DOTNET_MODIFIABLE_ASSEMBLIES, W("DOTNET_MODIFIABLE_ASSEMBLIES"), "Enables hot reload on debug built assemblies with the 'debug' keyword", CLRConfig::DontPrependCOMPlus_ | CLRConfig::TrimWhiteSpaceFromStringValue);
+CONFIG_DWORD_INFO(INTERNAL_MD_ApplyDeltaBreak, W("MD_ApplyDeltaBreak"), 0, "ASSERT when applying EnC")
+RETAIL_CONFIG_DWORD_INFO(INTERNAL_AssertOnBadImageFormat, W("AssertOnBadImageFormat"), 0, "ASSERT when invalid MD read")
+RETAIL_CONFIG_DWORD_INFO(INTERNAL_MD_DeltaCheck, W("MD_DeltaCheck"), 1, "Some checks of GUID when applying EnC (?)")
+CONFIG_DWORD_INFO(INTERNAL_MD_EncDelta, W("MD_EncDelta"), 0, "Forces EnC Delta format in MD (?)")
+RETAIL_CONFIG_DWORD_INFO(INTERNAL_MD_ForceNoColDesSharing, W("MD_ForceNoColDesSharing"), 0, "Don't know - the only usage I could find is #if 0 (?)")
+CONFIG_DWORD_INFO(INTERNAL_MD_KeepKnownCA, W("MD_KeepKnownCA"), 0, "Something with known CAs (?)")
+CONFIG_DWORD_INFO(INTERNAL_MD_MiniMDBreak, W("MD_MiniMDBreak"), 0, "ASSERT when creating CMiniMdRw class")
+CONFIG_DWORD_INFO(INTERNAL_MD_PreSaveBreak, W("MD_PreSaveBreak"), 0, "ASSERT when calling CMiniMdRw::PreSave")
+CONFIG_DWORD_INFO(INTERNAL_MD_RegMetaBreak, W("MD_RegMetaBreak"), 0, "ASSERT when creating RegMeta class")
+CONFIG_DWORD_INFO(INTERNAL_MD_RegMetaDump, W("MD_RegMetaDump"), 0, "Dump MD in 4 functions (?)")
+RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_DOTNET_MODIFIABLE_ASSEMBLIES, W("DOTNET_MODIFIABLE_ASSEMBLIES"), "Enables hot reload on debug built assemblies with the 'debug' keyword", CLRConfig::LookupOptions::DontPrependCOMPlus_ | CLRConfig::LookupOptions::TrimWhiteSpaceFromStringValue);
// Metadata - mscordbi only - this flag is only intended to mitigate potential issues in bug fix 458597.
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_MD_PreserveDebuggerMetadataMemory, W("MD_PreserveDebuggerMetadataMemory"), 0, "Save all versions of metadata memory in the debugger when debuggee metadata is updated", CLRConfig::EEConfig_default)
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_MD_PreserveDebuggerMetadataMemory, W("MD_PreserveDebuggerMetadataMemory"), 0, "Save all versions of metadata memory in the debugger when debuggee metadata is updated")
///
/// Spinning heuristics
///
// Note that these only take effect once the runtime has been started; prior to that the values hardcoded in g_SpinConstants (vars.cpp) are used
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_SpinInitialDuration, W("SpinInitialDuration"), 0x32, "Hex value specifying the first spin duration", EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_SpinBackoffFactor, W("SpinBackoffFactor"), 0x3, "Hex value specifying the growth of each successive spin duration", EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_SpinLimitProcCap, W("SpinLimitProcCap"), 0xFFFFFFFF, "Hex value specifying the largest value of NumProcs to use when calculating the maximum spin duration", EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_SpinLimitProcFactor, W("SpinLimitProcFactor"), 0x4E20, "Hex value specifying the multiplier on NumProcs to use when calculating the maximum spin duration", EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_SpinLimitConstant, W("SpinLimitConstant"), 0x0, "Hex value specifying the constant to add when calculating the maximum spin duration", EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_SpinRetryCount, W("SpinRetryCount"), 0xA, "Hex value specifying the number of times the entire spin process is repeated (when applicable)", EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_Monitor_SpinCount, W("Monitor_SpinCount"), 0x1e, "Hex value specifying the maximum number of spin iterations Monitor may perform upon contention on acquiring the lock before waiting.", EEConfig_default)
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_SpinInitialDuration, W("SpinInitialDuration"), 0x32, "Hex value specifying the first spin duration")
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_SpinBackoffFactor, W("SpinBackoffFactor"), 0x3, "Hex value specifying the growth of each successive spin duration")
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_SpinLimitProcCap, W("SpinLimitProcCap"), 0xFFFFFFFF, "Hex value specifying the largest value of NumProcs to use when calculating the maximum spin duration")
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_SpinLimitProcFactor, W("SpinLimitProcFactor"), 0x4E20, "Hex value specifying the multiplier on NumProcs to use when calculating the maximum spin duration")
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_SpinLimitConstant, W("SpinLimitConstant"), 0x0, "Hex value specifying the constant to add when calculating the maximum spin duration")
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_SpinRetryCount, W("SpinRetryCount"), 0xA, "Hex value specifying the number of times the entire spin process is repeated (when applicable)")
+RETAIL_CONFIG_DWORD_INFO(INTERNAL_Monitor_SpinCount, W("Monitor_SpinCount"), 0x1e, "Hex value specifying the maximum number of spin iterations Monitor may perform upon contention on acquiring the lock before waiting.")
///
/// Native Binder
@@ -475,27 +467,26 @@ CONFIG_DWORD_INFO(INTERNAL_NgenBind_ZapForbid, W("NgenBind_ZapForbid
CONFIG_STRING_INFO(INTERNAL_NgenBind_ZapForbidExcludeList, W("NgenBind_ZapForbidExcludeList"), "")
CONFIG_STRING_INFO(INTERNAL_NgenBind_ZapForbidList, W("NgenBind_ZapForbidList"), "")
-CONFIG_DWORD_INFO_EX(INTERNAL_SymDiffDump, W("SymDiffDump"), 0, "Used to create the map file while binding the assembly. Used by SemanticDiffer", CLRConfig::EEConfig_default)
+CONFIG_DWORD_INFO(INTERNAL_SymDiffDump, W("SymDiffDump"), 0, "Used to create the map file while binding the assembly. Used by SemanticDiffer")
///
/// NGEN
///
-RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_NGen_JitName, W("NGen_JitName"), "", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_NGenFramed, W("NGenFramed"), (DWORD)-1, "Same as JitFramed, but for ngen", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_NGenOnlyOneMethod, W("NGenOnlyOneMethod"), 0, "", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_NgenOrder, W("NgenOrder"), 0, "", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_partialNGenStress, W("partialNGenStress"), 0, "", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_ZapDoNothing, W("ZapDoNothing"), 0, "", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_NgenForceFailureMask, W("NgenForceFailureMask"), (DWORD)-1, "Bitmask used to control which locations will check and raise the failure (defaults to bits: -1)", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_NgenForceFailureCount, W("NgenForceFailureCount"), 0, "If set to >0 and we have IBC data we will force a failure after we reference an IBC data item times", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_NgenForceFailureKind, W("NgenForceFailureKind"), 1, "If set to 1, We will throw a TypeLoad exception; If set to 2, We will cause an A/V", CLRConfig::EEConfig_default)
+RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_NGenFramed, W("NGenFramed"), (DWORD)-1, "Same as JitFramed, but for ngen")
+CONFIG_DWORD_INFO(INTERNAL_NGenOnlyOneMethod, W("NGenOnlyOneMethod"), 0, "")
+CONFIG_DWORD_INFO(INTERNAL_NgenOrder, W("NgenOrder"), 0, "")
+CONFIG_DWORD_INFO(INTERNAL_partialNGenStress, W("partialNGenStress"), 0, "")
+CONFIG_DWORD_INFO(INTERNAL_ZapDoNothing, W("ZapDoNothing"), 0, "")
+CONFIG_DWORD_INFO(INTERNAL_NgenForceFailureMask, W("NgenForceFailureMask"), (DWORD)-1, "Bitmask used to control which locations will check and raise the failure (defaults to bits: -1)")
+CONFIG_DWORD_INFO(INTERNAL_NgenForceFailureCount, W("NgenForceFailureCount"), 0, "If set to >0 and we have IBC data we will force a failure after we reference an IBC data item times")
+CONFIG_DWORD_INFO(INTERNAL_NgenForceFailureKind, W("NgenForceFailureKind"), 1, "If set to 1, We will throw a TypeLoad exception; If set to 2, We will cause an A/V")
RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_NGenEnableCreatePdb, W("NGenEnableCreatePdb"), 0, "If set to >0 ngen.exe displays help on, recognizes createpdb in the command line")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_NGenSimulateDiskFull, W("NGenSimulateDiskFull"), 0, "If set to 1, ngen will throw a Disk full exception in ZapWriter.cpp:Save()")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_PartialNGen, W("PartialNGen"), (DWORD)-1, "Generate partial NGen images")
CONFIG_DWORD_INFO(INTERNAL_NoASLRForNgen, W("NoASLRForNgen"), 0, "Turn off IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE bit in generated ngen images. Makes nidump output repeatable from run to run.")
-RETAIL_CONFIG_STRING_INFO_EX(INTERNAL_NativeImageSearchPaths, W("NativeImageSearchPaths"), "Extra search paths for native composite R2R images", CLRConfig::EEConfig_default)
+RETAIL_CONFIG_STRING_INFO(INTERNAL_NativeImageSearchPaths, W("NativeImageSearchPaths"), "Extra search paths for native composite R2R images")
#ifdef CROSSGEN_COMPILE
RETAIL_CONFIG_DWORD_INFO(INTERNAL_CrossGenAssumeInputSigned, W("CrossGenAssumeInputSigned"), 1, "CrossGen should assume that its input assemblies will be signed before deployment")
@@ -504,19 +495,19 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_CrossGenAssumeInputSigned, W("CrossGenAssumeIn
///
/// Profiling API / ETW
///
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_COR_ENABLE_PROFILING, W("COR_ENABLE_PROFILING"), 0, "Flag to indicate whether profiling should be enabled for the currently running process.", CLRConfig::DontPrependCOMPlus_)
-RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_COR_PROFILER, W("COR_PROFILER"), "Specifies GUID of profiler to load into currently running process", CLRConfig::DontPrependCOMPlus_)
-RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_COR_PROFILER_PATH, W("COR_PROFILER_PATH"), "Specifies the path to the DLL of profiler to load into currently running process", CLRConfig::DontPrependCOMPlus_)
-RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_COR_PROFILER_PATH_32, W("COR_PROFILER_PATH_32"), "Specifies the path to the DLL of profiler to load into currently running 32 bits process", CLRConfig::DontPrependCOMPlus_)
-RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_COR_PROFILER_PATH_64, W("COR_PROFILER_PATH_64"), "Specifies the path to the DLL of profiler to load into currently running 64 bits process", CLRConfig::DontPrependCOMPlus_)
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_CORECLR_ENABLE_PROFILING, W("CORECLR_ENABLE_PROFILING"), 0, "CoreCLR only: Flag to indicate whether profiling should be enabled for the currently running process.", CLRConfig::DontPrependCOMPlus_)
-RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_CORECLR_PROFILER, W("CORECLR_PROFILER"), "CoreCLR only: Specifies GUID of profiler to load into currently running process", CLRConfig::DontPrependCOMPlus_)
-RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_CORECLR_PROFILER_PATH, W("CORECLR_PROFILER_PATH"), "CoreCLR only: Specifies the path to the DLL of profiler to load into currently running process", CLRConfig::DontPrependCOMPlus_)
-RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_CORECLR_PROFILER_PATH_32, W("CORECLR_PROFILER_PATH_32"), "CoreCLR only: Specifies the path to the DLL of profiler to load into currently running 32 process", CLRConfig::DontPrependCOMPlus_)
-RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_CORECLR_PROFILER_PATH_64, W("CORECLR_PROFILER_PATH_64"), "CoreCLR only: Specifies the path to the DLL of profiler to load into currently running 64 process", CLRConfig::DontPrependCOMPlus_)
-RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_CORECLR_PROFILER_PATH_ARM32, W("CORECLR_PROFILER_PATH_ARM32"), "CoreCLR only: Specifies the path to the DLL of profiler to load into currently running ARM32 process", CLRConfig::DontPrependCOMPlus_)
-RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_CORECLR_PROFILER_PATH_ARM64, W("CORECLR_PROFILER_PATH_ARM64"), "CoreCLR only: Specifies the path to the DLL of profiler to load into currently running ARM64 process", CLRConfig::DontPrependCOMPlus_)
-RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_ProfAPI_ProfilerCompatibilitySetting, W("ProfAPI_ProfilerCompatibilitySetting"), "Specifies the profiler loading policy (the default is not to load a V2 profiler in V4)", CLRConfig::EEConfig_default | CLRConfig::TrimWhiteSpaceFromStringValue)
+RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_COR_ENABLE_PROFILING, W("COR_ENABLE_PROFILING"), 0, "Flag to indicate whether profiling should be enabled for the currently running process.", CLRConfig::LookupOptions::DontPrependCOMPlus_)
+RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_COR_PROFILER, W("COR_PROFILER"), "Specifies GUID of profiler to load into currently running process", CLRConfig::LookupOptions::DontPrependCOMPlus_)
+RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_COR_PROFILER_PATH, W("COR_PROFILER_PATH"), "Specifies the path to the DLL of profiler to load into currently running process", CLRConfig::LookupOptions::DontPrependCOMPlus_)
+RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_COR_PROFILER_PATH_32, W("COR_PROFILER_PATH_32"), "Specifies the path to the DLL of profiler to load into currently running 32 bits process", CLRConfig::LookupOptions::DontPrependCOMPlus_)
+RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_COR_PROFILER_PATH_64, W("COR_PROFILER_PATH_64"), "Specifies the path to the DLL of profiler to load into currently running 64 bits process", CLRConfig::LookupOptions::DontPrependCOMPlus_)
+RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_CORECLR_ENABLE_PROFILING, W("CORECLR_ENABLE_PROFILING"), 0, "CoreCLR only: Flag to indicate whether profiling should be enabled for the currently running process.", CLRConfig::LookupOptions::DontPrependCOMPlus_)
+RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_CORECLR_PROFILER, W("CORECLR_PROFILER"), "CoreCLR only: Specifies GUID of profiler to load into currently running process", CLRConfig::LookupOptions::DontPrependCOMPlus_)
+RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_CORECLR_PROFILER_PATH, W("CORECLR_PROFILER_PATH"), "CoreCLR only: Specifies the path to the DLL of profiler to load into currently running process", CLRConfig::LookupOptions::DontPrependCOMPlus_)
+RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_CORECLR_PROFILER_PATH_32, W("CORECLR_PROFILER_PATH_32"), "CoreCLR only: Specifies the path to the DLL of profiler to load into currently running 32 process", CLRConfig::LookupOptions::DontPrependCOMPlus_)
+RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_CORECLR_PROFILER_PATH_64, W("CORECLR_PROFILER_PATH_64"), "CoreCLR only: Specifies the path to the DLL of profiler to load into currently running 64 process", CLRConfig::LookupOptions::DontPrependCOMPlus_)
+RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_CORECLR_PROFILER_PATH_ARM32, W("CORECLR_PROFILER_PATH_ARM32"), "CoreCLR only: Specifies the path to the DLL of profiler to load into currently running ARM32 process", CLRConfig::LookupOptions::DontPrependCOMPlus_)
+RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_CORECLR_PROFILER_PATH_ARM64, W("CORECLR_PROFILER_PATH_ARM64"), "CoreCLR only: Specifies the path to the DLL of profiler to load into currently running ARM64 process", CLRConfig::LookupOptions::DontPrependCOMPlus_)
+RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_ProfAPI_ProfilerCompatibilitySetting, W("ProfAPI_ProfilerCompatibilitySetting"), "Specifies the profiler loading policy (the default is not to load a V2 profiler in V4)", CLRConfig::LookupOptions::TrimWhiteSpaceFromStringValue)
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_ProfAPI_DetachMinSleepMs, W("ProfAPI_DetachMinSleepMs"), 0, "The minimum time, in milliseconds, the CLR will wait before checking whether a profiler that is in the process of detaching is ready to be unloaded.")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_ProfAPI_DetachMaxSleepMs, W("ProfAPI_DetachMaxSleepMs"), 0, "The maximum time, in milliseconds, the CLR will wait before checking whether a profiler that is in the process of detaching is ready to be unloaded.")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_ProfAPI_RejitOnAttach, W("ProfApi_RejitOnAttach"), 1, "Enables the ability for profilers to rejit methods on attach.")
@@ -528,13 +519,13 @@ CONFIG_DWORD_INFO(INTERNAL_TestOnlyEnableICorProfilerInfo, W("ProfAPI_TestOnlyEn
CONFIG_DWORD_INFO(INTERNAL_TestOnlyEnableObjectAllocatedHook, W("TestOnlyEnableObjectAllocatedHook"), 0, "Test-only flag that forces CLR to initialize on startup as if ObjectAllocated callback were requested, to enable post-attach ObjectAllocated functionality.")
CONFIG_DWORD_INFO(INTERNAL_TestOnlyEnableSlowELTHooks, W("TestOnlyEnableSlowELTHooks"), 0, "Test-only flag that forces CLR to initialize on startup as if slow-ELT were requested, to enable post-attach ELT functionality.")
-RETAIL_CONFIG_STRING_INFO_EX(UNSUPPORTED_ETW_ObjectAllocationEventsPerTypePerSec, W("ETW_ObjectAllocationEventsPerTypePerSec"), "Desired number of GCSampledObjectAllocation ETW events to be logged per type per second. If 0, then the default built in to the implementation for the enabled event (e.g., High, Low), will be used.", CLRConfig::EEConfig_default)
+RETAIL_CONFIG_STRING_INFO(UNSUPPORTED_ETW_ObjectAllocationEventsPerTypePerSec, W("ETW_ObjectAllocationEventsPerTypePerSec"), "Desired number of GCSampledObjectAllocation ETW events to be logged per type per second. If 0, then the default built in to the implementation for the enabled event (e.g., High, Low), will be used.")
RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_ProfAPI_ValidateNGENInstrumentation, W("ProfAPI_ValidateNGENInstrumentation"), 0, "This flag enables additional validations when using the IMetaDataEmit APIs for NGEN'ed images to ensure only supported edits are made.")
#ifdef FEATURE_PERFMAP
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_PerfMapEnabled, W("PerfMapEnabled"), 0, "This flag is used on Linux to enable writing /tmp/perf-$pid.map. It is disabled by default", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_PerfMapJitDumpPath, W("PerfMapJitDumpPath"), "Specifies a path to write the perf jitdump file. Defaults to GetTempPathA()", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_PerfMapIgnoreSignal, W("PerfMapIgnoreSignal"), 0, "When perf map is enabled, this option will configure the specified signal to be accepted and ignored as a marker in the perf logs. It is disabled by default", CLRConfig::EEConfig_default)
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_PerfMapEnabled, W("PerfMapEnabled"), 0, "This flag is used on Linux to enable writing /tmp/perf-$pid.map. It is disabled by default")
+RETAIL_CONFIG_STRING_INFO(EXTERNAL_PerfMapJitDumpPath, W("PerfMapJitDumpPath"), "Specifies a path to write the perf jitdump file. Defaults to GetTempPathA()")
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_PerfMapIgnoreSignal, W("PerfMapIgnoreSignal"), 0, "When perf map is enabled, this option will configure the specified signal to be accepted and ignored as a marker in the perf logs. It is disabled by default")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_PerfMapShowOptimizationTiers, W("PerfMapShowOptimizationTiers"), 1, "Shows optimization tiers in the perf map for methods, as part of the symbol name. Useful for seeing separate stack frames for different optimization tiers of each method.")
RETAIL_CONFIG_STRING_INFO(EXTERNAL_NativeImagePerfMapFormat, W("NativeImagePerfMapFormat"), "Specifies the format of native image perfmap files generated by crossgen. Valid options are RVA or OFFSET.")
#endif
@@ -544,13 +535,12 @@ RETAIL_CONFIG_STRING_INFO(EXTERNAL_StartupDelayMS, W("StartupDelayMS"), "")
///
/// Stress
///
-CONFIG_DWORD_INFO_EX(INTERNAL_StressCOMCall, W("StressCOMCall"), 0, "", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_StressLog, W("StressLog"), "Turns on the stress log.")
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_ForceEnc, W("ForceEnc"), "Forces Edit and Continue to be on for all eligible modules.")
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_StressLogSize, W("StressLogSize"), "Stress log size in bytes per thread.")
-RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(UNSUPPORTED_StressLogFilename, W("StressLogFilename"), "Stress log filename for memory mapped stress log.")
-CONFIG_DWORD_INFO_EX(INTERNAL_stressSynchronized, W("stressSynchronized"), 0, "Unknown if or where this is used; unless a test is specifically depending on this, it can be removed.", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_StressThreadCount, W("StressThreadCount"), "")
+RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_StressLog, W("StressLog"), 0, "Turns on the stress log.")
+RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_ForceEnc, W("ForceEnc"), 0, "Forces Edit and Continue to be on for all eligible modules.")
+RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_StressLogSize, W("StressLogSize"), 0, "Stress log size in bytes per thread.")
+RETAIL_CONFIG_STRING_INFO(UNSUPPORTED_StressLogFilename, W("StressLogFilename"), "Stress log filename for memory mapped stress log.")
+CONFIG_DWORD_INFO(INTERNAL_stressSynchronized, W("stressSynchronized"), 0, "Unknown if or where this is used; unless a test is specifically depending on this, it can be removed.")
+RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_TotalStressLogSize, W("TotalStressLogSize"), 0, "Total stress log size in bytes.")
///
/// Thread Suspend
@@ -635,7 +625,7 @@ CONFIG_DWORD_INFO(INTERNAL_OSR_HighId, W("OSR_HighId"), 10000000, "High end of e
/// Profile Guided Opts
///
#ifdef FEATURE_PGO
-RETAIL_CONFIG_STRING_INFO_EX(INTERNAL_PGODataPath, W("PGODataPath"), "Read/Write PGO data from/to the indicated file.", CLRConfig::EEConfig_default)
+RETAIL_CONFIG_STRING_INFO(INTERNAL_PGODataPath, W("PGODataPath"), "Read/Write PGO data from/to the indicated file.")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_ReadPGOData, W("ReadPGOData"), 0, "Read PGO data")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_WritePGOData, W("WritePGOData"), 0, "Write PGO data")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_TieredPGO, W("TieredPGO"), 0, "Instrument Tier0 code and make counts available to Tier1")
@@ -656,14 +646,14 @@ CONFIG_DWORD_INFO(INTERNAL_TypeLoader_InjectInterfaceDuplicates, W("INTERNAL_Typ
///
/// Virtual call stubs
///
-CONFIG_DWORD_INFO_EX(INTERNAL_VirtualCallStubCollideMonoPct, W("VirtualCallStubCollideMonoPct"), 0, "Used only when STUB_LOGGING is defined, which by default is not.", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_VirtualCallStubCollideWritePct, W("VirtualCallStubCollideWritePct"), 100, "Used only when STUB_LOGGING is defined, which by default is not.", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_VirtualCallStubDumpLogCounter, W("VirtualCallStubDumpLogCounter"), 0, "Used only when STUB_LOGGING is defined, which by default is not.", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_VirtualCallStubDumpLogIncr, W("VirtualCallStubDumpLogIncr"), 0, "Used only when STUB_LOGGING is defined, which by default is not.", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_VirtualCallStubLogging, W("VirtualCallStubLogging"), 0, "Worth keeping, but should be moved into \"#ifdef STUB_LOGGING\" blocks. This goes for most (or all) of the stub logging infrastructure.", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_VirtualCallStubMissCount, W("VirtualCallStubMissCount"), 100, "Used only when STUB_LOGGING is defined, which by default is not.", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_VirtualCallStubResetCacheCounter, W("VirtualCallStubResetCacheCounter"), 0, "Used only when STUB_LOGGING is defined, which by default is not.", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_VirtualCallStubResetCacheIncr, W("VirtualCallStubResetCacheIncr"), 0, "Used only when STUB_LOGGING is defined, which by default is not.", CLRConfig::EEConfig_default)
+CONFIG_DWORD_INFO(INTERNAL_VirtualCallStubCollideMonoPct, W("VirtualCallStubCollideMonoPct"), 0, "Used only when STUB_LOGGING is defined, which by default is not.")
+CONFIG_DWORD_INFO(INTERNAL_VirtualCallStubCollideWritePct, W("VirtualCallStubCollideWritePct"), 100, "Used only when STUB_LOGGING is defined, which by default is not.")
+CONFIG_DWORD_INFO(INTERNAL_VirtualCallStubDumpLogCounter, W("VirtualCallStubDumpLogCounter"), 0, "Used only when STUB_LOGGING is defined, which by default is not.")
+CONFIG_DWORD_INFO(INTERNAL_VirtualCallStubDumpLogIncr, W("VirtualCallStubDumpLogIncr"), 0, "Used only when STUB_LOGGING is defined, which by default is not.")
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_VirtualCallStubLogging, W("VirtualCallStubLogging"), 0, "Worth keeping, but should be moved into \"#ifdef STUB_LOGGING\" blocks. This goes for most (or all) of the stub logging infrastructure.")
+CONFIG_DWORD_INFO(INTERNAL_VirtualCallStubMissCount, W("VirtualCallStubMissCount"), 100, "Used only when STUB_LOGGING is defined, which by default is not.")
+CONFIG_DWORD_INFO(INTERNAL_VirtualCallStubResetCacheCounter, W("VirtualCallStubResetCacheCounter"), 0, "Used only when STUB_LOGGING is defined, which by default is not.")
+CONFIG_DWORD_INFO(INTERNAL_VirtualCallStubResetCacheIncr, W("VirtualCallStubResetCacheIncr"), 0, "Used only when STUB_LOGGING is defined, which by default is not.")
///
/// Watson
@@ -681,15 +671,15 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_CreateDumpDiagnostics, W("CreateDumpDiagnostic
///
/// Zap
///
-RETAIL_CONFIG_STRING_INFO_EX(INTERNAL_ZapBBInstr, W("ZapBBInstr"), "", CLRConfig::EEConfig_default)
+RETAIL_CONFIG_STRING_INFO(INTERNAL_ZapBBInstr, W("ZapBBInstr"), "")
RETAIL_CONFIG_STRING_INFO(EXTERNAL_ZapBBInstrDir, W("ZapBBInstrDir"), "")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_ZapDisable, W("ZapDisable"), 0, "")
-CONFIG_STRING_INFO_EX(INTERNAL_ZapExclude, W("ZapExclude"), "", CLRConfig::EEConfig_default)
-CONFIG_STRING_INFO_EX(INTERNAL_ZapOnly, W("ZapOnly"), "", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_ZapRequire, W("ZapRequire"), "")
+CONFIG_STRING_INFO(INTERNAL_ZapExclude, W("ZapExclude"), "")
+CONFIG_STRING_INFO(INTERNAL_ZapOnly, W("ZapOnly"), "")
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_ZapRequire, W("ZapRequire"), 0, "")
RETAIL_CONFIG_STRING_INFO(EXTERNAL_ZapRequireExcludeList, W("ZapRequireExcludeList"), "")
RETAIL_CONFIG_STRING_INFO(EXTERNAL_ZapRequireList, W("ZapRequireList"), "")
-RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_ZapSet, W("ZapSet"), "", CLRConfig::EEConfig_default)
+RETAIL_CONFIG_STRING_INFO(EXTERNAL_ZapSet, W("ZapSet"), "")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_ReadyToRun, W("ReadyToRun"), 1, "Enable/disable use of ReadyToRun native code") // On by default for CoreCLR
RETAIL_CONFIG_STRING_INFO(EXTERNAL_ReadyToRunExcludeList, W("ReadyToRunExcludeList"), "List of assemblies that cannot use Ready to Run images")
@@ -704,12 +694,11 @@ RETAIL_CONFIG_STRING_INFO(INTERNAL_EventNameFilter, W("EventNameFilter"), "")
///
/// Interop
///
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_ExposeExceptionsInCOM, W("ExposeExceptionsInCOM"), "")
+CONFIG_DWORD_INFO(INTERNAL_ExposeExceptionsInCOM, W("ExposeExceptionsInCOM"), 0, "")
RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_InteropValidatePinnedObjects, W("InteropValidatePinnedObjects"), 0, "After returning from a managed-to-unmanaged interop call, validate GC heap around objects pinned by IL stubs.")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_InteropLogArguments, W("InteropLogArguments"), 0, "Log all pinned arguments passed to an interop call")
RETAIL_CONFIG_STRING_INFO(UNSUPPORTED_LogCCWRefCountChange, W("LogCCWRefCountChange"), "Outputs debug information and calls LogCCWRefCountChange_BREAKPOINT when AddRef or Release is called on a CCW.")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_EnableRCWCleanupOnSTAShutdown, W("EnableRCWCleanupOnSTAShutdown"), 0, "Performs RCW cleanup when STA shutdown is detected using IInitializeSpy in classic processes.")
-RETAIL_CONFIG_DWORD_INFO(EXTERNAL_AllowDComReflection, W("AllowDComReflection"), 0, "Allows out of process DCOM clients to marshal blocked reflection types.")
//
// EventPipe
@@ -733,14 +722,14 @@ RETAIL_CONFIG_STRING_INFO(INTERNAL_GCGenAnalysisCmd, W("GCGenAnalysisCmd"), "An
//
// Diagnostics Ports
//
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_DOTNET_DefaultDiagnosticPortSuspend, W("DOTNET_DefaultDiagnosticPortSuspend"), 0, "This sets the deafult diagnostic port to suspend causing the runtime to pause during startup before major subsystems are started. Resume using the Diagnostics IPC ResumeStartup command on the default diagnostic port.", CLRConfig::DontPrependCOMPlus_);
-RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_DOTNET_DiagnosticPorts, W("DOTNET_DiagnosticPorts"), "A semicolon delimited list of additional Diagnostic Ports, where a Diagnostic Port is a NamedPipe path without '\\\\.\\pipe\\' on Windows or the full path of Unix Domain Socket on Linux/Unix followed by optional tags, e.g., ',connect,nosuspend;'", CLRConfig::DontPrependCOMPlus_);
+RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_DOTNET_DefaultDiagnosticPortSuspend, W("DOTNET_DefaultDiagnosticPortSuspend"), 0, "This sets the deafult diagnostic port to suspend causing the runtime to pause during startup before major subsystems are started. Resume using the Diagnostics IPC ResumeStartup command on the default diagnostic port.", CLRConfig::LookupOptions::DontPrependCOMPlus_);
+RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_DOTNET_DiagnosticPorts, W("DOTNET_DiagnosticPorts"), "A semicolon delimited list of additional Diagnostic Ports, where a Diagnostic Port is a NamedPipe path without '\\\\.\\pipe\\' on Windows or the full path of Unix Domain Socket on Linux/Unix followed by optional tags, e.g., ',connect,nosuspend;'", CLRConfig::LookupOptions::DontPrependCOMPlus_);
//
// LTTng
//
RETAIL_CONFIG_STRING_INFO(INTERNAL_LTTngConfig, W("LTTngConfig"), "Configuration for LTTng.")
-RETAIL_CONFIG_DWORD_INFO(UNSUPORTED_LTTng, W("LTTng"), 1, "If COMPlus_LTTng is set to 0, this will prevent the LTTng library from being loaded at runtime")
+RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_LTTng, W("LTTng"), 1, "If COMPlus_LTTng is set to 0, this will prevent the LTTng library from being loaded at runtime")
#ifdef FEATURE_GDBJIT
@@ -765,37 +754,33 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_GDBJitEmitDebugFrame, W("GDBJitEmitDebugFrame"
//
// DO NOT ADD ANY MORE CONFIG SWITCHES TO THIS SECTION!
// **
-CONFIG_DWORD_INFO_EX(INTERNAL_ActivatePatchSkip, W("ActivatePatchSkip"), 0, "Allows an assert when ActivatePatchSkip is called", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_AlwaysUseMetadataInterfaceMapLayout, W("AlwaysUseMetadataInterfaceMapLayout"), "Used for debugging generic interface map layout.")
+CONFIG_DWORD_INFO(INTERNAL_ActivatePatchSkip, W("ActivatePatchSkip"), 0, "Allows an assert when ActivatePatchSkip is called")
+CONFIG_DWORD_INFO(INTERNAL_AlwaysUseMetadataInterfaceMapLayout, W("AlwaysUseMetadataInterfaceMapLayout"), 0, "Used for debugging generic interface map layout.")
CONFIG_DWORD_INFO(INTERNAL_AssertOnUnneededThis, W("AssertOnUnneededThis"), 0, "While the ConfigDWORD is unnecessary, the contained ASSERT should be kept. This may result in some work tracking down violating MethodDescCallSites.")
-CONFIG_DWORD_INFO_EX(INTERNAL_AssertStacktrace, W("AssertStacktrace"), 1, "", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_clearNativeImageStress, W("clearNativeImageStress"), 0, "", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_CPUFamily, W("CPUFamily"), "")
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_CPUFeatures, W("CPUFeatures"), "")
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_DisableConfigCache, W("DisableConfigCache"), 0, "Used to disable the \"probabilistic\" config cache, which walks through the appropriate config registry keys on init and probabilistically keeps track of which exist.", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_DisableStackwalkCache, W("DisableStackwalkCache"), "")
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_DoubleArrayToLargeObjectHeap, W("DoubleArrayToLargeObjectHeap"), "Controls double[] placement")
+CONFIG_DWORD_INFO(INTERNAL_AssertStacktrace, W("AssertStacktrace"), 1, "")
+CONFIG_DWORD_INFO(INTERNAL_clearNativeImageStress, W("clearNativeImageStress"), 0, "")
+CONFIG_DWORD_INFO(INTERNAL_CPUFamily, W("CPUFamily"), 0xFFFFFFFF, "")
+CONFIG_DWORD_INFO(INTERNAL_CPUFeatures, W("CPUFeatures"), 0xFFFFFFFF, "")
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_DisableConfigCache, W("DisableConfigCache"), 0, "Used to disable the \"probabilistic\" config cache, which walks through the appropriate config registry keys on init and probabilistically keeps track of which exist.")
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_DisableStackwalkCache, W("DisableStackwalkCache"), 0, "")
+RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_DoubleArrayToLargeObjectHeap, W("DoubleArrayToLargeObjectHeap"), 0, "Controls double[] placement")
CONFIG_STRING_INFO(INTERNAL_DumpOnClassLoad, W("DumpOnClassLoad"), "Dumps information about loaded class to log.")
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_ExpandAllOnLoad, W("ExpandAllOnLoad"), "")
-CONFIG_STRING_INFO_DIRECT_ACCESS(INTERNAL_ForcedRuntime, W("ForcedRuntime"), "Verify version of CLR loaded")
-CONFIG_DWORD_INFO_EX(INTERNAL_ForceRelocs, W("ForceRelocs"), 0, "", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_GenerateLongJumpDispatchStubRatio, W("GenerateLongJumpDispatchStubRatio"), "Useful for testing VSD on AMD64")
-CONFIG_DWORD_INFO_EX(INTERNAL_HashStack, W("HashStack"), 0, "", CLRConfig::EEConfig_default)
+CONFIG_DWORD_INFO(INTERNAL_ExpandAllOnLoad, W("ExpandAllOnLoad"), 0, "")
+CONFIG_DWORD_INFO(INTERNAL_ForceRelocs, W("ForceRelocs"), 0, "")
+CONFIG_DWORD_INFO(INTERNAL_GenerateLongJumpDispatchStubRatio, W("GenerateLongJumpDispatchStubRatio"), 0, "Useful for testing VSD on AMD64")
+CONFIG_DWORD_INFO(INTERNAL_HashStack, W("HashStack"), 0, "")
CONFIG_DWORD_INFO(INTERNAL_HostManagerConfig, W("HostManagerConfig"), (DWORD)-1, "")
CONFIG_DWORD_INFO(INTERNAL_HostTestThreadAbort, W("HostTestThreadAbort"), 0, "")
CONFIG_STRING_INFO(INTERNAL_InvokeHalt, W("InvokeHalt"), "Throws an assert when the given method is invoked through reflection.")
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_MaxStackDepth, W("MaxStackDepth"), "")
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_MaxStubUnwindInfoSegmentSize, W("MaxStubUnwindInfoSegmentSize"), "")
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_MaxThreadRecord, W("MaxThreadRecord"), "")
+CONFIG_DWORD_INFO(INTERNAL_MaxStubUnwindInfoSegmentSize, W("MaxStubUnwindInfoSegmentSize"), 0, "")
CONFIG_DWORD_INFO(INTERNAL_MessageDebugOut, W("MessageDebugOut"), 0, "")
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_NativeImageRequire, W("NativeImageRequire"), 0, "", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_NestedEhOom, W("NestedEhOom"), 0, "", CLRConfig::EEConfig_default)
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_NativeImageRequire, W("NativeImageRequire"), 0, "")
+CONFIG_DWORD_INFO(INTERNAL_NestedEhOom, W("NestedEhOom"), 0, "")
#define INTERNAL_NoGuiOnAssert_Default 1
-RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_NoGuiOnAssert, W("NoGuiOnAssert"), INTERNAL_NoGuiOnAssert_Default, "", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_NoProcedureSplitting, W("NoProcedureSplitting"), 0, "", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_NoStringInterning, W("NoStringInterning"), 1, "Disallows string interning. I see no value in it anymore.", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_NotifyBadAppCfg, W("NotifyBadAppCfg"), "Whether to show a message box for bad application config file.")
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_PauseOnLoad, W("PauseOnLoad"), "Stops in SystemDomain::init. I think it can be removed.")
+RETAIL_CONFIG_DWORD_INFO(INTERNAL_NoGuiOnAssert, W("NoGuiOnAssert"), INTERNAL_NoGuiOnAssert_Default, "")
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_NoProcedureSplitting, W("NoProcedureSplitting"), 0, "")
+CONFIG_DWORD_INFO(INTERNAL_NoStringInterning, W("NoStringInterning"), 1, "Disallows string interning. I see no value in it anymore.")
+CONFIG_DWORD_INFO(INTERNAL_PauseOnLoad, W("PauseOnLoad"), 0, "Stops in SystemDomain::init. I think it can be removed.")
CONFIG_DWORD_INFO(INTERNAL_PerfAllocsSizeThreshold, W("PerfAllocsSizeThreshold"), 0x3FFFFFFF, "Log facility LF_GCALLOC logs object allocations. This flag controls which ones also log stacktraces. Predates ClrProfiler.")
CONFIG_DWORD_INFO(INTERNAL_PerfNumAllocsThreshold, W("PerfNumAllocsThreshold"), 0x3FFFFFFF, "Log facility LF_GCALLOC logs object allocations. This flag controls which ones also log stacktraces. Predates ClrProfiler.")
CONFIG_STRING_INFO(INTERNAL_PerfTypesToLog, W("PerfTypesToLog"), "Log facility LF_GCALLOC logs object allocations. This flag controls which ones also log stacktraces. Predates ClrProfiler.")
@@ -803,33 +788,24 @@ RETAIL_CONFIG_DWORD_INFO(EXTERNAL_Prepopulate1, W("Prepopulate1"), 1, "")
CONFIG_STRING_INFO(INTERNAL_PrestubGC, W("PrestubGC"), "")
CONFIG_STRING_INFO(INTERNAL_PrestubHalt, W("PrestubHalt"), "")
RETAIL_CONFIG_STRING_INFO(EXTERNAL_RestrictedGCStressExe, W("RestrictedGCStressExe"), "")
-CONFIG_DWORD_INFO_EX(INTERNAL_ReturnSourceTypeForTesting, W("ReturnSourceTypeForTesting"), 0, "Allows returning the (internal only) source type of an IL to Native mapping for debugging purposes", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_RSStressLog, W("RSStressLog"), 0, "Allows turning on logging for RS startup", CLRConfig::EEConfig_default)
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_SaveThreadInfo, W("SaveThreadInfo"), "")
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_SaveThreadInfoMask, W("SaveThreadInfoMask"), "")
+CONFIG_DWORD_INFO(INTERNAL_ReturnSourceTypeForTesting, W("ReturnSourceTypeForTesting"), 0, "Allows returning the (internal only) source type of an IL to Native mapping for debugging purposes")
+RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_RSStressLog, W("RSStressLog"), 0, "Allows turning on logging for RS startup")
CONFIG_DWORD_INFO(INTERNAL_SBDumpOnNewIndex, W("SBDumpOnNewIndex"), 0, "Used for Syncblock debugging. It's been a while since any of those have been used.")
CONFIG_DWORD_INFO(INTERNAL_SBDumpOnResize, W("SBDumpOnResize"), 0, "Used for Syncblock debugging. It's been a while since any of those have been used.")
CONFIG_DWORD_INFO(INTERNAL_SBDumpStyle, W("SBDumpStyle"), 0, "Used for Syncblock debugging. It's been a while since any of those have been used.")
-RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(UNSUPPORTED_ShimDatabaseVersion, W("ShimDatabaseVersion"), "Force using shim database version in registry")
RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_SleepOnExit, W("SleepOnExit"), 0, "Used for lrak detection. I'd say deprecated by umdh.")
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_StubLinkerUnwindInfoVerificationOn, W("StubLinkerUnwindInfoVerificationOn"), "")
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_SuccessExit, W("SuccessExit"), 0, "", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_SymbolReadingPolicy, W("SymbolReadingPolicy"), "Specifies when PDBs may be read")
+CONFIG_DWORD_INFO(INTERNAL_StubLinkerUnwindInfoVerificationOn, W("StubLinkerUnwindInfoVerificationOn"), 0, "")
+RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_SuccessExit, W("SuccessExit"), 0, "")
RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_TestDataConsistency, W("TestDataConsistency"), FALSE, "Allows ensuring the left side is not holding locks (and may thus be in an inconsistent state) when inspection occurs")
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_ThreadGuardPages, W("ThreadGuardPages"), 0, "", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_Timeline, W("Timeline"), 0, "", CLRConfig::EEConfig_default)
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_TotalStressLogSize, W("TotalStressLogSize"), "Total stress log size in bytes.")
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_ThreadGuardPages, W("ThreadGuardPages"), 0, "")
#ifdef _DEBUG
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_TraceIUnknown, W("TraceIUnknown"), "")
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_TraceWrap, W("TraceWrap"), "")
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_TraceWrap, W("TraceWrap"), 0, "")
#endif
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_TURNOFFDEBUGINFO, W("TURNOFFDEBUGINFO"), "")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_UseMethodDataCache, W("UseMethodDataCache"), FALSE, "Used during feature development; may now be removed.")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_UseParentMethodData, W("UseParentMethodData"), TRUE, "Used during feature development; may now be removed.")
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_VerifierOff, W("VerifierOff"), "")
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_VerifyAllOnLoad, W("VerifyAllOnLoad"), "")
+CONFIG_DWORD_INFO(INTERNAL_VerifierOff, W("VerifierOff"), 0, "")
// **
// PLEASE MOVE ANY CONFIG SWITCH YOU OWN OUT OF THIS SECTION INTO A CATEGORY ABOVE
//
diff --git a/src/coreclr/inc/corhdr.h b/src/coreclr/inc/corhdr.h
index a4c5e6d639bf..de3e95df31e0 100644
--- a/src/coreclr/inc/corhdr.h
+++ b/src/coreclr/inc/corhdr.h
@@ -16,18 +16,6 @@
#ifndef __CORHDR_H__
#define __CORHDR_H__
-#define FRAMEWORK_REGISTRY_KEY "Software\\Microsoft\\.NETFramework"
-#define FRAMEWORK_REGISTRY_KEY_W W("Software\\Microsoft\\.NETFramework")
-
-// keys for HKCU
-#ifdef HOST_64BIT
-#define USER_FRAMEWORK_REGISTRY_KEY "Software\\Microsoft\\.NETFramework64"
-#define USER_FRAMEWORK_REGISTRY_KEY_W W("Software\\Microsoft\\.NETFramework64")
-#else
-#define USER_FRAMEWORK_REGISTRY_KEY "Software\\Microsoft\\.NETFramework"
-#define USER_FRAMEWORK_REGISTRY_KEY_W W("Software\\Microsoft\\.NETFramework")
-#endif
-
#include
#ifdef _MSC_VER
diff --git a/src/coreclr/inc/stresslog.h b/src/coreclr/inc/stresslog.h
index 706f3c942377..d125591b7364 100644
--- a/src/coreclr/inc/stresslog.h
+++ b/src/coreclr/inc/stresslog.h
@@ -267,7 +267,7 @@ struct StressLogMsg;
class StressLog {
public:
static void Initialize(unsigned facilities, unsigned level, unsigned maxBytesPerThread,
- ULONGLONG maxBytesTotal, void* moduleBase, LPWSTR logFilename = nullptr);
+ unsigned maxBytesTotal, void* moduleBase, LPWSTR logFilename = nullptr);
static void Terminate(BOOL fProcessDetach=FALSE);
static void ThreadDetach(); // call at DllMain THREAD_DETACH if you want to recycle thread logs
#ifndef STRESS_LOG_ANALYZER
diff --git a/src/coreclr/inc/utilcode.h b/src/coreclr/inc/utilcode.h
index 22193da0ff36..a3c446bb7478 100644
--- a/src/coreclr/inc/utilcode.h
+++ b/src/coreclr/inc/utilcode.h
@@ -1010,177 +1010,6 @@ void SplitPath(__in SString const &path,
__inout_opt SString *fname,
__inout_opt SString *ext);
-#if !defined(NO_CLRCONFIG)
-
-//*****************************************************************************
-//
-// **** REGUTIL - Static helper functions for reading/writing to Windows registry.
-//
-//*****************************************************************************
-
-
-class REGUTIL
-{
-public:
-//*****************************************************************************
-
- enum CORConfigLevel
- {
- COR_CONFIG_ENV = 0x01,
- COR_CONFIG_USER = 0x02,
- COR_CONFIG_MACHINE = 0x04,
-
- COR_CONFIG_REGISTRY = (COR_CONFIG_USER|COR_CONFIG_MACHINE),
- COR_CONFIG_ALL = (COR_CONFIG_ENV|COR_CONFIG_USER|COR_CONFIG_MACHINE),
- };
-
- //
- // NOTE: The following function is deprecated; use the CLRConfig class instead.
- // To access a configuration value through CLRConfig, add an entry in file:../inc/CLRConfigValues.h.
- //
- static DWORD GetConfigDWORD_DontUse_(
- LPCWSTR name,
- DWORD defValue,
- CORConfigLevel level = COR_CONFIG_ALL,
- BOOL fPrependCOMPLUS = TRUE);
-
- //
- // NOTE: The following function is deprecated; use the CLRConfig class instead.
- // To access a configuration value through CLRConfig, add an entry in file:../inc/CLRConfigValues.h.
- //
- static HRESULT GetConfigDWORD_DontUse_(
- LPCWSTR name,
- DWORD defValue,
- __out DWORD * result,
- CORConfigLevel level = COR_CONFIG_ALL,
- BOOL fPrependCOMPLUS = TRUE);
-
- static ULONGLONG GetConfigULONGLONG_DontUse_(
- LPCWSTR name,
- ULONGLONG defValue,
- CORConfigLevel level = COR_CONFIG_ALL,
- BOOL fPrependCOMPLUS = TRUE);
-
- //
- // NOTE: The following function is deprecated; use the CLRConfig class instead.
- // To access a configuration value through CLRConfig, add an entry in file:../inc/CLRConfigValues.h.
- //
- static DWORD GetConfigFlag_DontUse_(
- LPCWSTR name,
- DWORD bitToSet,
- BOOL defValue = FALSE);
-
- //
- // NOTE: The following function is deprecated; use the CLRConfig class instead.
- // To access a configuration value through CLRConfig, add an entry in file:../inc/CLRConfigValues.h.
- //
- static LPWSTR GetConfigString_DontUse_(
- LPCWSTR name,
- BOOL fPrependCOMPLUS = TRUE,
- CORConfigLevel level = COR_CONFIG_ALL,
- BOOL fUsePerfCache = TRUE);
-
- static void FreeConfigString(__in __in_z LPWSTR name);
-
-private:
- static LPWSTR EnvGetString(LPCWSTR name, BOOL fPrependCOMPLUS);
-
-private:
-//*****************************************************************************
-// Get either a DWORD or ULONGLONG. Always puts the result in a ULONGLONG that
-// you can safely cast to a DWORD if fGetDWORD is TRUE.
-//*****************************************************************************
- static HRESULT GetConfigInteger(
- LPCWSTR name,
- ULONGLONG defValue,
- __out ULONGLONG * result,
- BOOL fGetDWORD = TRUE,
- CORConfigLevel level = COR_CONFIG_ALL,
- BOOL fPrependCOMPLUS = TRUE);
-public:
-
-
-//*****************************************************************************
-// (Optional) Initialize the config registry cache
-// (see ConfigCacheValueNameSeenPerhaps, below.)
-//*****************************************************************************
- static void InitOptionalConfigCache();
-
-private:
-
-
-//*****************************************************************************
-// Return TRUE if the registry value name might have been seen in the registry
-// at startup;
-// return FALSE if the value was definitely not seen at startup.
-//
-// Perf Optimization for VSWhidbey:113373.
-//*****************************************************************************
- static BOOL RegCacheValueNameSeenPerhaps(
- LPCWSTR name);
-//*****************************************************************************
-// Return TRUE if the environment variable name might have been seen at startup;
-// return FALSE if the value was definitely not seen at startup.
-//*****************************************************************************
- static BOOL EnvCacheValueNameSeenPerhaps(
- LPCWSTR name);
-
- static BOOL s_fUseRegCache; // Enable registry cache; if FALSE, CCVNSP
- // always returns TRUE.
- static BOOL s_fUseEnvCache; // Enable env cache.
-
- // Open the .NetFramework keys once and cache the handles
- static HKEY s_hMachineFrameworkKey;
- static HKEY s_hUserFrameworkKey;
-};
-
-// need this here because CLRConfig depends on REGUTIL, and ConfigStringHolder depends on CLRConfig
-#include "clrconfig.h"
-
-//-----------------------------------------------------------------------------
-// Wrapper for configuration strings.
-// This serves as a holder to call FreeConfigString.
-class ConfigStringHolder
-{
-public:
- ConfigStringHolder() { m_wszString = NULL; }
- ~ConfigStringHolder()
- {
- Clear();
- }
-
- //
- // NOTE: The following function is deprecated; use the CLRConfig class instead.
- // To access a configuration value through CLRConfig, add an entry in file:../inc/CLRConfigValues.h.
- //
- void Init_DontUse_(LPCWSTR wszName)
- {
- Clear();
- m_wszString = REGUTIL::GetConfigString_DontUse_(wszName);
- }
-
- // Free resources.
- void Clear()
- {
- if (m_wszString != NULL)
- {
- REGUTIL::FreeConfigString(m_wszString);
- m_wszString = NULL;
- }
- }
-
- // Get the string value. NULL if not set.
- LPCWSTR Value()
- {
- return m_wszString;
- }
-
-private:
- LPWSTR m_wszString;
-};
-
-#endif // defined(NO_CLRCONFIG)
-
#include "ostype.h"
#define CLRGetTickCount64() GetTickCount64()
@@ -3784,10 +3613,10 @@ class MethodNamesList : public MethodNamesListBase
}
};
-#if !defined(NO_CLRCONFIG)
+#include "clrconfig.h"
/**************************************************************************/
-/* simple wrappers around the REGUTIL and MethodNameList routines that make
+/* simple wrappers around the CLRConfig and MethodNameList routines that make
the lookup lazy */
/* to be used as static variable - no constructor/destructor, assumes zero
@@ -3796,19 +3625,6 @@ class MethodNamesList : public MethodNamesListBase
class ConfigDWORD
{
public:
- //
- // NOTE: The following function is deprecated; use the CLRConfig class instead.
- // To access a configuration value through CLRConfig, add an entry in file:../inc/CLRConfigValues.h.
- //
- inline DWORD val_DontUse_(__in __in_z LPCWSTR keyName, DWORD defaultVal=0)
- {
- WRAPPER_NO_CONTRACT;
- // make sure that the memory was zero initialized
- _ASSERTE(m_inited == 0 || m_inited == 1);
-
- if (!m_inited) init_DontUse_(keyName, defaultVal);
- return m_value;
- }
inline DWORD val(const CLRConfig::ConfigDWORDInfo & info)
{
WRAPPER_NO_CONTRACT;
@@ -3820,7 +3636,6 @@ class ConfigDWORD
}
private:
- void init_DontUse_(__in __in_z LPCWSTR keyName, DWORD defaultVal=0);
void init(const CLRConfig::ConfigDWORDInfo & info);
private:
@@ -3892,8 +3707,6 @@ class ConfigMethodSet
BYTE m_inited;
};
-#endif // !defined(NO_CLRCONFIG)
-
//*****************************************************************************
// Convert a pointer to a string into a GUID.
//*****************************************************************************
diff --git a/src/coreclr/jit/bitsetasshortlong.h b/src/coreclr/jit/bitsetasshortlong.h
index 078cdc810e9d..0eda55e1e105 100644
--- a/src/coreclr/jit/bitsetasshortlong.h
+++ b/src/coreclr/jit/bitsetasshortlong.h
@@ -910,17 +910,18 @@ const char* BitSetOps*BitSetType*/ BitSetShortLongRep,
for (unsigned i = len; 0 < i; i--)
{
size_t bits = bs[i - 1];
- for (unsigned bytesDone = 0; bytesDone < sizeof(size_t); bytesDone += sizeof(unsigned))
+ if (sizeof(size_t) == sizeof(int64_t))
{
- unsigned bits0 = (unsigned)bits;
- sprintf_s(temp, remaining, "%08X", bits0);
+ sprintf_s(temp, remaining, "%016zX", bits);
+ temp += 16;
+ remaining -= 16;
+ }
+ else
+ {
+ assert(sizeof(size_t) == sizeof(unsigned));
+ sprintf_s(temp, remaining, "%08X", (unsigned)bits);
temp += 8;
remaining -= 8;
- bytesDone += 4;
- assert(sizeof(unsigned) == 4);
- // Doing this twice by 16, rather than once by 32, avoids warnings when size_t == unsigned.
- bits = bits >> 16;
- bits = bits >> 16;
}
}
return res;
diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp
index 7d87e0e51bfa..421614c291fd 100644
--- a/src/coreclr/jit/compiler.cpp
+++ b/src/coreclr/jit/compiler.cpp
@@ -2879,17 +2879,38 @@ void Compiler::compInitOptions(JitFlags* jitFlags)
fgPgoData = nullptr;
fgPgoSchema = nullptr;
}
- // Optionally, discard the profile data.
+ // Optionally, disable use of profile data.
//
- else if (JitConfig.JitDisablePGO() != 0)
+ else if (JitConfig.JitDisablePgo() > 0)
{
- fgPgoFailReason = "PGO data available, but JitDisablePGO != 0";
+ fgPgoFailReason = "PGO data available, but JitDisablePgo > 0";
fgPgoQueryResult = E_FAIL;
fgPgoData = nullptr;
fgPgoSchema = nullptr;
+ fgPgoDisabled = true;
}
-
#ifdef DEBUG
+ // Optionally, enable use of profile data for only some methods.
+ //
+ else
+ {
+ static ConfigMethodRange JitEnablePgoRange;
+ JitEnablePgoRange.EnsureInit(JitConfig.JitEnablePgoRange());
+
+ // Base this decision on the root method hash, so a method either sees all available
+ // profile data (including that for inlinees), or none of it.
+ //
+ const unsigned hash = impInlineRoot()->info.compMethodHash();
+ if (!JitEnablePgoRange.Contains(hash))
+ {
+ fgPgoFailReason = "PGO data available, but method hash NOT within JitEnablePgoRange";
+ fgPgoQueryResult = E_FAIL;
+ fgPgoData = nullptr;
+ fgPgoSchema = nullptr;
+ fgPgoDisabled = true;
+ }
+ }
+
// A successful result implies a non-NULL fgPgoSchema
//
if (SUCCEEDED(fgPgoQueryResult))
diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h
index 5e2c23795cd3..6138d87379c2 100644
--- a/src/coreclr/jit/compiler.h
+++ b/src/coreclr/jit/compiler.h
@@ -5644,6 +5644,7 @@ class Compiler
public:
const char* fgPgoFailReason;
+ bool fgPgoDisabled;
ICorJitInfo::PgoInstrumentationSchema* fgPgoSchema;
BYTE* fgPgoData;
UINT32 fgPgoSchemaCount;
diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp
index 5713e748ba09..cd626cbd335d 100644
--- a/src/coreclr/jit/emit.cpp
+++ b/src/coreclr/jit/emit.cpp
@@ -3460,6 +3460,10 @@ void emitter::emitDispIGflags(unsigned flags)
{
printf(", extend");
}
+ if (flags & IGF_LOOP_ALIGN)
+ {
+ printf(", align");
+ }
}
void emitter::emitDispIG(insGroup* ig, insGroup* igPrev, bool verbose)
diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp
index a67212ab85a5..9ac2e8bc9fe5 100644
--- a/src/coreclr/jit/fgbasic.cpp
+++ b/src/coreclr/jit/fgbasic.cpp
@@ -165,6 +165,7 @@ void Compiler::fgInit()
#endif
fgHasSwitch = false;
+ fgPgoDisabled = false;
fgPgoSchema = nullptr;
fgPgoData = nullptr;
fgPgoSchemaCount = 0;
diff --git a/src/coreclr/jit/fgprofile.cpp b/src/coreclr/jit/fgprofile.cpp
index 8c158ddc458a..384c42d80f14 100644
--- a/src/coreclr/jit/fgprofile.cpp
+++ b/src/coreclr/jit/fgprofile.cpp
@@ -2521,6 +2521,11 @@ void Compiler::fgIncorporateEdgeCounts()
// slop - profile slush fund
// wbUsedSlop [out] - true if we tapped into the slush fund
//
+// Returns:
+// true if the edge weight was adjusted
+// false if the edge weight update was inconsistent with the
+// edge's current [min,max}
+//
bool flowList::setEdgeWeightMinChecked(BasicBlock::weight_t newWeight,
BasicBlock* bDst,
BasicBlock::weight_t slop,
@@ -2556,10 +2561,8 @@ bool flowList::setEdgeWeightMinChecked(BasicBlock::weight_t newWeight,
}
}
}
- else
+ else if (flEdgeWeightMin > newWeight)
{
- assert(flEdgeWeightMin > newWeight);
-
// We have already determined that this edge's weight
// is more than newWeight, so we just allow for the slop
if ((newWeight + slop) >= flEdgeWeightMin)
@@ -2581,31 +2584,28 @@ bool flowList::setEdgeWeightMinChecked(BasicBlock::weight_t newWeight,
// If we are returning true then we should have adjusted the range so that
// the newWeight is in new range [Min..Max] or fgEdgeWeightMax is zero.
// Also we should have set wbUsedSlop to true.
- if (result == true)
+ if (result)
{
assert((flEdgeWeightMax == BB_ZERO_WEIGHT) ||
((newWeight <= flEdgeWeightMax) && (newWeight >= flEdgeWeightMin)));
- if (wbUsedSlop != nullptr)
- {
- assert(*wbUsedSlop == true);
- }
+ assert((wbUsedSlop == nullptr) || (*wbUsedSlop));
}
}
#if DEBUG
- if (result == false)
+ if (result)
+ {
+ JITDUMP("Updated min weight of " FMT_BB " -> " FMT_BB " to [" FMT_WT ".." FMT_WT "]\n", getBlock()->bbNum,
+ bDst->bbNum, flEdgeWeightMin, flEdgeWeightMax);
+ }
+ else
{
JITDUMP("Not adjusting min weight of " FMT_BB " -> " FMT_BB "; new value " FMT_WT " not in range [" FMT_WT
".." FMT_WT "] (+/- " FMT_WT ")\n",
getBlock()->bbNum, bDst->bbNum, newWeight, flEdgeWeightMin, flEdgeWeightMax, slop);
result = false; // break here
}
- else
- {
- JITDUMP("Updated min weight of " FMT_BB " -> " FMT_BB " to [" FMT_WT ".." FMT_WT "]\n", getBlock()->bbNum,
- bDst->bbNum, flEdgeWeightMin, flEdgeWeightMax);
- }
#endif // DEBUG
return result;
@@ -2620,6 +2620,11 @@ bool flowList::setEdgeWeightMinChecked(BasicBlock::weight_t newWeight,
// slop - profile slush fund
// wbUsedSlop [out] - true if we tapped into the slush fund
//
+// Returns:
+// true if the edge weight was adjusted
+// false if the edge weight update was inconsistent with the
+// edge's current [min,max}
+//
bool flowList::setEdgeWeightMaxChecked(BasicBlock::weight_t newWeight,
BasicBlock* bDst,
BasicBlock::weight_t slop,
@@ -2654,10 +2659,8 @@ bool flowList::setEdgeWeightMaxChecked(BasicBlock::weight_t newWeight,
}
}
}
- else
+ else if (flEdgeWeightMin > newWeight)
{
- assert(flEdgeWeightMin > newWeight);
-
// We have already determined that this edge's weight
// is more than newWeight, so we just allow for the slop
if ((newWeight + slop) >= flEdgeWeightMin)
@@ -2680,28 +2683,28 @@ bool flowList::setEdgeWeightMaxChecked(BasicBlock::weight_t newWeight,
// If we are returning true then we should have adjusted the range so that
// the newWeight is in new range [Min..Max] or fgEdgeWeightMax is zero
// Also we should have set wbUsedSlop to true, unless it is NULL
- if (result == true)
+ if (result)
{
assert((flEdgeWeightMax == BB_ZERO_WEIGHT) ||
((newWeight <= flEdgeWeightMax) && (newWeight >= flEdgeWeightMin)));
- assert((wbUsedSlop == nullptr) || (*wbUsedSlop == true));
+ assert((wbUsedSlop == nullptr) || (*wbUsedSlop));
}
}
#if DEBUG
- if (result == false)
+ if (result)
+ {
+ JITDUMP("Updated max weight of " FMT_BB " -> " FMT_BB " to [" FMT_WT ".." FMT_WT "]\n", getBlock()->bbNum,
+ bDst->bbNum, flEdgeWeightMin, flEdgeWeightMax);
+ }
+ else
{
JITDUMP("Not adjusting max weight of " FMT_BB " -> " FMT_BB "; new value " FMT_WT " not in range [" FMT_WT
".." FMT_WT "] (+/- " FMT_WT ")\n",
getBlock()->bbNum, bDst->bbNum, newWeight, flEdgeWeightMin, flEdgeWeightMax, slop);
result = false; // break here
}
- else
- {
- JITDUMP("Updated max weight of " FMT_BB " -> " FMT_BB " to [" FMT_WT ".." FMT_WT "]\n", getBlock()->bbNum,
- bDst->bbNum, flEdgeWeightMin, flEdgeWeightMax);
- }
#endif // DEBUG
return result;
@@ -3099,31 +3102,40 @@ void Compiler::fgComputeEdgeWeights()
}
otherEdge = fgGetPredForBlock(otherDst, bSrc);
- noway_assert(edge->edgeWeightMin() <= edge->edgeWeightMax());
- noway_assert(otherEdge->edgeWeightMin() <= otherEdge->edgeWeightMax());
+ // If we see min/max violations, just give up on the computations
+ //
+ const bool edgeWeightSensible = edge->edgeWeightMin() <= edge->edgeWeightMax();
+ const bool otherEdgeWeightSensible = otherEdge->edgeWeightMin() <= otherEdge->edgeWeightMax();
- // Adjust edge->flEdgeWeightMin up or adjust otherEdge->flEdgeWeightMax down
- diff = bSrc->bbWeight - (edge->edgeWeightMin() + otherEdge->edgeWeightMax());
- if (diff > 0)
- {
- assignOK &= edge->setEdgeWeightMinChecked(edge->edgeWeightMin() + diff, bDst, slop, &usedSlop);
- }
- else if (diff < 0)
- {
- assignOK &= otherEdge->setEdgeWeightMaxChecked(otherEdge->edgeWeightMax() + diff, otherDst,
- slop, &usedSlop);
- }
+ assignOK &= edgeWeightSensible && otherEdgeWeightSensible;
- // Adjust otherEdge->flEdgeWeightMin up or adjust edge->flEdgeWeightMax down
- diff = bSrc->bbWeight - (otherEdge->edgeWeightMin() + edge->edgeWeightMax());
- if (diff > 0)
- {
- assignOK &= otherEdge->setEdgeWeightMinChecked(otherEdge->edgeWeightMin() + diff, otherDst,
- slop, &usedSlop);
- }
- else if (diff < 0)
+ if (assignOK)
{
- assignOK &= edge->setEdgeWeightMaxChecked(edge->edgeWeightMax() + diff, bDst, slop, &usedSlop);
+ // Adjust edge->flEdgeWeightMin up or adjust otherEdge->flEdgeWeightMax down
+ diff = bSrc->bbWeight - (edge->edgeWeightMin() + otherEdge->edgeWeightMax());
+ if (diff > 0)
+ {
+ assignOK &=
+ edge->setEdgeWeightMinChecked(edge->edgeWeightMin() + diff, bDst, slop, &usedSlop);
+ }
+ else if (diff < 0)
+ {
+ assignOK &= otherEdge->setEdgeWeightMaxChecked(otherEdge->edgeWeightMax() + diff, otherDst,
+ slop, &usedSlop);
+ }
+
+ // Adjust otherEdge->flEdgeWeightMin up or adjust edge->flEdgeWeightMax down
+ diff = bSrc->bbWeight - (otherEdge->edgeWeightMin() + edge->edgeWeightMax());
+ if (diff > 0)
+ {
+ assignOK &= otherEdge->setEdgeWeightMinChecked(otherEdge->edgeWeightMin() + diff, otherDst,
+ slop, &usedSlop);
+ }
+ else if (diff < 0)
+ {
+ assignOK &=
+ edge->setEdgeWeightMaxChecked(edge->edgeWeightMax() + diff, bDst, slop, &usedSlop);
+ }
}
if (!assignOK)
@@ -3194,33 +3206,41 @@ void Compiler::fgComputeEdgeWeights()
// otherMaxEdgesWeightSum is the sum of all of the other edges flEdgeWeightMax values
// This can be used to compute a lower bound for our minimum edge weight
- noway_assert(maxEdgeWeightSum >= edge->edgeWeightMax());
- BasicBlock::weight_t otherMaxEdgesWeightSum = maxEdgeWeightSum - edge->edgeWeightMax();
-
- // otherMinEdgesWeightSum is the sum of all of the other edges flEdgeWeightMin values
- // This can be used to compute an upper bound for our maximum edge weight
- noway_assert(minEdgeWeightSum >= edge->edgeWeightMin());
- BasicBlock::weight_t otherMinEdgesWeightSum = minEdgeWeightSum - edge->edgeWeightMin();
+ //
+ BasicBlock::weight_t const otherMaxEdgesWeightSum = maxEdgeWeightSum - edge->edgeWeightMax();
- if (bDstWeight >= otherMaxEdgesWeightSum)
+ if (otherMaxEdgesWeightSum >= BB_ZERO_WEIGHT)
{
- // minWeightCalc is our minWeight when every other path to bDst takes it's flEdgeWeightMax value
- BasicBlock::weight_t minWeightCalc =
- (BasicBlock::weight_t)(bDstWeight - otherMaxEdgesWeightSum);
- if (minWeightCalc > edge->edgeWeightMin())
+ if (bDstWeight >= otherMaxEdgesWeightSum)
{
- assignOK &= edge->setEdgeWeightMinChecked(minWeightCalc, bDst, slop, &usedSlop);
+ // minWeightCalc is our minWeight when every other path to bDst takes it's flEdgeWeightMax
+ // value
+ BasicBlock::weight_t minWeightCalc =
+ (BasicBlock::weight_t)(bDstWeight - otherMaxEdgesWeightSum);
+ if (minWeightCalc > edge->edgeWeightMin())
+ {
+ assignOK &= edge->setEdgeWeightMinChecked(minWeightCalc, bDst, slop, &usedSlop);
+ }
}
}
- if (bDstWeight >= otherMinEdgesWeightSum)
+ // otherMinEdgesWeightSum is the sum of all of the other edges flEdgeWeightMin values
+ // This can be used to compute an upper bound for our maximum edge weight
+ //
+ BasicBlock::weight_t const otherMinEdgesWeightSum = minEdgeWeightSum - edge->edgeWeightMin();
+
+ if (otherMinEdgesWeightSum >= BB_ZERO_WEIGHT)
{
- // maxWeightCalc is our maxWeight when every other path to bDst takes it's flEdgeWeightMin value
- BasicBlock::weight_t maxWeightCalc =
- (BasicBlock::weight_t)(bDstWeight - otherMinEdgesWeightSum);
- if (maxWeightCalc < edge->edgeWeightMax())
+ if (bDstWeight >= otherMinEdgesWeightSum)
{
- assignOK &= edge->setEdgeWeightMaxChecked(maxWeightCalc, bDst, slop, &usedSlop);
+ // maxWeightCalc is our maxWeight when every other path to bDst takes it's flEdgeWeightMin
+ // value
+ BasicBlock::weight_t maxWeightCalc =
+ (BasicBlock::weight_t)(bDstWeight - otherMinEdgesWeightSum);
+ if (maxWeightCalc < edge->edgeWeightMax())
+ {
+ assignOK &= edge->setEdgeWeightMaxChecked(maxWeightCalc, bDst, slop, &usedSlop);
+ }
}
}
diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp
index e8250cd56dd0..54deec92534c 100644
--- a/src/coreclr/jit/importer.cpp
+++ b/src/coreclr/jit/importer.cpp
@@ -21539,12 +21539,12 @@ void Compiler::considerGuardedDevirtualization(
JITDUMP("Considering guarded devirtualization\n");
- // We currently only get likely class guesses when there is PGO data. So if we've disabled
- // PGO, just bail out.
-
- if (JitConfig.JitDisablePGO() != 0)
+ // We currently only get likely class guesses when there is PGO data
+ // with class profiles.
+ //
+ if (fgPgoClassProfiles == 0)
{
- JITDUMP("Not guessing for class; pgo disabled\n");
+ JITDUMP("Not guessing for class: no class profile pgo data, or pgo disabled\n");
return;
}
diff --git a/src/coreclr/jit/jitconfigvalues.h b/src/coreclr/jit/jitconfigvalues.h
index d283522b2cdd..055750272e33 100644
--- a/src/coreclr/jit/jitconfigvalues.h
+++ b/src/coreclr/jit/jitconfigvalues.h
@@ -463,7 +463,10 @@ CONFIG_INTEGER(JitClassProfiling, W("JitClassProfiling"), 1)
CONFIG_INTEGER(JitEdgeProfiling, W("JitEdgeProfiling"), 1)
// Profile consumption options
-CONFIG_INTEGER(JitDisablePGO, W("JitDisablePGO"), 0) // Ignore pgo data
+CONFIG_INTEGER(JitDisablePgo, W("JitDisablePgo"), 0) // Ignore pgo data for all methods
+#if defined(DEBUG)
+CONFIG_STRING(JitEnablePgoRange, W("JitEnablePgoRange")) // Enable pgo data for only some methods
+#endif // debug
// Control when Virtual Calls are expanded
CONFIG_INTEGER(JitExpandCallsEarly, W("JitExpandCallsEarly"), 1) // Expand Call targets early (in the global morph
diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp
index 433750b37f26..8fbce8a586e7 100644
--- a/src/coreclr/jit/morph.cpp
+++ b/src/coreclr/jit/morph.cpp
@@ -14411,8 +14411,12 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
case GT_NOT:
case GT_NEG:
- // Remove double negation/not
- if (op1->OperIs(oper) && opts.OptimizationEnabled())
+ // Remove double negation/not.
+ // Note: this is not a safe tranformation if "tree" is a CSE candidate.
+ // Consider for example the following expression: NEG(NEG(OP)), where the top-level
+ // NEG is a CSE candidate. Were we to morph this to just OP, CSE would fail to find
+ // the original NEG in the statement.
+ if (op1->OperIs(oper) && opts.OptimizationEnabled() && !gtIsActiveCSE_Candidate(tree))
{
GenTree* child = op1->AsOp()->gtGetOp1();
return child;
diff --git a/src/coreclr/md/debug_metadata.h b/src/coreclr/md/debug_metadata.h
index 7f98c4c182b5..6dfb79931490 100644
--- a/src/coreclr/md/debug_metadata.h
+++ b/src/coreclr/md/debug_metadata.h
@@ -33,7 +33,7 @@
#pragma once
-// Include for REGUTIL class used in Debug_ReportError
+// Include for CLRConfig class used in Debug_ReportError
#include
// --------------------------------------------------------------------------------------
@@ -60,7 +60,7 @@
#define Debug_ReportError(strMessage) \
do { \
- if (REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_AssertOnBadImageFormat, 0)) \
+ if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_AssertOnBadImageFormat)) \
{ _ASSERTE_MSG(FALSE, (strMessage)); } \
} while(0)
#define Debug_ReportInternalError(strMessage) _ASSERTE_MSG(FALSE, (strMessage))
diff --git a/src/coreclr/md/enc/mdinternalrw.cpp b/src/coreclr/md/enc/mdinternalrw.cpp
index 629300415ae2..c051bb405fd9 100644
--- a/src/coreclr/md/enc/mdinternalrw.cpp
+++ b/src/coreclr/md/enc/mdinternalrw.cpp
@@ -720,7 +720,7 @@ ULONG MDInternalRW::GetCountWithTokenKind( // return hresult
break;
default:
#ifdef _DEBUG
- if(REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_AssertOnBadImageFormat, 1))
+ if(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_AssertOnBadImageFormat, 1))
_ASSERTE(!"Invalid Blob Offset");
#endif
ulCount = 0;
@@ -2367,7 +2367,7 @@ MDInternalRW::GetSigFromToken(
// not a known token type.
#ifdef _DEBUG
- if(REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_AssertOnBadImageFormat, 1))
+ if(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_AssertOnBadImageFormat, 1))
_ASSERTE(!"Unexpected token type");
#endif
*pcbSig = 0;
diff --git a/src/coreclr/md/inc/metamodel.h b/src/coreclr/md/inc/metamodel.h
index a3a615fc6cd8..e3206a589ad9 100644
--- a/src/coreclr/md/inc/metamodel.h
+++ b/src/coreclr/md/inc/metamodel.h
@@ -1368,7 +1368,7 @@ template class CMiniMdTemplate : public CMiniMdBase
break;
case mdtString:
default:
- if(REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_AssertOnBadImageFormat, 0))
+ if(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_AssertOnBadImageFormat))
_ASSERTE(!"Unexpected token type in FindCustomAttributeByName");
hr = COR_E_BADIMAGEFORMAT;
goto ErrExit;
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Resources/Strings.resx b/src/coreclr/nativeaot/System.Private.CoreLib/src/Resources/Strings.resx
index c65ac77e478f..0a35cbd8d6e0 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Resources/Strings.resx
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Resources/Strings.resx
@@ -1137,6 +1137,9 @@
--- End of inner exception stack trace ---
+
+ --- End of stack trace from previous location ---
+
Exception of type '{0}' was thrown.
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Diagnostics/StackTrace.CoreRT.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Diagnostics/StackTrace.CoreRT.cs
index 2c988ad10652..c35ae4ec9e36 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Diagnostics/StackTrace.CoreRT.cs
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Diagnostics/StackTrace.CoreRT.cs
@@ -89,14 +89,13 @@ private void InitializeForIpAddressArray(IntPtr[] ipAddresses, int skipFrames, i
}
#if !TARGET_WASM
- internal string ToString(TraceFormat traceFormat)
+ internal void ToString(TraceFormat traceFormat, StringBuilder builder)
{
if (_stackFrames == null)
{
- return "";
+ return;
}
- StringBuilder builder = new StringBuilder();
foreach (StackFrame frame in _stackFrames)
{
frame.AppendToStackTrace(builder);
@@ -104,8 +103,6 @@ internal string ToString(TraceFormat traceFormat)
if (traceFormat == TraceFormat.Normal && builder.Length >= Environment.NewLine.Length)
builder.Length -= Environment.NewLine.Length;
-
- return builder.ToString();
}
#endif
}
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Exception.CoreRT.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Exception.CoreRT.cs
index f76d022b179e..c05b05ebc770 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Exception.CoreRT.cs
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Exception.CoreRT.cs
@@ -29,7 +29,6 @@ public MethodBase TargetSite
private IDictionary CreateDataContainer() => new ListDictionaryInternal();
private string SerializationStackTraceString => StackTrace;
- private string SerializationRemoteStackTraceString => null;
private string SerializationWatsonBuckets => null;
private string CreateSourceName() => HasBeenThrown ? "" : null;
@@ -46,21 +45,29 @@ public MethodBase TargetSite
private int _HResult; // HResult
// To maintain compatibility across runtimes, if this object was deserialized, it will store its stack trace as a string
- private string _stackTraceString;
+ private string? _stackTraceString;
+ private string? _remoteStackTraceString;
// Returns the stack trace as a string. If no stack trace is
// available, null is returned.
- public virtual string StackTrace
+ public virtual string? StackTrace
{
get
{
- if (_stackTraceString != null)
- return _stackTraceString;
+ string? stackTraceString = _stackTraceString;
+ string? remoteStackTraceString = _remoteStackTraceString;
+ // if no stack trace, try to get one
+ if (stackTraceString != null)
+ {
+ return remoteStackTraceString + stackTraceString;
+ }
if (!HasBeenThrown)
- return null;
+ {
+ return remoteStackTraceString;
+ }
- return StackTraceHelper.FormatStackTrace(GetStackIPs(), true);
+ return remoteStackTraceString + StackTraceHelper.FormatStackTrace(GetStackIPs(), true);
}
}
@@ -232,12 +239,6 @@ public DispatchState(IntPtr[] stackTrace)
}
}
- [StackTraceHidden]
- internal void SetCurrentStackTrace()
- {
- // TODO: Exception.SetCurrentStackTrace
- }
-
// This is the object against which a lock will be taken
// when attempt to restore the EDI. Since its static, its possible
// that unrelated exception object restorations could get blocked
@@ -289,5 +290,19 @@ internal unsafe byte[] SerializeForDump()
return buffer;
}
}
+
+ // Returns true if setting the _remoteStackTraceString field is legal, false if not (immutable exception).
+ // A false return value means the caller should early-exit the operation.
+ // Can also throw InvalidOperationException if a stack trace is already set or if object has been thrown.
+ private bool CanSetRemoteStackTrace()
+ {
+ // Check to see if the exception already has a stack set in it.
+ if (HasBeenThrown || _stackTraceString != null || _remoteStackTraceString != null)
+ {
+ ThrowHelper.ThrowInvalidOperationException();
+ }
+
+ return true; // CoreRT runtime doesn't have immutable agile exceptions, always return true
+ }
}
}
diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj b/src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj
index 596dc2a75b66..9a820f0fe213 100644
--- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj
+++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/System.Private.TypeLoader.csproj
@@ -210,6 +210,12 @@
Internal\TypeSystem\ModuleDesc.cs
+
+ TypeSystem\Common\NotFoundBehavior.cs
+
+
+ TypeSystem\Common\ResolutionFailure.cs
+
Internal\TypeSystem\ParameterizedType.cs
diff --git a/src/coreclr/scripts/superpmi.py b/src/coreclr/scripts/superpmi.py
index f26b63bc6737..9c4b670de34d 100755
--- a/src/coreclr/scripts/superpmi.py
+++ b/src/coreclr/scripts/superpmi.py
@@ -93,6 +93,10 @@
Upload a collection to SuperPMI Azure storage.
"""
+upload_private_description = """\
+Upload a collection to a local file system path.
+"""
+
download_description = """\
Download collections from SuperPMI Azure storage.
Normally, collections are automatically downloaded to a local cache
@@ -162,6 +166,11 @@
the Azure Storage MCH file store. UNC paths will be downloaded and cached locally.
"""
+private_store_help = """\
+Specify the path to one or more private SuperPMI data stores. Default: use the semicolon separated
+value of the SUPERPMI_PRIVATE_STORE environment variable, if it exists.
+"""
+
filter_help = """\
Specify one or more filters to restrict the set of MCH files to download or use from the local cache.
A filter is a simple case-insensitive substring search against the MCH file path. If multiple filter
@@ -219,7 +228,7 @@
core_root_parser.add_argument("-log_file", help=log_file_help)
core_root_parser.add_argument("-spmi_location", help=spmi_location_help)
-# Create a set of arguments common to target specification. Used for replay, upload, download, list-collections.
+# Create a set of arguments common to target specification. Used for replay, upload, upload-private, download, list-collections.
target_parser = argparse.ArgumentParser(add_help=False)
@@ -277,6 +286,7 @@
replay_common_parser.add_argument("-product_location", help=product_location_help)
replay_common_parser.add_argument("--force_download", action="store_true", help=force_download_help)
replay_common_parser.add_argument("-jit_ee_version", help=jit_ee_version_help)
+replay_common_parser.add_argument("-private_store", action="append", help=private_store_help)
# subparser for replay
replay_parser = subparsers.add_parser("replay", description=replay_description, parents=[core_root_parser, target_parser, superpmi_common_parser, replay_common_parser])
@@ -287,7 +297,6 @@
# subparser for asmdiffs
asm_diff_parser = subparsers.add_parser("asmdiffs", description=asm_diff_description, parents=[core_root_parser, target_parser, superpmi_common_parser, replay_common_parser])
-# Add required arguments
asm_diff_parser.add_argument("-base_jit_path", help="Path to baseline clrjit. Defaults to baseline JIT from rolling build, by computing baseline git hash.")
asm_diff_parser.add_argument("-diff_jit_path", help="Path to diff clrjit. Defaults to Core_Root JIT.")
asm_diff_parser.add_argument("-git_hash", help="Use this git hash as the current hash for use to find a baseline JIT. Defaults to current git hash of source tree.")
@@ -295,8 +304,9 @@
asm_diff_parser.add_argument("--diff_jit_dump", action="store_true", help="Generate JitDump output for diffs. Default: only generate asm, not JitDump.")
asm_diff_parser.add_argument("-temp_dir", help="Specify a temporary directory used for a previous ASM diffs run (for which --skip_cleanup was used) to view the results. The replay command is skipped.")
asm_diff_parser.add_argument("--gcinfo", action="store_true", help="Include GC info in disassembly (sets COMPlus_JitGCDump/COMPlus_NgenGCDump; requires instructions to be prefixed by offsets).")
-asm_diff_parser.add_argument("-base_jit_option", action="append", help="Option to pass to the baselne JIT. Format is key=value, where key is the option name without leading COMPlus_...")
+asm_diff_parser.add_argument("-base_jit_option", action="append", help="Option to pass to the baseline JIT. Format is key=value, where key is the option name without leading COMPlus_...")
asm_diff_parser.add_argument("-diff_jit_option", action="append", help="Option to pass to the diff JIT. Format is key=value, where key is the option name without leading COMPlus_...")
+asm_diff_parser.add_argument("-tag", help="Specify a word to add to the directory name where the asm diffs will be placed")
# subparser for upload
upload_parser = subparsers.add_parser("upload", description=upload_description, parents=[core_root_parser, target_parser])
@@ -306,6 +316,14 @@
upload_parser.add_argument("-jit_ee_version", help=jit_ee_version_help)
upload_parser.add_argument("--skip_cleanup", action="store_true", help=skip_cleanup_help)
+# subparser for upload-private
+upload_private_parser = subparsers.add_parser("upload-private", description=upload_private_description, parents=[core_root_parser, target_parser])
+
+upload_private_parser.add_argument("-mch_files", metavar="MCH_FILE", required=True, nargs='+', help=upload_mch_files_help)
+upload_private_parser.add_argument("-private_store", required=True, help="Target directory root of the private store in which to place the files.")
+upload_private_parser.add_argument("-jit_ee_version", help=jit_ee_version_help)
+upload_private_parser.add_argument("--skip_cleanup", action="store_true", help=skip_cleanup_help)
+
# subparser for download
download_parser = subparsers.add_parser("download", description=download_description, parents=[core_root_parser, target_parser])
@@ -314,6 +332,7 @@
download_parser.add_argument("--skip_cleanup", action="store_true", help=skip_cleanup_help)
download_parser.add_argument("--force_download", action="store_true", help=force_download_help)
download_parser.add_argument("-mch_files", metavar="MCH_FILE", nargs='+', help=replay_mch_files_help)
+download_parser.add_argument("-private_store", action="append", help=private_store_help)
# subparser for list-collections
list_collections_parser = subparsers.add_parser("list-collections", description=list_collections_description, parents=[core_root_parser, target_parser])
@@ -648,7 +667,7 @@ def run_and_log(command, log_level=logging.DEBUG):
Process return code
"""
- logging.debug("Invoking: %s", " ".join(command))
+ logging.log(log_level, "Invoking: %s", " ".join(command))
proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout_output, _ = proc.communicate()
for line in stdout_output.decode('utf-8', errors='replace').splitlines(): # There won't be any stderr output since it was piped to stdout
@@ -697,6 +716,46 @@ def check_target_arch(coreclr_args, target_arch):
def check_mch_arch(coreclr_args, mch_arch):
return (mch_arch is not None) and (mch_arch in coreclr_args.valid_arches)
+
+def create_artifacts_base_name(coreclr_args, mch_file):
+ """ Create an appropriate "base" name for use creating a directory name related to MCH file playback.
+ This will later be prepended by "asm." or "jitdump.", for example, and
+ create_unique_directory_name() should be called on the final name to ensure it is unique.
+
+ Use the MCH file base name as the main part of the directory name, removing
+ the trailing ".mch", if any.
+
+ If there is a tag specified (for asm diffs), prepend the tag.
+
+ Args:
+ coreclr_args : the parsed arguments
+ mch_file (str) : the MCH file name that is being replayed.
+
+ Returns:
+ A directory name to be used.
+ """
+ artifacts_base_name = os.path.basename(mch_file)
+ if artifacts_base_name.lower().endswith(".mch"):
+ artifacts_base_name = artifacts_base_name[:-4]
+ if hasattr(coreclr_args, "tag") and coreclr_args.tag is not None:
+ artifacts_base_name = "{}.{}".format(coreclr_args.tag, artifacts_base_name)
+ return artifacts_base_name
+
+
+def is_url(path):
+ """ Return True if this looks like a URL
+
+ Args:
+ path (str) : name to check
+
+ Returns:
+ True it it looks like an URL, False otherwise.
+ """
+ # Probably could use urllib.parse to be more precise.
+ # If it doesn't look like an URL, treat it like a file, possibly a UNC file.
+ return path.lower().startswith("http:") or path.lower().startswith("https:")
+
+
################################################################################
# Helper classes
################################################################################
@@ -1471,14 +1530,14 @@ def print_fail_mcl_file_method_numbers(fail_mcl_file):
logging.debug(line)
-def save_repro_mc_files(temp_location, coreclr_args, repro_base_command_line):
+def save_repro_mc_files(temp_location, coreclr_args, artifacts_base_name, repro_base_command_line):
""" For commands that use the superpmi "-r" option to create "repro" .mc files, copy these to a
location where they are saved (and not in a "temp" directory) for easy use by the user.
"""
# If there are any .mc files, drop them into artifacts/repro/../*.mc
mc_files = [os.path.join(temp_location, item) for item in os.listdir(temp_location) if item.endswith(".mc")]
if len(mc_files) > 0:
- repro_location = create_unique_directory_name(coreclr_args.spmi_location, "repro.{}.{}.{}".format(coreclr_args.host_os, coreclr_args.arch, coreclr_args.build_type))
+ repro_location = create_unique_directory_name(coreclr_args.spmi_location, "repro.{}".format(artifacts_base_name))
repro_files = []
for item in mc_files:
@@ -1623,7 +1682,8 @@ def replay(self):
logging.warning("Warning: SuperPMI returned a zero exit code, but generated a non-zero-sized mcl file")
print_fail_mcl_file_method_numbers(fail_mcl_file)
repro_base_command_line = "{} {} {}".format(self.superpmi_path, " ".join(repro_flags), self.jit_path)
- save_repro_mc_files(temp_location, self.coreclr_args, repro_base_command_line)
+ artifacts_base_name = create_artifacts_base_name(self.coreclr_args, mch_file)
+ save_repro_mc_files(temp_location, self.coreclr_args, artifacts_base_name, repro_base_command_line)
if not self.coreclr_args.skip_cleanup:
if os.path.isfile(fail_mcl_file):
@@ -1824,13 +1884,15 @@ def replay_with_asm_diffs(self):
files_with_replay_failures.append(mch_file)
result = False
+ artifacts_base_name = create_artifacts_base_name(self.coreclr_args, mch_file)
+
if is_nonzero_length_file(fail_mcl_file):
# Unclean replay. Examine the contents of the fail.mcl file to dig into failures.
if return_code == 0:
logging.warning("Warning: SuperPMI returned a zero exit code, but generated a non-zero-sized mcl file")
print_fail_mcl_file_method_numbers(fail_mcl_file)
repro_base_command_line = "{} {} {}".format(self.superpmi_path, " ".join(altjit_asm_diffs_flags), self.diff_jit_path)
- save_repro_mc_files(temp_location, self.coreclr_args, repro_base_command_line)
+ save_repro_mc_files(temp_location, self.coreclr_args, artifacts_base_name, repro_base_command_line)
# There were diffs. Go through each method that created diffs and
# create a base/diff asm file with diffable asm. In addition, create
@@ -1850,7 +1912,7 @@ def replay_with_asm_diffs(self):
mcl_lines = [item.strip() for item in mcl_lines]
self.diff_mcl_contents = mcl_lines
- asm_root_dir = create_unique_directory_name(self.coreclr_args.spmi_location, "asm.{}.{}.{}".format(self.coreclr_args.host_os, self.coreclr_args.arch, self.coreclr_args.build_type))
+ asm_root_dir = create_unique_directory_name(self.coreclr_args.spmi_location, "asm.{}".format(artifacts_base_name))
base_asm_location = os.path.join(asm_root_dir, "base")
diff_asm_location = os.path.join(asm_root_dir, "diff")
os.makedirs(base_asm_location)
@@ -1858,7 +1920,7 @@ def replay_with_asm_diffs(self):
if self.coreclr_args.diff_jit_dump:
# If JIT dumps are requested, create a diff and baseline directory for JIT dumps
- jitdump_root_dir = create_unique_directory_name(self.coreclr_args.spmi_location, "jitdump.{}.{}.{}".format(self.coreclr_args.host_os, self.coreclr_args.arch, self.coreclr_args.build_type))
+ jitdump_root_dir = create_unique_directory_name(self.coreclr_args.spmi_location, "jitdump.{}".format(artifacts_base_name))
base_dump_location = os.path.join(jitdump_root_dir, "base")
diff_dump_location = os.path.join(jitdump_root_dir, "diff")
os.makedirs(base_dump_location)
@@ -1907,12 +1969,12 @@ async def create_one_artifact(jit_path: str, location: str, flags: list[str]) ->
for item in self.diff_mcl_contents:
diff_items.append(item)
- logging.info("Creating dasm files")
+ logging.info("Creating dasm files: %s %s", base_asm_location, diff_asm_location)
subproc_helper = AsyncSubprocessHelper(diff_items, verbose=True)
subproc_helper.run_to_completion(create_replay_artifacts, self, mch_file, asm_complus_vars_full_env, text_differences, base_asm_location, diff_asm_location, ".dasm")
if self.coreclr_args.diff_jit_dump:
- logging.info("Creating JitDump files")
+ logging.info("Creating JitDump files: %s %s", base_dump_location, diff_dump_location)
subproc_helper.run_to_completion(create_replay_artifacts, self, mch_file, jit_dump_complus_vars_full_env, jit_dump_differences, base_dump_location, diff_dump_location, ".txt")
logging.info("Differences found. To replay SuperPMI use:")
@@ -2264,7 +2326,7 @@ def determine_jit_ee_version(coreclr_args):
NOTE: When using mcs, we need to run the tool. So we need a version that will run. If a user specifies
an "-arch" argument that creates a Core_Root path that won't run, like an arm32 Core_Root on an
- x64 machine, this won't work. This could happen if doing "upload" or "list-collections" on
+ x64 machine, this won't work. This could happen if doing "upload", "upload-private", or "list-collections" on
collections from a machine that didn't create the native collections. We should create a "native"
Core_Root and use that in case there are "cross-arch" scenarios.
@@ -2436,35 +2498,27 @@ def list_superpmi_collections_container(path_filter=lambda unused: True):
return list_superpmi_collections_container_via_rest_api(path_filter)
-def process_mch_files_arg(coreclr_args):
- """ Process the -mch_files argument. If the argument is empty, then download files from Azure Storage.
- If the argument is non-empty, check it for UNC paths and download/cache those files, replacing
- them with a reference to the newly cached local paths (this is on Windows only).
+def process_local_mch_files(coreclr_args, mch_files, mch_cache_dir):
+ """ Process the MCH files to use.
Args:
coreclr_args (CoreclrArguments): parsed args
+ mch_files (list): list of MCH files locations. Normally, this comes from the `-mch_files` argument, but it can
+ also come from the `private_store` argument. It can be a list of files or directories or both.
+ mch_cache_dir (str): the directory to cache any downloads.
Returns:
- nothing
-
- coreclr_args.mch_files is updated
-
+ list of full paths of locally cached MCH files to use
"""
- if coreclr_args.mch_files is None:
- coreclr_args.mch_files = download_mch(coreclr_args, include_baseline_jit=True)
- return
-
# Create the cache location. Note that we'll create it even if we end up not copying anything.
- default_mch_root_dir = os.path.join(coreclr_args.spmi_location, "mch")
- default_mch_dir = os.path.join(default_mch_root_dir, "{}.{}.{}".format(coreclr_args.jit_ee_version, coreclr_args.target_os, coreclr_args.mch_arch))
- if not os.path.isdir(default_mch_dir):
- os.makedirs(default_mch_dir)
+ if not os.path.isdir(mch_cache_dir):
+ os.makedirs(mch_cache_dir)
# Process the mch_files list. Download and cache UNC and HTTP files.
urls = []
local_mch_files = []
- for item in coreclr_args.mch_files:
+ for item in mch_files:
# On Windows only, see if any of the mch_files are UNC paths (i.e., "\\server\share\...").
# If so, download and cache all the files found there to our usual local cache location, to avoid future network access.
if coreclr_args.host_os == "windows" and item.startswith("\\\\"):
@@ -2472,30 +2526,30 @@ def process_mch_files_arg(coreclr_args):
# This happens naturally if a directory is passed and we search for all .mch and .mct files in that directory.
mch_file = os.path.abspath(item)
if os.path.isfile(mch_file) and mch_file.endswith(".mch"):
- files = [ mch_file ]
+ urls.append(mch_file)
mct_file = mch_file + ".mct"
if os.path.isfile(mct_file):
- files.append(mct_file)
+ urls.append(mct_file)
else:
- files = get_files_from_path(mch_file, match_func=lambda path: any(path.endswith(extension) for extension in [".mch", ".mct"]))
-
- for file in files:
- # Download file to cache, and report that as the file to use.
- cache_file = os.path.join(default_mch_dir, os.path.basename(file))
- logging.info("Cache %s => %s", file, cache_file)
- local_mch_file = shutil.copy2(file, cache_file)
- local_mch_files.append(local_mch_file)
+ urls += get_files_from_path(mch_file, match_func=lambda path: any(path.lower().endswith(extension) for extension in [".mch", ".mct", ".zip"]))
elif item.lower().startswith("http:") or item.lower().startswith("https:"): # probably could use urllib.parse to be more precise
urls.append(item)
else:
# Doesn't appear to be a UNC path (on Windows) or a URL, so just use it as-is.
local_mch_files.append(item)
+ # Now apply any filtering we've been asked to do.
+ def filter_local_path(path):
+ path = path.lower()
+ return (coreclr_args.filter is None) or any((filter_item.lower() in path) for filter_item in coreclr_args.filter)
+
+ urls = [url for url in urls if filter_local_path(url)]
+
# Download all the urls at once, and add the local cache filenames to our accumulated list of local file names.
if len(urls) != 0:
- local_mch_files += download_urls(urls, default_mch_dir)
+ local_mch_files += download_files(urls, mch_cache_dir)
- # Special case: walk the URLs list list and for every ".mch" or ".mch.zip" file, check to see that either the associated ".mct" file is already
+ # Special case: walk the URLs list and for every ".mch" or ".mch.zip" file, check to see that either the associated ".mct" file is already
# in the list, or add it to a new list to attempt to download (but don't fail the download if it doesn't exist).
mct_urls = []
for url in urls:
@@ -2504,36 +2558,76 @@ def process_mch_files_arg(coreclr_args):
if mct_url not in urls:
mct_urls.append(mct_url)
if len(mct_urls) != 0:
- local_mch_files += download_urls(mct_urls, default_mch_dir, fail_if_not_found=False)
+ local_mch_files += download_files(mct_urls, mch_cache_dir, fail_if_not_found=False)
- coreclr_args.mch_files = local_mch_files
+ # Even though we might have downloaded MCT files, only return the set of MCH files.
+ local_mch_files = [file for file in local_mch_files if any(file.lower().endswith(extension) for extension in [".mch"])]
+ return local_mch_files
-def download_mch(coreclr_args, include_baseline_jit=False):
- """ Download the mch files. This can be called to re-download files and
- overwrite them in the target location.
+
+def process_mch_files_arg(coreclr_args):
+ """ Process the -mch_files argument. If the argument is not specified, then download files
+ from Azure Storage and any specified private MCH stores.
+
+ Any files on UNC (i.e., "\\server\share" paths on Windows) or Azure Storage stores,
+ even if specified via the `-mch_files` argument, will be downloaded and cached locally,
+ replacing the paths with a reference to the newly cached local paths.
+
+ If the `-mch_files` argument is specified, files are always either used directly or copied and
+ cached locally. These will be the only files used.
+
+ If the `-mch_files` argument is not specified, and there exists a cache, then only files already
+ in the cache are used and no MCH stores are consulted, unless the `--force_download` option is
+ specified, in which case normal MCH store processing is done. This behavior is to avoid
+ touching the network unless required.
Args:
coreclr_args (CoreclrArguments): parsed args
- include_baseline_jit (bool): If True, also download the baseline jit
Returns:
- list containing the directory to which the files were downloaded
-
+ list of local full paths of MCH files or directories to use
"""
- default_mch_root_dir = os.path.join(coreclr_args.spmi_location, "mch")
- default_mch_dir = os.path.join(default_mch_root_dir, "{}.{}.{}".format(coreclr_args.jit_ee_version, coreclr_args.target_os, coreclr_args.mch_arch))
+ mch_cache_dir = os.path.join(coreclr_args.spmi_location, "mch", "{}.{}.{}".format(coreclr_args.jit_ee_version, coreclr_args.target_os, coreclr_args.mch_arch))
+
+ # If an `-mch_files` argument was given, then use exactly that set of files.
+ if coreclr_args.mch_files is not None:
+ return process_local_mch_files(coreclr_args, coreclr_args.mch_files, mch_cache_dir)
- if os.path.isdir(default_mch_dir) and not coreclr_args.force_download:
+ # Otherwise, use both Azure Storage, and optionally, private stores.
+ # See if the cache directory already exists. If so, we just use it (unless `--force_download` is passed).
+
+ if os.path.isdir(mch_cache_dir) and not coreclr_args.force_download:
# The cache directory is already there, and "--force_download" was passed, so just
# assume it's got what we want.
# NOTE: a different solution might be to verify that everything we would download is
# already in the cache, and simply not download if it is. However, that would
# require hitting the network, and currently once you've cached these, you
# don't need to do that.
- logging.info("Found download cache directory \"%s\" and --force_download not set; skipping download", default_mch_dir)
- return [ default_mch_dir ]
+ logging.info("Found download cache directory \"%s\" and --force_download not set; skipping download", mch_cache_dir)
+ return [ mch_cache_dir ]
+
+ local_mch_paths = download_mch_from_azure(coreclr_args, mch_cache_dir)
+
+ # Add the private store files
+ if coreclr_args.private_store is not None:
+ local_mch_paths += process_local_mch_files(coreclr_args, coreclr_args.private_store, mch_cache_dir)
+
+ return local_mch_paths
+
+
+def download_mch_from_azure(coreclr_args, target_dir):
+ """ Download the mch files. This can be called to re-download files and
+ overwrite them in the target location.
+
+ Args:
+ coreclr_args (CoreclrArguments): parsed args
+ target_dir (str): target directory to download the files
+
+ Returns:
+ list containing the local path of files downloaded
+ """
blob_filter_string = "{}/{}/{}/".format(coreclr_args.jit_ee_version, coreclr_args.target_os, coreclr_args.mch_arch).lower()
@@ -2544,50 +2638,58 @@ def download_mch(coreclr_args, include_baseline_jit=False):
# If there are filters, only download those matching files.
def filter_superpmi_collections(path):
path = path.lower()
- if "clrjit" in path and not include_baseline_jit:
- return False
return path.startswith(blob_filter_string) and ((coreclr_args.filter is None) or any((filter_item.lower() in path) for filter_item in coreclr_args.filter))
paths = list_superpmi_collections_container(filter_superpmi_collections)
if paths is None or len(paths) == 0:
- print("No MCH files to download from {}".format(blob_filter_string))
+ print("No Azure Storage MCH files to download from {}".format(blob_filter_string))
return []
blob_url_prefix = "{}/{}/".format(az_blob_storage_superpmi_container_uri, az_collections_root_folder)
urls = [blob_url_prefix + path for path in paths]
- download_urls(urls, default_mch_dir)
- return [ default_mch_dir ]
+ return download_files(urls, target_dir)
-def download_urls(urls, target_dir, verbose=True, fail_if_not_found=True):
- """ Download a set of files, specified as URLs, to a target directory.
- If the URLs are to .ZIP files, then uncompress them and copy all contents
- to the target directory.
+def download_files(paths, target_dir, verbose=True, fail_if_not_found=True):
+ """ Download a set of files, specified as URLs or paths (such as Windows UNC paths),
+ to a target directory. If a file is a .ZIP file, then uncompress the file and
+ copy all its contents to the target directory.
Args:
- urls (list): the URLs to download
- target_dir (str): target directory where files are copied. Directory must exist
+ paths (list): the URLs and paths to download
+ target_dir (str): target directory where files are copied.
+ verbse (bool): if True, do verbose logging.
fail_if_not_found (bool): if True, fail if a download fails due to file not found (HTTP error 404).
Otherwise, ignore the failure.
Returns:
- list of local filenames of downloaded files
+ list of full paths of local filenames of downloaded files in the target directory
"""
+ if len(paths) == 0:
+ logging.warning("No files specified to download")
+ return None
+
if verbose:
logging.info("Downloading:")
- for url in urls:
- logging.info(" %s", url)
+ for item_path in paths:
+ logging.info(" %s", item_path)
- local_files = []
+ # Create the target directory now, if it doesn't already exist.
+ target_dir = os.path.abspath(target_dir)
+ if not os.path.isdir(target_dir):
+ os.makedirs(target_dir)
+
+ local_paths = []
# In case we'll need a temp directory for ZIP file processing, create it first.
with TempDir() as temp_location:
- for url in urls:
- item_name = url.split("/")[-1]
+ for item_path in paths:
+ is_item_url = is_url(item_path)
+ item_name = item_path.split("/")[-1] if is_item_url else os.path.basename(item_path)
- if url.lower().endswith(".zip"):
+ if item_path.lower().endswith(".zip"):
# Delete everything in the temp_location (from previous iterations of this loop, so previous URL downloads).
temp_location_items = [os.path.join(temp_location, item) for item in os.listdir(temp_location)]
for item in temp_location_items:
@@ -2597,9 +2699,15 @@ def download_urls(urls, target_dir, verbose=True, fail_if_not_found=True):
os.remove(item)
download_path = os.path.join(temp_location, item_name)
- ok = download_one_url(url, download_path, fail_if_not_found)
- if not ok:
- continue
+ if is_item_url:
+ ok = download_one_url(item_path, download_path, fail_if_not_found)
+ if not ok:
+ continue
+ else:
+ if fail_if_not_found or os.path.isfile(item_path):
+ if verbose:
+ logging.info("Download: %s -> %s", item_path, download_path)
+ shutil.copy2(item_path, download_path)
if verbose:
logging.info("Uncompress %s", download_path)
@@ -2607,26 +2715,28 @@ def download_urls(urls, target_dir, verbose=True, fail_if_not_found=True):
file_handle.extractall(temp_location)
# Copy everything that was extracted to the target directory.
- if not os.path.isdir(target_dir):
- os.makedirs(target_dir)
items = [ os.path.join(temp_location, item) for item in os.listdir(temp_location) if not item.endswith(".zip") ]
for item in items:
target_path = os.path.join(target_dir, os.path.basename(item))
if verbose:
logging.info("Copy %s -> %s", item, target_path)
shutil.copy2(item, target_dir)
- local_files.append(target_path)
+ local_paths.append(target_path)
else:
# Not a zip file; download directory to target directory
- if not os.path.isdir(target_dir):
- os.makedirs(target_dir)
download_path = os.path.join(target_dir, item_name)
- ok = download_one_url(url, download_path, fail_if_not_found)
- if not ok:
- continue
- local_files.append(download_path)
+ if is_item_url:
+ ok = download_one_url(item_path, download_path, fail_if_not_found)
+ if not ok:
+ continue
+ else:
+ if fail_if_not_found or os.path.isfile(item_path):
+ if verbose:
+ logging.info("Download: %s -> %s", item_path, download_path)
+ shutil.copy2(item_path, download_path)
+ local_paths.append(download_path)
- return local_files
+ return local_paths
def upload_mch(coreclr_args):
@@ -2698,6 +2808,63 @@ def upload_blob(file, blob_name):
logging.info("Uploaded {:n} bytes".format(total_bytes_uploaded))
+def upload_private_mch(coreclr_args):
+ """ Upload a set of MCH files. Each MCH file is first ZIP compressed to save data space and upload/download time.
+
+ Args:
+ coreclr_args (CoreclrArguments): parsed args
+ """
+
+ files = []
+ for item in coreclr_args.mch_files:
+ files += get_files_from_path(item, match_func=lambda path: any(path.endswith(extension) for extension in [".mch"]))
+
+ files_to_upload = []
+ # Special case: walk the files list and for every ".mch" file, check to see that either the associated ".mct" file is already
+ # in the list, or add it if the ".mct" file exists.
+ for file in files.copy():
+ if file.endswith(".mch") and os.stat(file).st_size > 0:
+ files_to_upload.append(file)
+ mct_file = file + ".mct"
+ if os.path.isfile(mct_file) and os.stat(mct_file).st_size > 0:
+ files_to_upload.append(mct_file)
+
+ logging.info("Uploading:")
+ for item in files_to_upload:
+ logging.info(" %s", item)
+
+ file_folder_name = os.path.join(coreclr_args.private_store, coreclr_args.jit_ee_version, coreclr_args.target_os, coreclr_args.mch_arch)
+ if not os.path.isdir(file_folder_name):
+ os.makedirs(file_folder_name)
+
+ total_bytes_uploaded = 0
+
+ with TempDir() as temp_location:
+ for file in files_to_upload:
+ # Zip compress the file we will upload
+ zip_name = os.path.basename(file) + ".zip"
+ zip_path = os.path.join(temp_location, zip_name)
+ logging.info("Compress %s -> %s", file, zip_path)
+ with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zip_file:
+ zip_file.write(file, os.path.basename(file))
+
+ original_stat_result = os.stat(file)
+ zip_stat_result = os.stat(zip_path)
+ logging.info("Compressed {:n} to {:n} bytes".format(original_stat_result.st_size, zip_stat_result.st_size))
+ total_bytes_uploaded += zip_stat_result.st_size
+
+ target_path = os.path.join(file_folder_name, zip_name)
+ logging.info("Uploading: %s (%s) -> %s", file, zip_path, target_path)
+
+ if os.path.exists(target_path):
+ logging.warning("Warning: replacing existing file '%s'!", target_path)
+ os.remove(target_path)
+
+ shutil.copy2(zip_path, target_path)
+
+ logging.info("Uploaded {:n} bytes".format(total_bytes_uploaded))
+
+
def list_collections_command(coreclr_args):
""" List the SuperPMI collections in Azure Storage
@@ -2816,28 +2983,30 @@ def merge_mch(coreclr_args):
return True
-def get_mch_files_for_replay(coreclr_args):
- """ Given the argument `mch_files`, and any specified filters, find all the MCH files to
- use for replay.
+def get_mch_files_for_replay(local_mch_paths, filters):
+ """ Given a list of local MCH files, and any specified filters (in coreclr_args.filter),
+ find all the MCH files to use for replay. Note that `local_mch_paths` can contain
+ both files and directories.
Args:
- coreclr_args (CoreclrArguments) : parsed args
+ local_mch_paths (list) : list of local files and directories to use to find MCH files to use
+ filters (list) : list of strings, one of which must match each candidate MCH path
Returns:
- None if error (with an error message already printed), else a list of MCH files.
+ None if error (with an error message already printed), else a filtered list of full paths of MCH files.
"""
- if coreclr_args.mch_files is None:
+ if local_mch_paths is None:
logging.error("No MCH files specified")
return None
mch_files = []
- for item in coreclr_args.mch_files:
+ for item in local_mch_paths:
# If there are specified filters, only run those matching files.
mch_files += get_files_from_path(item,
match_func=lambda path:
any(path.endswith(extension) for extension in [".mch"])
- and ((coreclr_args.filter is None) or any(filter_item.lower() in path for filter_item in coreclr_args.filter)))
+ and ((filters is None) or any(filter_item.lower() in path for filter_item in filters)))
if len(mch_files) == 0:
logging.error("No MCH files found to replay")
@@ -2884,6 +3053,7 @@ def process_base_jit_path_arg(coreclr_args):
if coreclr_args.base_jit_path is not None:
if not os.path.isfile(coreclr_args.base_jit_path):
raise RuntimeError("Specified -base_jit_path does not point to a file")
+ coreclr_args.base_jit_path = os.path.abspath(coreclr_args.base_jit_path)
return
# We cache baseline jits under the following directory. Note that we can't create the full directory path
@@ -2961,7 +3131,7 @@ def process_base_jit_path_arg(coreclr_args):
blob_folder_name = "{}/{}/{}/{}/{}/{}".format(az_builds_root_folder, git_hash, coreclr_args.host_os, coreclr_args.arch, coreclr_args.build_type, jit_name)
blob_uri = "{}/{}".format(az_blob_storage_jitrollingbuild_container_uri, blob_folder_name)
urls = [ blob_uri ]
- local_files = download_urls(urls, basejit_dir, verbose=False, fail_if_not_found=False)
+ local_files = download_files(urls, basejit_dir, verbose=False, fail_if_not_found=False)
if len(local_files) > 0:
if hashnum > 1:
@@ -3178,6 +3348,12 @@ def verify_replay_common_args():
lambda unused: True,
"Unable to set mch_files")
+ coreclr_args.verify(args,
+ "private_store",
+ lambda item: True,
+ "Specify private_store or set environment variable SUPERPMI_PRIVATE_STORE to use a private store.",
+ modify_arg=lambda arg: os.environ["SUPERPMI_PRIVATE_STORE"].split(";") if arg is None and "SUPERPMI_PRIVATE_STORE" in os.environ else arg)
+
if coreclr_args.mode == "collect":
verify_target_args()
@@ -3451,6 +3627,12 @@ def verify_replay_common_args():
lambda unused: True,
"Unable to set diff_jit_option.")
+ coreclr_args.verify(args,
+ "tag",
+ lambda unused: True,
+ "Unable to set tag.",
+ modify_arg=lambda arg: make_safe_filename(arg) if arg is not None else arg)
+
process_base_jit_path_arg(coreclr_args)
jit_in_product_location = False
@@ -3518,6 +3700,31 @@ def verify_replay_common_args():
lambda unused: True,
"Unable to set mch_files")
+ elif coreclr_args.mode == "upload-private":
+
+ verify_target_args()
+ verify_jit_ee_version_arg()
+
+ coreclr_args.verify(args,
+ "mch_files",
+ lambda unused: True,
+ "Unable to set mch_files")
+
+ coreclr_args.verify(args,
+ "private_store",
+ lambda unused: True,
+ "Unable to set private_store")
+
+ if not os.path.isdir(coreclr_args.private_store):
+ print("Error: private store directory '" + coreclr_args.private_store + "' not found.")
+ sys.exit(1)
+
+ # Safety measure: don't allow CLRJIT_AZ_KEY to be set if we are uploading to a private store.
+ # Note that this should be safe anyway, since we're publishing something private, not public.
+ if "CLRJIT_AZ_KEY" in os.environ:
+ print("Error: environment variable CLRJIT_AZ_KEY is set, but command is `upload-private`, not `upload`. That is not allowed.")
+ sys.exit(1)
+
elif coreclr_args.mode == "download":
verify_target_args()
@@ -3538,6 +3745,12 @@ def verify_replay_common_args():
lambda unused: True,
"Unable to set mch_files")
+ coreclr_args.verify(args,
+ "private_store",
+ lambda item: True,
+ "Specify private_store or set environment variable SUPERPMI_PRIVATE_STORE to use a private store.",
+ modify_arg=lambda arg: os.environ["SUPERPMI_PRIVATE_STORE"].split(";") if arg is None and "SUPERPMI_PRIVATE_STORE" in os.environ else arg)
+
elif coreclr_args.mode == "list-collections":
verify_target_args()
@@ -3566,6 +3779,12 @@ def verify_replay_common_args():
lambda unused: True,
"Unable to set pattern")
+ if coreclr_args.mode == "replay" or coreclr_args.mode == "asmdiffs" or coreclr_args.mode == "download":
+ if hasattr(coreclr_args, "private_store") and coreclr_args.private_store is not None:
+ logging.info("Using private stores:")
+ for path in coreclr_args.private_store:
+ logging.info(" %s", path)
+
return coreclr_args
################################################################################
@@ -3618,8 +3837,8 @@ def main(args):
elif coreclr_args.mode == "replay":
# Start a new SuperPMI Replay
- process_mch_files_arg(coreclr_args)
- mch_files = get_mch_files_for_replay(coreclr_args)
+ local_mch_paths = process_mch_files_arg(coreclr_args)
+ mch_files = get_mch_files_for_replay(local_mch_paths, coreclr_args.filter)
if mch_files is None:
return 1
@@ -3649,8 +3868,8 @@ def main(args):
elif coreclr_args.mode == "asmdiffs":
# Start a new SuperPMI Replay with AsmDiffs
- process_mch_files_arg(coreclr_args)
- mch_files = get_mch_files_for_replay(coreclr_args)
+ local_mch_paths = process_mch_files_arg(coreclr_args)
+ mch_files = get_mch_files_for_replay(local_mch_paths, coreclr_args.filter)
if mch_files is None:
return 1
@@ -3695,6 +3914,22 @@ def main(args):
logging.debug("Finish time: %s", end_time.strftime("%H:%M:%S"))
logging.debug("Elapsed time: %s", elapsed_time)
+ elif coreclr_args.mode == "upload-private":
+
+ begin_time = datetime.datetime.now()
+
+ logging.info("SuperPMI upload-private")
+ logging.debug("------------------------------------------------------------")
+ logging.debug("Start time: %s", begin_time.strftime("%H:%M:%S"))
+
+ upload_private_mch(coreclr_args)
+
+ end_time = datetime.datetime.now()
+ elapsed_time = end_time - begin_time
+
+ logging.debug("Finish time: %s", end_time.strftime("%H:%M:%S"))
+ logging.debug("Elapsed time: %s", elapsed_time)
+
elif coreclr_args.mode == "download":
begin_time = datetime.datetime.now()
diff --git a/src/coreclr/tools/Common/Compiler/Logging/DocumentationSignatureParser.cs b/src/coreclr/tools/Common/Compiler/Logging/DocumentationSignatureParser.cs
index d73aea0ef87b..70cf77cb4374 100644
--- a/src/coreclr/tools/Common/Compiler/Logging/DocumentationSignatureParser.cs
+++ b/src/coreclr/tools/Common/Compiler/Logging/DocumentationSignatureParser.cs
@@ -549,7 +549,7 @@ static void GetMatchingTypes(ModuleDesc module, TypeDesc declaringType, string n
namepart = name;
}
- var type = module.GetType(namespacepart, namepart, throwIfNotFound: false);
+ var type = module.GetType(namespacepart, namepart, NotFoundBehavior.ReturnNull);
if (type != null)
{
results.Add(type);
diff --git a/src/coreclr/tools/Common/Compiler/TypeExtensions.cs b/src/coreclr/tools/Common/Compiler/TypeExtensions.cs
index e75f982abcdc..c9418961afd9 100644
--- a/src/coreclr/tools/Common/Compiler/TypeExtensions.cs
+++ b/src/coreclr/tools/Common/Compiler/TypeExtensions.cs
@@ -32,7 +32,7 @@ public static DefType GetClosestDefType(this TypeDesc type)
{
if (!type.IsArrayTypeWithoutGenericInterfaces())
{
- MetadataType arrayShadowType = type.Context.SystemModule.GetType("System", "Array`1", throwIfNotFound: false);
+ MetadataType arrayShadowType = type.Context.SystemModule.GetType("System", "Array`1", NotFoundBehavior.ReturnNull);
if (arrayShadowType != null)
{
return arrayShadowType.MakeInstantiatedType(((ArrayType)type).ElementType);
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/ExceptionStringID.cs b/src/coreclr/tools/Common/TypeSystem/Common/ExceptionStringID.cs
index d9d3de41634d..dd38a715c5fe 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/ExceptionStringID.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/ExceptionStringID.cs
@@ -40,5 +40,6 @@ public enum ExceptionStringID
// BadImageFormatException
BadImageFormatGeneric,
+ BadImageFormatSpecific,
}
}
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataTypeSystemContext.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataTypeSystemContext.cs
index b578eb6ca6ab..d8ed92df961e 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataTypeSystemContext.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataTypeSystemContext.cs
@@ -73,7 +73,7 @@ public virtual void SetSystemModule(ModuleDesc systemModule)
{
// Require System.Object to be present as a minimal sanity check.
// The set of required well-known types is not strictly defined since different .NET profiles implement different subsets.
- MetadataType type = systemModule.GetType("System", s_wellKnownTypeNames[typeIndex], typeIndex == (int)WellKnownType.Object);
+ MetadataType type = systemModule.GetType("System", s_wellKnownTypeNames[typeIndex], typeIndex == (int)WellKnownType.Object ? NotFoundBehavior.Throw : NotFoundBehavior.ReturnNull);
if (type != null)
{
type.SetWellKnownType((WellKnownType)(typeIndex + 1));
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/ModuleDesc.cs b/src/coreclr/tools/Common/TypeSystem/Common/ModuleDesc.cs
index c1e143dfe192..f2d45c1550b2 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/ModuleDesc.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/ModuleDesc.cs
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System;
using System.Collections.Generic;
namespace Internal.TypeSystem
@@ -28,8 +29,13 @@ public ModuleDesc(TypeSystemContext context, IAssemblyDesc assembly)
///
/// Gets a type in this module with the specified name.
+ /// If notFoundBehavior == NotFoundBehavior.ReturnResolutionFailure
+ /// then ModuleDesc.GetTypeResolutionFailure will be set to the failure, and the function will return null
///
- public abstract MetadataType GetType(string nameSpace, string name, bool throwIfNotFound = true);
+ public abstract MetadataType GetType(string nameSpace, string name, NotFoundBehavior notFoundBehavior = NotFoundBehavior.Throw);
+
+ [ThreadStatic]
+ public static ResolutionFailure GetTypeResolutionFailure;
///
/// Gets the global <Module> type.
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/NotFoundBehavior.cs b/src/coreclr/tools/Common/TypeSystem/Common/NotFoundBehavior.cs
new file mode 100644
index 000000000000..1403bb8e0863
--- /dev/null
+++ b/src/coreclr/tools/Common/TypeSystem/Common/NotFoundBehavior.cs
@@ -0,0 +1,12 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Internal.TypeSystem
+{
+ public enum NotFoundBehavior
+ {
+ Throw,
+ ReturnNull,
+ ReturnResolutionFailure
+ }
+}
\ No newline at end of file
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/Properties/Resources.resx b/src/coreclr/tools/Common/TypeSystem/Common/Properties/Resources.resx
index b0efd67b4adc..489fa6d1e3d9 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/Properties/Resources.resx
+++ b/src/coreclr/tools/Common/TypeSystem/Common/Properties/Resources.resx
@@ -180,4 +180,7 @@
The format of a DLL or executable being loaded is invalid
+
+ The format of a DLL or executable being loaded is invalid with {0}
+
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/ResolutionFailure.cs b/src/coreclr/tools/Common/TypeSystem/Common/ResolutionFailure.cs
new file mode 100644
index 000000000000..882537e27f73
--- /dev/null
+++ b/src/coreclr/tools/Common/TypeSystem/Common/ResolutionFailure.cs
@@ -0,0 +1,110 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Internal.TypeSystem
+{
+ public sealed class ResolutionFailure
+ {
+ private enum FailureType
+ {
+ TypeLoadException1,
+ TypeLoadException2,
+ TypeLoadException3,
+ MissingMethodException1,
+ MissingFieldException1,
+ MissingAssemblyException1,
+ }
+
+ private ResolutionFailure() { }
+
+ private FailureType _failureType;
+ private string _namespace;
+ private string _name;
+ private string _moduleName;
+ private ModuleDesc _module;
+ private TypeDesc _owningType;
+ private MethodSignature _methodSignature;
+
+
+ public static ResolutionFailure GetTypeLoadResolutionFailure(string nestedTypeName, ModuleDesc module)
+ {
+ ResolutionFailure failure = new ResolutionFailure();
+ failure._failureType = FailureType.TypeLoadException1;
+ failure._name = nestedTypeName;
+ failure._module = module;
+ return failure;
+ }
+
+ public static ResolutionFailure GetTypeLoadResolutionFailure(string @namespace, string name, ModuleDesc module)
+ {
+ ResolutionFailure failure = new ResolutionFailure();
+ failure._failureType = FailureType.TypeLoadException2;
+ failure._namespace = @namespace;
+ failure._name = name;
+ failure._module = module;
+ return failure;
+ }
+
+ public static ResolutionFailure GetTypeLoadResolutionFailure(string @namespace, string name, string moduleName)
+ {
+ ResolutionFailure failure = new ResolutionFailure();
+ failure._failureType = FailureType.TypeLoadException3;
+ failure._namespace = @namespace;
+ failure._name = name;
+ failure._moduleName = moduleName;
+ return failure;
+ }
+
+ public static ResolutionFailure GetMissingMethodFailure(TypeDesc owningType, string methodName, MethodSignature signature)
+ {
+ ResolutionFailure failure = new ResolutionFailure();
+ failure._failureType = FailureType.MissingMethodException1;
+ failure._methodSignature = signature;
+ failure._name = methodName;
+ failure._owningType = owningType;
+ return failure;
+ }
+
+ public static ResolutionFailure GetMissingFieldFailure(TypeDesc owningType, string fieldName)
+ {
+ ResolutionFailure failure = new ResolutionFailure();
+ failure._failureType = FailureType.MissingMethodException1;
+ failure._name = fieldName;
+ failure._owningType = owningType;
+ return failure;
+ }
+
+ public static ResolutionFailure GetAssemblyResolutionFailure(string simpleName)
+ {
+ ResolutionFailure failure = new ResolutionFailure();
+ failure._failureType = FailureType.MissingAssemblyException1;
+ failure._name = simpleName;
+ return failure;
+ }
+
+ public void Throw()
+ {
+ switch (_failureType)
+ {
+ case FailureType.TypeLoadException1:
+ ThrowHelper.ThrowTypeLoadException(_name, _module);
+ break;
+ case FailureType.TypeLoadException2:
+ ThrowHelper.ThrowTypeLoadException(_namespace, _name, _module);
+ break;
+ case FailureType.TypeLoadException3:
+ ThrowHelper.ThrowTypeLoadException(_namespace, _name, _moduleName);
+ break;
+ case FailureType.MissingMethodException1:
+ ThrowHelper.ThrowMissingMethodException(_owningType, _name, _methodSignature);
+ break;
+ case FailureType.MissingFieldException1:
+ ThrowHelper.ThrowMissingFieldException(_owningType, _name);
+ break;
+ case FailureType.MissingAssemblyException1:
+ ThrowHelper.ThrowFileNotFoundException(ExceptionStringID.FileLoadErrorGeneric, _name);
+ break;
+ }
+ }
+ }
+}
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/ThrowHelper.Common.cs b/src/coreclr/tools/Common/TypeSystem/Common/ThrowHelper.Common.cs
index bfe36b4cd829..cf644ad14d4c 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/ThrowHelper.Common.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/ThrowHelper.Common.cs
@@ -22,6 +22,11 @@ public static void ThrowTypeLoadException(string @namespace, string name, Module
ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, Format.Type(@namespace, name), Format.Module(module));
}
+ public static void ThrowTypeLoadException(string @namespace, string name, string moduleName)
+ {
+ ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, Format.Type(@namespace, name), moduleName);
+ }
+
[System.Diagnostics.DebuggerHidden]
public static void ThrowTypeLoadException(TypeDesc type)
{
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/ThrowHelper.cs b/src/coreclr/tools/Common/TypeSystem/Common/ThrowHelper.cs
index 094ade10faca..90c02f6ad3aa 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/ThrowHelper.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/ThrowHelper.cs
@@ -59,6 +59,12 @@ public static void ThrowBadImageFormatException()
throw new TypeSystemException.BadImageFormatException();
}
+ [System.Diagnostics.DebuggerHidden]
+ public static void ThrowBadImageFormatException(string message)
+ {
+ throw new TypeSystemException.BadImageFormatException(message);
+ }
+
private static partial class Format
{
public static string OwningModule(TypeDesc type)
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/TypeSystemException.cs b/src/coreclr/tools/Common/TypeSystem/Common/TypeSystemException.cs
index 17836ca309bd..598f0f602748 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/TypeSystemException.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/TypeSystemException.cs
@@ -155,6 +155,12 @@ internal BadImageFormatException()
: base(ExceptionStringID.BadImageFormatGeneric)
{
}
+
+ internal BadImageFormatException(string reason)
+ : base(ExceptionStringID.BadImageFormatSpecific, reason)
+ {
+
+ }
}
}
}
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs b/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs
index 1b901f5e623e..d63e92da5476 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs
@@ -276,7 +276,7 @@ private static MetadataType GetType(this ModuleDesc module, string fullName, boo
namespaceName = fullName.Substring(0, split);
typeName = fullName.Substring(split + 1);
}
- return module.GetType(namespaceName, typeName, throwIfNotFound);
+ return module.GetType(namespaceName, typeName, throwIfNotFound ? NotFoundBehavior.Throw : NotFoundBehavior.ReturnNull);
}
private static AssemblyName FindAssemblyIfNamePresent(string name)
diff --git a/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaField.cs b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaField.cs
index 31a4c8def5c5..b6d5e4fd41f8 100644
--- a/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaField.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaField.cs
@@ -98,7 +98,7 @@ private TypeDesc InitializeFieldType()
var metadataReader = MetadataReader;
BlobReader signatureReader = metadataReader.GetBlobReader(metadataReader.GetFieldDefinition(_handle).Signature);
- EcmaSignatureParser parser = new EcmaSignatureParser(Module, signatureReader);
+ EcmaSignatureParser parser = new EcmaSignatureParser(Module, signatureReader, NotFoundBehavior.Throw);
var fieldType = parser.ParseFieldSignature();
return (_fieldType = fieldType);
}
@@ -264,7 +264,7 @@ public override MarshalAsDescriptor GetMarshalAsDescriptor()
if ((definition.Attributes & FieldAttributes.HasFieldMarshal) != 0)
{
BlobReader marshalAsReader = reader.GetBlobReader(definition.GetMarshallingDescriptor());
- EcmaSignatureParser parser = new EcmaSignatureParser(_type.EcmaModule, marshalAsReader);
+ EcmaSignatureParser parser = new EcmaSignatureParser(_type.EcmaModule, marshalAsReader, NotFoundBehavior.Throw);
return parser.ParseMarshalAsDescriptor();
}
diff --git a/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaMethod.cs b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaMethod.cs
index da5126529e48..182a87c56765 100644
--- a/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaMethod.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaMethod.cs
@@ -82,7 +82,7 @@ private MethodSignature InitializeSignature()
var metadataReader = MetadataReader;
BlobReader signatureReader = metadataReader.GetBlobReader(metadataReader.GetMethodDefinition(_handle).Signature);
- EcmaSignatureParser parser = new EcmaSignatureParser(Module, signatureReader);
+ EcmaSignatureParser parser = new EcmaSignatureParser(Module, signatureReader, NotFoundBehavior.Throw);
var signature = parser.ParseMethodSignature();
return (_signature = signature);
}
@@ -573,7 +573,7 @@ private MarshalAsDescriptor GetMarshalAsDescriptor(Parameter parameter)
{
MetadataReader metadataReader = MetadataReader;
BlobReader marshalAsReader = metadataReader.GetBlobReader(parameter.GetMarshallingDescriptor());
- EcmaSignatureParser parser = new EcmaSignatureParser(Module, marshalAsReader);
+ EcmaSignatureParser parser = new EcmaSignatureParser(Module, marshalAsReader, NotFoundBehavior.Throw);
MarshalAsDescriptor marshalAs = parser.ParseMarshalAsDescriptor();
Debug.Assert(marshalAs != null);
return marshalAs;
diff --git a/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaModule.cs b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaModule.cs
index 389f0607399b..737b266b9b6e 100644
--- a/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaModule.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaModule.cs
@@ -96,7 +96,7 @@ protected override IEntityHandleObject CreateValueFromKey(EntityHandle handle)
{
MethodDefinitionHandle methodDefinitionHandle = (MethodDefinitionHandle)handle;
TypeDefinitionHandle typeDefinitionHandle = _module._metadataReader.GetMethodDefinition(methodDefinitionHandle).GetDeclaringType();
- EcmaType type = (EcmaType)_module.GetObject(typeDefinitionHandle);
+ EcmaType type = (EcmaType)_module.GetObject(typeDefinitionHandle, NotFoundBehavior.Throw);
item = new EcmaMethod(type, methodDefinitionHandle);
}
break;
@@ -105,7 +105,7 @@ protected override IEntityHandleObject CreateValueFromKey(EntityHandle handle)
{
FieldDefinitionHandle fieldDefinitionHandle = (FieldDefinitionHandle)handle;
TypeDefinitionHandle typeDefinitionHandle = _module._metadataReader.GetFieldDefinition(fieldDefinitionHandle).GetDeclaringType();
- EcmaType type = (EcmaType)_module.GetObject(typeDefinitionHandle);
+ EcmaType type = (EcmaType)_module.GetObject(typeDefinitionHandle, NotFoundBehavior.Throw);
item = new EcmaField(type, fieldDefinitionHandle);
}
break;
@@ -149,7 +149,9 @@ protected override IEntityHandleObject CreateValueFromKey(EntityHandle handle)
break;
default:
- throw new BadImageFormatException("Unknown metadata token type: " + handle.Kind);
+ ThrowHelper.ThrowBadImageFormatException("unknown metadata token type: " + handle.Kind);
+ item = null;
+ break;
}
switch (handle.Kind)
@@ -261,7 +263,8 @@ public MethodDesc EntryPoint
}
// Bad metadata
- throw new BadImageFormatException();
+ ThrowHelper.ThrowBadImageFormatException();
+ return null;
}
}
@@ -277,7 +280,7 @@ public bool IsPlatformNeutral
}
}
- public sealed override MetadataType GetType(string nameSpace, string name, bool throwIfNotFound = true)
+ public sealed override MetadataType GetType(string nameSpace, string name, NotFoundBehavior notFoundBehavior)
{
var stringComparer = _metadataReader.StringComparer;
@@ -300,12 +303,20 @@ public sealed override MetadataType GetType(string nameSpace, string name, bool
{
if (exportedType.IsForwarder)
{
- Object implementation = GetObject(exportedType.Implementation);
+ Object implementation = GetObject(exportedType.Implementation, notFoundBehavior);
+
+ if (implementation == null)
+ return null;
if (implementation is ModuleDesc)
{
return ((ModuleDesc)(implementation)).GetType(nameSpace, name);
}
+ else if (implementation is ResolutionFailure failure)
+ {
+ ModuleDesc.GetTypeResolutionFailure = failure;
+ return null;
+ }
// TODO
throw new NotImplementedException();
@@ -315,42 +326,57 @@ public sealed override MetadataType GetType(string nameSpace, string name, bool
}
}
- if (throwIfNotFound)
- ThrowHelper.ThrowTypeLoadException(nameSpace, name, this);
+ if (notFoundBehavior != NotFoundBehavior.ReturnNull)
+ {
+ var failure = ResolutionFailure.GetTypeLoadResolutionFailure(nameSpace, name, this);
+ if (notFoundBehavior == NotFoundBehavior.Throw)
+ failure.Throw();
+
+ ModuleDesc.GetTypeResolutionFailure = failure;
+ return null;
+ }
return null;
}
public TypeDesc GetType(EntityHandle handle)
{
- TypeDesc type = GetObject(handle) as TypeDesc;
+ TypeDesc type = GetObject(handle, NotFoundBehavior.Throw) as TypeDesc;
if (type == null)
- throw new BadImageFormatException("Type expected");
+ ThrowHelper.ThrowBadImageFormatException($"type expected for handle {handle.ToString()}");
return type;
}
public MethodDesc GetMethod(EntityHandle handle)
{
- MethodDesc method = GetObject(handle) as MethodDesc;
+ MethodDesc method = GetObject(handle, NotFoundBehavior.Throw) as MethodDesc;
if (method == null)
- throw new BadImageFormatException("Method expected");
+ ThrowHelper.ThrowBadImageFormatException($"method expected for handle {handle.ToString()}");
return method;
}
public FieldDesc GetField(EntityHandle handle)
{
- FieldDesc field = GetObject(handle) as FieldDesc;
+ FieldDesc field = GetObject(handle, NotFoundBehavior.Throw) as FieldDesc;
if (field == null)
- throw new BadImageFormatException("Field expected");
+ ThrowHelper.ThrowBadImageFormatException($"field expected for handle {handle.ToString()}");
return field;
}
- public Object GetObject(EntityHandle handle)
+ public Object GetObject(EntityHandle handle, NotFoundBehavior notFoundBehavior = NotFoundBehavior.Throw)
{
IEntityHandleObject obj = _resolvedTokens.GetOrCreateValue(handle);
if (obj is EcmaObjectLookupWrapper)
{
- return ((EcmaObjectLookupWrapper)obj).Object;
+ object result = ((EcmaObjectLookupWrapper)obj).Object;
+ if ((result is ResolutionFailure failure) && (notFoundBehavior != NotFoundBehavior.ReturnResolutionFailure))
+ {
+ if (notFoundBehavior == NotFoundBehavior.ReturnNull)
+ return null;
+ else
+ failure.Throw();
+ }
+ return result;
}
else
{
@@ -362,12 +388,22 @@ private Object ResolveMethodSpecification(MethodSpecificationHandle handle)
{
MethodSpecification methodSpecification = _metadataReader.GetMethodSpecification(handle);
- MethodDesc methodDef = GetMethod(methodSpecification.Method);
+ object resolvedMethod = GetObject(methodSpecification.Method, NotFoundBehavior.ReturnResolutionFailure);
+ if (resolvedMethod is ResolutionFailure)
+ return resolvedMethod;
+
+ MethodDesc methodDef = resolvedMethod as MethodDesc;
+ if (methodDef == null)
+ ThrowHelper.ThrowBadImageFormatException($"method expected for handle {handle.ToString()}");
BlobReader signatureReader = _metadataReader.GetBlobReader(methodSpecification.Signature);
- EcmaSignatureParser parser = new EcmaSignatureParser(this, signatureReader);
+ EcmaSignatureParser parser = new EcmaSignatureParser(this, signatureReader, NotFoundBehavior.ReturnResolutionFailure);
TypeDesc[] instantiation = parser.ParseMethodSpecSignature();
+
+ if (instantiation == null)
+ return parser.ResolutionFailure;
+
return Context.GetInstantiatedMethod(methodDef, new Instantiation(instantiation));
}
@@ -375,9 +411,11 @@ private Object ResolveStandaloneSignature(StandaloneSignatureHandle handle)
{
StandaloneSignature signature = _metadataReader.GetStandaloneSignature(handle);
BlobReader signatureReader = _metadataReader.GetBlobReader(signature.Signature);
- EcmaSignatureParser parser = new EcmaSignatureParser(this, signatureReader);
+ EcmaSignatureParser parser = new EcmaSignatureParser(this, signatureReader, NotFoundBehavior.ReturnResolutionFailure);
MethodSignature methodSig = parser.ParseMethodSignature();
+ if (methodSig == null)
+ return parser.ResolutionFailure;
return methodSig;
}
@@ -386,23 +424,30 @@ private Object ResolveTypeSpecification(TypeSpecificationHandle handle)
TypeSpecification typeSpecification = _metadataReader.GetTypeSpecification(handle);
BlobReader signatureReader = _metadataReader.GetBlobReader(typeSpecification.Signature);
- EcmaSignatureParser parser = new EcmaSignatureParser(this, signatureReader);
+ EcmaSignatureParser parser = new EcmaSignatureParser(this, signatureReader, NotFoundBehavior.ReturnResolutionFailure);
- return parser.ParseType();
+ TypeDesc parsedType = parser.ParseType();
+ if (parsedType == null)
+ return parser.ResolutionFailure;
+ else
+ return parsedType;
}
private Object ResolveMemberReference(MemberReferenceHandle handle)
{
MemberReference memberReference = _metadataReader.GetMemberReference(handle);
- Object parent = GetObject(memberReference.Parent);
+ Object parent = GetObject(memberReference.Parent, NotFoundBehavior.ReturnResolutionFailure);
+
+ if (parent is ResolutionFailure)
+ return parent;
TypeDesc parentTypeDesc = parent as TypeDesc;
if (parentTypeDesc != null)
{
BlobReader signatureReader = _metadataReader.GetBlobReader(memberReference.Signature);
- EcmaSignatureParser parser = new EcmaSignatureParser(this, signatureReader);
+ EcmaSignatureParser parser = new EcmaSignatureParser(this, signatureReader, NotFoundBehavior.ReturnResolutionFailure);
string name = _metadataReader.GetString(memberReference.Name);
@@ -412,11 +457,13 @@ private Object ResolveMemberReference(MemberReferenceHandle handle)
if (field != null)
return field;
- ThrowHelper.ThrowMissingFieldException(parentTypeDesc, name);
+ return ResolutionFailure.GetMissingFieldFailure(parentTypeDesc, name);
}
else
{
MethodSignature sig = parser.ParseMethodSignature();
+ if (sig == null)
+ return parser.ResolutionFailure;
TypeDesc typeDescToInspect = parentTypeDesc;
Instantiation substitution = default(Instantiation);
@@ -460,7 +507,7 @@ private Object ResolveMemberReference(MemberReferenceHandle handle)
typeDescToInspect = baseType;
} while (typeDescToInspect != null);
- ThrowHelper.ThrowMissingMethodException(parentTypeDesc, name, sig);
+ return ResolutionFailure.GetMissingMethodFailure(parentTypeDesc, name, sig);
}
}
else if (parent is MethodDesc)
@@ -472,18 +519,26 @@ private Object ResolveMemberReference(MemberReferenceHandle handle)
throw new NotImplementedException("MemberRef to a global function or variable.");
}
- throw new BadImageFormatException();
+ ThrowHelper.ThrowBadImageFormatException();
+ return null;
}
private Object ResolveTypeReference(TypeReferenceHandle handle)
{
TypeReference typeReference = _metadataReader.GetTypeReference(handle);
- Object resolutionScope = GetObject(typeReference.ResolutionScope);
+ Object resolutionScope = GetObject(typeReference.ResolutionScope, NotFoundBehavior.ReturnResolutionFailure);
+ if (resolutionScope is ResolutionFailure)
+ {
+ return resolutionScope;
+ }
if (resolutionScope is ModuleDesc)
{
- return ((ModuleDesc)(resolutionScope)).GetType(_metadataReader.GetString(typeReference.Namespace), _metadataReader.GetString(typeReference.Name));
+ object result = ((ModuleDesc)(resolutionScope)).GetType(_metadataReader.GetString(typeReference.Namespace), _metadataReader.GetString(typeReference.Name), NotFoundBehavior.ReturnResolutionFailure);
+ if (result == null)
+ result = ModuleDesc.GetTypeResolutionFailure;
+ return result;
}
else
if (resolutionScope is MetadataType)
@@ -495,7 +550,7 @@ private Object ResolveTypeReference(TypeReferenceHandle handle)
if (result != null)
return result;
- ThrowHelper.ThrowTypeLoadException(typeName, ((MetadataType)resolutionScope).Module);
+ return ResolutionFailure.GetTypeLoadResolutionFailure(typeName, ((MetadataType)resolutionScope).Module);
}
// TODO
@@ -523,20 +578,24 @@ private Object ResolveAssemblyReference(AssemblyReferenceHandle handle)
an.CultureName = _metadataReader.GetString(assemblyReference.Culture);
an.ContentType = GetContentTypeFromAssemblyFlags(assemblyReference.Flags);
- return _moduleResolver.ResolveAssembly(an);
+ var assembly = _moduleResolver.ResolveAssembly(an, throwIfNotFound: false);
+ if (assembly == null)
+ return ResolutionFailure.GetAssemblyResolutionFailure(an.Name);
+ else
+ return assembly;
}
private Object ResolveExportedType(ExportedTypeHandle handle)
{
ExportedType exportedType = _metadataReader.GetExportedType(handle);
- var implementation = GetObject(exportedType.Implementation);
+ var implementation = GetObject(exportedType.Implementation, NotFoundBehavior.ReturnResolutionFailure);
if (implementation is ModuleDesc)
{
var module = (ModuleDesc)implementation;
string nameSpace = _metadataReader.GetString(exportedType.Namespace);
string name = _metadataReader.GetString(exportedType.Name);
- return module.GetType(nameSpace, name);
+ return module.GetType(nameSpace, name, NotFoundBehavior.ReturnResolutionFailure);
}
else
if (implementation is MetadataType)
@@ -545,12 +604,17 @@ private Object ResolveExportedType(ExportedTypeHandle handle)
string name = _metadataReader.GetString(exportedType.Name);
var nestedType = type.GetNestedType(name);
if (nestedType == null)
- ThrowHelper.ThrowTypeLoadException(name, this);
+ return ResolutionFailure.GetTypeLoadResolutionFailure(name, this);
return nestedType;
}
+ else if (implementation is ResolutionFailure)
+ {
+ return implementation;
+ }
else
{
- throw new BadImageFormatException("Unknown metadata token type for exported type");
+ ThrowHelper.ThrowBadImageFormatException();
+ return null;
}
}
diff --git a/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaSignatureParser.cs b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaSignatureParser.cs
index 9a39fc67c126..cb3766f98bc6 100644
--- a/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaSignatureParser.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Ecma/EcmaSignatureParser.cs
@@ -14,40 +14,75 @@ namespace Internal.TypeSystem.Ecma
public struct EcmaSignatureParser
{
private TypeSystemContext _tsc;
- private Func _typeResolver;
+ private Func _typeResolver;
+ private NotFoundBehavior _notFoundBehavior;
private EcmaModule _ecmaModule;
private BlobReader _reader;
+ private ResolutionFailure _resolutionFailure;
private Stack _indexStack;
private List _embeddedSignatureDataList;
- public EcmaSignatureParser(TypeSystemContext tsc, Func typeResolver, BlobReader reader)
+ public EcmaSignatureParser(TypeSystemContext tsc, Func typeResolver, BlobReader reader, NotFoundBehavior notFoundBehavior)
{
+ _notFoundBehavior = notFoundBehavior;
_ecmaModule = null;
_tsc = tsc;
_typeResolver = typeResolver;
_reader = reader;
_indexStack = null;
_embeddedSignatureDataList = null;
+ _resolutionFailure = null;
}
- public EcmaSignatureParser(EcmaModule ecmaModule, BlobReader reader)
+ public EcmaSignatureParser(EcmaModule ecmaModule, BlobReader reader, NotFoundBehavior notFoundBehavior)
{
+ _notFoundBehavior = notFoundBehavior;
_ecmaModule = ecmaModule;
_tsc = ecmaModule.Context;
_typeResolver = null;
_reader = reader;
_indexStack = null;
_embeddedSignatureDataList = null;
+ _resolutionFailure = null;
}
+ void SetResolutionFailure(ResolutionFailure failure)
+ {
+ if (_resolutionFailure == null)
+ _resolutionFailure = failure;
+ }
+
+ public ResolutionFailure ResolutionFailure => _resolutionFailure;
+
private TypeDesc ResolveHandle(EntityHandle handle)
{
+ object resolvedValue;
if (_ecmaModule != null)
- return _ecmaModule.GetType(handle);
+ {
+ resolvedValue = _ecmaModule.GetObject(handle, _notFoundBehavior);
+ }
else
- return _typeResolver(handle);
+ {
+ resolvedValue = _typeResolver(handle, _notFoundBehavior);
+ }
+
+ if (resolvedValue == null)
+ return null;
+ if (resolvedValue is ResolutionFailure failure)
+ {
+ SetResolutionFailure(failure);
+ return null;
+ }
+ if (resolvedValue is TypeDesc type)
+ {
+ return type;
+ }
+ else
+ {
+ throw new BadImageFormatException("Type expected");
+ }
}
private TypeDesc GetWellKnownType(WellKnownType wellKnownType)
@@ -57,7 +92,6 @@ private TypeDesc GetWellKnownType(WellKnownType wellKnownType)
private TypeDesc ParseType(SignatureTypeCode typeCode)
{
-
if (_indexStack != null)
{
int was = _indexStack.Pop();
@@ -114,7 +148,12 @@ private TypeDesc ParseTypeImpl(SignatureTypeCode typeCode)
case SignatureTypeCode.TypeHandle:
return ResolveHandle(_reader.ReadTypeHandle());
case SignatureTypeCode.SZArray:
- return _tsc.GetArrayType(ParseType());
+ {
+ var elementType = ParseType();
+ if (elementType == null)
+ return null;
+ return _tsc.GetArrayType(elementType);
+ }
case SignatureTypeCode.Array:
{
var elementType = ParseType();
@@ -128,12 +167,27 @@ private TypeDesc ParseTypeImpl(SignatureTypeCode typeCode)
for (int j = 0; j < lowerBoundsCount; j++)
_reader.ReadCompressedInteger();
- return _tsc.GetArrayType(elementType, rank);
+ if (elementType != null)
+ return _tsc.GetArrayType(elementType, rank);
+ else
+ return null;
}
case SignatureTypeCode.ByReference:
- return ParseType().MakeByRefType();
+ {
+ TypeDesc byRefedType = ParseType();
+ if (byRefedType != null)
+ return byRefedType.MakeByRefType();
+ else
+ return null;
+ }
case SignatureTypeCode.Pointer:
- return _tsc.GetPointerType(ParseType());
+ {
+ TypeDesc pointedAtType = ParseType();
+ if (pointedAtType != null)
+ return _tsc.GetPointerType(pointedAtType);
+ else
+ return null;
+ }
case SignatureTypeCode.GenericTypeParameter:
return _tsc.GetSignatureVariable(_reader.ReadCompressedInteger(), false);
case SignatureTypeCode.GenericMethodParameter:
@@ -141,19 +195,36 @@ private TypeDesc ParseTypeImpl(SignatureTypeCode typeCode)
case SignatureTypeCode.GenericTypeInstance:
{
TypeDesc typeDef = ParseType();
- MetadataType metadataTypeDef = typeDef as MetadataType;
- if (metadataTypeDef == null)
- throw new BadImageFormatException();
+ MetadataType metadataTypeDef = null;
+
+ if (typeDef != null)
+ {
+ metadataTypeDef = typeDef as MetadataType;
+ if (metadataTypeDef == null)
+ throw new BadImageFormatException();
+ }
TypeDesc[] instance = new TypeDesc[_reader.ReadCompressedInteger()];
for (int i = 0; i < instance.Length; i++)
+ {
instance[i] = ParseType();
- return _tsc.GetInstantiatedType(metadataTypeDef, new Instantiation(instance));
+ if (instance[i] == null)
+ metadataTypeDef = null;
+ }
+
+ if (metadataTypeDef != null)
+ return _tsc.GetInstantiatedType(metadataTypeDef, new Instantiation(instance));
+ else
+ return null;
}
case SignatureTypeCode.TypedReference:
return GetWellKnownType(WellKnownType.TypedReference);
case SignatureTypeCode.FunctionPointer:
- return _tsc.GetFunctionPointerType(ParseMethodSignatureInternal(skipEmbeddedSignatureData: true));
+ MethodSignature sig = ParseMethodSignatureInternal(skipEmbeddedSignatureData: true);
+ if (sig != null)
+ return _tsc.GetFunctionPointerType(sig);
+ else
+ return null;
default:
throw new BadImageFormatException();
}
@@ -320,12 +391,19 @@ private MethodSignature ParseMethodSignatureImpl(bool skipEmbeddedSignatureData)
EmbeddedSignatureData[] embeddedSignatureDataArray = (_embeddedSignatureDataList == null || _embeddedSignatureDataList.Count == 0 || skipEmbeddedSignatureData) ? null : _embeddedSignatureDataList.ToArray();
- return new MethodSignature(flags, arity, returnType, parameters, embeddedSignatureDataArray);
+ if (_resolutionFailure == null)
+ return new MethodSignature(flags, arity, returnType, parameters, embeddedSignatureDataArray);
+ else
+ return null;
}
public PropertySignature ParsePropertySignature()
{
+ // As PropertySignature is a struct, we cannot return null
+ if (_notFoundBehavior != NotFoundBehavior.Throw)
+ throw new ArgumentException();
+
SignatureHeader header = _reader.ReadSignatureHeader();
if (header.Kind != SignatureKind.Property)
throw new BadImageFormatException();
@@ -392,7 +470,10 @@ public LocalVariableDefinition[] ParseLocalsSignature()
{
locals = Array.Empty();
}
- return locals;
+ if (_resolutionFailure == null)
+ return locals;
+ else
+ return null;
}
public TypeDesc[] ParseMethodSpecSignature()
@@ -410,7 +491,10 @@ public TypeDesc[] ParseMethodSpecSignature()
{
arguments[i] = ParseType();
}
- return arguments;
+ if (_resolutionFailure == null)
+ return arguments;
+ else
+ return null;
}
public MarshalAsDescriptor ParseMarshalAsDescriptor()
diff --git a/src/coreclr/tools/Common/TypeSystem/IL/EcmaMethodIL.cs b/src/coreclr/tools/Common/TypeSystem/IL/EcmaMethodIL.cs
index e0142800be95..02e5207c90a8 100644
--- a/src/coreclr/tools/Common/TypeSystem/IL/EcmaMethodIL.cs
+++ b/src/coreclr/tools/Common/TypeSystem/IL/EcmaMethodIL.cs
@@ -89,7 +89,7 @@ public override LocalVariableDefinition[] GetLocals()
return Array.Empty();
BlobReader signatureReader = metadataReader.GetBlobReader(metadataReader.GetStandaloneSignature(localSignature).Signature);
- EcmaSignatureParser parser = new EcmaSignatureParser(_module, signatureReader);
+ EcmaSignatureParser parser = new EcmaSignatureParser(_module, signatureReader, NotFoundBehavior.Throw);
LocalVariableDefinition[] locals = parser.ParseLocalsSignature();
Interlocked.CompareExchange(ref _locals, locals, null);
@@ -131,13 +131,13 @@ public override ILExceptionRegion[] GetExceptionRegions()
return _ilExceptionRegions;
}
- public override object GetObject(int token)
+ public override object GetObject(int token, NotFoundBehavior notFoundBehavior = NotFoundBehavior.Throw)
{
// UserStrings cannot be wrapped in EntityHandle
if ((token & 0xFF000000) == 0x70000000)
return _module.GetUserString(MetadataTokens.UserStringHandle(token));
- return _module.GetObject(MetadataTokens.EntityHandle(token));
+ return _module.GetObject(MetadataTokens.EntityHandle(token), notFoundBehavior);
}
}
}
diff --git a/src/coreclr/tools/Common/TypeSystem/IL/HelperExtensions.cs b/src/coreclr/tools/Common/TypeSystem/IL/HelperExtensions.cs
index 0723d40b363f..3c6d4c1d0b22 100644
--- a/src/coreclr/tools/Common/TypeSystem/IL/HelperExtensions.cs
+++ b/src/coreclr/tools/Common/TypeSystem/IL/HelperExtensions.cs
@@ -22,7 +22,7 @@ public static MetadataType GetHelperType(this TypeSystemContext context, string
public static MetadataType GetOptionalHelperType(this TypeSystemContext context, string name)
{
- MetadataType helperType = context.SystemModule.GetType(HelperTypesNamespace, name, throwIfNotFound: false);
+ MetadataType helperType = context.SystemModule.GetType(HelperTypesNamespace, name, NotFoundBehavior.ReturnNull);
return helperType;
}
@@ -111,7 +111,7 @@ public static MetadataType GetKnownNestedType(this MetadataType type, string nam
///
public static MetadataType GetKnownType(this ModuleDesc module, string @namespace, string name)
{
- MetadataType type = module.GetType(@namespace, name, false);
+ MetadataType type = module.GetType(@namespace, name, NotFoundBehavior.ReturnNull);
if (type == null)
{
throw new InvalidOperationException(
diff --git a/src/coreclr/tools/Common/TypeSystem/IL/InstantiatedMethodIL.cs b/src/coreclr/tools/Common/TypeSystem/IL/InstantiatedMethodIL.cs
index 7192e547f39a..9def3ed499b8 100644
--- a/src/coreclr/tools/Common/TypeSystem/IL/InstantiatedMethodIL.cs
+++ b/src/coreclr/tools/Common/TypeSystem/IL/InstantiatedMethodIL.cs
@@ -89,9 +89,9 @@ public override LocalVariableDefinition[] GetLocals()
return (clone == null) ? locals : clone;
}
- public override Object GetObject(int token)
+ public override Object GetObject(int token, NotFoundBehavior notFoundBehavior)
{
- Object o = _methodIL.GetObject(token);
+ Object o = _methodIL.GetObject(token, notFoundBehavior);
if (o is MethodDesc)
{
diff --git a/src/coreclr/tools/Common/TypeSystem/IL/MethodIL.cs b/src/coreclr/tools/Common/TypeSystem/IL/MethodIL.cs
index 83fecc15119b..cfe1f93998b0 100644
--- a/src/coreclr/tools/Common/TypeSystem/IL/MethodIL.cs
+++ b/src/coreclr/tools/Common/TypeSystem/IL/MethodIL.cs
@@ -86,7 +86,7 @@ public abstract partial class MethodIL
/// (typically a , , ,
/// or ).
///
- public abstract Object GetObject(int token);
+ public abstract Object GetObject(int token, NotFoundBehavior notFoundBehavior = NotFoundBehavior.Throw);
///
/// Gets a list of exception regions this method body defines.
diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/DynamicInvokeMethodThunk.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/DynamicInvokeMethodThunk.cs
index 55e562c0a152..af07693af6f0 100644
--- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/DynamicInvokeMethodThunk.cs
+++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/DynamicInvokeMethodThunk.cs
@@ -33,7 +33,7 @@ public DynamicInvokeMethodThunk(TypeDesc owningType, DynamicInvokeMethodSignatur
internal static bool SupportsDynamicInvoke(TypeSystemContext context)
{
- return context.SystemModule.GetType("System", "InvokeUtils", false) != null;
+ return context.SystemModule.GetType("System", "InvokeUtils", NotFoundBehavior.ReturnNull) != null;
}
private static TypeDesc UnwrapByRef(TypeDesc type)
diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs
index 67f79ad809dc..aa203289c3c6 100644
--- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs
+++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs
@@ -620,7 +620,7 @@ public override LocalVariableDefinition[] GetLocals()
{
return _locals;
}
- public override Object GetObject(int token)
+ public override Object GetObject(int token, NotFoundBehavior notFoundBehavior)
{
return _tokens[(token & 0xFFFFFF) - 1];
}
diff --git a/src/coreclr/tools/Common/TypeSystem/IL/TypeSystemContext.GeneratedAssembly.cs b/src/coreclr/tools/Common/TypeSystem/IL/TypeSystemContext.GeneratedAssembly.cs
index 4126aba76d9d..834fb18deeb7 100644
--- a/src/coreclr/tools/Common/TypeSystem/IL/TypeSystemContext.GeneratedAssembly.cs
+++ b/src/coreclr/tools/Common/TypeSystem/IL/TypeSystemContext.GeneratedAssembly.cs
@@ -55,14 +55,10 @@ public AssemblyName GetName()
return new AssemblyName("System.Private.CompilerGenerated");
}
- public override MetadataType GetType(string nameSpace, string name, bool throwIfNotFound = true)
+ public override MetadataType GetType(string nameSpace, string name, NotFoundBehavior notFoundBehavior)
{
Debug.Fail("Resolving a TypeRef in the compiler generated assembly?");
-
- if (throwIfNotFound)
- ThrowHelper.ThrowTypeLoadException(nameSpace, name, this);
-
- return null;
+ throw new NotImplementedException();
}
}
diff --git a/src/coreclr/tools/ILVerification/ILVerification.projitems b/src/coreclr/tools/ILVerification/ILVerification.projitems
index c68e48bdc552..35b992f6f023 100644
--- a/src/coreclr/tools/ILVerification/ILVerification.projitems
+++ b/src/coreclr/tools/ILVerification/ILVerification.projitems
@@ -46,6 +46,12 @@
TypeSystem\Common\ModuleDesc.cs
+
+ TypeSystem\Common\NotFoundBehavior.cs
+
+
+ TypeSystem\Common\ResolutionFailure.cs
+
TypeSystem\Common\TypeSystemEntity.cs
diff --git a/src/coreclr/tools/ILVerification/SimpleArrayOfTRuntimeInterfacesAlgorithm.cs b/src/coreclr/tools/ILVerification/SimpleArrayOfTRuntimeInterfacesAlgorithm.cs
index 3a08440c4fa7..019f669a73a0 100644
--- a/src/coreclr/tools/ILVerification/SimpleArrayOfTRuntimeInterfacesAlgorithm.cs
+++ b/src/coreclr/tools/ILVerification/SimpleArrayOfTRuntimeInterfacesAlgorithm.cs
@@ -35,7 +35,7 @@ public SimpleArrayOfTRuntimeInterfacesAlgorithm(ModuleDesc systemModule)
int count = 0;
for (int i = 0; i < s_genericRuntimeInterfacesNames.Length; ++i)
{
- MetadataType runtimeInterface =_systemModule.GetType("System.Collections.Generic", s_genericRuntimeInterfacesNames[i], false);
+ MetadataType runtimeInterface =_systemModule.GetType("System.Collections.Generic", s_genericRuntimeInterfacesNames[i], NotFoundBehavior.ReturnNull);
if (runtimeInterface != null)
_genericRuntimeInterfaces[count++] = runtimeInterface;
};
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/BlockedInternalsBlockingPolicy.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/BlockedInternalsBlockingPolicy.cs
index b12d22202531..f9dbc66d91fd 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/BlockedInternalsBlockingPolicy.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/BlockedInternalsBlockingPolicy.cs
@@ -46,11 +46,11 @@ protected override ModuleBlockingState CreateValueFromKey(ModuleDesc module)
{
ModuleBlockingMode blockingMode = ModuleBlockingMode.None;
- if (module.GetType("System.Runtime.CompilerServices", "__BlockAllReflectionAttribute", false) != null)
+ if (module.GetType("System.Runtime.CompilerServices", "__BlockAllReflectionAttribute", NotFoundBehavior.ReturnNull) != null)
{
blockingMode = ModuleBlockingMode.FullyBlocked;
}
- else if (module.GetType("System.Runtime.CompilerServices", "__BlockReflectionAttribute", false) != null)
+ else if (module.GetType("System.Runtime.CompilerServices", "__BlockReflectionAttribute", NotFoundBehavior.ReturnNull) != null)
{
blockingMode = ModuleBlockingMode.BlockedInternals;
}
@@ -152,8 +152,8 @@ public BlockedInternalsBlockingPolicy(TypeSystemContext context)
{
_blockedTypes = new BlockedTypeHashtable(_blockedModules);
- ArrayOfTType = context.SystemModule.GetType("System", "Array`1", false);
- AttributeType = context.SystemModule.GetType("System", "Attribute", false);
+ ArrayOfTType = context.SystemModule.GetType("System", "Array`1", NotFoundBehavior.ReturnNull);
+ AttributeType = context.SystemModule.GetType("System", "Attribute", NotFoundBehavior.ReturnNull);
}
public override bool IsBlocked(MetadataType type)
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ReflectionMethodBodyScanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ReflectionMethodBodyScanner.cs
index cd7f469fe4f6..91d3278e2b6f 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ReflectionMethodBodyScanner.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ReflectionMethodBodyScanner.cs
@@ -69,13 +69,13 @@ public static bool ResolveType(string name, ModuleDesc callingModule, TypeSystem
return false;
// Resolve type in the assembly
- type = referenceModule.GetType(typeNamespace.ToString(), typeName.ToString(), false);
+ type = referenceModule.GetType(typeNamespace.ToString(), typeName.ToString(), NotFoundBehavior.ReturnNull);
// If it didn't resolve and wasn't assembly-qualified, we also try core library
if (type == null && assemblyName.Length == 0)
{
referenceModule = context.SystemModule;
- type = referenceModule.GetType(typeNamespace.ToString(), typeName.ToString(), false);
+ type = referenceModule.GetType(typeNamespace.ToString(), typeName.ToString(), NotFoundBehavior.ReturnNull);
}
return type != null;
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/FeatureSwitchManager.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/FeatureSwitchManager.cs
index 5a61c2428e48..5f06913b97d3 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/FeatureSwitchManager.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/FeatureSwitchManager.cs
@@ -665,7 +665,7 @@ public SubstitutedMethodIL(MethodIL wrapped, byte[] body, ILExceptionRegion[] eh
public override ILExceptionRegion[] GetExceptionRegions() => _ehRegions;
public override byte[] GetILBytes() => _body;
public override LocalVariableDefinition[] GetLocals() => _wrappedMethodIL.GetLocals();
- public override object GetObject(int token) => _wrappedMethodIL.GetObject(token);
+ public override object GetObject(int token, NotFoundBehavior notFoundBehavior) => _wrappedMethodIL.GetObject(token, notFoundBehavior);
public override MethodDebugInformation GetDebugInfo() => _debugInfo;
}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/LibraryInitializers.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/LibraryInitializers.cs
index 35ffad88e638..bdd7f6d1465e 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/LibraryInitializers.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/LibraryInitializers.cs
@@ -48,7 +48,7 @@ private void InitLibraryInitializers()
foreach (var assembly in _librariesWithInitializers)
{
- TypeDesc containingType = assembly.GetType(LibraryInitializerContainerNamespaceName, LibraryInitializerContainerTypeName, false);
+ TypeDesc containingType = assembly.GetType(LibraryInitializerContainerNamespaceName, LibraryInitializerContainerTypeName, NotFoundBehavior.ReturnNull);
if (containingType == null)
continue;
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/PreinitializationManager.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/PreinitializationManager.cs
index 250180960615..1440991c3278 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/PreinitializationManager.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/PreinitializationManager.cs
@@ -17,7 +17,7 @@ public class PreinitializationManager
public PreinitializationManager(TypeSystemContext context, CompilationModuleGroup compilationGroup, ILProvider ilprovider, bool enableInterpreter)
{
- _supportsLazyCctors = context.SystemModule.GetType("System.Runtime.CompilerServices", "ClassConstructorRunner", false) != null;
+ _supportsLazyCctors = context.SystemModule.GetType("System.Runtime.CompilerServices", "ClassConstructorRunner", NotFoundBehavior.ReturnNull) != null;
_preinitHashTable = new PreinitializationInfoHashtable(compilationGroup, ilprovider);
_enableInterpreter = enableInterpreter;
}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/PropertyPseudoDesc.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/PropertyPseudoDesc.cs
index 75e8fafb8563..3113c629926c 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/PropertyPseudoDesc.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/PropertyPseudoDesc.cs
@@ -21,7 +21,7 @@ public class PropertyPseudoDesc : TypeSystemEntity
private PropertyDefinition Definition => _type.MetadataReader.GetPropertyDefinition(_handle);
public PropertySignature Signature =>
- new EcmaSignatureParser(_type.EcmaModule, _type.MetadataReader.GetBlobReader(Definition.Signature))
+ new EcmaSignatureParser(_type.EcmaModule, _type.MetadataReader.GetBlobReader(Definition.Signature), NotFoundBehavior.Throw)
.ParsePropertySignature();
public MethodDesc GetMethod
diff --git a/src/coreclr/tools/aot/ILCompiler.MetadataTransform/ILCompiler/Metadata/Transform.Property.cs b/src/coreclr/tools/aot/ILCompiler.MetadataTransform/ILCompiler/Metadata/Transform.Property.cs
index f01f4726bbf0..b0c694e4a25a 100644
--- a/src/coreclr/tools/aot/ILCompiler.MetadataTransform/ILCompiler/Metadata/Transform.Property.cs
+++ b/src/coreclr/tools/aot/ILCompiler.MetadataTransform/ILCompiler/Metadata/Transform.Property.cs
@@ -33,7 +33,7 @@ private Property HandleProperty(Cts.Ecma.EcmaModule module, Ecma.PropertyDefinit
return null;
Ecma.BlobReader sigBlobReader = reader.GetBlobReader(propDef.Signature);
- Cts.PropertySignature sig = new Cts.Ecma.EcmaSignatureParser(module, sigBlobReader).ParsePropertySignature();
+ Cts.PropertySignature sig = new Cts.Ecma.EcmaSignatureParser(module, sigBlobReader, Cts.NotFoundBehavior.Throw).ParsePropertySignature();
Property result = new Property
{
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IBC/IBCProfileParser.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IBC/IBCProfileParser.cs
index b26d9ab6226f..8b419d4b3955 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IBC/IBCProfileParser.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IBC/IBCProfileParser.cs
@@ -106,7 +106,7 @@ public ProfileData ParseIBCDataFromModule(EcmaModule ecmaModule)
case CorTokenType.mdtMethodDef:
case CorTokenType.mdtMemberRef:
case CorTokenType.mdtMethodSpec:
- object metadataObject = ecmaModule.GetObject(System.Reflection.Metadata.Ecma335.MetadataTokens.EntityHandle((int)entry.Token));
+ object metadataObject = ecmaModule.GetObject(System.Reflection.Metadata.Ecma335.MetadataTokens.EntityHandle((int)entry.Token), NotFoundBehavior.ReturnNull);
if (metadataObject is MethodDesc)
{
associatedMethod = (MethodDesc)metadataObject;
@@ -346,7 +346,7 @@ private uint LookupIbcTypeToken(ref EcmaModule externalModule, uint ibcToken, Di
if (!(m is EcmaModule))
continue;
- foundType = (EcmaType)m.GetType(typeNamespace, typeName, throwIfNotFound: false);
+ foundType = (EcmaType)m.GetType(typeNamespace, typeName, NotFoundBehavior.ReturnNull);
if (foundType != null)
{
externalModule = foundType.EcmaModule;
@@ -356,7 +356,7 @@ private uint LookupIbcTypeToken(ref EcmaModule externalModule, uint ibcToken, Di
}
else
{
- foundType = (EcmaType)externalModule.GetType(typeNamespace, typeName, throwIfNotFound: false);
+ foundType = (EcmaType)externalModule.GetType(typeNamespace, typeName, NotFoundBehavior.ReturnNull);
}
if (foundType == null)
@@ -451,7 +451,7 @@ public EcmaModule GetModuleFromIndex(int index)
{
if (EcmaModule.MetadataReader.GetTableRowCount(TableIndex.AssemblyRef) < index)
return null;
- return EcmaModule.GetObject(MetadataTokens.EntityHandle(((int)CorTokenType.mdtAssemblyRef) | index)) as EcmaModule;
+ return EcmaModule.GetObject(MetadataTokens.EntityHandle(((int)CorTokenType.mdtAssemblyRef) | index), NotFoundBehavior.ReturnNull) as EcmaModule;
}
}
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IBC/MIbcProfileParser.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IBC/MIbcProfileParser.cs
index 987300df24b2..22e54a8922ad 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IBC/MIbcProfileParser.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IBC/MIbcProfileParser.cs
@@ -41,7 +41,12 @@ TypeSystemEntityOrUnknown IPgoSchemaDataLoader.TypeFr
// token type is 0, therefore it can't be a type
return new TypeSystemEntityOrUnknown((int)token);
}
- return new TypeSystemEntityOrUnknown((TypeDesc)_ilBody.GetObject((int)token));
+ TypeDesc foundType = _ilBody.GetObject((int)token, NotFoundBehavior.ReturnNull) as TypeDesc;
+ if (foundType == null)
+ {
+ return new TypeSystemEntityOrUnknown((int)token & 0x00FFFFFF);
+ }
+ return new TypeSystemEntityOrUnknown(foundType);
}
catch
{
@@ -265,7 +270,9 @@ static IEnumerable ReadMIbcGroup(TypeSystemContext tsc, EcmaM
metadataObject = null;
try
{
- metadataObject = ilBody.GetObject(token);
+ metadataObject = ilBody.GetObject(token, NotFoundBehavior.ReturnNull);
+ if (metadataObject == null)
+ metadataObject = metadataNotResolvable;
}
catch (TypeSystemException)
{
@@ -509,7 +516,7 @@ public override MetadataType GetGlobalModuleType()
throw new NotImplementedException();
}
- public override MetadataType GetType(string nameSpace, string name, bool throwIfNotFound = true)
+ public override MetadataType GetType(string nameSpace, string name, NotFoundBehavior notFoundBehavior)
{
TypeSystemContext context = Context;
@@ -519,9 +526,14 @@ public override MetadataType GetType(string nameSpace, string name, bool throwIf
return Context.UniversalCanonType;
else
{
- if (throwIfNotFound)
+ if (notFoundBehavior != NotFoundBehavior.ReturnNull)
{
- throw new TypeLoadException($"{nameSpace}.{name}");
+ var failure = ResolutionFailure.GetTypeLoadResolutionFailure(nameSpace, name, "System.Private.Canon");
+ ModuleDesc.GetTypeResolutionFailure = failure;
+ if (notFoundBehavior == NotFoundBehavior.Throw)
+ failure.Throw();
+
+ return null;
}
return null;
}
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
index 1ec3adb34e70..cd262716689e 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
@@ -1402,7 +1402,7 @@ private void ceeInfoGetCallInfo(
// Its basic meaning is that shared generic methods always need instantiating
// stubs as the shared generic code needs the method dictionary parameter that cannot
// be provided by other means.
- useInstantiatingStub = originalMethod.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstMethodDescArg();
+ useInstantiatingStub = originalMethod.OwningType.IsArray || originalMethod.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstMethodDescArg();
callerMethod = HandleToObject(callerHandle);
@@ -1602,7 +1602,8 @@ private void ceeInfoGetCallInfo(
}
methodToCall = targetMethod;
- MethodDesc canonMethod = targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);
+ bool isArrayConstructor = targetMethod.OwningType.IsArray && targetMethod.IsConstructor;
+ MethodDesc canonMethod = (isArrayConstructor ? null : targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific));
if (directCall)
{
@@ -1616,7 +1617,7 @@ private void ceeInfoGetCallInfo(
bool allowInstParam = (flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_ALLOWINSTPARAM) != 0;
- if (!allowInstParam && canonMethod.RequiresInstArg())
+ if (!allowInstParam && canonMethod != null && canonMethod.RequiresInstArg())
{
useInstantiatingStub = true;
}
@@ -1640,7 +1641,17 @@ private void ceeInfoGetCallInfo(
const CORINFO_CALLINFO_FLAGS LdVirtFtnMask = CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_LDFTN | CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_CALLVIRT;
bool unresolvedLdVirtFtn = ((flags & LdVirtFtnMask) == LdVirtFtnMask) && !resolvedCallVirt;
- if ((pResult->exactContextNeedsRuntimeLookup && useInstantiatingStub && (!allowInstParam || resolvedConstraint)) || forceUseRuntimeLookup)
+ if (isArrayConstructor)
+ {
+ // Constructors on arrays are special and don't actually have entrypoints.
+ // That would be fine by itself and wouldn't need special casing. But
+ // constructors on SzArray have a weird property that causes them not to have canonical forms.
+ // int[][] has a .ctor(int32,int32) to construct the jagged array in one go, but its canonical
+ // form of __Canon[] doesn't have the two-parameter constructor. The canonical form would need
+ // to have an unlimited number of constructors to cover stuff like "int[][][][][][]..."
+ pResult->kind = CORINFO_CALL_KIND.CORINFO_CALL;
+ }
+ else if ((pResult->exactContextNeedsRuntimeLookup && useInstantiatingStub && (!allowInstParam || resolvedConstraint)) || forceUseRuntimeLookup)
{
if (unresolvedLdVirtFtn)
{
@@ -1665,7 +1676,7 @@ private void ceeInfoGetCallInfo(
if (allowInstParam)
{
useInstantiatingStub = false;
- methodToCall = canonMethod;
+ methodToCall = canonMethod ?? methodToCall;
}
pResult->kind = CORINFO_CALL_KIND.CORINFO_CALL;
@@ -1892,12 +1903,19 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO
nonUnboxingMethod = rawPinvoke.Target;
}
- // READYTORUN: FUTURE: Direct calls if possible
- pResult->codePointerOrStubLookup.constLookup = CreateConstLookupToSymbol(
- _compilation.NodeFactory.MethodEntrypoint(
- ComputeMethodWithToken(nonUnboxingMethod, ref pResolvedToken, constrainedType, unboxing: isUnboxingStub),
- isInstantiatingStub: useInstantiatingStub,
- isPrecodeImportRequired: (flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_LDFTN) != 0));
+ if (methodToCall.OwningType.IsArray && methodToCall.IsConstructor)
+ {
+ pResult->codePointerOrStubLookup.constLookup = default;
+ }
+ else
+ {
+ // READYTORUN: FUTURE: Direct calls if possible
+ pResult->codePointerOrStubLookup.constLookup = CreateConstLookupToSymbol(
+ _compilation.NodeFactory.MethodEntrypoint(
+ ComputeMethodWithToken(nonUnboxingMethod, ref pResolvedToken, constrainedType, unboxing: isUnboxingStub),
+ isInstantiatingStub: useInstantiatingStub,
+ isPrecodeImportRequired: (flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_LDFTN) != 0));
+ }
// If the abi of the method isn't stable, this will cause a usage of the RequiresRuntimeJitSymbol, which will trigger a RequiresRuntimeJitException
UpdateConstLookupWithRequiresRuntimeJitSymbolIfNeeded(ref pResult->codePointerOrStubLookup.constLookup, targetMethod);
diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj
index c8e83d94bf84..580438dcc29d 100644
--- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj
+++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj
@@ -146,6 +146,12 @@
TypeSystem\Common\ModuleDesc.cs
+
+ TypeSystem\Common\NotFoundBehavior.cs
+
+
+ TypeSystem\Common\ResolutionFailure.cs
+
TypeSystem\Common\TypeSystemEntity.cs
diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csproj b/src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csproj
index 10fdc028e500..4aa53fd19c5e 100644
--- a/src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csproj
+++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem/ILCompiler.TypeSystem.csproj
@@ -135,6 +135,12 @@
TypeSystem\Common\ModuleDesc.cs
+
+ TypeSystem\Common\NotFoundBehavior.cs
+
+
+ TypeSystem\Common\ResolutionFailure.cs
+
TypeSystem\Common\TypeSystemEntity.cs
diff --git a/src/coreclr/tools/dotnet-pgo/R2RSignatureTypeProvider.cs b/src/coreclr/tools/dotnet-pgo/R2RSignatureTypeProvider.cs
index 0bc52929256b..a640425f209b 100644
--- a/src/coreclr/tools/dotnet-pgo/R2RSignatureTypeProvider.cs
+++ b/src/coreclr/tools/dotnet-pgo/R2RSignatureTypeProvider.cs
@@ -97,7 +97,11 @@ MethodDesc IR2RSignatureTypeProvider.GetMethodFromMemberRef(MetadataReader reader, MemberReferenceHandle handle, TypeDesc owningTypeOverride)
{
var ecmaModule = (EcmaModule)_tsc.GetModuleForSimpleName(reader.GetString(reader.GetAssemblyDefinition().Name));
- var method = (MethodDesc)ecmaModule.GetObject(handle);
+ var method = (MethodDesc)ecmaModule.GetObject(handle, NotFoundBehavior.ReturnNull);
+ if (method == null)
+ {
+ return null;
+ }
if (owningTypeOverride != null)
{
return _tsc.GetMethodForInstantiatedType(method.GetTypicalMethodDefinition(), (InstantiatedType)owningTypeOverride);
@@ -108,7 +112,11 @@ MethodDesc IR2RSignatureTypeProvider.GetMethodFromMethodDef(MetadataReader reader, MethodDefinitionHandle handle, TypeDesc owningTypeOverride)
{
var ecmaModule = (EcmaModule)_tsc.GetModuleForSimpleName(reader.GetString(reader.GetAssemblyDefinition().Name));
- var method = (MethodDesc)ecmaModule.GetObject(handle);
+ var method = (MethodDesc)ecmaModule.GetObject(handle, NotFoundBehavior.ReturnNull);
+ if (method == null)
+ {
+ return null;
+ }
if (owningTypeOverride != null)
{
return _tsc.GetMethodForInstantiatedType(method.GetTypicalMethodDefinition(), (InstantiatedType)owningTypeOverride);
@@ -214,19 +222,19 @@ TypeDesc ISZArrayTypeProvider.GetSZArrayType(TypeDesc elementType)
TypeDesc ISimpleTypeProvider.GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind)
{
var ecmaModule = (EcmaModule)_tsc.GetModuleForSimpleName(reader.GetString(reader.GetAssemblyDefinition().Name));
- return (TypeDesc)ecmaModule.GetObject(handle);
+ return (TypeDesc)ecmaModule.GetObject(handle, NotFoundBehavior.ReturnNull);
}
TypeDesc ISimpleTypeProvider.GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind)
{
var ecmaModule = (EcmaModule)_tsc.GetModuleForSimpleName(reader.GetString(reader.GetAssemblyDefinition().Name));
- return (TypeDesc)ecmaModule.GetObject(handle);
+ return (TypeDesc)ecmaModule.GetObject(handle, NotFoundBehavior.ReturnNull);
}
TypeDesc ISignatureTypeProvider.GetTypeFromSpecification(MetadataReader reader, R2RSigProviderContext genericContext, TypeSpecificationHandle handle, byte rawTypeKind)
{
var ecmaModule = (EcmaModule)_tsc.GetModuleForSimpleName(reader.GetString(reader.GetAssemblyDefinition().Name));
- return (TypeDesc)ecmaModule.GetObject(handle);
+ return (TypeDesc)ecmaModule.GetObject(handle, NotFoundBehavior.ReturnNull);
}
}
}
diff --git a/src/coreclr/tools/dotnet-pgo/TypeRefTypeSystem/TypeRefTypeSystemContext.cs b/src/coreclr/tools/dotnet-pgo/TypeRefTypeSystem/TypeRefTypeSystemContext.cs
index 1cb1138a4929..bb32521c0b75 100644
--- a/src/coreclr/tools/dotnet-pgo/TypeRefTypeSystem/TypeRefTypeSystemContext.cs
+++ b/src/coreclr/tools/dotnet-pgo/TypeRefTypeSystem/TypeRefTypeSystemContext.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
using System.Reflection.Metadata;
using System.Text;
@@ -120,7 +121,7 @@ public TypeRefTypeSystemContext(IEnumerable refReaders)
{
TypeRefSignatureParserProvider parserHelper = new TypeRefSignatureParserProvider(this, peInfo.handleLookup);
- Func resolverFunc = ResolveTypeRefForPeInfo;
+ Func resolverFunc = ResolveTypeRefForPeInfo;
int memberRefRowCount = peInfo.reader.GetTableRowCount(TableIndex.MemberRef);
for (int row = 1; row <= memberRefRowCount; row++)
{
@@ -142,7 +143,7 @@ public TypeRefTypeSystemContext(IEnumerable refReaders)
continue;
}
- EcmaSignatureParser ecmaSigParse = new EcmaSignatureParser(this, ResolveTypeRefForPeInfo, peInfo.reader.GetBlobReader(memberRef.Signature));
+ EcmaSignatureParser ecmaSigParse = new EcmaSignatureParser(this, ResolveTypeRefForPeInfo, peInfo.reader.GetBlobReader(memberRef.Signature), NotFoundBehavior.ReturnNull);
string name = peInfo.reader.GetString(memberRef.Name);
if (memberRef.GetKind() == MemberReferenceKind.Method)
@@ -157,8 +158,9 @@ public TypeRefTypeSystemContext(IEnumerable refReaders)
}
}
- TypeDesc ResolveTypeRefForPeInfo(EntityHandle handle)
+ TypeDesc ResolveTypeRefForPeInfo(EntityHandle handle, NotFoundBehavior notFoundBehavior)
{
+ Debug.Assert(notFoundBehavior == NotFoundBehavior.ReturnNull);
TypeRefTypeSystemType type = null;
if (handle.Kind == HandleKind.TypeReference)
{
diff --git a/src/coreclr/tools/dotnet-pgo/TypeRefTypeSystem/TypeRefTypeSystemModule.cs b/src/coreclr/tools/dotnet-pgo/TypeRefTypeSystem/TypeRefTypeSystemModule.cs
index 45529383eeab..d057112766cc 100644
--- a/src/coreclr/tools/dotnet-pgo/TypeRefTypeSystem/TypeRefTypeSystemModule.cs
+++ b/src/coreclr/tools/dotnet-pgo/TypeRefTypeSystem/TypeRefTypeSystemModule.cs
@@ -71,11 +71,16 @@ private TypeRefTypeSystemType GetTypeInternal(string nameSpace, string name)
return type;
}
- public override MetadataType GetType(string nameSpace, string name, bool throwIfNotFound = true)
+ public override MetadataType GetType(string nameSpace, string name, NotFoundBehavior notFoundBehavior)
{
MetadataType type = GetTypeInternal(nameSpace, name);
- if ((type == null) && throwIfNotFound)
- ThrowHelper.ThrowTypeLoadException(nameSpace, name, this);
+ if ((type == null) && notFoundBehavior != NotFoundBehavior.ReturnNull)
+ {
+ ResolutionFailure failure = ResolutionFailure.GetTypeLoadResolutionFailure(nameSpace, name, this);
+ ModuleDesc.GetTypeResolutionFailure = failure;
+ if (notFoundBehavior == NotFoundBehavior.Throw)
+ failure.Throw();
+ }
return type;
}
}
diff --git a/src/coreclr/utilcode/CMakeLists.txt b/src/coreclr/utilcode/CMakeLists.txt
index c7c5861f129b..0f9606d93535 100644
--- a/src/coreclr/utilcode/CMakeLists.txt
+++ b/src/coreclr/utilcode/CMakeLists.txt
@@ -36,7 +36,6 @@ set(UTILCODE_COMMON_SOURCES
corimage.cpp
format1.cpp
prettyprintsig.cpp
- regutil.cpp
sha1.cpp
sigbuilder.cpp
sigparser.cpp
diff --git a/src/coreclr/utilcode/clrconfig.cpp b/src/coreclr/utilcode/clrconfig.cpp
index 5142e395ac0e..01dd0412e68c 100644
--- a/src/coreclr/utilcode/clrconfig.cpp
+++ b/src/coreclr/utilcode/clrconfig.cpp
@@ -4,18 +4,333 @@
// CLRConfig.cpp
//
-//
-// Unified method of accessing configuration values from environment variables,
-// registry and config file. See file:../inc/CLRConfigValues.h for details on how to add config values.
-//
-//*****************************************************************************
-
#include "stdafx.h"
#include "clrconfig.h"
+#include "sstring.h"
+#include "ex.h"
+
+// Config prefixes
+#define COMPLUS_PREFIX W("COMPlus_")
+#define LEN_OF_COMPLUS_PREFIX 8
+
+using ConfigDWORDInfo = CLRConfig::ConfigDWORDInfo;
+using ConfigStringInfo = CLRConfig::ConfigStringInfo;
+using LookupOptions = CLRConfig::LookupOptions;
+
+namespace
+{
+ //
+ // ProbabilisticNameSet:
+ //
+ // (Used by ConfigCache, below. If used elsewhere, might justify
+ // promotion to a standalone header file.)
+ //
+ // Represent a set of names in a small, fixed amount of storage.
+ // We turn a name into a small integer, then add the integer to a bitvector.
+ // An old trick we used in VC++4 minimal rebuild.
+ //
+ // For best results, the number of elements should be a fraction of
+ // the total number of bits in 'bits'.
+ //
+ // Note, only the const methods are thread-safe.
+ // Callers are responsible for providing their own synchronization when
+ // constructing and Add'ing names to the set.
+ //
+ class ProbabilisticNameSet {
+ public:
+ ProbabilisticNameSet()
+ {
+ WRAPPER_NO_CONTRACT;
+
+ memset(bits, 0, sizeof(bits));
+ }
+
+ // Add a name to the set.
+ //
+ void Add(LPCWSTR name)
+ {
+ WRAPPER_NO_CONTRACT;
+
+ unsigned i, mask;
+ GetBitIndex(name, 0, &i, &mask);
+ bits[i] |= mask;
+ }
+
+ void Add(LPCWSTR name, DWORD count)
+ {
+ WRAPPER_NO_CONTRACT;
+
+ unsigned i, mask;
+ GetBitIndex(name, count, &i, &mask);
+ bits[i] |= mask;
+ }
+
+ // Return TRUE if a name *may have* been added to the set;
+ // return FALSE if the name *definitely* was NOT ever added to the set.
+ //
+ BOOL MayContain(LPCWSTR name) const
+ {
+ WRAPPER_NO_CONTRACT;
+
+ unsigned i, mask;
+ GetBitIndex(name, 0, &i, &mask);
+ return !!(bits[i] & mask);
+ }
+
+ private:
+ static const unsigned cbitSet = 256U;
+ static const unsigned cbitWord = 8U*sizeof(unsigned);
+ unsigned bits[cbitSet/cbitWord];
+
+ // Return the word index and bit mask corresponding to the bitvector member
+ // addressed by the *case-insensitive* hash of the given name.
+ //
+ void GetBitIndex(LPCWSTR name, DWORD count, unsigned* pi, unsigned* pmask) const
+ {
+ LIMITED_METHOD_CONTRACT;
+ unsigned hash;
+ if (count > 0)
+ hash = HashiStringNKnownLower80(name, count) % cbitSet;
+ else
+ hash = HashiStringKnownLower80(name) % cbitSet;
+ *pi = hash / cbitWord;
+ *pmask = (1U << (hash % cbitWord));
+ }
+ };
+
+ BOOL s_fUseEnvCache = FALSE;
+ ProbabilisticNameSet s_EnvNames; // set of environment value names seen
+
+ BOOL EnvCacheValueNameSeenPerhaps(LPCWSTR name)
+ {
+ WRAPPER_NO_CONTRACT;
+
+ return !s_fUseEnvCache
+ || s_EnvNames.MayContain(name);
+ }
+
+ //*****************************************************************************
+ // Reads from the environment setting
+ //*****************************************************************************
+ LPWSTR EnvGetString(LPCWSTR name, bool fPrependCOMPLUS)
+ {
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ FORBID_FAULT;
+ CANNOT_TAKE_LOCK;
+ }
+ CONTRACTL_END;
+
+ WCHAR buff[64];
+
+ if(wcslen(name) > (size_t)(64 - 1 - (fPrependCOMPLUS ? LEN_OF_COMPLUS_PREFIX : 0)))
+ {
+ return NULL;
+ }
+
+ if (fPrependCOMPLUS)
+ {
+ if (!EnvCacheValueNameSeenPerhaps(name))
+ return NULL;
+
+ wcscpy_s(buff, _countof(buff), COMPLUS_PREFIX);
+ }
+ else
+ {
+ *buff = 0;
+ }
+
+ wcscat_s(buff, _countof(buff), name);
+
+ FAULT_NOT_FATAL(); // We don't report OOM errors here, we return a default value.
+
+ NewArrayHolder ret = NULL;
+ HRESULT hr = S_OK;
+ DWORD Len;
+ EX_TRY
+ {
+ PathString temp;
+
+ Len = WszGetEnvironmentVariable(buff, temp);
+ if (Len != 0)
+ {
+ ret = temp.GetCopyOfUnicodeString();
+ }
+
+ }
+ EX_CATCH_HRESULT(hr);
+
+ if (hr != S_OK)
+ {
+ SetLastError(hr);
+ }
+
+ if(ret != NULL)
+ return ret.Extract();
+
+ return NULL;
+ }
+
+ HRESULT GetConfigDWORD(
+ LPCWSTR name,
+ DWORD defValue,
+ __out DWORD *result,
+ bool fPrependCOMPLUS)
+ {
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ FORBID_FAULT;
+ CANNOT_TAKE_LOCK;
+ }
+ CONTRACTL_END;
+
+ SUPPORTS_DAC_HOST_ONLY;
+
+ FAULT_NOT_FATAL(); // We don't report OOM errors here, we return a default value.
+
+ NewArrayHolder val = EnvGetString(name, fPrependCOMPLUS);
+ if (val != NULL)
+ {
+ errno = 0;
+ LPWSTR endPtr;
+ DWORD configMaybe = wcstoul(val, &endPtr, 16); // treat it has hex
+ BOOL fSuccess = ((errno != ERANGE) && (endPtr != val));
+ if (fSuccess)
+ {
+ *result = configMaybe;
+ return (S_OK);
+ }
+ }
+
+ *result = defValue;
+ return (E_FAIL);
+ }
+
+ LPWSTR GetConfigString(
+ LPCWSTR name,
+ bool fPrependCOMPLUS)
+ {
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ FORBID_FAULT;
+ }
+ CONTRACTL_END;
+
+ NewArrayHolder ret(NULL);
+
+ FAULT_NOT_FATAL(); // We don't report OOM errors here, we return a default value.
+
+ ret = EnvGetString(name, fPrependCOMPLUS);
+ if (ret != NULL)
+ {
+ if (*ret != W('\0'))
+ {
+ ret.SuppressRelease();
+ return(ret);
+ }
+ ret.Clear();
+ }
+
+ return NULL;
+ }
+
+ bool CheckLookupOption(const ConfigDWORDInfo & info, LookupOptions option)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return ((info.options & option) == option);
+ }
+
+ bool CheckLookupOption(const ConfigStringInfo & info, LookupOptions option)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return ((info.options & option) == option);
+ }
+
+ bool CheckLookupOption(LookupOptions infoOptions, LookupOptions optionToCheck)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return ((infoOptions & optionToCheck) == optionToCheck);
+ }
+
+ //---------------------------------------------------------------------------------------
+ //
+ // Given an input string, returns a newly-allocated string equal to the input but with
+ // leading and trailing whitespace trimmed off. If input is already trimmed, or if
+ // trimming would result in an empty string, this function sets the output string to NULL
+ //
+ // Caller must free *pwszTrimmed if non-NULL
+ //
+ // Arguments:
+ // * wszOrig - String to trim
+ // * pwszTrimmed - [out]: On return, points to newly allocated, trimmed string (or
+ // NULL)
+ //
+ // Return Value:
+ // HRESULT indicating success or failure.
+ //
+ HRESULT TrimWhiteSpace(LPCWSTR wszOrig, __deref_out_z LPWSTR * pwszTrimmed)
+ {
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ _ASSERTE(wszOrig != NULL);
+ _ASSERTE(pwszTrimmed != NULL);
+
+ // In case we return early, set [out] to NULL by default
+ *pwszTrimmed = NULL;
-#ifndef ERANGE
-#define ERANGE 34
-#endif
+ // Get pointers into internal string that show where to do the trimming.
+ size_t cchOrig = wcslen(wszOrig);
+ if (!FitsIn(cchOrig))
+ return COR_E_OVERFLOW;
+ DWORD cchAfterTrim = (DWORD) cchOrig;
+ LPCWSTR wszAfterTrim = wszOrig;
+ ::TrimWhiteSpace(&wszAfterTrim, &cchAfterTrim);
+
+ // Is input string already trimmed? If so, save an allocation and just return.
+ if ((wszOrig == wszAfterTrim) && (cchOrig == cchAfterTrim))
+ {
+ // Yup, just return success
+ return S_OK;
+ }
+
+ if (cchAfterTrim == 0)
+ {
+ // After trimming, there's nothing left, so just return NULL
+ return S_OK;
+ }
+
+ // Create a new buffer to hold a copy of the trimmed string. Caller will be
+ // responsible for this buffer if we return it.
+ NewArrayHolder wszTrimmedCopy(new (nothrow) WCHAR[cchAfterTrim + 1]);
+ if (wszTrimmedCopy == NULL)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ errno_t err = wcsncpy_s(wszTrimmedCopy, cchAfterTrim + 1, wszAfterTrim, cchAfterTrim);
+ if (err != 0)
+ {
+ return E_FAIL;
+ }
+
+ // Successfully made a copy of the trimmed string. Return it. Caller will be responsible for
+ // deleting it.
+ wszTrimmedCopy.SuppressRelease();
+ *pwszTrimmed = wszTrimmedCopy;
+ return S_OK;
+ }
+}
//
// Creating structs using the macro table in CLRConfigValues.h
@@ -23,46 +338,32 @@
// These macros intialize ConfigDWORDInfo structs.
#define RETAIL_CONFIG_DWORD_INFO(symbol, name, defaultValue, description) \
- const CLRConfig::ConfigDWORDInfo CLRConfig::symbol = {name, defaultValue, CLRConfig::EEConfig_default};
+ const CLRConfig::ConfigDWORDInfo CLRConfig::symbol = {name, defaultValue, CLRConfig::LookupOptions::Default};
#define RETAIL_CONFIG_DWORD_INFO_EX(symbol, name, defaultValue, description, lookupOptions) \
const CLRConfig::ConfigDWORDInfo CLRConfig::symbol = {name, defaultValue, lookupOptions};
// These macros intialize ConfigStringInfo structs.
#define RETAIL_CONFIG_STRING_INFO(symbol, name, description) \
- const CLRConfig::ConfigStringInfo CLRConfig::symbol = {name, CLRConfig::EEConfig_default};
+ const CLRConfig::ConfigStringInfo CLRConfig::symbol = {name, CLRConfig::LookupOptions::Default};
#define RETAIL_CONFIG_STRING_INFO_EX(symbol, name, description, lookupOptions) \
const CLRConfig::ConfigStringInfo CLRConfig::symbol = {name, lookupOptions};
-
-// TEMPORARY macros that intialize strings for config value accesses that haven't been moved over to
-// CLRConfig yet. Once all accesses have been moved, these macros (and corresponding instantiations in
-// file:../utilcode/CLRConfig.h) should be removed.
-#define RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(symbol, name, description) \
- const LPCWSTR CLRConfig::symbol = name;
-#define RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(symbol, name, description) \
- const LPCWSTR CLRConfig::symbol = name;
//
// Debug versions of the macros
//
#ifdef _DEBUG
#define CONFIG_DWORD_INFO(symbol, name, defaultValue, description) \
- const CLRConfig::ConfigDWORDInfo CLRConfig::symbol = {name, defaultValue, CLRConfig::EEConfig_default};
+ const CLRConfig::ConfigDWORDInfo CLRConfig::symbol = {name, defaultValue, CLRConfig::LookupOptions::Default};
#define CONFIG_DWORD_INFO_EX(symbol, name, defaultValue, description, lookupOptions) \
const CLRConfig::ConfigDWORDInfo CLRConfig::symbol = {name, defaultValue, lookupOptions};
#define CONFIG_STRING_INFO(symbol, name, description) \
- const CLRConfig::ConfigStringInfo CLRConfig::symbol = {name, CLRConfig::EEConfig_default};
+ const CLRConfig::ConfigStringInfo CLRConfig::symbol = {name, CLRConfig::LookupOptions::Default};
#define CONFIG_STRING_INFO_EX(symbol, name, description, lookupOptions) \
const CLRConfig::ConfigStringInfo CLRConfig::symbol = {name, lookupOptions};
- #define CONFIG_DWORD_INFO_DIRECT_ACCESS(symbol, name, description) \
- const LPCWSTR CLRConfig::symbol = name;
- #define CONFIG_STRING_INFO_DIRECT_ACCESS(symbol, name, description) \
- const LPCWSTR CLRConfig::symbol = name;
#else
#define CONFIG_DWORD_INFO(symbol, name, defaultValue, description)
#define CONFIG_DWORD_INFO_EX(symbol, name, defaultValue, description, lookupOptions)
#define CONFIG_STRING_INFO(symbol, name, description)
#define CONFIG_STRING_INFO_EX(symbol, name, description, lookupOptions)
- #define CONFIG_DWORD_INFO_DIRECT_ACCESS(symbol, name, description)
- #define CONFIG_STRING_INFO_DIRECT_ACCESS(symbol, name, description)
#endif // _DEBUG
// Now that we have defined what what the macros in file:../inc/CLRConfigValues.h mean, include it to generate the code.
@@ -72,15 +373,10 @@
#undef RETAIL_CONFIG_STRING_INFO
#undef RETAIL_CONFIG_DWORD_INFO_EX
#undef RETAIL_CONFIG_STRING_INFO_EX
-#undef RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS
-#undef RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS
#undef CONFIG_DWORD_INFO
#undef CONFIG_STRING_INFO
#undef CONFIG_DWORD_INFO_EX
#undef CONFIG_STRING_INFO_EX
-#undef CONFIG_DWORD_INFO_DIRECT_ACCESS
-#undef CONFIG_STRING_INFO_DIRECT_ACCESS
-
//
// Look up a DWORD config value.
@@ -88,19 +384,13 @@
// Arguments:
// * info - see file:../inc/CLRConfig.h for details.
//
-// * useDefaultIfNotSet - if true, fall back to the default value if the value is not set.
-//
-// * acceptExplicitDefaultFromRegutil - if false, only accept a value returned by REGUTIL if it is
-// different from the default value. This parameter is useful as a way to preserve existing
-// behavior.
-//
// * result - the result.
//
// Return value:
// * true for success, false otherwise.
//
// static
-DWORD CLRConfig::GetConfigValue(const ConfigDWORDInfo & info, bool acceptExplicitDefaultFromRegutil, /* [Out] */ bool *isDefault)
+DWORD CLRConfig::GetConfigValue(const ConfigDWORDInfo & info, /* [Out] */ bool *isDefault)
{
CONTRACTL
{
@@ -112,41 +402,40 @@ DWORD CLRConfig::GetConfigValue(const ConfigDWORDInfo & info, bool acceptExplici
_ASSERTE (isDefault != nullptr);
-
- //
- // Set up REGUTIL options.
- //
- REGUTIL::CORConfigLevel level = GetConfigLevel(info.options);
- BOOL prependCOMPlus = !CheckLookupOption(info, DontPrependCOMPlus_);
-
+ bool prependCOMPlus = !CheckLookupOption(info, LookupOptions::DontPrependCOMPlus_);
DWORD resultMaybe;
- HRESULT hr = REGUTIL::GetConfigDWORD_DontUse_(info.name, info.defaultValue, &resultMaybe, level, prependCOMPlus);
+ HRESULT hr = GetConfigDWORD(info.name, info.defaultValue, &resultMaybe, prependCOMPlus);
- if (!acceptExplicitDefaultFromRegutil)
+ // Ignore the default value even if it's set explicitly.
+ if (resultMaybe != info.defaultValue)
{
- // Ignore the default value even if it's set explicitly.
- if (resultMaybe != info.defaultValue)
- {
- *isDefault = false;
- return resultMaybe;
- }
- }
- else
- {
- // If we are willing to accept the default value when it's set explicitly,
- // checking the HRESULT here is sufficient. E_FAIL is returned when the
- // default is used.
- if (SUCCEEDED(hr))
- {
- *isDefault = false;
- return resultMaybe;
- }
+ *isDefault = false;
+ return resultMaybe;
}
*isDefault = true;
return info.defaultValue;
}
+//
+// Look up a DWORD config value.
+//
+// Arguments:
+// * info - see file:../inc/CLRConfig.h for details
+//
+// static
+DWORD CLRConfig::GetConfigValue(const ConfigDWORDInfo & info, DWORD defaultValue)
+{
+ bool isDefault = false;
+ DWORD valueMaybe = GetConfigValue(info, &isDefault);
+
+ // If the default value was returned, defer to the user supplied version.
+ if (isDefault)
+ return defaultValue;
+
+ return valueMaybe;
+}
+
//
// Look up a DWORD config value.
//
@@ -156,10 +445,8 @@ DWORD CLRConfig::GetConfigValue(const ConfigDWORDInfo & info, bool acceptExplici
// static
DWORD CLRConfig::GetConfigValue(const ConfigDWORDInfo & info)
{
- // We pass false for 'acceptExplicitDefaultFromRegutil' to maintain the existing behavior of this function.
- // Callers who don't need that behavior should switch to the other version of this function and pass true.
bool unused;
- return GetConfigValue(info, false /* acceptExplicitDefaultFromRegutil */, &unused);
+ return GetConfigValue(info, &unused);
}
//
@@ -217,16 +504,10 @@ HRESULT CLRConfig::GetConfigValue(const ConfigStringInfo & info, __deref_out_z L
LPWSTR result = NULL;
+ bool prependCOMPlus = !CheckLookupOption(info, LookupOptions::DontPrependCOMPlus_);
+ result = GetConfigString(info.name, prependCOMPlus);
- //
- // Set up REGUTIL options.
- //
- REGUTIL::CORConfigLevel level = GetConfigLevel(info.options);
- BOOL prependCOMPlus = !CheckLookupOption(info, DontPrependCOMPlus_);
-
- result = REGUTIL::GetConfigString_DontUse_(info.name, prependCOMPlus, level);
-
- if ((result != NULL) && CheckLookupOption(info, TrimWhiteSpaceFromStringValue))
+ if ((result != NULL) && CheckLookupOption(info, LookupOptions::TrimWhiteSpaceFromStringValue))
{
// If this fails, result remains untouched, so we'll just return the untrimmed
// value.
@@ -261,46 +542,44 @@ BOOL CLRConfig::IsConfigOptionSpecified(LPCWSTR name)
}
CONTRACTL_END;
- // Check REGUTIL, both with and without the COMPlus_ prefix
{
LPWSTR result = NULL;
- result = REGUTIL::GetConfigString_DontUse_(name, TRUE);
+ result = GetConfigString(name, true /* fPrependCOMPLUS */);
if (result != NULL)
{
FreeConfigString(result);
return TRUE;
}
- result = REGUTIL::GetConfigString_DontUse_(name, FALSE);
+ result = GetConfigString(name, false /* fPrependCOMPLUS */);
if (result != NULL)
{
FreeConfigString(result);
return TRUE;
}
-
}
return FALSE;
}
-//---------------------------------------------------------------------------------------
//
-// Given an input string, returns a newly-allocated string equal to the input but with
-// leading and trailing whitespace trimmed off. If input is already trimmed, or if
-// trimming would result in an empty string, this function sets the output string to NULL
-//
-// Caller must free *pwszTrimmed if non-NULL
+// Deallocation function for code:CLRConfig::FreeConfigString
//
-// Arguments:
-// * wszOrig - String to trim
-// * pwszTrimmed - [out]: On return, points to newly allocated, trimmed string (or
-// NULL)
+// static
+void CLRConfig::FreeConfigString(__in_z LPWSTR str)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ // See EnvGetString().
+ delete [] str;
+}
+
//
-// Return Value:
-// HRESULT indicating success or failure.
+// Initialize the internal cache faster lookup.
//
-HRESULT CLRConfig::TrimWhiteSpace(LPCWSTR wszOrig, __deref_out_z LPWSTR * pwszTrimmed)
+// static
+void CLRConfig::InitCache()
{
CONTRACTL
{
@@ -309,77 +588,49 @@ HRESULT CLRConfig::TrimWhiteSpace(LPCWSTR wszOrig, __deref_out_z LPWSTR * pwszTr
}
CONTRACTL_END;
- _ASSERTE(wszOrig != NULL);
- _ASSERTE(pwszTrimmed != NULL);
-
- // In case we return early, set [out] to NULL by default
- *pwszTrimmed = NULL;
-
- // Get pointers into internal string that show where to do the trimming.
- size_t cchOrig = wcslen(wszOrig);
- if (!FitsIn(cchOrig))
- return COR_E_OVERFLOW;
- DWORD cchAfterTrim = (DWORD) cchOrig;
- LPCWSTR wszAfterTrim = wszOrig;
- ::TrimWhiteSpace(&wszAfterTrim, &cchAfterTrim);
-
- // Is input string already trimmed? If so, save an allocation and just return.
- if ((wszOrig == wszAfterTrim) && (cchOrig == cchAfterTrim))
- {
- // Yup, just return success
- return S_OK;
- }
+ // Check if caching is disabled.
+ if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_DisableConfigCache) != 0)
+ return;
- if (cchAfterTrim == 0)
+#ifdef TARGET_WINDOWS
+ // Create a cache of environment variables
+ WCHAR* wszStrings = WszGetEnvironmentStrings();
+ if (wszStrings != NULL)
{
- // After trimming, there's nothing left, so just return NULL
- return S_OK;
- }
+ // GetEnvironmentStrings returns pointer to a null terminated block containing
+ // null terminated strings
+ for(WCHAR *wszCurr = wszStrings; *wszCurr; wszCurr++)
+ {
+ WCHAR wch = towlower(*wszCurr);
+
+ // Lets only cache env variables with the COMPlus prefix only
+ if (wch == W('c'))
+ {
+ WCHAR *wszName = wszCurr;
+
+ // Look for the separator between name and value
+ while (*wszCurr && *wszCurr != W('='))
+ wszCurr++;
+
+ if (*wszCurr == W('='))
+ {
+ // Check the prefix
+ if(!SString::_wcsnicmp(wszName, COMPLUS_PREFIX, LEN_OF_COMPLUS_PREFIX))
+ {
+ wszName += LEN_OF_COMPLUS_PREFIX;
+ s_EnvNames.Add(wszName, (DWORD) (wszCurr - wszName));
+ }
+ }
+
+ }
+ // Look for current string termination
+ while (*wszCurr)
+ wszCurr++;
- // Create a new buffer to hold a copy of the trimmed string. Caller will be
- // responsible for this buffer if we return it.
- NewArrayHolder wszTrimmedCopy(new (nothrow) WCHAR[cchAfterTrim + 1]);
- if (wszTrimmedCopy == NULL)
- {
- return E_OUTOFMEMORY;
- }
+ }
- errno_t err = wcsncpy_s(wszTrimmedCopy, cchAfterTrim + 1, wszAfterTrim, cchAfterTrim);
- if (err != 0)
- {
- return E_FAIL;
+ WszFreeEnvironmentStrings(wszStrings);
+ s_fUseEnvCache = TRUE;
}
-
- // Successfully made a copy of the trimmed string. Return it. Caller will be responsible for
- // deleting it.
- wszTrimmedCopy.SuppressRelease();
- *pwszTrimmed = wszTrimmedCopy;
- return S_OK;
-}
-
-
-//
-// Deallocation function for code:CLRConfig::FreeConfigString
-//
-void CLRConfig::FreeConfigString(__in_z LPWSTR str)
-{
- LIMITED_METHOD_CONTRACT;
-
- delete [] str;
-}
-
-//
-// Helper method to translate LookupOptions to REGUTIL::CORConfigLevel.
-//
-//static
-REGUTIL::CORConfigLevel CLRConfig::GetConfigLevel(LookupOptions options)
-{
- LIMITED_METHOD_CONTRACT;
-
- REGUTIL::CORConfigLevel level = (REGUTIL::CORConfigLevel) 0;
-
- if(CheckLookupOption(options, IgnoreEnv) == FALSE)
- level = static_cast(level | REGUTIL::COR_CONFIG_ENV);
-
- return static_cast(level | REGUTIL::COR_CONFIG_USER | REGUTIL::COR_CONFIG_MACHINE);
+#endif // TARGET_WINDOWS
}
diff --git a/src/coreclr/utilcode/configuration.cpp b/src/coreclr/utilcode/configuration.cpp
index e67507d5bae0..50a5e335a742 100644
--- a/src/coreclr/utilcode/configuration.cpp
+++ b/src/coreclr/utilcode/configuration.cpp
@@ -52,7 +52,7 @@ static LPCWSTR GetConfigurationValue(LPCWSTR name)
DWORD Configuration::GetKnobDWORDValue(LPCWSTR name, const CLRConfig::ConfigDWORDInfo& dwordInfo)
{
bool returnedDefaultValue;
- DWORD legacyValue = CLRConfig::GetConfigValue(dwordInfo, true /* acceptExplicitDefaultFromRegutil */, &returnedDefaultValue);
+ DWORD legacyValue = CLRConfig::GetConfigValue(dwordInfo, &returnedDefaultValue);
if (!returnedDefaultValue)
{
return legacyValue;
@@ -108,7 +108,7 @@ LPCWSTR Configuration::GetKnobStringValue(LPCWSTR name)
bool Configuration::GetKnobBooleanValue(LPCWSTR name, const CLRConfig::ConfigDWORDInfo& dwordInfo)
{
bool returnedDefaultValue;
- DWORD legacyValue = CLRConfig::GetConfigValue(dwordInfo, true /* acceptExplicitDefaultFromRegutil */, &returnedDefaultValue);
+ DWORD legacyValue = CLRConfig::GetConfigValue(dwordInfo, &returnedDefaultValue);
if (!returnedDefaultValue)
{
return (legacyValue != 0);
diff --git a/src/coreclr/utilcode/log.cpp b/src/coreclr/utilcode/log.cpp
index 37edc05b5cdb..b4a73f2cb6ba 100644
--- a/src/coreclr/utilcode/log.cpp
+++ b/src/coreclr/utilcode/log.cpp
@@ -47,16 +47,16 @@ VOID InitLogging()
// FIX bit of a workaround for now, check for the log file in the
// registry and if there, turn on file logging VPM
- LogFlags |= REGUTIL::GetConfigFlag_DontUse_(CLRConfig::INTERNAL_LogEnable, LOG_ENABLE);
- LogFacilityMask = REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_LogFacility, LogFacilityMask) | LF_ALWAYS;
- LogVMLevel = REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::EXTERNAL_LogLevel, LogVMLevel);
- LogFlags |= REGUTIL::GetConfigFlag_DontUse_(CLRConfig::INTERNAL_LogFileAppend, LOG_ENABLE_APPEND_FILE);
- LogFlags |= REGUTIL::GetConfigFlag_DontUse_(CLRConfig::INTERNAL_LogFlushFile, LOG_ENABLE_FLUSH_FILE);
- LogFlags |= REGUTIL::GetConfigFlag_DontUse_(CLRConfig::INTERNAL_LogToDebugger, LOG_ENABLE_DEBUGGER_LOGGING);
- LogFlags |= REGUTIL::GetConfigFlag_DontUse_(CLRConfig::INTERNAL_LogToFile, LOG_ENABLE_FILE_LOGGING);
- LogFlags |= REGUTIL::GetConfigFlag_DontUse_(CLRConfig::INTERNAL_LogToConsole, LOG_ENABLE_CONSOLE_LOGGING);
+ LogFlags |= (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_LogEnable) != 0) ? LOG_ENABLE : 0;
+ LogFacilityMask = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_LogFacility, LogFacilityMask) | LF_ALWAYS;
+ LogVMLevel = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_LogLevel, LogVMLevel);
+ LogFlags |= (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_LogFileAppend) != 0) ? LOG_ENABLE_APPEND_FILE : 0;
+ LogFlags |= (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_LogFlushFile) != 0) ? LOG_ENABLE_FLUSH_FILE : 0;
+ LogFlags |= (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_LogToDebugger) != 0) ? LOG_ENABLE_DEBUGGER_LOGGING : 0;
+ LogFlags |= (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_LogToFile) != 0) ? LOG_ENABLE_FILE_LOGGING : 0;
+ LogFlags |= (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_LogToConsole) != 0) ? LOG_ENABLE_CONSOLE_LOGGING : 0;
- LogFacilityMask2 = REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_LogFacility2, LogFacilityMask2) | LF_ALWAYS;
+ LogFacilityMask2 = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_LogFacility2, LogFacilityMask2) | LF_ALWAYS;
if (SUCCEEDED(szLogFileName.ReSizeNoThrow(MAX_LONGPATH)))
{
@@ -73,7 +73,7 @@ VOID InitLogging()
delete fileName;
}
- if (REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_LogWithPid, FALSE))
+ if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_LogWithPid))
{
WCHAR szPid[20];
swprintf_s(szPid, COUNTOF(szPid), W(".%d"), GetCurrentProcessId());
diff --git a/src/coreclr/utilcode/regutil.cpp b/src/coreclr/utilcode/regutil.cpp
deleted file mode 100644
index fcfbe6eb7c7c..000000000000
--- a/src/coreclr/utilcode/regutil.cpp
+++ /dev/null
@@ -1,759 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-//*****************************************************************************
-// regutil.cpp
-//
-
-//
-// This module contains a set of functions that can be used to access the
-// registry.
-//
-//*****************************************************************************
-
-
-#include "stdafx.h"
-#include "utilcode.h"
-#include "mscoree.h"
-#include "sstring.h"
-#include "ex.h"
-
-#define COMPLUS_PREFIX W("COMPlus_")
-#define LEN_OF_COMPLUS_PREFIX 8
-
-#if (!defined(FEATURE_UTILCODE_NO_DEPENDENCIES) || defined(DEBUG)) && !defined(TARGET_UNIX)
-#define ALLOW_REGISTRY
-#endif
-
-#undef WszRegCreateKeyEx
-#undef WszRegOpenKeyEx
-#undef WszRegOpenKey
-#define WszRegCreateKeyEx RegCreateKeyExW
-#define WszRegOpenKeyEx RegOpenKeyExW
-#define WszRegOpenKey(hKey, wszSubKey, phkRes) RegOpenKeyExW(hKey, wszSubKey, 0, KEY_ALL_ACCESS, phkRes)
-
-//*****************************************************************************
-// Reads from the environment setting
-//*****************************************************************************
-LPWSTR REGUTIL::EnvGetString(LPCWSTR name, BOOL fPrependCOMPLUS)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- FORBID_FAULT;
- CANNOT_TAKE_LOCK;
- }
- CONTRACTL_END;
-
- WCHAR buff[64];
-
- if(wcslen(name) > (size_t)(64 - 1 - (fPrependCOMPLUS ? LEN_OF_COMPLUS_PREFIX : 0)))
- {
- return NULL;
- }
-
- if (fPrependCOMPLUS)
- {
-#ifdef ALLOW_REGISTRY
- if (!EnvCacheValueNameSeenPerhaps(name))
- return NULL;
-#endif // ALLOW_REGISTRY
- wcscpy_s(buff, _countof(buff), COMPLUS_PREFIX);
- }
- else
- {
- *buff = 0;
- }
-
- wcscat_s(buff, _countof(buff), name);
-
- FAULT_NOT_FATAL(); // We don't report OOM errors here, we return a default value.
-
-
- NewArrayHolder ret = NULL;
- HRESULT hr = S_OK;
- DWORD Len;
- EX_TRY
- {
- PathString temp;
-
- Len = WszGetEnvironmentVariable(buff, temp);
- if (Len != 0)
- {
- ret = temp.GetCopyOfUnicodeString();
- }
-
- }
- EX_CATCH_HRESULT(hr);
-
- if (hr != S_OK)
- {
- SetLastError(hr);
- }
-
- if(ret != NULL)
- {
- return ret.Extract();
- }
-
- return NULL;
-
-
-}
-
-//*****************************************************************************
-// Reads a DWORD from the COR configuration according to the level specified
-// Returns back defValue if the key cannot be found
-//*****************************************************************************
-DWORD REGUTIL::GetConfigDWORD_DontUse_(LPCWSTR name, DWORD defValue, CORConfigLevel level, BOOL fPrependCOMPLUS)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- FORBID_FAULT;
- CANNOT_TAKE_LOCK;
- }
- CONTRACTL_END;
-
- SUPPORTS_DAC_HOST_ONLY;
-
- ULONGLONG result;
- GetConfigInteger(name, defValue, &result, TRUE, level, fPrependCOMPLUS);
-
- return (DWORD)result;
-}
-
-#define uniwcst(val, endptr, base) (fGetDWORD ? wcstoul(val, endptr, base) : _wcstoui64(val, endptr, base))
-
-//
-// Look up a dword config value, and write the result to the DWORD passed in by reference.
-//
-// Return value:
-// * E_FAIL if the value is not found. (result is assigned the default value)
-// * S_OK if the value is found. (result is assigned the value that was found)
-//
-// Arguments:
-// * info - see file:../inc/CLRConfig.h for details
-// * result - Pointer to the output DWORD.
-//
-// static
-HRESULT REGUTIL::GetConfigDWORD_DontUse_(LPCWSTR name, DWORD defValue, __out DWORD * result, CORConfigLevel level, BOOL fPrependCOMPLUS)
-{
- ULONGLONG ullResult;
- HRESULT hr = GetConfigInteger(name, defValue, &ullResult, TRUE, level, fPrependCOMPLUS);
- *result = (DWORD)ullResult;
- return hr;
-}
-
-ULONGLONG REGUTIL::GetConfigULONGLONG_DontUse_(LPCWSTR name, ULONGLONG defValue, CORConfigLevel level, BOOL fPrependCOMPLUS)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- FORBID_FAULT;
- CANNOT_TAKE_LOCK;
- }
- CONTRACTL_END;
-
- SUPPORTS_DAC_HOST_ONLY;
-
- ULONGLONG result;
- GetConfigInteger(name, defValue, &result, FALSE, level, fPrependCOMPLUS);
-
- return result;
-}
-
-// This function should really be refactored to return the string from the environment and let the caller decide
-// what to convert it to; and return the buffer read from the reg call.
-// Note for PAL: right now PAL does not have a _wcstoui64 API, so I am temporarily reading in all numbers as
-// a 32-bit number. When we have the _wcstoui64 API on MAC we will use uniwcst instead of wcstoul.
-HRESULT REGUTIL::GetConfigInteger(LPCWSTR name, ULONGLONG defValue, __out ULONGLONG * result, BOOL fGetDWORD, CORConfigLevel level, BOOL fPrependCOMPLUS)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- FORBID_FAULT;
- CANNOT_TAKE_LOCK;
- }
- CONTRACTL_END;
-
- SUPPORTS_DAC_HOST_ONLY;
-
- ULONGLONG rtn;
- ULONGLONG ret = 0;
- DWORD type = 0;
- DWORD size = 4;
-
- FAULT_NOT_FATAL(); // We don't report OOM errors here, we return a default value.
-
- if (level & COR_CONFIG_ENV)
- {
- WCHAR* val = EnvGetString(name, fPrependCOMPLUS); // try getting it from the environement first
- if (val != 0) {
- errno = 0;
- LPWSTR endPtr;
- rtn = uniwcst(val, &endPtr, 16); // treat it has hex
- BOOL fSuccess = ((errno != ERANGE) && (endPtr != val));
- delete[] val;
-
- if (fSuccess) // success
- {
- *result = rtn;
- return (S_OK);
- }
- }
- }
-
- // Early out if no registry access, simplifies following code.
- //
- if (!(level & COR_CONFIG_REGISTRY))
- {
- *result = defValue;
- return (E_FAIL);
- }
-
-#ifdef ALLOW_REGISTRY
- // Probe the config cache to see if there is any point
- // probing the registry; if not, don't bother.
- //
- if (!RegCacheValueNameSeenPerhaps(name))
- {
- *result = defValue;
- return (E_FAIL);
- }
-#endif // ALLOW_REGISTRY
-
- if (level & COR_CONFIG_USER)
- {
-#ifdef ALLOW_REGISTRY
- {
- LONG retVal = ERROR_SUCCESS;
- BOOL bCloseHandle = FALSE;
- HKEY userKey = s_hUserFrameworkKey;
-
- if (userKey == INVALID_HANDLE_VALUE)
- {
- retVal = WszRegOpenKeyEx(HKEY_CURRENT_USER, FRAMEWORK_REGISTRY_KEY_W, 0, KEY_READ, &userKey);
- bCloseHandle = TRUE;
- }
-
- if (retVal == ERROR_SUCCESS)
- {
- rtn = WszRegQueryValueEx(userKey, name, 0, &type, (LPBYTE)&ret, &size);
-
- if (bCloseHandle)
- VERIFY(!RegCloseKey(userKey));
-
- if (rtn == ERROR_SUCCESS && (type == REG_DWORD || (!fGetDWORD && type == REG_QWORD)))
- {
- *result = ret;
- return (S_OK);
- }
- }
- }
-#endif // ALLOW_REGISTRY
- }
-
- if (level & COR_CONFIG_MACHINE)
- {
-#ifdef ALLOW_REGISTRY
- {
- LONG retVal = ERROR_SUCCESS;
- BOOL bCloseHandle = FALSE;
- HKEY machineKey = s_hMachineFrameworkKey;
-
- if (machineKey == INVALID_HANDLE_VALUE)
- {
- retVal = WszRegOpenKeyEx(HKEY_LOCAL_MACHINE, FRAMEWORK_REGISTRY_KEY_W, 0, KEY_READ, &machineKey);
- bCloseHandle = TRUE;
- }
-
- if (retVal == ERROR_SUCCESS)
- {
- rtn = WszRegQueryValueEx(machineKey, name, 0, &type, (LPBYTE)&ret, &size);
-
- if (bCloseHandle)
- VERIFY(!RegCloseKey(machineKey));
-
- if (rtn == ERROR_SUCCESS && (type == REG_DWORD || (!fGetDWORD && type == REG_QWORD)))
- {
- *result = ret;
- return (S_OK);
- }
- }
- }
-#endif // ALLOW_REGISTRY
- }
-
- *result = defValue;
- return (E_FAIL);
-}
-
-//*****************************************************************************
-// Reads a string from the COR configuration according to the level specified
-// The caller is responsible for deallocating the returned string by
-// calling code:REGUTIL::FreeConfigString or using a code:ConfigStringHolder
-//*****************************************************************************
-
-LPWSTR REGUTIL::GetConfigString_DontUse_(LPCWSTR name, BOOL fPrependCOMPLUS, CORConfigLevel level, BOOL fUsePerfCache)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- FORBID_FAULT;
- }
- CONTRACTL_END;
-
-#ifdef ALLOW_REGISTRY
- HRESULT lResult;
- RegKeyHolder userKey = NULL;
- RegKeyHolder machineKey = NULL;
- RegKeyHolder fusionKey = NULL;
- DWORD type;
- DWORD size;
-#endif // ALLOW_REGISTRY
- NewArrayHolder ret(NULL);
-
- FAULT_NOT_FATAL(); // We don't report OOM errors here, we return a default value.
-
- if (level & COR_CONFIG_ENV)
- {
- ret = EnvGetString(name, fPrependCOMPLUS); // try getting it from the environement first
- if (ret != 0) {
- if (*ret != 0)
- {
- ret.SuppressRelease();
- return(ret);
- }
- ret.Clear();
- }
- }
-
- // Early out if no registry access, simplifies following code.
- //
- if (!(level & COR_CONFIG_REGISTRY))
- {
- return(ret);
- }
-
-#ifdef ALLOW_REGISTRY
- // Probe the config cache to see if there is any point
- // probing the registry; if not, don't bother.
- //
- if (fUsePerfCache && !RegCacheValueNameSeenPerhaps(name))
- return ret;
-#endif // ALLOW_REGISTRY
-
- if (level & COR_CONFIG_USER)
- {
-#ifdef ALLOW_REGISTRY
- BOOL bUsingCachedKey = FALSE;
-
- if (s_hUserFrameworkKey != INVALID_HANDLE_VALUE)
- {
- bUsingCachedKey = TRUE;
- userKey = s_hUserFrameworkKey;
- }
-
- if (bUsingCachedKey || WszRegOpenKeyEx(HKEY_CURRENT_USER, FRAMEWORK_REGISTRY_KEY_W, 0, KEY_READ, &userKey) == ERROR_SUCCESS)
- {
- BOOL bReturn = FALSE;
- if (WszRegQueryValueEx(userKey, name, 0, &type, 0, &size) == ERROR_SUCCESS &&
- type == REG_SZ)
- {
- ret = (LPWSTR) new (nothrow) BYTE [size];
- if (ret)
- {
- ret[0] = W('\0');
- lResult = WszRegQueryValueEx(userKey, name, 0, 0, (LPBYTE) ret.GetValue(), &size);
- _ASSERTE(lResult == ERROR_SUCCESS);
- {
- ret.SuppressRelease();
- }
- }
- bReturn = TRUE;
- }
-
- if (bUsingCachedKey)
- userKey.SuppressRelease();
-
- if (bReturn)
- return ret;
- }
-
-#endif // ALLOW_REGISTRY
- }
-
- if (level & COR_CONFIG_MACHINE)
- {
-#ifdef ALLOW_REGISTRY
- BOOL bUsingCachedKey = FALSE;
-
- if (s_hMachineFrameworkKey != INVALID_HANDLE_VALUE)
- {
- bUsingCachedKey = TRUE;
- machineKey = s_hMachineFrameworkKey;
- }
-
- if (bUsingCachedKey || WszRegOpenKeyEx(HKEY_LOCAL_MACHINE, FRAMEWORK_REGISTRY_KEY_W, 0, KEY_READ, &machineKey) == ERROR_SUCCESS)
- {
- BOOL bReturn = FALSE;
- if (WszRegQueryValueEx(machineKey, name, 0, &type, 0, &size) == ERROR_SUCCESS &&
- type == REG_SZ)
- {
- ret = (LPWSTR) new (nothrow) BYTE [size];
- if (ret)
- {
- ret[0] = W('\0');
- lResult = WszRegQueryValueEx(machineKey, name, 0, 0, (LPBYTE) ret.GetValue(), &size);
- _ASSERTE(lResult == ERROR_SUCCESS);
- {
- ret.SuppressRelease();
- }
- }
- bReturn = TRUE;
- }
-
- if (bUsingCachedKey)
- machineKey.SuppressRelease();
-
- if (bReturn)
- return ret;
- }
-
-#endif // ALLOW_REGISTRY
- }
-
- return NULL;
-}
-
-//*****************************************************************************
-// Deallocation function for code:REGUTIL::GetConfigString_DontUse_
-//
-// Notes:
-// Use a code:ConfigStringHolder to automatically call this.
-//*****************************************************************************
-void REGUTIL::FreeConfigString(__in_z LPWSTR str)
-{
- LIMITED_METHOD_CONTRACT;
-
- delete [] str;
-}
-
-//*****************************************************************************
-// Reads a BIT flag from the COR configuration according to the level specified
-// Returns back defValue if the key cannot be found
-//*****************************************************************************
-DWORD REGUTIL::GetConfigFlag_DontUse_(LPCWSTR name, DWORD bitToSet, BOOL defValue)
-{
- WRAPPER_NO_CONTRACT;
-
- return(GetConfigDWORD_DontUse_(name, defValue) != 0 ? bitToSet : 0);
-}
-
-
-#ifdef ALLOW_REGISTRY
-
-
-
-//
-// ProbabilisticNameSet:
-//
-// (Used by ConfigCache, below. If used elsewhere, might justify
-// promotion to a standalone header file.)
-//
-// Represent a set of names in a small, fixed amount of storage.
-// We turn a name into a small integer, then add the integer to a bitvector.
-// An old trick we used in VC++4 minimal rebuild.
-//
-// For best results, the number of elements should be a fraction of
-// the total number of bits in 'bits'.
-//
-// Note, only the const methods are thread-safe.
-// Callers are responsible for providing their own synchronization when
-// constructing and Add'ing names to the set.
-//
-class ProbabilisticNameSet {
-public:
- ProbabilisticNameSet()
- {
- WRAPPER_NO_CONTRACT;
-
- memset(bits, 0, sizeof(bits));
- }
-
- // Add a name to the set.
- //
- void Add(LPCWSTR name)
- {
- WRAPPER_NO_CONTRACT;
-
- unsigned i, mask;
- GetBitIndex(name, 0, &i, &mask);
- bits[i] |= mask;
- }
-
- void Add(LPCWSTR name, DWORD count)
- {
- WRAPPER_NO_CONTRACT;
-
- unsigned i, mask;
- GetBitIndex(name, count, &i, &mask);
- bits[i] |= mask;
- }
-
- // Return TRUE if a name *may have* been added to the set;
- // return FALSE if the name *definitely* was NOT ever added to the set.
- //
- BOOL MayContain(LPCWSTR name) const
- {
- WRAPPER_NO_CONTRACT;
-
- unsigned i, mask;
- GetBitIndex(name, 0, &i, &mask);
- return !!(bits[i] & mask);
- }
-
-private:
- static const unsigned cbitSet = 256U;
- static const unsigned cbitWord = 8U*sizeof(unsigned);
- unsigned bits[cbitSet/cbitWord];
-
- // Return the word index and bit mask corresponding to the bitvector member
- // addressed by the *case-insensitive* hash of the given name.
- //
- void GetBitIndex(LPCWSTR name, DWORD count, unsigned* pi, unsigned* pmask) const
- {
- LIMITED_METHOD_CONTRACT;
- unsigned hash;
- if (count > 0)
- hash = HashiStringNKnownLower80(name, count) % cbitSet;
- else
- hash = HashiStringKnownLower80(name) % cbitSet;
- *pi = hash / cbitWord;
- *pmask = (1U << (hash % cbitWord));
- }
-
-};
-
-
-// From the Win32 SDK docs:
-// Registry Element Size Limits
-// ...
-// The maximum size of a value name is as follows:
-// Windows Server 2003 and Windows XP: 16,383 characters
-// Windows 2000: 260 ANSI characters or 16,383 Unicode characters.
-// Windows Me/98/95: 255 characters
-// Despite that, we only cache value names of 80 characters or less --
-// longer names don't make sense as configuration settings names.
-//
-static const unsigned cchRegValueNameMax = 80;
-
-BOOL REGUTIL::s_fUseRegCache = FALSE;
-BOOL REGUTIL::s_fUseEnvCache = FALSE;
-HKEY REGUTIL::s_hMachineFrameworkKey = (HKEY) INVALID_HANDLE_VALUE;
-HKEY REGUTIL::s_hUserFrameworkKey = (HKEY) INVALID_HANDLE_VALUE;
-static ProbabilisticNameSet regNames; // set of registry value names seen; should be
- // a static field of REGUTIL but I don't
- // want to expose ProbabilisticNameSet.
-static ProbabilisticNameSet envNames; // set of environment value names seen;
-
-// "Registry Configuration Cache"
-//
-// Initialize the (optional) registry config cache.
-//
-// The purpose of the cache is to avoid hundreds of registry probes
-// otherwise incurred by calls to GetConfigDWORD_DontUse_ and GetConfigString_DontUse_.
-//
-// We accomplish this by enumerating the relevant registry keys and
-// remembering the extant value names; and then by avoiding probing
-// for a name that was not seen in the enumeration (initialization) phase.
-//
-// It is optional in the sense that REGUTIL facilities like
-// GetConfigDWORD_DontUse_ and GetConfigString_DontUse_ will work fine if the cache
-// is never initialized; however, each config access then will hit
-// the registry (typically multiple times to search HKCU and HKLM).
-//
-//
-// Initialization: Enumerate these registry keys
-// HKCU Software\Microsoft\.NetFramework
-// HKLM Software\Microsoft\.NetFramework
-// for value names, and "remember" them in the ProbalisticNameSet 'names'.
-//
-// If we ever find a reg value named DisableConfigCache under any of these
-// three keys, the feature is disabled.
-//
-// This method is not thread-safe. It should only be called once.
-//
-// Perf Optimization for VSWhidbey:113373.
-//
-void REGUTIL::InitOptionalConfigCache()
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- }
- CONTRACTL_END;
-
- static const HKEY roots[] = { HKEY_CURRENT_USER,
- HKEY_LOCAL_MACHINE};
-
- LONG l = ERROR_SUCCESS; // general Win32 API error return code
- HKEY hkey = NULL;
-
- // No caching if the environment variable COMPlus_DisableConfigCache is set
- //
- if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_DisableConfigCache) != 0)
- goto failure;
-
- // Enumerate each root
- //
- for (int i = 0; i < NumItems(roots); i++) {
- hkey = NULL; // defensive
- l = WszRegOpenKeyEx(roots[i], FRAMEWORK_REGISTRY_KEY_W, 0, KEY_READ, &hkey);
- if (l == ERROR_FILE_NOT_FOUND) {
- // That registry key is not present.
- // For example, installation with no HKCU\...\.NETFramework.
- // Should be OK to proceed.
- continue;
- }
- else if (l == ERROR_ACCESS_DENIED) {
- // If we encounter access denied for the current key, ignore
- // the failure and continue to cache the rest. Effectively this means
- // we are caching that key as containing no values, which is correct
- // because in the unlikely event there are values hiding underneath
- // later attempts to access them (open the key) would also hit access
- // denied and continue on probing other locations.
- continue;
- }
- else if (l != ERROR_SUCCESS) {
- // Something else went wrong. To be safe, don't enable the cache.
- goto failure;
- }
-
- // Enumerate every value name under this key.
- //
- for (int j = 0; ; j++) {
- WCHAR wszValue[cchRegValueNameMax + 1];
- DWORD dwValueSize = NumItems(wszValue);
- l = WszRegEnumValue(hkey, j, wszValue, &dwValueSize,
- NULL, NULL, NULL, NULL);
-
- if (l == ERROR_SUCCESS) {
- // Add value name to the names cache.
- regNames.Add(wszValue);
- }
- else if (l == ERROR_NO_MORE_ITEMS) {
- // Expected case: we've considered every value under this key.
- break;
- }
- else if ((l == ERROR_INSUFFICIENT_BUFFER || l == ERROR_MORE_DATA) &&
- (dwValueSize > cchRegValueNameMax)) {
- // Name is too long. That's OK, we don't cache such names.
- continue;
- }
- else if (l == ERROR_ACCESS_DENIED) {
- // As above, ignore access denied and continue on trying to cache
- continue;
- }
- else {
- // WszRegEnumValue failed OOM, or something else went wrong.
- // To be safe, don't enable the cache.
- goto failure;
- }
- }
-
- // Save the handles to framework regkeys so that future reads dont have to
- // open it again
- if (roots[i] == HKEY_CURRENT_USER)
- s_hUserFrameworkKey = hkey;
- else if (roots[i] == HKEY_LOCAL_MACHINE)
- s_hMachineFrameworkKey = hkey;
- else
- RegCloseKey(hkey);
-
- hkey = NULL;
- }
-
- // Success. We've enumerated all value names under the roots;
- // enable the REGUTIL value name config cache.
- //
- s_fUseRegCache = TRUE;
-
- // Now create a cache of environment variables
- if (WCHAR * wszStrings = WszGetEnvironmentStrings())
- {
- // GetEnvironmentStrings returns pointer to a null terminated block containing
- // null terminated strings
- for(WCHAR *wszCurr = wszStrings; *wszCurr; wszCurr++)
- {
- WCHAR wch = towlower(*wszCurr);
-
- // Lets only cache env variables with the COMPlus prefix only
- if (wch == W('c'))
- {
- WCHAR *wszName = wszCurr;
-
- // Look for the separator between name and value
- while (*wszCurr && *wszCurr != W('='))
- wszCurr++;
-
- if (*wszCurr == W('='))
- {
- // Check the prefix
- if(!SString::_wcsnicmp(wszName, COMPLUS_PREFIX, LEN_OF_COMPLUS_PREFIX))
- {
- wszName += LEN_OF_COMPLUS_PREFIX;
- envNames.Add(wszName, (DWORD) (wszCurr - wszName));
- }
- }
-
- }
- // Look for current string termination
- while (*wszCurr)
- wszCurr++;
-
- }
-
- WszFreeEnvironmentStrings(wszStrings);
- s_fUseEnvCache = TRUE;
-
- }
- return;
-
-failure:
- if (hkey != NULL)
- RegCloseKey(hkey);
-}
-
-// Return TRUE if the registry value name was seen (or might have been seen)
-// in the registry at cache initialization time;
-// return FALSE if it definitely was not seen at startup.
-//
-// If not using the config cache, return TRUE always.
-//
-// Perf Optimization for VSWhidbey:113373.
-//
-BOOL REGUTIL::RegCacheValueNameSeenPerhaps(LPCWSTR name)
-{
- WRAPPER_NO_CONTRACT;
-
- return !s_fUseRegCache
- || (wcslen(name) > cchRegValueNameMax)
- || regNames.MayContain(name);
-}
-
-BOOL REGUTIL::EnvCacheValueNameSeenPerhaps(LPCWSTR name)
-{
- WRAPPER_NO_CONTRACT;
-
- return !s_fUseEnvCache
- || envNames.MayContain(name);
-}
-
-#endif // ALLOW_REGISTRY
diff --git a/src/coreclr/utilcode/stresslog.cpp b/src/coreclr/utilcode/stresslog.cpp
index 2b81551eb387..6203d5727017 100644
--- a/src/coreclr/utilcode/stresslog.cpp
+++ b/src/coreclr/utilcode/stresslog.cpp
@@ -142,7 +142,7 @@ void StressLog::Leave(CRITSEC_COOKIE) {
/*********************************************************************************/
void StressLog::Initialize(unsigned facilities, unsigned level, unsigned maxBytesPerThread,
- ULONGLONG maxBytesTotal, void* moduleBase, LPWSTR logFilename)
+ unsigned maxBytesTotal, void* moduleBase, LPWSTR logFilename)
{
STATIC_CONTRACT_LEAF;
diff --git a/src/coreclr/utilcode/util.cpp b/src/coreclr/utilcode/util.cpp
index 018ea351c530..1be42772b6e2 100644
--- a/src/coreclr/utilcode/util.cpp
+++ b/src/coreclr/utilcode/util.cpp
@@ -1405,22 +1405,6 @@ bool ConfigMethodSet::contains(LPCUTF8 methodName, LPCUTF8 className, CORINFO_SI
return(m_list.IsInList(methodName, className, pSigInfo));
}
-/**************************************************************************/
-void ConfigDWORD::init_DontUse_(__in_z LPCWSTR keyName, DWORD defaultVal)
-{
- CONTRACTL
- {
- NOTHROW;
- }
- CONTRACTL_END;
-
- // make sure that the memory was zero initialized
- _ASSERTE(m_inited == 0 || m_inited == 1);
-
- m_value = REGUTIL::GetConfigDWORD_DontUse_(keyName, defaultVal);
- m_inited = 1;
-}
-
/**************************************************************************/
void ConfigString::init(const CLRConfig::ConfigStringInfo & info)
{
diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp
index 46aa6f3d6e17..8494ff4a6ed0 100644
--- a/src/coreclr/vm/appdomain.cpp
+++ b/src/coreclr/vm/appdomain.cpp
@@ -1291,7 +1291,7 @@ void SystemDomain::Init()
}
#ifdef _DEBUG
- BOOL fPause = EEConfig::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_PauseOnLoad, FALSE);
+ BOOL fPause = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_PauseOnLoad);
while (fPause)
{
diff --git a/src/coreclr/vm/ceeload.cpp b/src/coreclr/vm/ceeload.cpp
index 8a5ad542c5a5..f84714c9ce67 100644
--- a/src/coreclr/vm/ceeload.cpp
+++ b/src/coreclr/vm/ceeload.cpp
@@ -11855,7 +11855,7 @@ HRESULT Module::WriteMethodProfileDataLogFile(bool cleanup)
{
if (GetAssembly()->IsInstrumented() && (m_pProfilingBlobTable != NULL) && (m_tokenProfileData != NULL))
{
- ProfileEmitter * pEmitter = new ProfileEmitter();
+ NewHolder pEmitter(new ProfileEmitter());
// Get this ahead of time - metadata access may be logged, which will
// take the m_tokenProfileData->crst, which we take a couple lines below
diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp
index 62926cdef32c..3efde73df285 100644
--- a/src/coreclr/vm/ceemain.cpp
+++ b/src/coreclr/vm/ceemain.cpp
@@ -305,12 +305,8 @@ HRESULT EnsureEEStarted()
{
BEGIN_ENTRYPOINT_NOTHROW;
-#ifndef TARGET_UNIX
- // The sooner we do this, the sooner we avoid probing registry entries.
- // (Perf Optimization for VSWhidbey:113373.)
- REGUTIL::InitOptionalConfigCache();
-#endif
-
+ // Initialize our configuration cache to avoid unuseful probing.
+ CLRConfig::InitCache();
BOOL bStarted=FALSE;
@@ -705,12 +701,12 @@ void EEStartupHelper()
#endif // TARGET_UNIX
#ifdef STRESS_LOG
- if (REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_StressLog, g_pConfig->StressLog ()) != 0) {
- unsigned facilities = REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_LogFacility, LF_ALL);
- unsigned level = REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::EXTERNAL_LogLevel, LL_INFO1000);
- unsigned bytesPerThread = REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_StressLogSize, STRESSLOG_CHUNK_SIZE * 4);
- ULONGLONG totalBytes = REGUTIL::GetConfigULONGLONG_DontUse_(CLRConfig::UNSUPPORTED_TotalStressLogSize, STRESSLOG_CHUNK_SIZE * 1024);
- LPWSTR logFilename = REGUTIL::GetConfigString_DontUse_(CLRConfig::UNSUPPORTED_StressLogFilename);
+ if (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_StressLog, g_pConfig->StressLog()) != 0) {
+ unsigned facilities = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_LogFacility, LF_ALL);
+ unsigned level = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_LogLevel, LL_INFO1000);
+ unsigned bytesPerThread = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_StressLogSize, STRESSLOG_CHUNK_SIZE * 4);
+ unsigned totalBytes = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_TotalStressLogSize, STRESSLOG_CHUNK_SIZE * 1024);
+ CLRConfigStringHolder logFilename = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_StressLogFilename);
StressLog::Initialize(facilities, level, bytesPerThread, totalBytes, GetClrModuleBase(), logFilename);
g_pStressLog = &StressLog::theLog;
}
diff --git a/src/coreclr/vm/comcallablewrapper.cpp b/src/coreclr/vm/comcallablewrapper.cpp
index 06357458e769..018cb91076e7 100644
--- a/src/coreclr/vm/comcallablewrapper.cpp
+++ b/src/coreclr/vm/comcallablewrapper.cpp
@@ -4192,11 +4192,6 @@ BOOL ComCallWrapperTemplate::IsSafeTypeForMarshalling()
return TRUE;
}
- if ((CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_AllowDComReflection) != 0))
- {
- return TRUE;
- }
-
BOOL isSafe = TRUE;
PTR_MethodTable pMt = this->GetClassType().GetMethodTable();
EX_TRY
diff --git a/src/coreclr/vm/commodule.cpp b/src/coreclr/vm/commodule.cpp
index 9eb5e8ead771..2ac2b03392e9 100644
--- a/src/coreclr/vm/commodule.cpp
+++ b/src/coreclr/vm/commodule.cpp
@@ -44,7 +44,7 @@ static ISymUnmanagedWriter **CreateISymWriterForDynamicModule(ReflectionModule *
static ConfigDWORD dbgForcePDBSymbols;
- if(dbgForcePDBSymbols.val_DontUse_(W("DbgForcePDBSymbols"), 0) == 1)
+ if(dbgForcePDBSymbols.val(CLRConfig::INTERNAL_DbgForcePDBSymbols) == 1)
{
symFormatToUse = eSymbolFormatPDB;
}
diff --git a/src/coreclr/vm/compatibilityswitch.cpp b/src/coreclr/vm/compatibilityswitch.cpp
index 49ce4a400c6e..aedddbc7cbbf 100644
--- a/src/coreclr/vm/compatibilityswitch.cpp
+++ b/src/coreclr/vm/compatibilityswitch.cpp
@@ -23,7 +23,7 @@ FCIMPL1(StringObject*, CompatibilitySwitch::GetValue, StringObject* switchNameUN
HELPER_METHOD_FRAME_BEGIN_RET_1(name);
CLRConfig::ConfigStringInfo info;
info.name = name->GetBuffer();
- info.options = CLRConfig::EEConfig_default;
+ info.options = CLRConfig::LookupOptions::Default;
LPWSTR strVal = CLRConfig::GetConfigValue(info);
refName = StringObject::NewString(strVal);
HELPER_METHOD_FRAME_END();
diff --git a/src/coreclr/vm/comthreadpool.cpp b/src/coreclr/vm/comthreadpool.cpp
index f3aac0e4db8d..578f30e4f3d1 100644
--- a/src/coreclr/vm/comthreadpool.cpp
+++ b/src/coreclr/vm/comthreadpool.cpp
@@ -150,7 +150,7 @@ FCIMPL4(INT32, ThreadPoolNative::GetNextConfigUInt32Value,
[=](const CLRConfig::ConfigDWORDInfo &configInfo, bool isBoolean, const WCHAR *appContextConfigName) -> bool
{
bool wasNotConfigured = true;
- *configValueRef = CLRConfig::GetConfigValue(configInfo, true /* acceptExplicitDefaultFromRegutil */, &wasNotConfigured);
+ *configValueRef = CLRConfig::GetConfigValue(configInfo, &wasNotConfigured);
if (wasNotConfigured)
{
return false;
diff --git a/src/coreclr/vm/eeconfig.cpp b/src/coreclr/vm/eeconfig.cpp
index 6d5ea5a3d267..5dd61484cd48 100644
--- a/src/coreclr/vm/eeconfig.cpp
+++ b/src/coreclr/vm/eeconfig.cpp
@@ -123,6 +123,7 @@ HRESULT EEConfig::Init()
fNgenBindOptimizeNonGac = false;
fStressLog = false;
+ fForceEnc = false;
fProbeForStackOverflow = true;
INDEBUG(fStressLog = true;)
@@ -150,8 +151,6 @@ HRESULT EEConfig::Init()
pPerfTypesToLog = NULL;
iFastGCStress = 0;
iInjectFatalError = 0;
- fSaveThreadInfo = FALSE;
- dwSaveThreadInfoMask = (DWORD)-1;
#ifdef TEST_DATA_CONSISTENCY
// indicates whether to run the self test to determine that we are detecting when a lock is held by the
// LS in DAC builds. Initialized via the environment variable TestDataConsistency
@@ -180,6 +179,7 @@ HRESULT EEConfig::Init()
fSuppressChecks = false;
fConditionalContracts = false;
fEnableFullDebug = false;
+ iExposeExceptionsInCOM = 0;
#endif
#ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
@@ -201,7 +201,6 @@ HRESULT EEConfig::Init()
#ifdef _DEBUG
// interop logging
- m_pTraceIUnknown = NULL;
m_TraceWrapper = 0;
#endif
@@ -343,81 +342,6 @@ HRESULT EEConfig::Cleanup()
return S_OK;
}
-
-//
-// NOTE: This function is deprecated; use the CLRConfig class instead.
-// To use the CLRConfig class, add an entry in file:../inc/CLRConfigValues.h.
-//
-HRESULT EEConfig::GetConfigString_DontUse_(__in_z LPCWSTR name, __deref_out_z LPWSTR *outVal, BOOL fPrependCOMPLUS)
-{
- CONTRACT(HRESULT) {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- INJECT_FAULT (CONTRACT_RETURN E_OUTOFMEMORY);
- PRECONDITION(CheckPointer(name));
- POSTCONDITION(CheckPointer(outVal, NULL_OK));
- } CONTRACT_END;
-
- *outVal = REGUTIL::GetConfigString_DontUse_(name, fPrependCOMPLUS);
-
- RETURN S_OK;
-}
-
-
-//
-// NOTE: This function is deprecated; use the CLRConfig class instead.
-// To use the CLRConfig class, add an entry in file:../inc/CLRConfigValues.h.
-//
-DWORD EEConfig::GetConfigDWORD_DontUse_(__in_z LPCWSTR name, DWORD defValue, DWORD level, BOOL fPrependCOMPLUS)
-{
- CONTRACTL {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(CheckPointer(name));
- } CONTRACTL_END;
-
- // @TODO: After everyone has moved off registry, key remove the following line in golden
- return REGUTIL::GetConfigDWORD_DontUse_(name, defValue, (REGUTIL::CORConfigLevel)level, fPrependCOMPLUS);
-}
-
-//
-// NOTE: This function is deprecated; use the CLRConfig class instead.
-// To use the CLRConfig class, add an entry in file:../inc/CLRConfigValues.h.
-//
-// Note for PAL: right now PAL does not have a _wcstoui64 API, so I am temporarily reading in all numbers as
-// a 32-bit number. When we have the _wcstoui64 API on MAC we will use that instead of wcstoul.
-ULONGLONG EEConfig::GetConfigULONGLONG_DontUse_(__in_z LPCWSTR name, ULONGLONG defValue, DWORD level, BOOL fPrependCOMPLUS)
-{
- CONTRACTL {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(CheckPointer(name));
- } CONTRACTL_END;
-
- // @TODO: After everyone has moved off registry, key remove the following line in golden
- return REGUTIL::GetConfigULONGLONG_DontUse_(name, defValue, (REGUTIL::CORConfigLevel)level, fPrependCOMPLUS);
-}
-
-//
-// NOTE: This function is deprecated; use the CLRConfig class instead.
-// To use the CLRConfig class, add an entry in file:../inc/CLRConfigValues.h.
-//
-DWORD EEConfig::GetConfigDWORDInternal_DontUse_(__in_z LPCWSTR name, DWORD defValue, DWORD level, BOOL fPrependCOMPLUS)
-{
- CONTRACTL {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(CheckPointer(name));
- } CONTRACTL_END;
-
- // @TODO: After everyone has moved off registry, key remove the following line in golden
- return REGUTIL::GetConfigDWORD_DontUse_(name, defValue, (REGUTIL::CORConfigLevel)level, fPrependCOMPLUS);
-}
-
/**************************************************************/
HRESULT EEConfig::sync()
@@ -436,10 +360,10 @@ HRESULT EEConfig::sync()
// Note the global variable is not updated directly by the GetRegKey function
// so we only update it once (to avoid reentrancy windows)
-fTrackDynamicMethodDebugInfo = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_TrackDynamicMethodDebugInfo);
+ fTrackDynamicMethodDebugInfo = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_TrackDynamicMethodDebugInfo);
#ifdef _DEBUG
- iFastGCStress = GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_FastGCStress, iFastGCStress);
+ iFastGCStress = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_FastGCStress);
IfFailRet(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_GcCoverage, (LPWSTR*)&pszGcCoverageOnMethod));
pszGcCoverageOnMethod = NarrowWideChar((LPWSTR)pszGcCoverageOnMethod);
@@ -527,7 +451,7 @@ fTrackDynamicMethodDebugInfo = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_
#ifdef VERIFY_HEAP
if (bGCStressAndHeapVerifyAllowed)
{
- iGCHeapVerify = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_HeapVerify, iGCHeapVerify);
+ iGCHeapVerify = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_HeapVerify);
}
#endif
@@ -552,21 +476,10 @@ fTrackDynamicMethodDebugInfo = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_
iGCAllowVeryLargeObjects = (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_gcAllowVeryLargeObjects) != 0);
#endif
- fGCBreakOnOOM = (GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_GCBreakOnOOM, fGCBreakOnOOM) != 0);
-
-#ifdef TRACE_GC
- iGCtraceStart = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_GCtraceStart, iGCtraceStart);
- iGCtraceEnd = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_GCtraceEnd, iGCtraceEnd);
- iGCtraceFac = GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_GCtraceFacility, iGCtraceFac);
- iGCprnLvl = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_GCprnLvl, iGCprnLvl);
-#endif
+ fGCBreakOnOOM = (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_GCBreakOnOOM) != 0);
#ifdef _DEBUG
- iInjectFatalError = GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_InjectFatalError, iInjectFatalError);
-
- fSaveThreadInfo = (GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_SaveThreadInfo, fSaveThreadInfo) != 0);
-
- dwSaveThreadInfoMask = GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_SaveThreadInfoMask, dwSaveThreadInfoMask);
+ iInjectFatalError = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_InjectFatalError);
{
LPWSTR wszSkipGCCoverageList = NULL;
@@ -581,8 +494,8 @@ fTrackDynamicMethodDebugInfo = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_
IfFailRet(hr);
}
#endif
- fStressLog = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_StressLog, fStressLog) != 0;
- fForceEnc = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_ForceEnc, fForceEnc) != 0;
+ fStressLog = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_StressLog, fStressLog) != 0;
+ fForceEnc = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_ForceEnc) != 0;
{
NewArrayHolder wszModifiableAssemblies;
@@ -591,7 +504,7 @@ fTrackDynamicMethodDebugInfo = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_
fDebugAssembliesModifiable = _wcsicmp(wszModifiableAssemblies, W("debug")) == 0;
}
- iRequireZaps = RequireZapsType(GetConfigDWORD_DontUse_(CLRConfig::EXTERNAL_ZapRequire, iRequireZaps));
+ iRequireZaps = RequireZapsType(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ZapRequire, iRequireZaps));
if (IsCompilationProcess() || iRequireZaps >= REQUIRE_ZAPS_COUNT)
iRequireZaps = REQUIRE_ZAPS_NONE;
@@ -644,7 +557,7 @@ fTrackDynamicMethodDebugInfo = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_
#endif
#ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
- DoubleArrayToLargeObjectHeapThreshold = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_DoubleArrayToLargeObjectHeap, DoubleArrayToLargeObjectHeapThreshold);
+ DoubleArrayToLargeObjectHeapThreshold = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_DoubleArrayToLargeObjectHeap, DoubleArrayToLargeObjectHeapThreshold);
#endif
IfFailRet(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ZapBBInstr, (LPWSTR*)&szZapBBInstr));
@@ -669,7 +582,7 @@ fTrackDynamicMethodDebugInfo = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_
g_IBCLogger.DisableAllInstr();
- dwDisableStackwalkCache = GetConfigDWORD_DontUse_(CLRConfig::EXTERNAL_DisableStackwalkCache, dwDisableStackwalkCache);
+ dwDisableStackwalkCache = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_DisableStackwalkCache, dwDisableStackwalkCache);
#ifdef _DEBUG
@@ -695,9 +608,9 @@ fTrackDynamicMethodDebugInfo = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_
dwJitHostMaxSlabCache = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_JitHostMaxSlabCache);
- fJitFramed = (GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_JitFramed, fJitFramed) != 0);
- fJitMinOpts = (GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_JITMinOpts, fJitMinOpts) == 1);
- iJitOptimizeType = GetConfigDWORD_DontUse_(CLRConfig::EXTERNAL_JitOptimizeType, iJitOptimizeType);
+ fJitFramed = (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_JitFramed) != 0);
+ fJitMinOpts = (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_JITMinOpts) == 1);
+ iJitOptimizeType = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_JitOptimizeType);
if (iJitOptimizeType > OPT_RANDOM) iJitOptimizeType = OPT_DEFAULT;
#ifdef TARGET_X86
@@ -706,7 +619,7 @@ fTrackDynamicMethodDebugInfo = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_
#ifdef _DEBUG
- fDebuggable = (GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_JitDebuggable, fDebuggable) != 0);
+ fDebuggable = (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitDebuggable) != 0);
LPWSTR wszPreStubStuff = NULL;
@@ -741,25 +654,25 @@ fTrackDynamicMethodDebugInfo = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_
IfFailRet(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnStructMarshalSetup, (LPWSTR*)&pszBreakOnStructMarshalSetup));
pszBreakOnStructMarshalSetup = NarrowWideChar((LPWSTR)pszBreakOnStructMarshalSetup);
- m_fAssertOnBadImageFormat = (GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_AssertOnBadImageFormat, m_fAssertOnBadImageFormat) != 0);
- m_fAssertOnFailFast = (GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_AssertOnFailFast, m_fAssertOnFailFast) != 0);
+ m_fAssertOnBadImageFormat = (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_AssertOnBadImageFormat) != 0);
+ m_fAssertOnFailFast = (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_AssertOnFailFast) != 0);
- fSuppressChecks = (GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_SuppressChecks, fSuppressChecks) != 0);
+ fSuppressChecks = (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_SuppressChecks) != 0);
CHECK::SetAssertEnforcement(!fSuppressChecks);
- fConditionalContracts = (GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_ConditionalContracts, fConditionalContracts) != 0);
+ fConditionalContracts = (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ConditionalContracts) != 0);
#ifdef ENABLE_CONTRACTS_IMPL
Contract::SetUnconditionalContractEnforcement(!fConditionalContracts);
#endif
- fEnableFullDebug = (GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_EnableFullDebug, fEnableFullDebug) != 0);
+ fEnableFullDebug = (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EnableFullDebug) != 0);
- fVerifierOff = (GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_VerifierOff, fVerifierOff) != 0);
+ fVerifierOff = (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_VerifierOff) != 0);
- fJitVerificationDisable = (GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_JitVerificationDisable, fJitVerificationDisable) != 0);
+ fJitVerificationDisable = (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitVerificationDisable) != 0);
- iExposeExceptionsInCOM = GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_ExposeExceptionsInCOM, iExposeExceptionsInCOM);
+ iExposeExceptionsInCOM = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ExposeExceptionsInCOM, iExposeExceptionsInCOM);
#endif
#ifdef FEATURE_COMINTEROP
@@ -772,7 +685,7 @@ fTrackDynamicMethodDebugInfo = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_
#endif // FEATURE_COMINTEROP
#ifdef _DEBUG
- fExpandAllOnLoad = (GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_ExpandAllOnLoad, fExpandAllOnLoad) != 0);
+ fExpandAllOnLoad = (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ExpandAllOnLoad) != 0);
#endif //_DEBUG
#ifdef ENABLE_STARTUP_DELAY
@@ -803,19 +716,7 @@ fTrackDynamicMethodDebugInfo = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_
fInited = true;
#ifdef _DEBUG
- m_pTraceIUnknown = (IUnknown*)(DWORD_PTR)(GetConfigDWORD_DontUse_(CLRConfig::EXTERNAL_TraceIUnknown, (DWORD)(DWORD_PTR)(m_pTraceIUnknown))); // WIN64 - conversion from DWORD to IUnknown* of greater size
- m_TraceWrapper = GetConfigDWORD_DontUse_(CLRConfig::EXTERNAL_TraceWrap, m_TraceWrapper);
-
- // can't have both
- if (m_pTraceIUnknown != 0)
- {
- m_TraceWrapper = 0;
- }
- else
- if (m_TraceWrapper != 0)
- {
- m_pTraceIUnknown = (IUnknown*)-1;
- }
+ m_TraceWrapper = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_TraceWrap);
#endif
#ifdef _DEBUG
@@ -849,7 +750,7 @@ fTrackDynamicMethodDebugInfo = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_
#endif
#if defined(_DEBUG) && defined(STUBLINKER_GENERATES_UNWIND_INFO)
- fStubLinkerUnwindInfoVerificationOn = (GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_StubLinkerUnwindInfoVerificationOn, fStubLinkerUnwindInfoVerificationOn) != 0);
+ fStubLinkerUnwindInfoVerificationOn = (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_StubLinkerUnwindInfoVerificationOn) != 0);
#endif
if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_UseMethodDataCache) != 0) {
@@ -862,7 +763,7 @@ fTrackDynamicMethodDebugInfo = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_
#if defined(_DEBUG) && defined(TARGET_AMD64)
- m_cGenerateLongJumpDispatchStubRatio = GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_GenerateLongJumpDispatchStubRatio,
+ m_cGenerateLongJumpDispatchStubRatio = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_GenerateLongJumpDispatchStubRatio,
static_cast(m_cGenerateLongJumpDispatchStubRatio));
#endif
diff --git a/src/coreclr/vm/eeconfig.h b/src/coreclr/vm/eeconfig.h
index 11f1d286d9f9..b4941fd0bc2d 100644
--- a/src/coreclr/vm/eeconfig.h
+++ b/src/coreclr/vm/eeconfig.h
@@ -417,22 +417,11 @@ class EEConfig
LIMITED_METHOD_CONTRACT;
return iInjectFatalError;
}
-
- inline BOOL SaveThreadInfo() const
- {
- return fSaveThreadInfo;
- }
-
- inline DWORD SaveThreadInfoMask() const
- {
- return dwSaveThreadInfoMask;
- }
#endif
#ifdef _DEBUG
// Interop config
- IUnknown* GetTraceIUnknown() const {LIMITED_METHOD_CONTRACT; return m_pTraceIUnknown; }
int GetTraceWrapper() const {LIMITED_METHOD_CONTRACT; return m_TraceWrapper; }
#endif
@@ -469,36 +458,6 @@ class EEConfig
HRESULT sync(); // check the registry again and update local state
- // Helpers to read configuration
-
- //
- // NOTE: The following function is deprecated; use the CLRConfig class instead.
- // To access a configuration value through CLRConfig, add an entry in file:../inc/CLRConfigValues.h.
- //
- static HRESULT GetConfigString_DontUse_(__in_z LPCWSTR name, __deref_out_z LPWSTR*out, BOOL fPrependCOMPLUS = TRUE); // Note that you own the returned string!
-
- //
- // NOTE: The following function is deprecated; use the CLRConfig class instead.
- // To access a configuration value through CLRConfig, add an entry in file:../inc/CLRConfigValues.h.
- //
- static DWORD GetConfigDWORD_DontUse_(__in_z LPCWSTR name, DWORD defValue,
- DWORD level=(DWORD) REGUTIL::COR_CONFIG_ALL,
- BOOL fPrependCOMPLUS = TRUE);
-
- //
- // NOTE: The following function is deprecated; use the CLRConfig class instead.
- // To access a configuration value through CLRConfig, add an entry in file:../inc/CLRConfigValues.h.
- //
- static ULONGLONG GetConfigULONGLONG_DontUse_(__in_z LPCWSTR name, ULONGLONG defValue,
- DWORD level=(DWORD) REGUTIL::COR_CONFIG_ALL,
- BOOL fPrependCOMPLUS = TRUE);
-
- //
- // NOTE: The following function is deprecated; use the CLRConfig class instead.
- // To access a configuration value through CLRConfig, add an entry in file:../inc/CLRConfigValues.h.
- //
- static DWORD GetConfigFlag_DontUse_(__in_z LPCWSTR name, DWORD bitToSet, bool defValue = FALSE);
-
#ifdef _DEBUG
// GC alloc logging
bool ShouldLogAlloc(const char *pClass) const { LIMITED_METHOD_CONTRACT; return pPerfTypesToLog && pPerfTypesToLog->IsInList(pClass);}
@@ -660,9 +619,6 @@ class EEConfig
DWORD iInjectFatalError;
- BOOL fSaveThreadInfo;
- DWORD dwSaveThreadInfoMask;
-
AssemblyNamesList *pSkipGCCoverageList;
#endif
@@ -703,7 +659,6 @@ class EEConfig
#ifdef _DEBUG
// interop logging
- IUnknown* m_pTraceIUnknown;
int m_TraceWrapper;
#endif
@@ -764,10 +719,6 @@ class EEConfig
#endif
public:
- DWORD GetConfigDWORDInternal_DontUse_ (__in_z LPCWSTR name, DWORD defValue, //for getting data in the constructor of EEConfig
- DWORD level=(DWORD) REGUTIL::COR_CONFIG_ALL,
- BOOL fPrependCOMPLUS = TRUE);
-
enum BitForMask {
CallSite_1 = 0x0001,
CallSite_2 = 0x0002,
diff --git a/src/coreclr/vm/gcenv.ee.cpp b/src/coreclr/vm/gcenv.ee.cpp
index 2318c7ba2810..7849958d0687 100644
--- a/src/coreclr/vm/gcenv.ee.cpp
+++ b/src/coreclr/vm/gcenv.ee.cpp
@@ -1125,7 +1125,7 @@ bool GCToEEInterface::GetBooleanConfigValue(const char* privateKey, const char*
// otherwise, ask the config subsystem.
if (CLRConfig::IsConfigOptionSpecified(configKey))
{
- CLRConfig::ConfigDWORDInfo info { configKey , 0, CLRConfig::EEConfig_default };
+ CLRConfig::ConfigDWORDInfo info { configKey , 0, CLRConfig::LookupOptions::Default };
*value = CLRConfig::GetConfigValue(info) != 0;
return true;
}
@@ -1170,7 +1170,7 @@ bool GCToEEInterface::GetIntConfigValue(const char* privateKey, const char* publ
// so have to fake it with getting the string and converting to uint64_t
if (CLRConfig::IsConfigOptionSpecified(configKey))
{
- CLRConfig::ConfigStringInfo info { configKey, CLRConfig::EEConfig_default };
+ CLRConfig::ConfigStringInfo info { configKey, CLRConfig::LookupOptions::Default };
LPWSTR out = CLRConfig::GetConfigValue(info);
if (!out)
{
@@ -1226,7 +1226,7 @@ bool GCToEEInterface::GetStringConfigValue(const char* privateKey, const char* p
return false;
}
- CLRConfig::ConfigStringInfo info { configKey, CLRConfig::EEConfig_default };
+ CLRConfig::ConfigStringInfo info { configKey, CLRConfig::LookupOptions::Default };
LPWSTR fromClrConfig = CLRConfig::GetConfigValue(info);
LPCWSTR out = fromClrConfig;
if (out == NULL)
diff --git a/src/coreclr/vm/i386/cgenx86.cpp b/src/coreclr/vm/i386/cgenx86.cpp
index caab476b15fa..c8a38e2f3b3f 100644
--- a/src/coreclr/vm/i386/cgenx86.cpp
+++ b/src/coreclr/vm/i386/cgenx86.cpp
@@ -109,7 +109,7 @@ void GetSpecificCpuInfo(CORINFO_CPU * cpuInfo)
const DWORD cpuDefault = 0xFFFFFFFF;
static ConfigDWORD cpuFamily;
- DWORD configCpuFamily = cpuFamily.val_DontUse_(CLRConfig::INTERNAL_CPUFamily, cpuDefault);
+ DWORD configCpuFamily = cpuFamily.val(CLRConfig::INTERNAL_CPUFamily);
if (configCpuFamily != cpuDefault)
{
assert((configCpuFamily & 0xFFF) == configCpuFamily);
@@ -125,7 +125,7 @@ void GetSpecificCpuInfo(CORINFO_CPU * cpuInfo)
const DWORD cpuFeaturesDefault = 0xFFFFFFFF;
static ConfigDWORD cpuFeatures;
- DWORD configCpuFeatures = cpuFeatures.val_DontUse_(CLRConfig::INTERNAL_CPUFeatures, cpuFeaturesDefault);
+ DWORD configCpuFeatures = cpuFeatures.val(CLRConfig::INTERNAL_CPUFeatures);
if (configCpuFeatures != cpuFeaturesDefault)
{
tempVal.dwFeatures = configCpuFeatures;
diff --git a/src/coreclr/vm/interoputil.cpp b/src/coreclr/vm/interoputil.cpp
index a2d46af6cf61..738918911880 100644
--- a/src/coreclr/vm/interoputil.cpp
+++ b/src/coreclr/vm/interoputil.cpp
@@ -3890,13 +3890,12 @@ void InitializeComInterop()
//-------------------------------------------------------------------
static int g_TraceCount = 0;
-static IUnknown* g_pTraceIUnknown = 0;
+static IUnknown* g_pTraceIUnknown = NULL;
VOID IntializeInteropLogging()
{
WRAPPER_NO_CONTRACT;
- g_pTraceIUnknown = g_pConfig->GetTraceIUnknown();
g_TraceCount = g_pConfig->GetTraceWrapper();
}
diff --git a/src/coreclr/vm/jithost.cpp b/src/coreclr/vm/jithost.cpp
index 798d594c4630..504e389faa62 100644
--- a/src/coreclr/vm/jithost.cpp
+++ b/src/coreclr/vm/jithost.cpp
@@ -26,7 +26,7 @@ int JitHost::getIntConfigValue(const WCHAR* name, int defaultValue)
WRAPPER_NO_CONTRACT;
// Translate JIT call into runtime configuration query
- CLRConfig::ConfigDWORDInfo info{ name, (DWORD)defaultValue, CLRConfig::EEConfig_default };
+ CLRConfig::ConfigDWORDInfo info{ name, (DWORD)defaultValue, CLRConfig::LookupOptions::Default };
// Perform a CLRConfig look up on behalf of the JIT.
return CLRConfig::GetConfigValue(info);
@@ -37,7 +37,7 @@ const WCHAR* JitHost::getStringConfigValue(const WCHAR* name)
WRAPPER_NO_CONTRACT;
// Translate JIT call into runtime configuration query
- CLRConfig::ConfigStringInfo info{ name, CLRConfig::EEConfig_default };
+ CLRConfig::ConfigStringInfo info{ name, CLRConfig::LookupOptions::Default };
// Perform a CLRConfig look up on behalf of the JIT.
return CLRConfig::GetConfigValue(info);
diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp
index 7ad02600f11e..f14d3e2c0202 100644
--- a/src/coreclr/vm/methodtablebuilder.cpp
+++ b/src/coreclr/vm/methodtablebuilder.cpp
@@ -9011,7 +9011,7 @@ MethodTableBuilder::LoadExactInterfaceMap(MethodTable *pMT)
pMT->GetAssembly()->ThrowTypeLoadException(pMT->GetMDImport(), pMT->GetCl(), IDS_CLASSLOAD_BADFORMAT);
}
#ifdef _DEBUG
- duplicates |= EEConfig::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_AlwaysUseMetadataInterfaceMapLayout, FALSE);
+ duplicates |= CLRConfig::GetConfigValue(CLRConfig::INTERNAL_AlwaysUseMetadataInterfaceMapLayout);
//#InjectInterfaceDuplicates_LoadExactInterfaceMap
// If we are injecting duplicates also for non-generic interfaces in check builds, we have to use
diff --git a/src/coreclr/vm/stackingallocator.cpp b/src/coreclr/vm/stackingallocator.cpp
index 911132afc86d..8806bceabb2f 100644
--- a/src/coreclr/vm/stackingallocator.cpp
+++ b/src/coreclr/vm/stackingallocator.cpp
@@ -26,21 +26,8 @@
#include "common.h"
#include "excep.h"
-
-#if 0
-#define INC_COUNTER(_name, _amount) do { \
- unsigned _count = REGUTIL::GetLong(W("AllocCounter_") _name, 0, NULL, HKEY_CURRENT_USER); \
- REGUTIL::SetLong(W("AllocCounter_") _name, _count+(_amount), NULL, HKEY_CURRENT_USER); \
- } while (0)
-#define MAX_COUNTER(_name, _amount) do { \
- unsigned _count = REGUTIL::GetLong(W("AllocCounter_") _name, 0, NULL, HKEY_CURRENT_USER); \
- REGUTIL::SetLong(W("AllocCounter_") _name, max(_count, (_amount)), NULL, HKEY_CURRENT_USER); \
- } while (0)
-#else
#define INC_COUNTER(_name, _amount)
#define MAX_COUNTER(_name, _amount)
-#endif
-
StackingAllocator::StackingAllocator()
{
diff --git a/src/coreclr/vm/stublink.cpp b/src/coreclr/vm/stublink.cpp
index 00d5c84c9db2..261cd15f7607 100644
--- a/src/coreclr/vm/stublink.cpp
+++ b/src/coreclr/vm/stublink.cpp
@@ -1343,7 +1343,7 @@ bool StubLinker::EmitUnwindInfo(Stub* pStub, int globalsize, LoaderHeap* pHeap)
#ifdef _DEBUG
static SIZE_T MaxSegmentSize = -1;
if (MaxSegmentSize == (SIZE_T)-1)
- MaxSegmentSize = EEConfig::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_MaxStubUnwindInfoSegmentSize, DYNAMIC_FUNCTION_TABLE_MAX_RANGE);
+ MaxSegmentSize = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MaxStubUnwindInfoSegmentSize, DYNAMIC_FUNCTION_TABLE_MAX_RANGE);
#else
const SIZE_T MaxSegmentSize = DYNAMIC_FUNCTION_TABLE_MAX_RANGE;
#endif
diff --git a/src/coreclr/zap/zaplog.h b/src/coreclr/zap/zaplog.h
index e07cb29e51e3..a9f5e2e27798 100644
--- a/src/coreclr/zap/zaplog.h
+++ b/src/coreclr/zap/zaplog.h
@@ -27,7 +27,7 @@ inline void ThrowAndLog(HRESULT hr, INDEBUG_COMMA(__in_z const char * szMsg) IND
// Log failures when StressLog is on
static ConfigDWORD g_iStressLog;
- BOOL bLog = g_iStressLog.val_DontUse_(CLRConfig::UNSUPPORTED_StressLog, 0);
+ BOOL bLog = g_iStressLog.val(CLRConfig::UNSUPPORTED_StressLog);
if (bLog)
{
#ifdef _DEBUG
diff --git a/src/coreclr/zap/zapper.cpp b/src/coreclr/zap/zapper.cpp
index a98fc6cc2934..248e82e1b0d2 100644
--- a/src/coreclr/zap/zapper.cpp
+++ b/src/coreclr/zap/zapper.cpp
@@ -1155,7 +1155,7 @@ void Zapper::InitializeCompilerFlags(CORCOMPILE_VERSION_INFO * pVersionInfo)
// Set CORJIT_FLAG_MIN_OPT only if COMPlus_JitMinOpts == 1
static ConfigDWORD g_jitMinOpts;
- if (g_jitMinOpts.val_DontUse_(CLRConfig::UNSUPPORTED_JITMinOpts, 0) == 1)
+ if (g_jitMinOpts.val(CLRConfig::UNSUPPORTED_JITMinOpts) == 1)
{
m_pOpt->m_compilerFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT);
}
diff --git a/src/installer/managed/Microsoft.NET.HostModel/Bundle/BundleOptions.cs b/src/installer/managed/Microsoft.NET.HostModel/Bundle/BundleOptions.cs
index 646e1b094310..22030386d267 100644
--- a/src/installer/managed/Microsoft.NET.HostModel/Bundle/BundleOptions.cs
+++ b/src/installer/managed/Microsoft.NET.HostModel/Bundle/BundleOptions.cs
@@ -17,5 +17,6 @@ public enum BundleOptions
BundleOtherFiles = 2,
BundleSymbolFiles = 4,
BundleAllContent = BundleNativeBinaries | BundleOtherFiles,
+ EnableCompression = 8,
};
}
diff --git a/src/installer/managed/Microsoft.NET.HostModel/Bundle/Bundler.cs b/src/installer/managed/Microsoft.NET.HostModel/Bundle/Bundler.cs
index 0505d2dcefbf..bee21ddc065d 100644
--- a/src/installer/managed/Microsoft.NET.HostModel/Bundle/Bundler.cs
+++ b/src/installer/managed/Microsoft.NET.HostModel/Bundle/Bundler.cs
@@ -1,14 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using Microsoft.NET.HostModel.AppHost;
using System;
using System.Collections.Generic;
using System.Diagnostics;
-using System.Linq;
using System.IO;
+using System.IO.Compression;
+using System.Linq;
using System.Reflection.PortableExecutable;
using System.Runtime.InteropServices;
+using Microsoft.NET.HostModel.AppHost;
namespace Microsoft.NET.HostModel.Bundle
{
@@ -18,6 +19,9 @@ namespace Microsoft.NET.HostModel.Bundle
///
public class Bundler
{
+ public const uint BundlerMajorVersion = 6;
+ public const uint BundlerMinorVersion = 0;
+
private readonly string HostName;
private readonly string OutputDir;
private readonly string DepsJson;
@@ -44,22 +48,72 @@ public Bundler(string hostName,
OutputDir = Path.GetFullPath(string.IsNullOrEmpty(outputDir) ? Environment.CurrentDirectory : outputDir);
Target = new TargetInfo(targetOS, targetArch, targetFrameworkVersion);
+ if (Target.BundleMajorVersion < 6 &&
+ (options & BundleOptions.EnableCompression) != 0)
+ {
+ throw new ArgumentException("Compression requires framework version 6.0 or above", nameof(options));
+ }
+
appAssemblyName ??= Target.GetAssemblyName(hostName);
DepsJson = appAssemblyName + ".deps.json";
RuntimeConfigJson = appAssemblyName + ".runtimeconfig.json";
RuntimeConfigDevJson = appAssemblyName + ".runtimeconfig.dev.json";
- BundleManifest = new Manifest(Target.BundleVersion, netcoreapp3CompatMode: options.HasFlag(BundleOptions.BundleAllContent));
+ BundleManifest = new Manifest(Target.BundleMajorVersion, netcoreapp3CompatMode: options.HasFlag(BundleOptions.BundleAllContent));
Options = Target.DefaultOptions | options;
}
+ private bool ShouldCompress(FileType type)
+ {
+ if (!Options.HasFlag(BundleOptions.EnableCompression))
+ {
+ return false;
+ }
+
+ switch (type)
+ {
+ case FileType.Symbols:
+ case FileType.NativeBinary:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
///
/// Embed 'file' into 'bundle'
///
- /// Returns the offset of the start 'file' within 'bundle'
-
- private long AddToBundle(Stream bundle, Stream file, FileType type)
+ ///
+ /// startOffset: offset of the start 'file' within 'bundle'
+ /// compressedSize: size of the compressed data, if entry was compressed, otherwise 0
+ ///
+ private (long startOffset, long compressedSize) AddToBundle(Stream bundle, Stream file, FileType type)
{
+ long startOffset = bundle.Position;
+ if (ShouldCompress(type))
+ {
+ long fileLength = file.Length;
+ file.Position = 0;
+
+ // We use DeflateStream here.
+ // It uses GZip algorithm, but with a trivial header that does not contain file info.
+ using (DeflateStream compressionStream = new DeflateStream(bundle, CompressionLevel.Optimal, leaveOpen: true))
+ {
+ file.CopyTo(compressionStream);
+ }
+
+ long compressedSize = bundle.Position - startOffset;
+ if (compressedSize < fileLength * 0.75)
+ {
+ return (startOffset, compressedSize);
+ }
+
+ // compression rate was not good enough
+ // roll back the bundle offset and let the uncompressed code path take care of the entry.
+ bundle.Seek(startOffset, SeekOrigin.Begin);
+ }
+
if (type == FileType.Assembly)
{
long misalignment = (bundle.Position % Target.AssemblyAlignment);
@@ -72,10 +126,10 @@ private long AddToBundle(Stream bundle, Stream file, FileType type)
}
file.Position = 0;
- long startOffset = bundle.Position;
+ startOffset = bundle.Position;
file.CopyTo(bundle);
- return startOffset;
+ return (startOffset, 0);
}
private bool IsHost(string fileRelativePath)
@@ -186,8 +240,8 @@ private FileType InferType(FileSpec fileSpec)
///
public string GenerateBundle(IReadOnlyList fileSpecs)
{
- Tracer.Log($"Bundler version: {Manifest.CurrentVersion}");
- Tracer.Log($"Bundler Header: {BundleManifest.DesiredVersion}");
+ Tracer.Log($"Bundler Version: {BundlerMajorVersion}.{BundlerMinorVersion}");
+ Tracer.Log($"Bundle Version: {BundleManifest.BundleVersion}");
Tracer.Log($"Target Runtime: {Target}");
Tracer.Log($"Bundler Options: {Options}");
@@ -254,8 +308,8 @@ public string GenerateBundle(IReadOnlyList fileSpecs)
using (FileStream file = File.OpenRead(fileSpec.SourcePath))
{
FileType targetType = Target.TargetSpecificFileType(type);
- long startOffset = AddToBundle(bundle, file, targetType);
- FileEntry entry = BundleManifest.AddEntry(targetType, relativePath, startOffset, file.Length);
+ (long startOffset, long compressedSize) = AddToBundle(bundle, file, targetType);
+ FileEntry entry = BundleManifest.AddEntry(targetType, relativePath, startOffset, file.Length, compressedSize, Target.BundleMajorVersion);
Tracer.Log($"Embed: {entry}");
}
}
diff --git a/src/installer/managed/Microsoft.NET.HostModel/Bundle/FileEntry.cs b/src/installer/managed/Microsoft.NET.HostModel/Bundle/FileEntry.cs
index 7315c2a02631..e71a7faaa457 100644
--- a/src/installer/managed/Microsoft.NET.HostModel/Bundle/FileEntry.cs
+++ b/src/installer/managed/Microsoft.NET.HostModel/Bundle/FileEntry.cs
@@ -15,32 +15,44 @@ namespace Microsoft.NET.HostModel.Bundle
/// * Name ("NameLength" Bytes)
/// * Offset (Int64)
/// * Size (Int64)
+ /// === present only in bundle version 3+
+ /// * CompressedSize (Int64) 0 indicates No Compression
///
public class FileEntry
{
+ public readonly uint BundleMajorVersion;
+
public readonly long Offset;
public readonly long Size;
+ public readonly long CompressedSize;
public readonly FileType Type;
public readonly string RelativePath; // Path of an embedded file, relative to the Bundle source-directory.
public const char DirectorySeparatorChar = '/';
- public FileEntry(FileType fileType, string relativePath, long offset, long size)
+ public FileEntry(FileType fileType, string relativePath, long offset, long size, long compressedSize, uint bundleMajorVersion)
{
+ BundleMajorVersion = bundleMajorVersion;
Type = fileType;
RelativePath = relativePath.Replace('\\', DirectorySeparatorChar);
Offset = offset;
Size = size;
+ CompressedSize = compressedSize;
}
public void Write(BinaryWriter writer)
{
writer.Write(Offset);
writer.Write(Size);
+ // compression is used only in version 6.0+
+ if (BundleMajorVersion >= 6)
+ {
+ writer.Write(CompressedSize);
+ }
writer.Write((byte)Type);
writer.Write(RelativePath);
}
- public override string ToString() => $"{RelativePath} [{Type}] @{Offset} Sz={Size}";
+ public override string ToString() => $"{RelativePath} [{Type}] @{Offset} Sz={Size} CompressedSz={CompressedSize}";
}
}
diff --git a/src/installer/managed/Microsoft.NET.HostModel/Bundle/Manifest.cs b/src/installer/managed/Microsoft.NET.HostModel/Bundle/Manifest.cs
index 0beddb2b8cac..73e7b3b10fd2 100644
--- a/src/installer/managed/Microsoft.NET.HostModel/Bundle/Manifest.cs
+++ b/src/installer/managed/Microsoft.NET.HostModel/Bundle/Manifest.cs
@@ -66,32 +66,26 @@ private enum HeaderFlags : ulong
// with path-names so that the AppHost can use it in
// extraction path.
public readonly string BundleID;
-
- public const uint CurrentMajorVersion = 2;
- public readonly uint DesiredMajorVersion;
+ public readonly uint BundleMajorVersion;
// The Minor version is currently unused, and is always zero
- public const uint MinorVersion = 0;
-
- public static string CurrentVersion => $"{CurrentMajorVersion}.{MinorVersion}";
- public string DesiredVersion => $"{DesiredMajorVersion}.{MinorVersion}";
-
+ public const uint BundleMinorVersion = 0;
private FileEntry DepsJsonEntry;
private FileEntry RuntimeConfigJsonEntry;
private HeaderFlags Flags;
-
public List Files;
+ public string BundleVersion => $"{BundleMajorVersion}.{BundleMinorVersion}";
- public Manifest(uint desiredVersion, bool netcoreapp3CompatMode = false)
+ public Manifest(uint bundleMajorVersion, bool netcoreapp3CompatMode = false)
{
- DesiredMajorVersion = desiredVersion;
+ BundleMajorVersion = bundleMajorVersion;
Files = new List();
BundleID = Path.GetRandomFileName();
- Flags = (netcoreapp3CompatMode) ? HeaderFlags.NetcoreApp3CompatMode: HeaderFlags.None;
+ Flags = (netcoreapp3CompatMode) ? HeaderFlags.NetcoreApp3CompatMode : HeaderFlags.None;
}
- public FileEntry AddEntry(FileType type, string relativePath, long offset, long size)
+ public FileEntry AddEntry(FileType type, string relativePath, long offset, long size, long compressedSize, uint bundleMajorVersion)
{
- FileEntry entry = new FileEntry(type, relativePath, offset, size);
+ FileEntry entry = new FileEntry(type, relativePath, offset, size, compressedSize, bundleMajorVersion);
Files.Add(entry);
switch (entry.Type)
@@ -118,12 +112,12 @@ public long Write(BinaryWriter writer)
long startOffset = writer.BaseStream.Position;
// Write the bundle header
- writer.Write(DesiredMajorVersion);
- writer.Write(MinorVersion);
+ writer.Write(BundleMajorVersion);
+ writer.Write(BundleMinorVersion);
writer.Write(Files.Count);
writer.Write(BundleID);
- if (DesiredMajorVersion == 2)
+ if (BundleMajorVersion >= 2)
{
writer.Write((DepsJsonEntry != null) ? DepsJsonEntry.Offset : 0);
writer.Write((DepsJsonEntry != null) ? DepsJsonEntry.Size : 0);
diff --git a/src/installer/managed/Microsoft.NET.HostModel/Bundle/TargetInfo.cs b/src/installer/managed/Microsoft.NET.HostModel/Bundle/TargetInfo.cs
index 05d5ff9d89ee..2d3f6566a5ad 100644
--- a/src/installer/managed/Microsoft.NET.HostModel/Bundle/TargetInfo.cs
+++ b/src/installer/managed/Microsoft.NET.HostModel/Bundle/TargetInfo.cs
@@ -25,7 +25,7 @@ public class TargetInfo
public readonly OSPlatform OS;
public readonly Architecture Arch;
public readonly Version FrameworkVersion;
- public readonly uint BundleVersion;
+ public readonly uint BundleMajorVersion;
public readonly BundleOptions DefaultOptions;
public readonly int AssemblyAlignment;
@@ -33,18 +33,23 @@ public TargetInfo(OSPlatform? os, Architecture? arch, Version targetFrameworkVer
{
OS = os ?? HostOS;
Arch = arch ?? RuntimeInformation.OSArchitecture;
- FrameworkVersion = targetFrameworkVersion ?? net50;
+ FrameworkVersion = targetFrameworkVersion ?? net60;
Debug.Assert(IsLinux || IsOSX || IsWindows);
- if (FrameworkVersion.CompareTo(net50) >= 0)
+ if (FrameworkVersion.CompareTo(net60) >= 0)
{
- BundleVersion = 2u;
+ BundleMajorVersion = 6u;
+ DefaultOptions = BundleOptions.None;
+ }
+ else if (FrameworkVersion.CompareTo(net50) >= 0)
+ {
+ BundleMajorVersion = 2u;
DefaultOptions = BundleOptions.None;
}
else if (FrameworkVersion.Major == 3 && (FrameworkVersion.Minor == 0 || FrameworkVersion.Minor == 1))
{
- BundleVersion = 1u;
+ BundleMajorVersion = 1u;
DefaultOptions = BundleOptions.BundleAllContent;
}
else
@@ -94,7 +99,7 @@ public override string ToString()
// The .net core 3 apphost doesn't care about semantics of FileType -- all files are extracted at startup.
// However, the apphost checks that the FileType value is within expected bounds, so set it to the first enumeration.
- public FileType TargetSpecificFileType(FileType fileType) => (BundleVersion == 1) ? FileType.Unknown : fileType;
+ public FileType TargetSpecificFileType(FileType fileType) => (BundleMajorVersion == 1) ? FileType.Unknown : fileType;
// In .net core 3.x, bundle processing happens within the AppHost.
// Therefore HostFxr and HostPolicy can be bundled within the single-file app.
@@ -105,6 +110,7 @@ public override string ToString()
public bool ShouldExclude(string relativePath) =>
(FrameworkVersion.Major != 3) && (relativePath.Equals(HostFxr) || relativePath.Equals(HostPolicy));
+ private readonly Version net60 = new Version(6, 0);
private readonly Version net50 = new Version(5, 0);
private string HostFxr => IsWindows ? "hostfxr.dll" : IsLinux ? "libhostfxr.so" : "libhostfxr.dylib";
private string HostPolicy => IsWindows ? "hostpolicy.dll" : IsLinux ? "libhostpolicy.so" : "libhostpolicy.dylib";
diff --git a/src/installer/managed/Microsoft.NET.HostModel/Microsoft.NET.HostModel.csproj b/src/installer/managed/Microsoft.NET.HostModel/Microsoft.NET.HostModel.csproj
index 923e75d0772d..64ac366ee390 100644
--- a/src/installer/managed/Microsoft.NET.HostModel/Microsoft.NET.HostModel.csproj
+++ b/src/installer/managed/Microsoft.NET.HostModel/Microsoft.NET.HostModel.csproj
@@ -15,6 +15,7 @@
MicrosoftAspNetCoretrue
+ Microsoft.Net.HostModel.PGO
diff --git a/src/installer/pkg/sfx/bundle/Microsoft.NETCore.App.Bundle.bundleproj b/src/installer/pkg/sfx/bundle/Microsoft.NETCore.App.Bundle.bundleproj
index 3c9a701c9637..307a2fdca470 100644
--- a/src/installer/pkg/sfx/bundle/Microsoft.NETCore.App.Bundle.bundleproj
+++ b/src/installer/pkg/sfx/bundle/Microsoft.NETCore.App.Bundle.bundleproj
@@ -6,6 +6,7 @@
product band to upgrade in place.
-->
true
+ false.NET Core Shared Framework Bundle Installer$(MSBuildProjectDirectory)dotnet-runtime
@@ -18,7 +19,7 @@
-
+
diff --git a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleExtractToSpecificPath.cs b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleExtractToSpecificPath.cs
index 1741c9584b32..33c895548b21 100644
--- a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleExtractToSpecificPath.cs
+++ b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleExtractToSpecificPath.cs
@@ -31,8 +31,8 @@ private void Bundle_Extraction_To_Specific_Path_Succeeds()
var hostName = BundleHelper.GetHostName(fixture);
// Publish the bundle
- UseSingleFileSelfContainedHost(fixture);
- Bundler bundler = BundleHelper.BundleApp(fixture, out string singleFile, options: BundleOptions.BundleNativeBinaries);
+ BundleOptions options = BundleOptions.BundleNativeBinaries;
+ Bundler bundler = BundleSelfContainedApp(fixture, out string singleFile, options);
// Verify expected files in the bundle directory
var bundleDir = BundleHelper.GetBundleDir(fixture);
@@ -80,8 +80,7 @@ private void Bundle_Extraction_To_Relative_Path_Succeeds(string relativePath, Bu
return;
var fixture = sharedTestState.TestFixture.Copy();
- UseSingleFileSelfContainedHost(fixture);
- var bundler = BundleHelper.BundleApp(fixture, out var singleFile, bundleOptions);
+ var bundler = BundleSelfContainedApp(fixture, out var singleFile, bundleOptions);
// Run the bundled app (extract files to )
var cmd = Command.Create(singleFile);
@@ -110,8 +109,8 @@ private void Bundle_extraction_is_reused()
var fixture = sharedTestState.TestFixture.Copy();
// Publish the bundle
- UseSingleFileSelfContainedHost(fixture);
- Bundler bundler = BundleHelper.BundleApp(fixture, out string singleFile, BundleOptions.BundleNativeBinaries);
+ BundleOptions options = BundleOptions.BundleNativeBinaries;
+ Bundler bundler = BundleSelfContainedApp(fixture, out string singleFile, options);
// Create a directory for extraction.
var extractBaseDir = BundleHelper.GetExtractionRootDir(fixture);
@@ -160,13 +159,12 @@ private void Bundle_extraction_can_recover_missing_files()
var appName = Path.GetFileNameWithoutExtension(hostName);
// Publish the bundle
- UseSingleFileSelfContainedHost(fixture);
- Bundler bundler = BundleHelper.BundleApp(fixture, out string singleFile, BundleOptions.BundleNativeBinaries);
+ BundleOptions options = BundleOptions.BundleNativeBinaries;
+ Bundler bundler = BundleSelfContainedApp(fixture, out string singleFile, options);
// Create a directory for extraction.
var extractBaseDir = BundleHelper.GetExtractionRootDir(fixture);
-
// Run the bunded app for the first time, and extract files to
// $DOTNET_BUNDLE_EXTRACT_BASE_DIR//bundle-id
Command.Create(singleFile)
diff --git a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleTestBase.cs b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleTestBase.cs
index c71aaa35e5bd..18aba06f6d97 100644
--- a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleTestBase.cs
+++ b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleTestBase.cs
@@ -44,10 +44,28 @@ public static string UseFrameworkDependentHost(TestProjectFixture testFixture)
public static string BundleSelfContainedApp(
TestProjectFixture testFixture,
BundleOptions options = BundleOptions.None,
- Version targetFrameworkVersion = null)
+ Version targetFrameworkVersion = null,
+ bool disableCompression = false)
+ {
+ string singleFile;
+ BundleSelfContainedApp(testFixture, out singleFile, options, targetFrameworkVersion);
+ return singleFile;
+ }
+
+ public static Bundler BundleSelfContainedApp(
+ TestProjectFixture testFixture,
+ out string singleFile,
+ BundleOptions options = BundleOptions.None,
+ Version targetFrameworkVersion = null,
+ bool disableCompression = false)
{
UseSingleFileSelfContainedHost(testFixture);
- return BundleHelper.BundleApp(testFixture, options, targetFrameworkVersion);
+ if (targetFrameworkVersion == null || targetFrameworkVersion >= new Version(6, 0))
+ {
+ options |= BundleOptions.EnableCompression;
+ }
+
+ return BundleHelper.BundleApp(testFixture, out singleFile, options, targetFrameworkVersion);
}
public abstract class SharedTestStateBase
diff --git a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundledAppWithSubDirs.cs b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundledAppWithSubDirs.cs
index 2a0dc9ad537b..9ede20c516e3 100644
--- a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundledAppWithSubDirs.cs
+++ b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundledAppWithSubDirs.cs
@@ -59,7 +59,54 @@ public void Bundled_Framework_dependent_App_Run_Succeeds(BundleOptions options)
public void Bundled_Self_Contained_App_Run_Succeeds(BundleOptions options)
{
var fixture = sharedTestState.TestSelfContainedFixture.Copy();
- var singleFile = BundleHelper.BundleApp(fixture, options);
+ var singleFile = BundleSelfContainedApp(fixture, options);
+
+ // Run the bundled app (extract files)
+ RunTheApp(singleFile, fixture);
+
+ // Run the bundled app again (reuse extracted files)
+ RunTheApp(singleFile, fixture);
+ }
+
+ [InlineData(BundleOptions.None)]
+ [InlineData(BundleOptions.BundleNativeBinaries)]
+ [InlineData(BundleOptions.BundleAllContent)]
+ [Theory]
+ public void Bundled_Self_Contained_NoCompression_App_Run_Succeeds(BundleOptions options)
+ {
+ var fixture = sharedTestState.TestSelfContainedFixture.Copy();
+ var singleFile = BundleSelfContainedApp(fixture, options, disableCompression: true);
+
+ // Run the bundled app (extract files)
+ RunTheApp(singleFile, fixture);
+
+ // Run the bundled app again (reuse extracted files)
+ RunTheApp(singleFile, fixture);
+ }
+
+ [InlineData(BundleOptions.None)]
+ [InlineData(BundleOptions.BundleNativeBinaries)]
+ [InlineData(BundleOptions.BundleAllContent)]
+ [Theory]
+ public void Bundled_Self_Contained_Targeting50_App_Run_Succeeds(BundleOptions options)
+ {
+ var fixture = sharedTestState.TestSelfContainedFixture.Copy();
+ var singleFile = BundleSelfContainedApp(fixture, options, new Version(5, 0));
+
+ // Run the bundled app (extract files)
+ RunTheApp(singleFile, fixture);
+
+ // Run the bundled app again (reuse extracted files)
+ RunTheApp(singleFile, fixture);
+ }
+
+ [InlineData(BundleOptions.BundleAllContent)]
+ [Theory]
+ public void Bundled_Framework_dependent_Targeting50_App_Run_Succeeds(BundleOptions options)
+ {
+ var fixture = sharedTestState.TestSelfContainedFixture.Copy();
+ UseFrameworkDependentHost(fixture);
+ var singleFile = BundleHelper.BundleApp(fixture, options, new Version(5, 0));
// Run the bundled app (extract files)
RunTheApp(singleFile, fixture);
@@ -68,6 +115,17 @@ public void Bundled_Self_Contained_App_Run_Succeeds(BundleOptions options)
RunTheApp(singleFile, fixture);
}
+ [Fact]
+ public void Bundled_Self_Contained_Targeting50_WithCompression_Throws()
+ {
+ var fixture = sharedTestState.TestSelfContainedFixture.Copy();
+ UseSingleFileSelfContainedHost(fixture);
+ // compression must be off when targeting 5.0
+ var options = BundleOptions.EnableCompression;
+
+ Assert.Throws(()=>BundleHelper.BundleApp(fixture, options, new Version(5, 0)));
+ }
+
[InlineData(BundleOptions.None)]
[InlineData(BundleOptions.BundleNativeBinaries)]
[InlineData(BundleOptions.BundleAllContent)]
@@ -75,7 +133,7 @@ public void Bundled_Self_Contained_App_Run_Succeeds(BundleOptions options)
public void Bundled_With_Empty_File_Succeeds(BundleOptions options)
{
var fixture = sharedTestState.TestAppWithEmptyFileFixture.Copy();
- var singleFile = BundleHelper.BundleApp(fixture, options);
+ var singleFile = BundleSelfContainedApp(fixture, options);
// Run the app
RunTheApp(singleFile, fixture);
diff --git a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/NetCoreApp3CompatModeTests.cs b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/NetCoreApp3CompatModeTests.cs
index 95e1061f20c2..cb8bdf9d44a8 100644
--- a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/NetCoreApp3CompatModeTests.cs
+++ b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/NetCoreApp3CompatModeTests.cs
@@ -26,8 +26,8 @@ public NetCoreApp3CompatModeTests(SingleFileSharedState fixture)
public void Bundle_Is_Extracted()
{
var fixture = sharedTestState.TestFixture.Copy();
- UseSingleFileSelfContainedHost(fixture);
- Bundler bundler = BundleHelper.BundleApp(fixture, out string singleFile, BundleOptions.BundleAllContent);
+ BundleOptions options = BundleOptions.BundleAllContent;
+ Bundler bundler = BundleSelfContainedApp(fixture, out string singleFile, options);
var extractionBaseDir = BundleHelper.GetExtractionRootDir(fixture);
Command.Create(singleFile, "executing_assembly_location trusted_platform_assemblies assembly_location System.Console")
diff --git a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/SingleFileApiTests.cs b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/SingleFileApiTests.cs
index 60425b9c7192..0efa9a781918 100644
--- a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/SingleFileApiTests.cs
+++ b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/SingleFileApiTests.cs
@@ -91,7 +91,7 @@ public void GetCommandLineArgs_0_Non_Bundled_App()
public void AppContext_Native_Search_Dirs_Contains_Bundle_Dir()
{
var fixture = sharedTestState.TestFixture.Copy();
- Bundler bundler = BundleHelper.BundleApp(fixture, out string singleFile);
+ Bundler bundler = BundleSelfContainedApp(fixture, out string singleFile);
string extractionDir = BundleHelper.GetExtractionDir(fixture, bundler).Name;
string bundleDir = BundleHelper.GetBundleDir(fixture).FullName;
@@ -110,7 +110,7 @@ public void AppContext_Native_Search_Dirs_Contains_Bundle_Dir()
public void AppContext_Native_Search_Dirs_Contains_Bundle_And_Extraction_Dirs()
{
var fixture = sharedTestState.TestFixture.Copy();
- Bundler bundler = BundleHelper.BundleApp(fixture, out string singleFile, BundleOptions.BundleNativeBinaries);
+ Bundler bundler = BundleSelfContainedApp(fixture, out string singleFile, BundleOptions.BundleNativeBinaries);
string extractionDir = BundleHelper.GetExtractionDir(fixture, bundler).Name;
string bundleDir = BundleHelper.GetBundleDir(fixture).FullName;
diff --git a/src/installer/tests/Microsoft.NET.HostModel.Tests/Helpers/BundleHelper.cs b/src/installer/tests/Microsoft.NET.HostModel.Tests/Helpers/BundleHelper.cs
index 6a102ddade96..ecd00f75c6fd 100644
--- a/src/installer/tests/Microsoft.NET.HostModel.Tests/Helpers/BundleHelper.cs
+++ b/src/installer/tests/Microsoft.NET.HostModel.Tests/Helpers/BundleHelper.cs
@@ -60,7 +60,7 @@ public static string[] GetBundledFiles(TestProjectFixture fixture)
public static string[] GetExtractedFiles(TestProjectFixture fixture, BundleOptions bundleOptions)
{
- switch (bundleOptions)
+ switch (bundleOptions & ~BundleOptions.EnableCompression)
{
case BundleOptions.None:
case BundleOptions.BundleOtherFiles:
diff --git a/src/libraries/Common/src/System/Net/ArrayBuffer.cs b/src/libraries/Common/src/System/Net/ArrayBuffer.cs
index 5dbc5a158cb7..56413164232d 100644
--- a/src/libraries/Common/src/System/Net/ArrayBuffer.cs
+++ b/src/libraries/Common/src/System/Net/ArrayBuffer.cs
@@ -41,15 +41,12 @@ public void Dispose()
_activeStart = 0;
_availableStart = 0;
- if (_usePool)
- {
- byte[] array = _bytes;
- _bytes = null!;
+ byte[] array = _bytes;
+ _bytes = null!;
- if (array != null)
- {
- ArrayPool.Shared.Return(array);
- }
+ if (_usePool && array != null)
+ {
+ ArrayPool.Shared.Return(array);
}
}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSACng.SignVerify.cs b/src/libraries/Common/src/System/Security/Cryptography/RSACng.SignVerify.cs
index 7eaf3f9e9a6d..82709832cd88 100644
--- a/src/libraries/Common/src/System/Security/Cryptography/RSACng.SignVerify.cs
+++ b/src/libraries/Common/src/System/Security/Cryptography/RSACng.SignVerify.cs
@@ -32,9 +32,9 @@ private static int GetHashSizeInBytes(HashAlgorithmName hashAlgorithm)
{
return s_hashSizes.GetOrAdd(
hashAlgorithm,
- alg =>
+ static hashAlgorithm =>
{
- using (HashProviderCng hashProvider = new HashProviderCng(alg.Name!, null))
+ using (HashProviderCng hashProvider = new HashProviderCng(hashAlgorithm.Name!, null))
{
return hashProvider.HashSizeInBytes;
}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs b/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs
index f7aa5b4204b3..9538db141432 100644
--- a/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs
+++ b/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs
@@ -39,7 +39,7 @@ internal sealed class RsaPaddingProcessor
private static readonly byte[] s_digestInfoSha512 =
{
- 0x30, 0x41, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48,
+ 0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48,
0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04,
0x40,
};
@@ -74,7 +74,7 @@ internal static RsaPaddingProcessor OpenProcessor(HashAlgorithmName hashAlgorith
{
return s_lookup.GetOrAdd(
hashAlgorithmName,
- alg =>
+ static hashAlgorithmName =>
{
using (IncrementalHash hasher = IncrementalHash.CreateHash(hashAlgorithmName))
{
diff --git a/src/libraries/Common/tests/SingleFileTestRunner/SingleFileTestRunner.cs b/src/libraries/Common/tests/SingleFileTestRunner/SingleFileTestRunner.cs
new file mode 100644
index 000000000000..7b67a1338e5a
--- /dev/null
+++ b/src/libraries/Common/tests/SingleFileTestRunner/SingleFileTestRunner.cs
@@ -0,0 +1,77 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#nullable disable
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.Loader;
+using System.Threading.Tasks;
+using System.Xml.Linq;
+using Xunit;
+using Xunit.Abstractions;
+using Xunit.Sdk;
+
+public class SingleFileTestRunner : XunitTestFramework
+{
+ private SingleFileTestRunner(IMessageSink messageSink)
+ : base(messageSink) { }
+
+ public static int Main(string[] args)
+ {
+ var asm = typeof(SingleFileTestRunner).Assembly;
+ Console.WriteLine("Running assembly:" + asm.FullName);
+
+ var diagnosticSink = new ConsoleDiagnosticMessageSink();
+ var testsFinished = new TaskCompletionSource();
+ var testSink = new TestMessageSink();
+ var summarySink = new DelegatingExecutionSummarySink(testSink,
+ () => false,
+ (completed, summary) => Console.WriteLine($"Tests run: {summary.Total}, Errors: {summary.Errors}, Failures: {summary.Failed}, Skipped: {summary.Skipped}. Time: {TimeSpan.FromSeconds((double)summary.Time).TotalSeconds}s"));
+ var resultsXmlAssembly = new XElement("assembly");
+ var resultsSink = new DelegatingXmlCreationSink(summarySink, resultsXmlAssembly);
+
+ testSink.Execution.TestSkippedEvent += args => { Console.WriteLine($"[SKIP] {args.Message.Test.DisplayName}"); };
+ testSink.Execution.TestFailedEvent += args => { Console.WriteLine($"[FAIL] {args.Message.Test.DisplayName}{Environment.NewLine}{Xunit.ExceptionUtility.CombineMessages(args.Message)}{Environment.NewLine}{Xunit.ExceptionUtility.CombineStackTraces(args.Message)}"); };
+
+ testSink.Execution.TestAssemblyFinishedEvent += args =>
+ {
+ Console.WriteLine($"Finished {args.Message.TestAssembly.Assembly}{Environment.NewLine}");
+ testsFinished.SetResult();
+ };
+
+ var xunitTestFx = new SingleFileTestRunner(diagnosticSink);
+ var asmInfo = Reflector.Wrap(asm);
+ var asmName = asm.GetName();
+
+ var discoverySink = new TestDiscoverySink();
+ var discoverer = xunitTestFx.CreateDiscoverer(asmInfo);
+ discoverer.Find(false, discoverySink, TestFrameworkOptions.ForDiscovery());
+ discoverySink.Finished.WaitOne();
+ XunitFilters filters = new XunitFilters();
+ filters.ExcludedTraits.Add("category", new List { "failing" });
+ var filteredTestCases = discoverySink.TestCases.Where(filters.Filter).ToList();
+ var executor = xunitTestFx.CreateExecutor(asmName);
+ executor.RunTests(filteredTestCases, resultsSink, TestFrameworkOptions.ForExecution());
+
+ resultsSink.Finished.WaitOne();
+
+ var failed = resultsSink.ExecutionSummary.Failed > 0 || resultsSink.ExecutionSummary.Errors > 0;
+ return failed ? 1 : 0;
+ }
+}
+
+internal class ConsoleDiagnosticMessageSink : IMessageSink
+{
+ public bool OnMessage(IMessageSinkMessage message)
+ {
+ if (message is IDiagnosticMessage diagnosticMessage)
+ {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Authentication.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Authentication.cs
index 3dd6e7ed9ba7..4df4100a8ed4 100644
--- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Authentication.cs
+++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Authentication.cs
@@ -33,7 +33,6 @@ public abstract class HttpClientHandler_Authentication_Test : HttpClientHandlerT
private async Task CreateAndValidateRequest(HttpClientHandler handler, Uri url, HttpStatusCode expectedStatusCode, ICredentials credentials)
{
handler.Credentials = credentials;
-
using (HttpClient client = CreateHttpClient(handler))
using (HttpResponseMessage response = await client.GetAsync(url))
{
@@ -94,6 +93,13 @@ public static IEnumerable
diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Comparer.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Comparer.cs
index c21928a7381f..cdfc29a7a3e4 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Comparer.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Comparer.cs
@@ -120,7 +120,7 @@ public override int GetHashCode() =>
[Serializable]
internal sealed partial class EnumComparer : Comparer, ISerializable where T : struct, Enum
{
- internal EnumComparer() { }
+ public EnumComparer() { }
// Used by the serialization engine.
private EnumComparer(SerializationInfo info, StreamingContext context) { }
diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.cs
index 0af18e7f7dd1..e7f23a80ab5f 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.cs
@@ -180,7 +180,7 @@ public override int GetHashCode() =>
// Needs to be public to support binary serialization compatibility
public sealed partial class EnumEqualityComparer : EqualityComparer, ISerializable where T : struct, Enum
{
- internal EnumEqualityComparer() { }
+ public EnumEqualityComparer() { }
// This is used by the serialization engine.
private EnumEqualityComparer(SerializationInfo information, StreamingContext context) { }
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/StackTrace.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/StackTrace.cs
index 3c6ba961c79d..47d5b71a306e 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/StackTrace.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/StackTrace.cs
@@ -187,7 +187,6 @@ internal enum TraceFormat
TrailingNewLine, // include a trailing new line character
}
-#if !CORERT
///
/// Builds a readable representation of the stack trace, specifying
/// the format for backwards compatibility.
@@ -199,6 +198,7 @@ internal string ToString(TraceFormat traceFormat)
return sb.ToString();
}
+#if !CORERT
internal void ToString(TraceFormat traceFormat, StringBuilder sb)
{
// Passing a default string for "at" in case SR.UsingResourceKeys() is true
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs
index 3146d1f70546..5d85b20e7b6b 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs
@@ -15,7 +15,9 @@ namespace Microsoft.Diagnostics.Tracing
namespace System.Diagnostics.Tracing
#endif
{
+#if NETCOREAPP
[UnsupportedOSPlatform("browser")]
+#endif
internal sealed class CounterGroup
{
private readonly EventSource _eventSource;
@@ -271,10 +273,9 @@ private static void PollForValues()
// We cache these outside of the scope of s_counterGroupLock because
// calling into the callbacks can cause a re-entrancy into CounterGroup.Enable()
// and result in a deadlock. (See https://github.com/dotnet/runtime/issues/40190 for details)
- List onTimers = new List();
+ var onTimers = new List();
while (true)
{
- onTimers.Clear();
int sleepDurationInMilliseconds = int.MaxValue;
lock (s_counterGroupLock)
{
@@ -284,7 +285,7 @@ private static void PollForValues()
DateTime now = DateTime.UtcNow;
if (counterGroup._nextPollingTimeStamp < now + new TimeSpan(0, 0, 0, 0, 1))
{
- onTimers.Add(() => counterGroup.OnTimer());
+ onTimers.Add(counterGroup);
}
int millisecondsTillNextPoll = (int)((counterGroup._nextPollingTimeStamp - now).TotalMilliseconds);
@@ -292,10 +293,11 @@ private static void PollForValues()
sleepDurationInMilliseconds = Math.Min(sleepDurationInMilliseconds, millisecondsTillNextPoll);
}
}
- foreach (Action onTimer in onTimers)
+ foreach (CounterGroup onTimer in onTimers)
{
- onTimer.Invoke();
+ onTimer.OnTimer();
}
+ onTimers.Clear();
if (sleepDurationInMilliseconds == int.MaxValue)
{
sleepDurationInMilliseconds = -1; // WaitOne uses -1 to mean infinite
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs
index 16724c371c49..0c23cf99222b 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs
@@ -20,7 +20,9 @@ namespace System.Diagnostics.Tracing
/// DiagnosticCounter is an abstract class that serves as the parent class for various Counter* classes,
/// namely EventCounter, PollingCounter, IncrementingEventCounter, and IncrementingPollingCounter.
///
+#if NETCOREAPP
[UnsupportedOSPlatform("browser")]
+#endif
public abstract class DiagnosticCounter : IDisposable
{
///
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs
index 52dac7973982..8a53d5690821 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs
@@ -24,7 +24,9 @@ namespace System.Diagnostics.Tracing
/// See https://github.com/dotnet/runtime/blob/main/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestEventCounter.cs
/// which shows tests, which are also useful in seeing actual use.
///
+#if NETCOREAPP
[UnsupportedOSPlatform("browser")]
+#endif
public partial class EventCounter : DiagnosticCounter
{
///
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/TraceLogging/EventPayload.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/TraceLogging/EventPayload.cs
index cd34723240c5..98cd97f567a5 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/TraceLogging/EventPayload.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/TraceLogging/EventPayload.cs
@@ -22,9 +22,9 @@ namespace System.Diagnostics.Tracing
///
internal sealed class EventPayload : IDictionary
{
- internal EventPayload(List payloadNames, List payloadValues)
+ internal EventPayload(string[] payloadNames, object?[] payloadValues)
{
- Debug.Assert(payloadNames.Count == payloadValues.Count);
+ Debug.Assert(payloadNames.Length == payloadValues.Length);
m_names = payloadNames;
m_values = payloadValues;
@@ -88,7 +88,7 @@ public bool ContainsKey(string key)
return false;
}
- public int Count => m_names.Count;
+ public int Count => m_names.Length;
public bool IsReadOnly => true;
@@ -142,8 +142,8 @@ public bool TryGetValue(string key, [MaybeNullWhen(false)] out object? value)
}
#region private
- private readonly List m_names;
- private readonly List m_values;
+ private readonly string[] m_names;
+ private readonly object?[] m_values;
#endregion
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/TraceLogging/InvokeTypeInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/TraceLogging/InvokeTypeInfo.cs
index 0cc42deb4fde..1fc44ac48917 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/TraceLogging/InvokeTypeInfo.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/TraceLogging/InvokeTypeInfo.cs
@@ -77,13 +77,13 @@ public override void WriteData(PropertyValue value)
{
if (this.properties != null)
{
- var membersNames = new List();
- var membersValues = new List();
+ var membersNames = new string[this.properties.Length];
+ var membersValues = new object?[this.properties.Length];
for (int i = 0; i < this.properties.Length; i++)
{
object? propertyValue = properties[i].propertyInfo.GetValue(value);
- membersNames.Add(properties[i].name);
- membersValues.Add(properties[i].typeInfo.GetData(propertyValue));
+ membersNames[i] = properties[i].name;
+ membersValues[i] = properties[i].typeInfo.GetData(propertyValue);
}
return new EventPayload(membersNames, membersValues);
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Exception.cs b/src/libraries/System.Private.CoreLib/src/System/Exception.cs
index 14e84a603cce..c53561a81713 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Exception.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Exception.cs
@@ -4,6 +4,7 @@
using System.Collections;
using System.Diagnostics;
using System.Runtime.Serialization;
+using System.Text;
namespace System
{
@@ -46,6 +47,7 @@ protected Exception(SerializationInfo info, StreamingContext context)
_innerException = (Exception?)(info.GetValue("InnerException", typeof(Exception))); // Do not rename (binary serialization)
_helpURL = info.GetString("HelpURL"); // Do not rename (binary serialization)
_stackTraceString = info.GetString("StackTraceString"); // Do not rename (binary serialization)
+ _remoteStackTraceString = info.GetString("RemoteStackTraceString"); // Do not rename (binary serialization)
_HResult = info.GetInt32("HResult"); // Do not rename (binary serialization)
_source = info.GetString("Source"); // Do not rename (binary serialization)
@@ -109,7 +111,7 @@ public virtual void GetObjectData(SerializationInfo info, StreamingContext conte
info.AddValue("InnerException", _innerException, typeof(Exception)); // Do not rename (binary serialization)
info.AddValue("HelpURL", _helpURL, typeof(string)); // Do not rename (binary serialization)
info.AddValue("StackTraceString", SerializationStackTraceString, typeof(string)); // Do not rename (binary serialization)
- info.AddValue("RemoteStackTraceString", SerializationRemoteStackTraceString, typeof(string)); // Do not rename (binary serialization)
+ info.AddValue("RemoteStackTraceString", _remoteStackTraceString, typeof(string)); // Do not rename (binary serialization)
info.AddValue("RemoteStackIndex", 0, typeof(int)); // Do not rename (binary serialization)
info.AddValue("ExceptionMethod", null, typeof(string)); // Do not rename (binary serialization)
info.AddValue("HResult", _HResult); // Do not rename (binary serialization)
@@ -197,5 +199,34 @@ public int HResult
public new Type GetType() => base.GetType();
partial void RestoreRemoteStackTrace(SerializationInfo info, StreamingContext context);
+
+ [StackTraceHidden]
+ internal void SetCurrentStackTrace()
+ {
+ if (!CanSetRemoteStackTrace())
+ {
+ return; // early-exit
+ }
+
+ // Store the current stack trace into the "remote" stack trace, which was originally introduced to support
+ // remoting of exceptions cross app-domain boundaries, and is thus concatenated into Exception.StackTrace
+ // when it's retrieved.
+ var sb = new StringBuilder(256);
+ new StackTrace(fNeedFileInfo: true).ToString(System.Diagnostics.StackTrace.TraceFormat.TrailingNewLine, sb);
+ sb.AppendLine(SR.Exception_EndStackTraceFromPreviousThrow);
+ _remoteStackTraceString = sb.ToString();
+ }
+
+ internal void SetRemoteStackTrace(string stackTrace)
+ {
+ if (!CanSetRemoteStackTrace())
+ {
+ return; // early-exit
+ }
+
+ // Store the provided text into the "remote" stack trace, following the same format SetCurrentStackTrace
+ // would have generated.
+ _remoteStackTraceString = stackTrace + Environment.NewLineConst + SR.Exception_EndStackTraceFromPreviousThrow + Environment.NewLineConst;
+ }
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/FileStreamCompletionSource.Win32.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/FileStreamCompletionSource.Win32.cs
index c23f04dc64b1..679d62422a4a 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/FileStreamCompletionSource.Win32.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/FileStreamCompletionSource.Win32.cs
@@ -10,7 +10,7 @@
namespace System.IO.Strategies
{
- // to avoid code duplicaiton of FileStreamCompletionSource for LegacyFileStreamStrategy and AsyncWindowsFileStreamStrategy
+ // to avoid code duplicaiton of FileStreamCompletionSource for Net5CompatFileStreamStrategy and AsyncWindowsFileStreamStrategy
// we have created the following interface that is a common contract for both of them
internal interface IFileStreamCompletionSourceStrategy
{
@@ -237,7 +237,7 @@ public static FileStreamCompletionSource Create(IFileStreamCompletionSourceStrat
// MemoryFileStreamCompletionSource, which Retains the memory, which will result in less pinning in the case
// where the underlying memory is backed by pre-pinned buffers.
return preallocatedOverlapped != null && MemoryMarshal.TryGetArray(memory, out ArraySegment buffer)
- && preallocatedOverlapped.IsUserObject(buffer.Array) // preallocatedOverlapped is allocated when BufferedStream|LegacyFileStreamStrategy allocates the buffer
+ && preallocatedOverlapped.IsUserObject(buffer.Array) // preallocatedOverlapped is allocated when BufferedStream|Net5CompatFileStreamStrategy allocates the buffer
? new FileStreamCompletionSource(strategy, preallocatedOverlapped, numBufferedBytesRead, buffer.Array)
: new MemoryFileStreamCompletionSource(strategy, numBufferedBytesRead, memory);
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/FileStreamHelpers.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/FileStreamHelpers.Unix.cs
index 9af81a5136d0..0d2c5df52be3 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/FileStreamHelpers.Unix.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/FileStreamHelpers.Unix.cs
@@ -15,10 +15,10 @@ internal static partial class FileStreamHelpers
{
// in the future we are most probably going to introduce more strategies (io_uring etc)
private static FileStreamStrategy ChooseStrategyCore(SafeFileHandle handle, FileAccess access, FileShare share, int bufferSize, bool isAsync)
- => new LegacyFileStreamStrategy(handle, access, bufferSize, isAsync);
+ => new Net5CompatFileStreamStrategy(handle, access, bufferSize, isAsync);
private static FileStreamStrategy ChooseStrategyCore(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options)
- => new LegacyFileStreamStrategy(path, mode, access, share, bufferSize, options);
+ => new Net5CompatFileStreamStrategy(path, mode, access, share, bufferSize, options);
internal static SafeFileHandle OpenHandle(string path, FileMode mode, FileAccess access, FileShare share, FileOptions options)
{
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/FileStreamHelpers.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/FileStreamHelpers.Windows.cs
index 661e84b10f67..fd3218f6eb4c 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/FileStreamHelpers.Windows.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/FileStreamHelpers.Windows.cs
@@ -21,9 +21,9 @@ internal static partial class FileStreamHelpers
private static FileStreamStrategy ChooseStrategyCore(SafeFileHandle handle, FileAccess access, FileShare share, int bufferSize, bool isAsync)
{
- if (UseLegacyStrategy)
+ if (UseNet5CompatStrategy)
{
- return new LegacyFileStreamStrategy(handle, access, bufferSize, isAsync);
+ return new Net5CompatFileStreamStrategy(handle, access, bufferSize, isAsync);
}
WindowsFileStreamStrategy strategy = isAsync
@@ -35,9 +35,9 @@ private static FileStreamStrategy ChooseStrategyCore(SafeFileHandle handle, File
private static FileStreamStrategy ChooseStrategyCore(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options)
{
- if (UseLegacyStrategy)
+ if (UseNet5CompatStrategy)
{
- return new LegacyFileStreamStrategy(path, mode, access, share, bufferSize, options);
+ return new Net5CompatFileStreamStrategy(path, mode, access, share, bufferSize, options);
}
WindowsFileStreamStrategy strategy = (options & FileOptions.Asynchronous) != 0
@@ -558,7 +558,7 @@ internal static async Task AsyncModeCopyToAsync(SafeFileHandle handle, string? p
}
}
- /// Used by AsyncWindowsFileStreamStrategy and LegacyFileStreamStrategy CopyToAsync to enable awaiting the result of an overlapped I/O operation with minimal overhead.
+ /// Used by AsyncWindowsFileStreamStrategy and Net5CompatFileStreamStrategy CopyToAsync to enable awaiting the result of an overlapped I/O operation with minimal overhead.
private sealed unsafe class AsyncCopyToAwaitable : ICriticalNotifyCompletion
{
/// Sentinel object used to indicate that the I/O operation has completed before being awaited.
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/FileStreamHelpers.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/FileStreamHelpers.cs
index 62e344db6e4f..d64677b48efe 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/FileStreamHelpers.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/FileStreamHelpers.cs
@@ -8,9 +8,9 @@ namespace System.IO.Strategies
internal static partial class FileStreamHelpers
{
// It's enabled by default. We are going to change that once we fix #16354, #25905 and #24847.
- internal static bool UseLegacyStrategy { get; } = GetLegacyFileStreamSetting();
+ internal static bool UseNet5CompatStrategy { get; } = GetNet5CompatFileStreamSetting();
- private static bool GetLegacyFileStreamSetting()
+ private static bool GetNet5CompatFileStreamSetting()
{
if (AppContext.TryGetSwitch("System.IO.UseNet5CompatFileStream", out bool fileConfig))
{
@@ -19,7 +19,7 @@ private static bool GetLegacyFileStreamSetting()
string? envVar = Environment.GetEnvironmentVariable("DOTNET_SYSTEM_IO_USENET5COMPATFILESTREAM");
return envVar is null
- ? true // legacy is currently enabled by default;
+ ? true // Net5Compat is currently enabled by default;
: bool.IsTrueStringIgnoreCase(envVar) || envVar.Equals("1");
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/LegacyFileStreamStrategy.Lock.OSX.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/Net5CompatFileStreamStrategy.Lock.OSX.cs
similarity index 86%
rename from src/libraries/System.Private.CoreLib/src/System/IO/Strategies/LegacyFileStreamStrategy.Lock.OSX.cs
rename to src/libraries/System.Private.CoreLib/src/System/IO/Strategies/Net5CompatFileStreamStrategy.Lock.OSX.cs
index 5d00486b26b0..d3ac0b7cf7f1 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/LegacyFileStreamStrategy.Lock.OSX.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/Net5CompatFileStreamStrategy.Lock.OSX.cs
@@ -3,7 +3,7 @@
namespace System.IO.Strategies
{
- internal sealed partial class LegacyFileStreamStrategy : FileStreamStrategy
+ internal sealed partial class Net5CompatFileStreamStrategy : FileStreamStrategy
{
internal override void Lock(long position, long length)
{
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/LegacyFileStreamStrategy.Lock.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/Net5CompatFileStreamStrategy.Lock.Unix.cs
similarity index 93%
rename from src/libraries/System.Private.CoreLib/src/System/IO/Strategies/LegacyFileStreamStrategy.Lock.Unix.cs
rename to src/libraries/System.Private.CoreLib/src/System/IO/Strategies/Net5CompatFileStreamStrategy.Lock.Unix.cs
index d6a534ffb259..20e065d6317f 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/LegacyFileStreamStrategy.Lock.Unix.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/Net5CompatFileStreamStrategy.Lock.Unix.cs
@@ -3,7 +3,7 @@
namespace System.IO.Strategies
{
- internal sealed partial class LegacyFileStreamStrategy : FileStreamStrategy
+ internal sealed partial class Net5CompatFileStreamStrategy : FileStreamStrategy
{
/// Prevents other processes from reading from or writing to the FileStream.
/// The beginning of the range to lock.
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/LegacyFileStreamStrategy.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/Net5CompatFileStreamStrategy.Unix.cs
similarity index 99%
rename from src/libraries/System.Private.CoreLib/src/System/IO/Strategies/LegacyFileStreamStrategy.Unix.cs
rename to src/libraries/System.Private.CoreLib/src/System/IO/Strategies/Net5CompatFileStreamStrategy.Unix.cs
index a9614b1d5538..eb1cebc37a7f 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/LegacyFileStreamStrategy.Unix.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/Net5CompatFileStreamStrategy.Unix.cs
@@ -11,7 +11,7 @@
namespace System.IO.Strategies
{
/// Provides an implementation of a file stream for Unix files.
- internal sealed partial class LegacyFileStreamStrategy : FileStreamStrategy
+ internal sealed partial class Net5CompatFileStreamStrategy : FileStreamStrategy
{
/// File mode.
private FileMode _mode;
@@ -224,7 +224,7 @@ public override ValueTask DisposeAsync()
// override may already exist on a derived type.
if (_useAsyncIO && _writePos > 0)
{
- return new ValueTask(Task.Factory.StartNew(static s => ((LegacyFileStreamStrategy)s!).Dispose(), this,
+ return new ValueTask(Task.Factory.StartNew(static s => ((Net5CompatFileStreamStrategy)s!).Dispose(), this,
CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default));
}
@@ -449,7 +449,7 @@ private unsafe int ReadNative(Span buffer)
// whereas on Windows it may happen before the write has completed.
Debug.Assert(t.Status == TaskStatus.RanToCompletion);
- var thisRef = (LegacyFileStreamStrategy)s!;
+ var thisRef = (Net5CompatFileStreamStrategy)s!;
Debug.Assert(thisRef._asyncState != null);
try
{
@@ -610,7 +610,7 @@ private ValueTask WriteAsyncInternal(ReadOnlyMemory source, CancellationTo
// whereas on Windows it may happen before the write has completed.
Debug.Assert(t.Status == TaskStatus.RanToCompletion);
- var thisRef = (LegacyFileStreamStrategy)s!;
+ var thisRef = (Net5CompatFileStreamStrategy)s!;
Debug.Assert(thisRef._asyncState != null);
try
{
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/LegacyFileStreamStrategy.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/Net5CompatFileStreamStrategy.Windows.cs
similarity index 99%
rename from src/libraries/System.Private.CoreLib/src/System/IO/Strategies/LegacyFileStreamStrategy.Windows.cs
rename to src/libraries/System.Private.CoreLib/src/System/IO/Strategies/Net5CompatFileStreamStrategy.Windows.cs
index e562f0c2e215..5ed9f5937aa2 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/LegacyFileStreamStrategy.Windows.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/Net5CompatFileStreamStrategy.Windows.cs
@@ -36,7 +36,7 @@
namespace System.IO.Strategies
{
- internal sealed partial class LegacyFileStreamStrategy : FileStreamStrategy, IFileStreamCompletionSourceStrategy
+ internal sealed partial class Net5CompatFileStreamStrategy : FileStreamStrategy, IFileStreamCompletionSourceStrategy
{
private bool _canSeek;
private bool _isPipe; // Whether to disable async buffering code.
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/LegacyFileStreamStrategy.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/Net5CompatFileStreamStrategy.cs
similarity index 97%
rename from src/libraries/System.Private.CoreLib/src/System/IO/Strategies/LegacyFileStreamStrategy.cs
rename to src/libraries/System.Private.CoreLib/src/System/IO/Strategies/Net5CompatFileStreamStrategy.cs
index 6d06e9614056..03ca3533e717 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/LegacyFileStreamStrategy.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/Net5CompatFileStreamStrategy.cs
@@ -9,8 +9,8 @@
namespace System.IO.Strategies
{
- // This type is partial so we can avoid code duplication between Windows and Unix Legacy implementations
- internal sealed partial class LegacyFileStreamStrategy : FileStreamStrategy
+ // This type is partial so we can avoid code duplication between Windows and Unix Net5Compat implementations
+ internal sealed partial class Net5CompatFileStreamStrategy : FileStreamStrategy
{
private byte[]? _buffer;
private readonly int _bufferLength;
@@ -61,7 +61,7 @@ internal sealed partial class LegacyFileStreamStrategy : FileStreamStrategy
/// Whether the file stream's handle has been exposed.
private bool _exposedHandle;
- internal LegacyFileStreamStrategy(SafeFileHandle handle, FileAccess access, int bufferSize, bool isAsync)
+ internal Net5CompatFileStreamStrategy(SafeFileHandle handle, FileAccess access, int bufferSize, bool isAsync)
{
_exposedHandle = true;
_bufferLength = bufferSize;
@@ -78,7 +78,7 @@ internal LegacyFileStreamStrategy(SafeFileHandle handle, FileAccess access, int
_fileHandle = handle;
}
- internal LegacyFileStreamStrategy(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options)
+ internal Net5CompatFileStreamStrategy(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options)
{
string fullPath = Path.GetFullPath(path);
@@ -105,7 +105,7 @@ internal LegacyFileStreamStrategy(string path, FileMode mode, FileAccess access,
}
}
- ~LegacyFileStreamStrategy() => Dispose(false); // mandatory to Flush the write buffer
+ ~Net5CompatFileStreamStrategy() => Dispose(false); // mandatory to Flush the write buffer
internal override void DisposeInternal(bool disposing) => Dispose(disposing);
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/WindowsFileStreamStrategy.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/WindowsFileStreamStrategy.cs
index 8c33d75aeebd..d42494c19086 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/WindowsFileStreamStrategy.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/Strategies/WindowsFileStreamStrategy.cs
@@ -4,7 +4,6 @@
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.Win32.SafeHandles;
-using System.Runtime.CompilerServices;
namespace System.IO.Strategies
{
@@ -28,6 +27,7 @@ internal abstract class WindowsFileStreamStrategy : FileStreamStrategy
protected long _filePosition;
private long _appendStart; // When appending, prevent overwriting file.
private long _length = -1; // When the file is locked for writes (_share <= FileShare.Read) cache file length in-memory, negative means that hasn't been fetched.
+ private bool _exposedHandle; // created from handle, or SafeFileHandle was used and the handle got exposed
internal WindowsFileStreamStrategy(SafeFileHandle handle, FileAccess access, FileShare share)
{
@@ -37,6 +37,7 @@ internal WindowsFileStreamStrategy(SafeFileHandle handle, FileAccess access, Fil
// but we can't as they're readonly.
_access = access;
_share = share;
+ _exposedHandle = true;
// As the handle was passed in, we must set the handle field at the very end to
// avoid the finalizer closing the handle when we throw errors.
@@ -77,15 +78,29 @@ internal WindowsFileStreamStrategy(string path, FileMode mode, FileAccess access
// When the file is locked for writes we can cache file length in memory
// and avoid subsequent native calls which are expensive.
- public unsafe sealed override long Length => _share > FileShare.Read ?
- FileStreamHelpers.GetFileLength(_fileHandle, _path) :
- _length < 0 ? _length = FileStreamHelpers.GetFileLength(_fileHandle, _path) : _length;
+ public unsafe sealed override long Length
+ {
+ get
+ {
+ if (_share > FileShare.Read || _exposedHandle)
+ {
+ return FileStreamHelpers.GetFileLength(_fileHandle, _path);
+ }
+
+ if (_length < 0)
+ {
+ _length = FileStreamHelpers.GetFileLength(_fileHandle, _path);
+ }
+
+ return _length;
+ }
+ }
protected void UpdateLengthOnChangePosition()
{
// Do not update the cached length if the file is not locked
// or if the length hasn't been fetched.
- if (_share > FileShare.Read || _length < 0)
+ if (_share > FileShare.Read || _length < 0 || _exposedHandle)
{
Debug.Assert(_length < 0);
return;
@@ -120,6 +135,10 @@ internal sealed override SafeFileHandle SafeFileHandle
// in memory position is out-of-sync with the actual file position.
FileStreamHelpers.Seek(_fileHandle, _path, _filePosition, SeekOrigin.Begin);
}
+
+ _exposedHandle = true;
+ _length = -1; // invalidate cached length
+
return _fileHandle;
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs
index b3b03d06ee93..826a129be7f8 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs
@@ -76,7 +76,7 @@ public static class BitOperations
internal static uint RoundUpToPowerOf2(uint value)
{
// TODO: https://github.com/dotnet/runtime/issues/43135
- // When this is exposed publicly, decide on behavior be for the boundary cases...
+ // When this is exposed publicly, decide on the behavior for the boundary cases...
// the accelerated and fallback paths differ.
Debug.Assert(value > 0 && value <= (uint.MaxValue / 2) + 1);
diff --git a/src/libraries/System.Private.CoreLib/src/System/Random.LegacyImpl.cs b/src/libraries/System.Private.CoreLib/src/System/Random.Net5CompatImpl.cs
similarity index 97%
rename from src/libraries/System.Private.CoreLib/src/System/Random.LegacyImpl.cs
rename to src/libraries/System.Private.CoreLib/src/System/Random.Net5CompatImpl.cs
index eea6e4c9f3ff..250c84cb971a 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Random.LegacyImpl.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Random.Net5CompatImpl.cs
@@ -16,7 +16,7 @@ public partial class Random
/// of Knuth's subtractive random number generator algorithm. See https://github.com/dotnet/runtime/issues/23198
/// for a discussion of some of the modifications / discrepancies.
///
- private sealed class LegacyImpl : ImplBase
+ private sealed class Net5CompatImpl : ImplBase
{
/// Thread-static instance used to seed any legacy implementations created with the default ctor.
[ThreadStatic]
@@ -29,11 +29,11 @@ private sealed class LegacyImpl : ImplBase
private int _inext;
private int _inextp;
- public LegacyImpl(Random parent) : this(parent, (t_seedGenerator ??= new()).Next())
+ public Net5CompatImpl(Random parent) : this(parent, (t_seedGenerator ??= new()).Next())
{
}
- public LegacyImpl(Random parent, int Seed)
+ public Net5CompatImpl(Random parent, int Seed)
{
_parent = parent;
diff --git a/src/libraries/System.Private.CoreLib/src/System/Random.cs b/src/libraries/System.Private.CoreLib/src/System/Random.cs
index daaa02e93a53..f725b4c73f21 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Random.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Random.cs
@@ -24,7 +24,7 @@ public Random() =>
// With no seed specified, if this is the base type, we can implement this however we like.
// If it's a derived type, for compat we respect the previous implementation, so that overrides
// are called as they were previously.
- _impl = GetType() == typeof(Random) ? new XoshiroImpl() : new LegacyImpl(this);
+ _impl = GetType() == typeof(Random) ? new XoshiroImpl() : new Net5CompatImpl(this);
/// Initializes a new instance of the Random class, using the specified seed value.
///
@@ -34,7 +34,7 @@ public Random() =>
public Random(int Seed) =>
// With a custom seed, for compat we respect the previous implementation so that the same sequence
// previously output continues to be output.
- _impl = new LegacyImpl(this, Seed);
+ _impl = new Net5CompatImpl(this, Seed);
/// Returns a non-negative random integer.
/// A 32-bit signed integer that is greater than or equal to 0 and less than .
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncMethodBuilderAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncMethodBuilderAttribute.cs
index 8c65d2f04173..026e43c24a45 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncMethodBuilderAttribute.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncMethodBuilderAttribute.cs
@@ -5,9 +5,10 @@ namespace System.Runtime.CompilerServices
{
///
/// Indicates the type of the async method builder that should be used by a language compiler to
- /// build the attributed type when used as the return type of an async method.
+ /// build the attributed async method or to build the attributed type when used as the return type
+ /// of an async method.
///
- [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Delegate | AttributeTargets.Enum, Inherited = false, AllowMultiple = false)]
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Delegate | AttributeTargets.Enum | AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
public sealed class AsyncMethodBuilderAttribute : Attribute
{
/// Initializes the .
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs
index c205a673a50d..bab1cdf3376e 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs
@@ -3,11 +3,6 @@
using System.Runtime.InteropServices;
using System.Threading.Tasks;
-using Internal.Runtime.CompilerServices;
-
-#if FEATURE_POOLASYNCVALUETASKS
-using StateMachineBox = System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder.StateMachineBox;
-#endif
namespace System.Runtime.CompilerServices
{
@@ -15,25 +10,14 @@ namespace System.Runtime.CompilerServices
[StructLayout(LayoutKind.Auto)]
public struct AsyncValueTaskMethodBuilder
{
-#if FEATURE_POOLASYNCVALUETASKS
- /// true if we should use reusable boxes for async completions of ValueTask methods; false if we should use tasks.
- ///
- /// We rely on tiered compilation turning this into a const and doing dead code elimination to make checks on this efficient.
- /// It's also required for safety that this value never changes once observed, as Unsafe.As casts are employed based on its value.
- ///
- internal static readonly bool s_valueTaskPoolingEnabled = GetPoolAsyncValueTasksSwitch();
- /// Maximum number of boxes that are allowed to be cached per state machine type.
- internal static readonly int s_valueTaskPoolingCacheSize = GetPoolAsyncValueTasksLimitValue();
-#endif
-
/// Sentinel object used to indicate that the builder completed synchronously and successfully.
- private static readonly object s_syncSuccessSentinel = AsyncValueTaskMethodBuilder.s_syncSuccessSentinel;
+ private static readonly Task s_syncSuccessSentinel = AsyncValueTaskMethodBuilder.s_syncSuccessSentinel;
- /// The wrapped state machine box or task, based on the value of s_valueTaskPoolingEnabled.
+ /// The wrapped task.
///
/// If the operation completed synchronously and successfully, this will be .
///
- private object? m_task; // Debugger depends on the exact name of this field.
+ private Task? m_task; // Debugger depends on the exact name of this field.
/// Creates an instance of the struct.
/// The initialized instance.
@@ -43,8 +27,7 @@ public struct AsyncValueTaskMethodBuilder
/// The type of the state machine.
/// The state machine instance, passed by reference.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Start(ref TStateMachine stateMachine)
- where TStateMachine : IAsyncStateMachine =>
+ public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine =>
AsyncMethodBuilderCore.Start(ref stateMachine);
/// Associates the builder with the specified state machine.
@@ -59,33 +42,16 @@ public void SetResult()
{
m_task = s_syncSuccessSentinel;
}
-#if FEATURE_POOLASYNCVALUETASKS
- else if (s_valueTaskPoolingEnabled)
- {
- Unsafe.As(m_task).SetResult(default);
- }
-#endif
else
{
- AsyncTaskMethodBuilder.SetExistingTaskResult(Unsafe.As>(m_task), default);
+ AsyncTaskMethodBuilder.SetExistingTaskResult(m_task, default);
}
}
/// Marks the task as failed and binds the specified exception to the task.
/// The exception to bind to the task.
- public void SetException(Exception exception)
- {
-#if FEATURE_POOLASYNCVALUETASKS
- if (s_valueTaskPoolingEnabled)
- {
- AsyncValueTaskMethodBuilder.SetException(exception, ref Unsafe.As(ref m_task));
- }
- else
-#endif
- {
- AsyncTaskMethodBuilder.SetException(exception, ref Unsafe.As?>(ref m_task));
- }
- }
+ public void SetException(Exception exception) =>
+ AsyncTaskMethodBuilder.SetException(exception, ref m_task);
/// Gets the task for this builder.
public ValueTask Task
@@ -102,29 +68,11 @@ public ValueTask Task
// or it should be completing asynchronously, in which case AwaitUnsafeOnCompleted would have similarly
// initialized m_task to a state machine object. However, if the type is used manually (not via
// compiler-generated code) and accesses Task directly, we force it to be initialized. Things will then
- // "work" but in a degraded mode, as we don't know the TStateMachine type here, and thus we use a box around
- // the interface instead.
+ // "work" but in a degraded mode, as we don't know the TStateMachine type here, and thus we use a normal
+ // task object instead.
-#if FEATURE_POOLASYNCVALUETASKS
- if (s_valueTaskPoolingEnabled)
- {
- var box = Unsafe.As(m_task);
- if (box is null)
- {
- m_task = box = AsyncValueTaskMethodBuilder.CreateWeaklyTypedStateMachineBox();
- }
- return new ValueTask(box, box.Version);
- }
- else
-#endif
- {
- var task = Unsafe.As?>(m_task);
- if (task is null)
- {
- m_task = task = new Task(); // base task used rather than box to minimize size when used as manual promise
- }
- return new ValueTask(task);
- }
+ Task? task = m_task ??= new Task(); // base task used rather than box to minimize size when used as manual promise
+ return new ValueTask(task);
}
}
@@ -135,19 +83,8 @@ public ValueTask Task
/// The state machine.
public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
- where TStateMachine : IAsyncStateMachine
- {
-#if FEATURE_POOLASYNCVALUETASKS
- if (s_valueTaskPoolingEnabled)
- {
- AsyncValueTaskMethodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine, ref Unsafe.As(ref m_task));
- }
- else
-#endif
- {
- AsyncTaskMethodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine, ref Unsafe.As?>(ref m_task));
- }
- }
+ where TStateMachine : IAsyncStateMachine =>
+ AsyncTaskMethodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine, ref m_task);
/// Schedules the state machine to proceed to the next action when the specified awaiter completes.
/// The type of the awaiter.
@@ -157,19 +94,8 @@ public void AwaitOnCompleted(ref TAwaiter awaiter, ref
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
- where TStateMachine : IAsyncStateMachine
- {
-#if FEATURE_POOLASYNCVALUETASKS
- if (s_valueTaskPoolingEnabled)
- {
- AsyncValueTaskMethodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine, ref Unsafe.As(ref m_task));
- }
- else
-#endif
- {
- AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine, ref Unsafe.As?>(ref m_task));
- }
- }
+ where TStateMachine : IAsyncStateMachine =>
+ AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine, ref m_task);
///
/// Gets an object that may be used to uniquely identify this builder to the debugger.
@@ -179,33 +105,6 @@ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter
/// It must only be used by the debugger and tracing purposes, and only in a single-threaded manner
/// when no other threads are in the middle of accessing this or other members that lazily initialize the box.
///
- internal object ObjectIdForDebugger
- {
- get
- {
- if (m_task is null)
- {
- m_task =
-#if FEATURE_POOLASYNCVALUETASKS
- s_valueTaskPoolingEnabled ? (object)
- AsyncValueTaskMethodBuilder.CreateWeaklyTypedStateMachineBox() :
-#endif
- AsyncTaskMethodBuilder.CreateWeaklyTypedStateMachineBox();
- }
-
- return m_task;
- }
- }
-
-#if FEATURE_POOLASYNCVALUETASKS
- private static bool GetPoolAsyncValueTasksSwitch() =>
- Environment.GetEnvironmentVariable("DOTNET_SYSTEM_THREADING_POOLASYNCVALUETASKS") is string value &&
- (bool.IsTrueStringIgnoreCase(value) || value == "1");
-
- private static int GetPoolAsyncValueTasksLimitValue() =>
- int.TryParse(Environment.GetEnvironmentVariable("DOTNET_SYSTEM_THREADING_POOLASYNCVALUETASKSLIMIT"), out int result) && result > 0 ?
- result :
- Environment.ProcessorCount * 4; // arbitrary default value
-#endif
+ internal object ObjectIdForDebugger => m_task ??= AsyncTaskMethodBuilder.CreateWeaklyTypedStateMachineBox();
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilderT.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilderT.cs
index a25fd8c22a5f..62499d54e761 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilderT.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilderT.cs
@@ -1,13 +1,8 @@
// 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.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
-using System.Threading;
using System.Threading.Tasks;
-using System.Threading.Tasks.Sources;
-using Internal.Runtime.CompilerServices;
namespace System.Runtime.CompilerServices
{
@@ -22,14 +17,10 @@ public struct AsyncValueTaskMethodBuilder
/// is valid for the mode in which we're operating. As such, it's cached on the generic builder per TResult
/// rather than having one sentinel instance for all types.
///
- internal static readonly object s_syncSuccessSentinel =
-#if FEATURE_POOLASYNCVALUETASKS
- AsyncValueTaskMethodBuilder.s_valueTaskPoolingEnabled ? (object)new SyncSuccessSentinelStateMachineBox() :
-#endif
- new Task(default(TResult)!);
+ internal static readonly Task s_syncSuccessSentinel = new Task(default(TResult)!);
- /// The wrapped state machine or task. If the operation completed synchronously and successfully, this will be a sentinel object compared by reference identity.
- private object? m_task; // Debugger depends on the exact name of this field.
+ /// The wrapped task. If the operation completed synchronously and successfully, this will be a sentinel object compared by reference identity.
+ private Task? m_task; // Debugger depends on the exact name of this field.
/// The result for this builder if it's completed synchronously, in which case will be .
private TResult _result;
@@ -58,45 +49,16 @@ public void SetResult(TResult result)
_result = result;
m_task = s_syncSuccessSentinel;
}
-#if FEATURE_POOLASYNCVALUETASKS
- else if (AsyncValueTaskMethodBuilder.s_valueTaskPoolingEnabled)
- {
- Unsafe.As(m_task).SetResult(result);
- }
-#endif
else
{
- AsyncTaskMethodBuilder.SetExistingTaskResult(Unsafe.As>(m_task), result);
+ AsyncTaskMethodBuilder.SetExistingTaskResult(m_task, result);
}
}
/// Marks the value task as failed and binds the specified exception to the value task.
/// The exception to bind to the value task.
- public void SetException(Exception exception)
- {
-#if FEATURE_POOLASYNCVALUETASKS
- if (AsyncValueTaskMethodBuilder.s_valueTaskPoolingEnabled)
- {
- SetException(exception, ref Unsafe.As(ref m_task));
- }
- else
-#endif
- {
- AsyncTaskMethodBuilder.SetException(exception, ref Unsafe.As?>(ref m_task));
- }
- }
-
-#if FEATURE_POOLASYNCVALUETASKS
- internal static void SetException(Exception exception, [NotNull] ref StateMachineBox? boxFieldRef)
- {
- if (exception is null)
- {
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.exception);
- }
-
- (boxFieldRef ??= CreateWeaklyTypedStateMachineBox()).SetException(exception);
- }
-#endif
+ public void SetException(Exception exception) =>
+ AsyncTaskMethodBuilder.SetException(exception, ref m_task);
/// Gets the value task for this builder.
public ValueTask Task
@@ -113,29 +75,11 @@ public ValueTask Task
// or it should be completing asynchronously, in which case AwaitUnsafeOnCompleted would have similarly
// initialized m_task to a state machine object. However, if the type is used manually (not via
// compiler-generated code) and accesses Task directly, we force it to be initialized. Things will then
- // "work" but in a degraded mode, as we don't know the TStateMachine type here, and thus we use a box around
- // the interface instead.
+ // "work" but in a degraded mode, as we don't know the TStateMachine type here, and thus we use a
+ // normal task object instead.
-#if FEATURE_POOLASYNCVALUETASKS
- if (AsyncValueTaskMethodBuilder.s_valueTaskPoolingEnabled)
- {
- var box = Unsafe.As(m_task);
- if (box is null)
- {
- m_task = box = CreateWeaklyTypedStateMachineBox();
- }
- return new ValueTask(box, box.Version);
- }
- else
-#endif
- {
- var task = Unsafe.As?>(m_task);
- if (task is null)
- {
- m_task = task = new Task(); // base task used rather than box to minimize size when used as manual promise
- }
- return new ValueTask(task);
- }
+ Task? task = m_task ??= new Task(); // base task used rather than box to minimize size when used as manual promise
+ return new ValueTask(task);
}
}
@@ -146,36 +90,8 @@ public ValueTask Task
/// The state machine.
public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
- where TStateMachine : IAsyncStateMachine
- {
-#if FEATURE_POOLASYNCVALUETASKS
- if (AsyncValueTaskMethodBuilder.s_valueTaskPoolingEnabled)
- {
- AwaitOnCompleted(ref awaiter, ref stateMachine, ref Unsafe.As(ref m_task));
- }
- else
-#endif
- {
- AsyncTaskMethodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine, ref Unsafe.As?>(ref m_task));
- }
- }
-
-#if FEATURE_POOLASYNCVALUETASKS
- internal static void AwaitOnCompleted(
- ref TAwaiter awaiter, ref TStateMachine stateMachine, ref StateMachineBox? box)
- where TAwaiter : INotifyCompletion
- where TStateMachine : IAsyncStateMachine
- {
- try
- {
- awaiter.OnCompleted(GetStateMachineBox(ref stateMachine, ref box).MoveNextAction);
- }
- catch (Exception e)
- {
- System.Threading.Tasks.Task.ThrowAsync(e, targetContext: null);
- }
- }
-#endif
+ where TStateMachine : IAsyncStateMachine =>
+ AsyncTaskMethodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine, ref m_task);
/// Schedules the state machine to proceed to the next action when the specified awaiter completes.
/// The type of the awaiter.
@@ -185,112 +101,8 @@ internal static void AwaitOnCompleted(
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
- where TStateMachine : IAsyncStateMachine
- {
-#if FEATURE_POOLASYNCVALUETASKS
- if (AsyncValueTaskMethodBuilder.s_valueTaskPoolingEnabled)
- {
- AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine, ref Unsafe.As(ref m_task));
- }
- else
-#endif
- {
- AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine, ref Unsafe.As?>(ref m_task));
- }
- }
-
-#if FEATURE_POOLASYNCVALUETASKS
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static void AwaitUnsafeOnCompleted(
- ref TAwaiter awaiter, ref TStateMachine stateMachine, [NotNull] ref StateMachineBox? boxRef)
- where TAwaiter : ICriticalNotifyCompletion
- where TStateMachine : IAsyncStateMachine
- {
- IAsyncStateMachineBox box = GetStateMachineBox(ref stateMachine, ref boxRef);
- AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted(ref awaiter, box);
- }
-#endif
-
-#if FEATURE_POOLASYNCVALUETASKS
- /// Gets the "boxed" state machine object.
- /// Specifies the type of the async state machine.
- /// The state machine.
- /// A reference to the field containing the initialized state machine box.
- /// The "boxed" state machine.
- private static IAsyncStateMachineBox GetStateMachineBox(
- ref TStateMachine stateMachine,
- [NotNull] ref StateMachineBox? boxFieldRef)
- where TStateMachine : IAsyncStateMachine
- {
- ExecutionContext? currentContext = ExecutionContext.Capture();
-
- // Check first for the most common case: not the first yield in an async method.
- // In this case, the first yield will have already "boxed" the state machine in
- // a strongly-typed manner into an AsyncStateMachineBox. It will already contain
- // the state machine as well as a MoveNextDelegate and a context. The only thing
- // we might need to do is update the context if that's changed since it was stored.
- if (boxFieldRef is StateMachineBox stronglyTypedBox)
- {
- if (stronglyTypedBox.Context != currentContext)
- {
- stronglyTypedBox.Context = currentContext;
- }
-
- return stronglyTypedBox;
- }
-
- // The least common case: we have a weakly-typed boxed. This results if the debugger
- // or some other use of reflection accesses a property like ObjectIdForDebugger. In
- // such situations, we need to get an object to represent the builder, but we don't yet
- // know the type of the state machine, and thus can't use TStateMachine. Instead, we
- // use the IAsyncStateMachine interface, which all TStateMachines implement. This will
- // result in a boxing allocation when storing the TStateMachine if it's a struct, but
- // this only happens in active debugging scenarios where such performance impact doesn't
- // matter.
- if (boxFieldRef is StateMachineBox weaklyTypedBox)
- {
- // If this is the first await, we won't yet have a state machine, so store it.
- if (weaklyTypedBox.StateMachine is null)
- {
- Debugger.NotifyOfCrossThreadDependency(); // same explanation as with usage below
- weaklyTypedBox.StateMachine = stateMachine;
- }
-
- // Update the context. This only happens with a debugger, so no need to spend
- // extra IL checking for equality before doing the assignment.
- weaklyTypedBox.Context = currentContext;
- return weaklyTypedBox;
- }
-
- // Alert a listening debugger that we can't make forward progress unless it slips threads.
- // If we don't do this, and a method that uses "await foo;" is invoked through funceval,
- // we could end up hooking up a callback to push forward the async method's state machine,
- // the debugger would then abort the funceval after it takes too long, and then continuing
- // execution could result in another callback being hooked up. At that point we have
- // multiple callbacks registered to push the state machine, which could result in bad behavior.
- Debugger.NotifyOfCrossThreadDependency();
-
- // At this point, m_task should really be null, in which case we want to create the box.
- // However, in a variety of debugger-related (erroneous) situations, it might be non-null,
- // e.g. if the Task property is examined in a Watch window, forcing it to be lazily-intialized
- // as a Task rather than as an ValueTaskStateMachineBox. The worst that happens in such
- // cases is we lose the ability to properly step in the debugger, as the debugger uses that
- // object's identity to track this specific builder/state machine. As such, we proceed to
- // overwrite whatever's there anyway, even if it's non-null.
- var box = StateMachineBox.GetOrCreateBox();
- boxFieldRef = box; // important: this must be done before storing stateMachine into box.StateMachine!
- box.StateMachine = stateMachine;
- box.Context = currentContext;
-
- return box;
- }
-
- ///
- /// Creates a box object for use when a non-standard access pattern is employed, e.g. when Task
- /// is evaluated in the debugger prior to the async method yielding for the first time.
- ///
- internal static StateMachineBox CreateWeaklyTypedStateMachineBox() => new StateMachineBox();
-#endif // FEATURE_POOLASYNCVALUETASKS
+ where TStateMachine : IAsyncStateMachine =>
+ AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine, ref m_task);
///
/// Gets an object that may be used to uniquely identify this builder to the debugger.
@@ -300,247 +112,6 @@ private static IAsyncStateMachineBox GetStateMachineBox(
/// It must only be used by the debugger and tracing purposes, and only in a single-threaded manner
/// when no other threads are in the middle of accessing this or other members that lazily initialize the box.
///
- internal object ObjectIdForDebugger
- {
- get
- {
- if (m_task is null)
- {
- m_task =
-#if FEATURE_POOLASYNCVALUETASKS
- AsyncValueTaskMethodBuilder.s_valueTaskPoolingEnabled ? (object)CreateWeaklyTypedStateMachineBox() :
-#endif
- AsyncTaskMethodBuilder.CreateWeaklyTypedStateMachineBox();
- }
-
- return m_task;
- }
- }
-
-#if FEATURE_POOLASYNCVALUETASKS
- /// The base type for all value task box reusable box objects, regardless of state machine type.
- internal abstract class StateMachineBox :
- IValueTaskSource, IValueTaskSource
- {
- /// A delegate to the MoveNext method.
- protected Action? _moveNextAction;
- /// Captured ExecutionContext with which to invoke MoveNext.
- public ExecutionContext? Context;
- /// Implementation for IValueTaskSource interfaces.
- protected ManualResetValueTaskSourceCore _valueTaskSource;
-
- /// Completes the box with a result.
- /// The result.
- public void SetResult(TResult result) =>
- _valueTaskSource.SetResult(result);
-
- /// Completes the box with an error.
- /// The exception.
- public void SetException(Exception error) =>
- _valueTaskSource.SetException(error);
-
- /// Gets the status of the box.
- public ValueTaskSourceStatus GetStatus(short token) => _valueTaskSource.GetStatus(token);
-
- /// Schedules the continuation action for this box.
- public void OnCompleted(Action continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags) =>
- _valueTaskSource.OnCompleted(continuation, state, token, flags);
-
- /// Gets the current version number of the box.
- public short Version => _valueTaskSource.Version;
-
- /// Implemented by derived type.
- TResult IValueTaskSource.GetResult(short token) => throw NotImplemented.ByDesign;
-
- /// Implemented by derived type.
- void IValueTaskSource.GetResult(short token) => throw NotImplemented.ByDesign;
- }
-
- private sealed class SyncSuccessSentinelStateMachineBox : StateMachineBox
- {
- public SyncSuccessSentinelStateMachineBox() => SetResult(default!);
- }
-
- /// Provides a strongly-typed box object based on the specific state machine type in use.
- private sealed class StateMachineBox :
- StateMachineBox,
- IValueTaskSource, IValueTaskSource, IAsyncStateMachineBox, IThreadPoolWorkItem
- where TStateMachine : IAsyncStateMachine
- {
- /// Delegate used to invoke on an ExecutionContext when passed an instance of this box type.
- private static readonly ContextCallback s_callback = ExecutionContextCallback;
-
- /// Lock used to protected the shared cache of boxes.
- /// The code that uses this assumes a runtime without thread aborts.
- private static int s_cacheLock;
- /// Singly-linked list cache of boxes.
- private static StateMachineBox? s_cache;
- /// The number of items stored in .
- private static int s_cacheSize;
-
- // TODO:
- // AsyncTaskMethodBuilder logs about the state machine box lifecycle; AsyncValueTaskMethodBuilder currently
- // does not when it employs these pooled boxes. That logging is based on Task IDs, which we lack here.
- // We could use the box's Version, but that is very likely to conflict with the IDs of other tasks in the system.
- // For now, we don't log, but should we choose to we'll probably want to store an int ID on the state machine box,
- // and initialize it an ID from Task's generator.
-
- /// If this box is stored in the cache, the next box in the cache.
- private StateMachineBox? _next;
-
- /// The state machine itself.
- public TStateMachine? StateMachine;
-
- /// Gets a box object to use for an operation. This may be a reused, pooled object, or it may be new.
- [MethodImpl(MethodImplOptions.AggressiveInlining)] // only one caller
- internal static StateMachineBox GetOrCreateBox()
- {
- // Try to acquire the lock to access the cache. If there's any contention, don't use the cache.
- if (Interlocked.CompareExchange(ref s_cacheLock, 1, 0) == 0)
- {
- // If there are any instances cached, take one from the cache stack and use it.
- StateMachineBox? box = s_cache;
- if (!(box is null))
- {
- s_cache = box._next;
- box._next = null;
- s_cacheSize--;
- Debug.Assert(s_cacheSize >= 0, "Expected the cache size to be non-negative.");
-
- // Release the lock and return the box.
- Volatile.Write(ref s_cacheLock, 0);
- return box;
- }
-
- // No objects were cached. We'll just create a new instance.
- Debug.Assert(s_cacheSize == 0, "Expected cache size to be 0.");
-
- // Release the lock.
- Volatile.Write(ref s_cacheLock, 0);
- }
-
- // Couldn't quickly get a cached instance, so create a new instance.
- return new StateMachineBox();
- }
-
- private void ReturnOrDropBox()
- {
- Debug.Assert(_next is null, "Expected box to not be part of cached list.");
-
- // Clear out the state machine and associated context to avoid keeping arbitrary state referenced by
- // lifted locals. We want to do this regardless of whether we end up caching the box or not, in case
- // the caller keeps the box alive for an arbitrary period of time.
- ClearStateUponCompletion();
-
- // Reset the MRVTSC. We can either do this here, in which case we may be paying the (small) overhead
- // to reset the box even if we're going to drop it, or we could do it while holding the lock, in which
- // case we'll only reset it if necessary but causing the lock to be held for longer, thereby causing
- // more contention. For now at least, we do it outside of the lock. (This must not be done after
- // the lock is released, since at that point the instance could already be in use elsewhere.)
- // We also want to increment the version number even if we're going to drop it, to maximize the chances
- // that incorrectly double-awaiting a ValueTask will produce an error.
- _valueTaskSource.Reset();
-
- // If reusing the object would result in potentially wrapping around its version number, just throw it away.
- // This provides a modicum of additional safety when ValueTasks are misused (helping to avoid the case where
- // a ValueTask is illegally re-awaited and happens to do so at exactly 2^16 uses later on this exact same instance),
- // at the expense of potentially incurring an additional allocation every 65K uses.
- if ((ushort)_valueTaskSource.Version == ushort.MaxValue)
- {
- return;
- }
-
- // Try to acquire the cache lock. If there's any contention, or if the cache is full, we just throw away the object.
- if (Interlocked.CompareExchange(ref s_cacheLock, 1, 0) == 0)
- {
- if (s_cacheSize < AsyncValueTaskMethodBuilder.s_valueTaskPoolingCacheSize)
- {
- // Push the box onto the cache stack for subsequent reuse.
- _next = s_cache;
- s_cache = this;
- s_cacheSize++;
- Debug.Assert(s_cacheSize > 0 && s_cacheSize <= AsyncValueTaskMethodBuilder.s_valueTaskPoolingCacheSize, "Expected cache size to be within bounds.");
- }
-
- // Release the lock.
- Volatile.Write(ref s_cacheLock, 0);
- }
- }
-
- ///
- /// Clear out the state machine and associated context to avoid keeping arbitrary state referenced by lifted locals.
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void ClearStateUponCompletion()
- {
- StateMachine = default;
- Context = default;
- }
-
- ///
- /// Used to initialize s_callback above. We don't use a lambda for this on purpose: a lambda would
- /// introduce a new generic type behind the scenes that comes with a hefty size penalty in AOT builds.
- ///
- private static void ExecutionContextCallback(object? s)
- {
- // Only used privately to pass directly to EC.Run
- Debug.Assert(s is StateMachineBox);
- Unsafe.As>(s).StateMachine!.MoveNext();
- }
-
- /// A delegate to the method.
- public Action MoveNextAction => _moveNextAction ??= new Action(MoveNext);
-
- /// Invoked to run MoveNext when this instance is executed from the thread pool.
- void IThreadPoolWorkItem.Execute() => MoveNext();
-
- /// Calls MoveNext on
- public void MoveNext()
- {
- ExecutionContext? context = Context;
-
- if (context is null)
- {
- Debug.Assert(!(StateMachine is null));
- StateMachine.MoveNext();
- }
- else
- {
- ExecutionContext.RunInternal(context, s_callback, this);
- }
- }
-
- /// Get the result of the operation.
- TResult IValueTaskSource.GetResult(short token)
- {
- try
- {
- return _valueTaskSource.GetResult(token);
- }
- finally
- {
- // Reuse this instance if possible, otherwise clear and drop it.
- ReturnOrDropBox();
- }
- }
-
- /// Get the result of the operation.
- void IValueTaskSource.GetResult(short token)
- {
- try
- {
- _valueTaskSource.GetResult(token);
- }
- finally
- {
- // Reuse this instance if possible, otherwise clear and drop it.
- ReturnOrDropBox();
- }
- }
-
- /// Gets the state machine as a boxed object. This should only be used for debugging purposes.
- IAsyncStateMachine IAsyncStateMachineBox.GetStateMachineObject() => StateMachine!; // likely boxes, only use for debugging
- }
-#endif // FEATURE_POOLASYNCVALUETASKS
+ internal object ObjectIdForDebugger => m_task ??= AsyncTaskMethodBuilder.CreateWeaklyTypedStateMachineBox();
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/PoolingAsyncValueTaskMethodBuilder.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/PoolingAsyncValueTaskMethodBuilder.cs
new file mode 100644
index 000000000000..84996a0e062f
--- /dev/null
+++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/PoolingAsyncValueTaskMethodBuilder.cs
@@ -0,0 +1,121 @@
+// 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.Runtime.InteropServices;
+using System.Threading.Tasks;
+
+using StateMachineBox = System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder.StateMachineBox;
+
+namespace System.Runtime.CompilerServices
+{
+ /// Represents a builder for asynchronous methods that return a .
+ [StructLayout(LayoutKind.Auto)]
+ public struct PoolingAsyncValueTaskMethodBuilder
+ {
+ /// Maximum number of boxes that are allowed to be cached per state machine type.
+ internal static readonly int s_valueTaskPoolingCacheSize =
+ int.TryParse(Environment.GetEnvironmentVariable("DOTNET_SYSTEM_THREADING_POOLINGASYNCVALUETASKSCACHESIZE"), NumberStyles.Integer, CultureInfo.InvariantCulture, out int result) && result > 0 ?
+ result :
+ Environment.ProcessorCount * 4; // arbitrary default value
+
+ /// Sentinel object used to indicate that the builder completed synchronously and successfully.
+ private static readonly StateMachineBox s_syncSuccessSentinel = PoolingAsyncValueTaskMethodBuilder.s_syncSuccessSentinel;
+
+ /// The wrapped state machine box.
+ ///
+ /// If the operation completed synchronously and successfully, this will be .
+ ///
+ private StateMachineBox? m_task; // Debugger depends on the exact name of this field.
+
+ /// Creates an instance of the struct.
+ /// The initialized instance.
+ public static PoolingAsyncValueTaskMethodBuilder Create() => default;
+
+ /// Begins running the builder with the associated state machine.
+ /// The type of the state machine.
+ /// The state machine instance, passed by reference.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Start(ref TStateMachine stateMachine)
+ where TStateMachine : IAsyncStateMachine =>
+ AsyncMethodBuilderCore.Start(ref stateMachine);
+
+ /// Associates the builder with the specified state machine.
+ /// The state machine instance to associate with the builder.
+ public void SetStateMachine(IAsyncStateMachine stateMachine) =>
+ AsyncMethodBuilderCore.SetStateMachine(stateMachine, task: null);
+
+ /// Marks the task as successfully completed.
+ public void SetResult()
+ {
+ if (m_task is null)
+ {
+ m_task = s_syncSuccessSentinel;
+ }
+ else
+ {
+ m_task.SetResult(default);
+ }
+ }
+
+ /// Marks the task as failed and binds the specified exception to the task.
+ /// The exception to bind to the task.
+ public void SetException(Exception exception) =>
+ PoolingAsyncValueTaskMethodBuilder.SetException(exception, ref m_task);
+
+ /// Gets the task for this builder.
+ public ValueTask Task
+ {
+ get
+ {
+ if (m_task == s_syncSuccessSentinel)
+ {
+ return default;
+ }
+
+ // With normal access paterns, m_task should always be non-null here: the async method should have
+ // either completed synchronously, in which case SetResult would have set m_task to a non-null object,
+ // or it should be completing asynchronously, in which case AwaitUnsafeOnCompleted would have similarly
+ // initialized m_task to a state machine object. However, if the type is used manually (not via
+ // compiler-generated code) and accesses Task directly, we force it to be initialized. Things will then
+ // "work" but in a degraded mode, as we don't know the TStateMachine type here, and thus we use a box around
+ // the interface instead.
+
+ StateMachineBox? box = m_task ??= PoolingAsyncValueTaskMethodBuilder.CreateWeaklyTypedStateMachineBox();
+ return new ValueTask(box, box.Version);
+ }
+ }
+
+ /// Schedules the state machine to proceed to the next action when the specified awaiter completes.
+ /// The type of the awaiter.
+ /// The type of the state machine.
+ /// The awaiter.
+ /// The state machine.
+ public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine)
+ where TAwaiter : INotifyCompletion
+ where TStateMachine : IAsyncStateMachine =>
+ PoolingAsyncValueTaskMethodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine, ref m_task);
+
+ /// Schedules the state machine to proceed to the next action when the specified awaiter completes.
+ /// The type of the awaiter.
+ /// The type of the state machine.
+ /// The awaiter.
+ /// The state machine.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine)
+ where TAwaiter : ICriticalNotifyCompletion
+ where TStateMachine : IAsyncStateMachine =>
+ PoolingAsyncValueTaskMethodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine, ref m_task);
+
+ ///
+ /// Gets an object that may be used to uniquely identify this builder to the debugger.
+ ///
+ ///
+ /// This property lazily instantiates the ID in a non-thread-safe manner.
+ /// It must only be used by the debugger and tracing purposes, and only in a single-threaded manner
+ /// when no other threads are in the middle of accessing this or other members that lazily initialize the box.
+ ///
+ internal object ObjectIdForDebugger =>
+ m_task ??= PoolingAsyncValueTaskMethodBuilder.CreateWeaklyTypedStateMachineBox();
+ }
+}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/PoolingAsyncValueTaskMethodBuilderT.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/PoolingAsyncValueTaskMethodBuilderT.cs
new file mode 100644
index 000000000000..02d15bb92c3b
--- /dev/null
+++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/PoolingAsyncValueTaskMethodBuilderT.cs
@@ -0,0 +1,473 @@
+// 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.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Threading.Tasks.Sources;
+using Internal.Runtime.CompilerServices;
+
+namespace System.Runtime.CompilerServices
+{
+ /// Represents a builder for asynchronous methods that returns a .
+ /// The type of the result.
+ [StructLayout(LayoutKind.Auto)]
+ public struct PoolingAsyncValueTaskMethodBuilder
+ {
+ /// Sentinel object used to indicate that the builder completed synchronously and successfully.
+ ///
+ /// To avoid memory safety issues even in the face of invalid race conditions, we ensure that the type of this object
+ /// is valid for the mode in which we're operating. As such, it's cached on the generic builder per TResult
+ /// rather than having one sentinel instance for all types.
+ ///
+ internal static readonly StateMachineBox s_syncSuccessSentinel = new SyncSuccessSentinelStateMachineBox();
+
+ /// The wrapped state machine or task. If the operation completed synchronously and successfully, this will be a sentinel object compared by reference identity.
+ private StateMachineBox? m_task; // Debugger depends on the exact name of this field.
+ /// The result for this builder if it's completed synchronously, in which case will be .
+ private TResult _result;
+
+ /// Creates an instance of the struct.
+ /// The initialized instance.
+ public static PoolingAsyncValueTaskMethodBuilder Create() => default;
+
+ /// Begins running the builder with the associated state machine.
+ /// The type of the state machine.
+ /// The state machine instance, passed by reference.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine =>
+ AsyncMethodBuilderCore.Start(ref stateMachine);
+
+ /// Associates the builder with the specified state machine.
+ /// The state machine instance to associate with the builder.
+ public void SetStateMachine(IAsyncStateMachine stateMachine) =>
+ AsyncMethodBuilderCore.SetStateMachine(stateMachine, task: null);
+
+ /// Marks the value task as successfully completed.
+ /// The result to use to complete the value task.
+ public void SetResult(TResult result)
+ {
+ if (m_task is null)
+ {
+ _result = result;
+ m_task = s_syncSuccessSentinel;
+ }
+ else
+ {
+ m_task.SetResult(result);
+ }
+ }
+
+ /// Marks the value task as failed and binds the specified exception to the value task.
+ /// The exception to bind to the value task.
+ public void SetException(Exception exception) =>
+ SetException(exception, ref m_task);
+
+ internal static void SetException(Exception exception, [NotNull] ref StateMachineBox? boxFieldRef)
+ {
+ if (exception is null)
+ {
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.exception);
+ }
+
+ (boxFieldRef ??= CreateWeaklyTypedStateMachineBox()).SetException(exception);
+ }
+
+ /// Gets the value task for this builder.
+ public ValueTask Task
+ {
+ get
+ {
+ if (m_task == s_syncSuccessSentinel)
+ {
+ return new ValueTask(_result);
+ }
+
+ // With normal access paterns, m_task should always be non-null here: the async method should have
+ // either completed synchronously, in which case SetResult would have set m_task to a non-null object,
+ // or it should be completing asynchronously, in which case AwaitUnsafeOnCompleted would have similarly
+ // initialized m_task to a state machine object. However, if the type is used manually (not via
+ // compiler-generated code) and accesses Task directly, we force it to be initialized. Things will then
+ // "work" but in a degraded mode, as we don't know the TStateMachine type here, and thus we use a box around
+ // the interface instead.
+
+ PoolingAsyncValueTaskMethodBuilder.StateMachineBox? box = m_task ??= CreateWeaklyTypedStateMachineBox();
+ return new ValueTask(box, box.Version);
+ }
+ }
+
+ /// Schedules the state machine to proceed to the next action when the specified awaiter completes.
+ /// The type of the awaiter.
+ /// The type of the state machine.
+ /// the awaiter
+ /// The state machine.
+ public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine)
+ where TAwaiter : INotifyCompletion
+ where TStateMachine : IAsyncStateMachine =>
+ AwaitOnCompleted(ref awaiter, ref stateMachine, ref m_task);
+
+ internal static void AwaitOnCompleted(
+ ref TAwaiter awaiter, ref TStateMachine stateMachine, ref StateMachineBox? box)
+ where TAwaiter : INotifyCompletion
+ where TStateMachine : IAsyncStateMachine
+ {
+ try
+ {
+ awaiter.OnCompleted(GetStateMachineBox(ref stateMachine, ref box).MoveNextAction);
+ }
+ catch (Exception e)
+ {
+ System.Threading.Tasks.Task.ThrowAsync(e, targetContext: null);
+ }
+ }
+
+ /// Schedules the state machine to proceed to the next action when the specified awaiter completes.
+ /// The type of the awaiter.
+ /// The type of the state machine.
+ /// the awaiter
+ /// The state machine.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine)
+ where TAwaiter : ICriticalNotifyCompletion
+ where TStateMachine : IAsyncStateMachine =>
+ AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine, ref m_task);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static void AwaitUnsafeOnCompleted(
+ ref TAwaiter awaiter, ref TStateMachine stateMachine, [NotNull] ref StateMachineBox? boxRef)
+ where TAwaiter : ICriticalNotifyCompletion
+ where TStateMachine : IAsyncStateMachine
+ {
+ IAsyncStateMachineBox box = GetStateMachineBox(ref stateMachine, ref boxRef);
+ AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted(ref awaiter, box);
+ }
+
+ /// Gets the "boxed" state machine object.
+ /// Specifies the type of the async state machine.
+ /// The state machine.
+ /// A reference to the field containing the initialized state machine box.
+ /// The "boxed" state machine.
+ private static IAsyncStateMachineBox GetStateMachineBox(
+ ref TStateMachine stateMachine,
+ [NotNull] ref StateMachineBox? boxFieldRef)
+ where TStateMachine : IAsyncStateMachine
+ {
+ ExecutionContext? currentContext = ExecutionContext.Capture();
+
+ // Check first for the most common case: not the first yield in an async method.
+ // In this case, the first yield will have already "boxed" the state machine in
+ // a strongly-typed manner into an AsyncStateMachineBox. It will already contain
+ // the state machine as well as a MoveNextDelegate and a context. The only thing
+ // we might need to do is update the context if that's changed since it was stored.
+ if (boxFieldRef is StateMachineBox stronglyTypedBox)
+ {
+ if (stronglyTypedBox.Context != currentContext)
+ {
+ stronglyTypedBox.Context = currentContext;
+ }
+
+ return stronglyTypedBox;
+ }
+
+ // The least common case: we have a weakly-typed boxed. This results if the debugger
+ // or some other use of reflection accesses a property like ObjectIdForDebugger. In
+ // such situations, we need to get an object to represent the builder, but we don't yet
+ // know the type of the state machine, and thus can't use TStateMachine. Instead, we
+ // use the IAsyncStateMachine interface, which all TStateMachines implement. This will
+ // result in a boxing allocation when storing the TStateMachine if it's a struct, but
+ // this only happens in active debugging scenarios where such performance impact doesn't
+ // matter.
+ if (boxFieldRef is StateMachineBox weaklyTypedBox)
+ {
+ // If this is the first await, we won't yet have a state machine, so store it.
+ if (weaklyTypedBox.StateMachine is null)
+ {
+ Debugger.NotifyOfCrossThreadDependency(); // same explanation as with usage below
+ weaklyTypedBox.StateMachine = stateMachine;
+ }
+
+ // Update the context. This only happens with a debugger, so no need to spend
+ // extra IL checking for equality before doing the assignment.
+ weaklyTypedBox.Context = currentContext;
+ return weaklyTypedBox;
+ }
+
+ // Alert a listening debugger that we can't make forward progress unless it slips threads.
+ // If we don't do this, and a method that uses "await foo;" is invoked through funceval,
+ // we could end up hooking up a callback to push forward the async method's state machine,
+ // the debugger would then abort the funceval after it takes too long, and then continuing
+ // execution could result in another callback being hooked up. At that point we have
+ // multiple callbacks registered to push the state machine, which could result in bad behavior.
+ Debugger.NotifyOfCrossThreadDependency();
+
+ // At this point, m_task should really be null, in which case we want to create the box.
+ // However, in a variety of debugger-related (erroneous) situations, it might be non-null,
+ // e.g. if the Task property is examined in a Watch window, forcing it to be lazily-intialized
+ // as a Task rather than as an ValueTaskStateMachineBox. The worst that happens in such
+ // cases is we lose the ability to properly step in the debugger, as the debugger uses that
+ // object's identity to track this specific builder/state machine. As such, we proceed to
+ // overwrite whatever's there anyway, even if it's non-null.
+ StateMachineBox box = StateMachineBox.GetOrCreateBox();
+ boxFieldRef = box; // important: this must be done before storing stateMachine into box.StateMachine!
+ box.StateMachine = stateMachine;
+ box.Context = currentContext;
+
+ return box;
+ }
+
+ ///
+ /// Creates a box object for use when a non-standard access pattern is employed, e.g. when Task
+ /// is evaluated in the debugger prior to the async method yielding for the first time.
+ ///
+ internal static StateMachineBox CreateWeaklyTypedStateMachineBox() => new StateMachineBox();
+
+ ///
+ /// Gets an object that may be used to uniquely identify this builder to the debugger.
+ ///
+ ///
+ /// This property lazily instantiates the ID in a non-thread-safe manner.
+ /// It must only be used by the debugger and tracing purposes, and only in a single-threaded manner
+ /// when no other threads are in the middle of accessing this or other members that lazily initialize the box.
+ ///
+ internal object ObjectIdForDebugger => m_task ??= CreateWeaklyTypedStateMachineBox();
+
+ /// The base type for all value task box reusable box objects, regardless of state machine type.
+ internal abstract class StateMachineBox : IValueTaskSource, IValueTaskSource
+ {
+ /// A delegate to the MoveNext method.
+ protected Action? _moveNextAction;
+ /// Captured ExecutionContext with which to invoke MoveNext.
+ public ExecutionContext? Context;
+ /// Implementation for IValueTaskSource interfaces.
+ protected ManualResetValueTaskSourceCore _valueTaskSource;
+
+ /// Completes the box with a result.
+ /// The result.
+ public void SetResult(TResult result) =>
+ _valueTaskSource.SetResult(result);
+
+ /// Completes the box with an error.
+ /// The exception.
+ public void SetException(Exception error) =>
+ _valueTaskSource.SetException(error);
+
+ /// Gets the status of the box.
+ public ValueTaskSourceStatus GetStatus(short token) => _valueTaskSource.GetStatus(token);
+
+ /// Schedules the continuation action for this box.
+ public void OnCompleted(Action continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags) =>
+ _valueTaskSource.OnCompleted(continuation, state, token, flags);
+
+ /// Gets the current version number of the box.
+ public short Version => _valueTaskSource.Version;
+
+ /// Implemented by derived type.
+ TResult IValueTaskSource.GetResult(short token) => throw NotImplemented.ByDesign;
+
+ /// Implemented by derived type.
+ void IValueTaskSource.GetResult(short token) => throw NotImplemented.ByDesign;
+ }
+
+ /// Type used as a singleton to indicate synchronous success for an async method.
+ private sealed class SyncSuccessSentinelStateMachineBox : StateMachineBox
+ {
+ public SyncSuccessSentinelStateMachineBox() => SetResult(default!);
+ }
+
+ /// Provides a strongly-typed box object based on the specific state machine type in use.
+ private sealed class StateMachineBox :
+ StateMachineBox,
+ IValueTaskSource, IValueTaskSource, IAsyncStateMachineBox, IThreadPoolWorkItem
+ where TStateMachine : IAsyncStateMachine
+ {
+ /// Delegate used to invoke on an ExecutionContext when passed an instance of this box type.
+ private static readonly ContextCallback s_callback = ExecutionContextCallback;
+ /// Thread-local cache of boxes. This currently only ever stores one.
+ [ThreadStatic]
+ private static StateMachineBox? t_tlsCache;
+ /// Lock used to protected the shared cache of boxes. 1 == held, 0 == not held.
+ /// The code that uses this assumes a runtime without thread aborts.
+ private static int s_cacheLock;
+ /// Singly-linked list cache of boxes.
+ private static StateMachineBox? s_cache;
+ /// The number of items stored in .
+ private static int s_cacheSize;
+
+ /// If this box is stored in the cache, the next box in the cache.
+ private StateMachineBox? _next;
+ /// The state machine itself.
+ public TStateMachine? StateMachine;
+
+ /// Gets a box object to use for an operation. This may be a reused, pooled object, or it may be new.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)] // only one caller
+ internal static StateMachineBox GetOrCreateBox()
+ {
+ StateMachineBox? box;
+
+ // First see if the thread-static cache of at most one box has one.
+ box = t_tlsCache;
+ if (box is not null)
+ {
+ t_tlsCache = null;
+ return box;
+ }
+
+ // Try to acquire the lock to access the cache. If there's any contention, don't use the cache.
+ if (s_cache is not null && // hot read just to see if there's any point paying for the interlocked
+ Interlocked.Exchange(ref s_cacheLock, 1) == 0)
+ {
+ // If there are any instances cached, take one from the cache stack and use it.
+ box = s_cache;
+ if (box is not null)
+ {
+ s_cache = box._next;
+ box._next = null;
+ s_cacheSize--;
+ Debug.Assert(s_cacheSize >= 0, "Expected the cache size to be non-negative.");
+
+ // Release the lock and return the box.
+ Volatile.Write(ref s_cacheLock, 0);
+ return box;
+ }
+
+ // No objects were cached. We'll just create a new instance.
+ Debug.Assert(s_cacheSize == 0, "Expected cache size to be 0.");
+
+ // Release the lock.
+ Volatile.Write(ref s_cacheLock, 0);
+ }
+
+ // Couldn't quickly get a cached instance, so create a new instance.
+ return new StateMachineBox();
+ }
+
+ /// Returns this instance to the cache, or drops it if the cache is full or this instance shouldn't be cached.
+ private void ReturnOrDropBox()
+ {
+ Debug.Assert(_next is null, "Expected box to not be part of cached list.");
+
+ // Clear out the state machine and associated context to avoid keeping arbitrary state referenced by
+ // lifted locals. We want to do this regardless of whether we end up caching the box or not, in case
+ // the caller keeps the box alive for an arbitrary period of time.
+ ClearStateUponCompletion();
+
+ // Reset the MRVTSC. We can either do this here, in which case we may be paying the (small) overhead
+ // to reset the box even if we're going to drop it, or we could do it while holding the lock, in which
+ // case we'll only reset it if necessary but causing the lock to be held for longer, thereby causing
+ // more contention. For now at least, we do it outside of the lock. (This must not be done after
+ // the lock is released, since at that point the instance could already be in use elsewhere.)
+ // We also want to increment the version number even if we're going to drop it, to maximize the chances
+ // that incorrectly double-awaiting a ValueTask will produce an error.
+ _valueTaskSource.Reset();
+
+ // If reusing the object would result in potentially wrapping around its version number, just throw it away.
+ // This provides a modicum of additional safety when ValueTasks are misused (helping to avoid the case where
+ // a ValueTask is illegally re-awaited and happens to do so at exactly 2^16 uses later on this exact same instance),
+ // at the expense of potentially incurring an additional allocation every 65K uses.
+ if ((ushort)_valueTaskSource.Version == ushort.MaxValue)
+ {
+ return;
+ }
+
+ // If the thread static cache is empty, store this into it and bail.
+ if (t_tlsCache is null)
+ {
+ t_tlsCache = this;
+ return;
+ }
+
+ // Try to acquire the cache lock. If there's any contention, or if the cache is full, we just throw away the object.
+ if (Interlocked.Exchange(ref s_cacheLock, 1) == 0)
+ {
+ if (s_cacheSize < PoolingAsyncValueTaskMethodBuilder.s_valueTaskPoolingCacheSize)
+ {
+ // Push the box onto the cache stack for subsequent reuse.
+ _next = s_cache;
+ s_cache = this;
+ s_cacheSize++;
+ Debug.Assert(s_cacheSize > 0 && s_cacheSize <= PoolingAsyncValueTaskMethodBuilder.s_valueTaskPoolingCacheSize, "Expected cache size to be within bounds.");
+ }
+
+ // Release the lock.
+ Volatile.Write(ref s_cacheLock, 0);
+ }
+ }
+
+ ///
+ /// Clear out the state machine and associated context to avoid keeping arbitrary state referenced by lifted locals.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void ClearStateUponCompletion()
+ {
+ StateMachine = default;
+ Context = default;
+ }
+
+ ///
+ /// Used to initialize s_callback above. We don't use a lambda for this on purpose: a lambda would
+ /// introduce a new generic type behind the scenes that comes with a hefty size penalty in AOT builds.
+ ///
+ private static void ExecutionContextCallback(object? s)
+ {
+ // Only used privately to pass directly to EC.Run
+ Debug.Assert(s is StateMachineBox);
+ Unsafe.As>(s).StateMachine!.MoveNext();
+ }
+
+ /// A delegate to the method.
+ public Action MoveNextAction => _moveNextAction ??= new Action(MoveNext);
+
+ /// Invoked to run MoveNext when this instance is executed from the thread pool.
+ void IThreadPoolWorkItem.Execute() => MoveNext();
+
+ /// Calls MoveNext on
+ public void MoveNext()
+ {
+ ExecutionContext? context = Context;
+
+ if (context is null)
+ {
+ Debug.Assert(!(StateMachine is null));
+ StateMachine.MoveNext();
+ }
+ else
+ {
+ ExecutionContext.RunInternal(context, s_callback, this);
+ }
+ }
+
+ /// Get the result of the operation.
+ TResult IValueTaskSource.GetResult(short token)
+ {
+ try
+ {
+ return _valueTaskSource.GetResult(token);
+ }
+ finally
+ {
+ // Reuse this instance if possible, otherwise clear and drop it.
+ ReturnOrDropBox();
+ }
+ }
+
+ /// Get the result of the operation.
+ void IValueTaskSource.GetResult(short token)
+ {
+ try
+ {
+ _valueTaskSource.GetResult(token);
+ }
+ finally
+ {
+ // Reuse this instance if possible, otherwise clear and drop it.
+ ReturnOrDropBox();
+ }
+ }
+
+ /// Gets the state machine as a boxed object. This should only be used for debugging purposes.
+ IAsyncStateMachine IAsyncStateMachineBox.GetStateMachineObject() => StateMachine!; // likely boxes, only use for debugging
+ }
+ }
+}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/ExceptionServices/ExceptionDispatchInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/ExceptionServices/ExceptionDispatchInfo.cs
index 18c72613056b..d89ef99c9ac7 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Runtime/ExceptionServices/ExceptionDispatchInfo.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/ExceptionServices/ExceptionDispatchInfo.cs
@@ -65,7 +65,7 @@ public void Throw()
/// Stores the current stack trace into the specified instance.
/// The unthrown instance.
/// The argument was null.
- /// The argument was previously thrown or previously had a stack trace stored into it..
+ /// The argument was previously thrown or previously had a stack trace stored into it.
/// The exception instance.
[StackTraceHidden]
public static Exception SetCurrentStackTrace(Exception source)
@@ -79,5 +79,36 @@ public static Exception SetCurrentStackTrace(Exception source)
return source;
}
+
+ ///
+ /// Stores the provided stack trace into the specified instance.
+ ///
+ /// The unthrown instance.
+ /// The stack trace string to persist within . This is normally acquired
+ /// from the property from the remote exception instance.
+ /// The or argument was null.
+ /// The argument was previously thrown or previously had a stack trace stored into it.
+ /// The exception instance.
+ ///
+ /// This method populates the property from an arbitrary string value.
+ /// The typical use case is the transmission of objects across processes with high fidelity,
+ /// allowing preservation of the exception object's stack trace information. .NET does not attempt to parse the
+ /// provided string value. The caller is responsible for normalizing line endings if required.
+ ///
+ public static Exception SetRemoteStackTrace(Exception source, string stackTrace)
+ {
+ if (source is null)
+ {
+ throw new ArgumentNullException(nameof(source));
+ }
+ if (stackTrace is null)
+ {
+ throw new ArgumentNullException(nameof(stackTrace));
+ }
+
+ source.SetRemoteStackTrace(stackTrace);
+
+ return source;
+ }
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs b/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs
index 690c26a7793e..efb7f5d50d79 100644
--- a/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs
@@ -578,9 +578,9 @@ private static string JoinCore(ReadOnlySpan separator, string?[] value, in
public static string Join(string? separator, IEnumerable values)
{
- if (values is List valuesIList)
+ if (values is List valuesList)
{
- return JoinCore(separator.AsSpan(), CollectionsMarshal.AsSpan(valuesIList));
+ return JoinCore(separator.AsSpan(), CollectionsMarshal.AsSpan(valuesList));
}
if (values is string?[] valuesArray)
diff --git a/src/libraries/System.Private.CoreLib/src/System/StringComparer.cs b/src/libraries/System.Private.CoreLib/src/System/StringComparer.cs
index 15a1055607ac..ce22da699c92 100644
--- a/src/libraries/System.Private.CoreLib/src/System/StringComparer.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/StringComparer.cs
@@ -62,6 +62,102 @@ public static StringComparer Create(CultureInfo culture, CompareOptions options)
return new CultureAwareComparer(culture, options);
}
+ ///
+ /// Determines whether the specified is a well-known ordinal string comparer.
+ ///
+ /// The comparer to query.
+ /// When this method returns, contains a value stating whether
+ /// is case-insensitive. Set to if this method returns .
+ ///
+ /// if is a well-known ordinal string comparer;
+ /// otherwise, .
+ ///
+ ///
+ /// A "well-known ordinal comparer" describes a comparer which behaves identically to
+ /// when passed to or .
+ /// For example, is a well-known ordinal comparer because
+ /// a given as a constructor
+ /// argument will behave identically to a given
+ /// as a constructor argument. If is on method exit,
+ /// then behaves identically to when passed to the
+ /// constructor of such a collection.
+ ///
+ public static bool IsWellKnownOrdinalComparer(IEqualityComparer? comparer, out bool ignoreCase)
+ {
+ if (comparer is IInternalStringEqualityComparer internalStringComparer)
+ {
+ comparer = internalStringComparer.GetUnderlyingEqualityComparer(); // unwrap if necessary
+ }
+
+ switch (comparer)
+ {
+ case StringComparer stringComparer:
+ return stringComparer.IsWellKnownOrdinalComparerCore(out ignoreCase);
+ case GenericEqualityComparer:
+ // special-case EqualityComparer.Default, which is Ordinal-equivalent
+ ignoreCase = false;
+ return true;
+ default:
+ // unknown comparer
+ ignoreCase = default;
+ return false;
+ }
+ }
+
+ private protected virtual bool IsWellKnownOrdinalComparerCore(out bool ignoreCase)
+ {
+ // unless specialized comparer overrides this, we're not a well-known ordinal comparer
+ ignoreCase = default;
+ return false;
+ }
+
+ ///
+ /// Determines whether the specified is a well-known culture-aware string comparer.
+ ///
+ /// The comparer to query.
+ /// When this method returns, contains a value indicating which was used
+ /// to create . Set to if this method returns .
+ /// When this method returns, contains a value indicating which was used
+ /// to create . Set to if this method returns .
+ /// whether
+ ///
+ /// if is a well-known culture-aware string comparer;
+ /// otherwise, .
+ ///
+ ///
+ /// A "well-known culture-aware comparer" describes a comparer which is tied to a specific using
+ /// some defined . To create a instance wrapped around a
+ /// and , use .
+ /// This method returns when given and other non-linguistic comparers as input.
+ ///
+ public static bool IsWellKnownCultureAwareComparer(IEqualityComparer? comparer, [NotNullWhen(true)] out CompareInfo? compareInfo, out CompareOptions compareOptions)
+ {
+ if (comparer is IInternalStringEqualityComparer internalStringComparer)
+ {
+ comparer = internalStringComparer.GetUnderlyingEqualityComparer(); // unwrap if necessary
+ }
+
+ if (comparer is StringComparer stringComparer)
+ {
+ return stringComparer.IsWellKnownCultureAwareComparerCore(out compareInfo, out compareOptions);
+ }
+ else
+ {
+ // unknown comparer
+ compareInfo = default;
+ compareOptions = default;
+ return false;
+ }
+ }
+
+ private protected virtual bool IsWellKnownCultureAwareComparerCore([NotNullWhen(true)] out CompareInfo? compareInfo, out CompareOptions compareOptions)
+ {
+ // unless specialized comparer overrides this, we're not a well-known culture-aware comparer
+ compareInfo = default;
+ compareOptions = default;
+ return false;
+ }
+
public int Compare(object? x, object? y)
{
if (x == y) return 0;
@@ -202,6 +298,13 @@ public void GetObjectData(SerializationInfo info, StreamingContext context)
info.AddValue("_options", _options);
info.AddValue("_ignoreCase", (_options & CompareOptions.IgnoreCase) != 0);
}
+
+ private protected override bool IsWellKnownCultureAwareComparerCore([NotNullWhen(true)] out CompareInfo? compareInfo, out CompareOptions compareOptions)
+ {
+ compareInfo = _compareInfo;
+ compareOptions = _options;
+ return true;
+ }
}
[Serializable]
@@ -280,6 +383,12 @@ public override int GetHashCode()
int hashCode = nameof(OrdinalComparer).GetHashCode();
return _ignoreCase ? (~hashCode) : hashCode;
}
+
+ private protected override bool IsWellKnownOrdinalComparerCore(out bool ignoreCase)
+ {
+ ignoreCase = _ignoreCase;
+ return true;
+ }
}
[Serializable]
diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationTokenSource.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationTokenSource.cs
index ebd38dd1afa4..54a7dc691cc0 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationTokenSource.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationTokenSource.cs
@@ -66,7 +66,7 @@ private static void TimerCallback(object? state) => // separated out into a name
/// canceled concurrently.
///
///
- public bool IsCancellationRequested => _state >= NotifyingState;
+ public bool IsCancellationRequested => _state != NotCanceledState;
/// A simple helper to determine whether cancellation has finished.
internal bool IsCancellationCompleted => _state == NotifyingCompleteState;
@@ -365,6 +365,54 @@ private void CancelAfter(uint millisecondsDelay)
}
}
+ ///
+ /// Attempts to reset the to be used for an unrelated operation.
+ ///
+ ///
+ /// true if the has not had cancellation requested and could
+ /// have its state reset to be reused for a subsequent operation; otherwise, false.
+ ///
+ ///
+ /// is intended to be used by the sole owner of the
+ /// when it is known that the operation with which the was used has
+ /// completed, no one else will be attempting to cancel it, and any registrations still remaining are erroneous.
+ /// Upon a successful reset, such registrations will no longer be notified for any subsequent cancellation of the
+ /// ; however, if any component still holds a reference to this
+ /// either directly or indirectly via a
+ /// handed out from it, polling via their reference will show the current state any time after the reset as
+ /// it's the same instance. Usage of concurrently with requesting cancellation is not
+ /// thread-safe and may result in TryReset returning true even if cancellation was already requested and may result
+ /// in registrations not being invoked as part of the concurrent cancellation request.
+ ///
+ public bool TryReset()
+ {
+ ThrowIfDisposed();
+
+ // We can only reset if cancellation has not yet been requested: we never want to allow a CancellationToken
+ // to transition from canceled to non-canceled.
+ if (_state == NotCanceledState)
+ {
+ // If there is no timer, then we're free to reset. If there is a timer, then we need to first try
+ // to reset it to be infinite so that it won't fire, and then recognize that it could have already
+ // fired by the time we successfully changed it, and so check to see whether that's possibly the case.
+ // If we successfully reset it and it never fired, then we can be sure it won't trigger cancellation.
+ bool reset =
+ _timer is not TimerQueueTimer timer ||
+ (timer.Change(Timeout.UnsignedInfinite, Timeout.UnsignedInfinite) && !timer._everQueued);
+
+ if (reset)
+ {
+ // We're not canceled and no timer will run to cancel us.
+ // Clear out all the registrations, and return that we've successfully reset.
+ Volatile.Read(ref _registrations)?.UnregisterAll();
+ return true;
+ }
+ }
+
+ // Failed to reset.
+ return false;
+ }
+
/// Releases the resources used by this .
/// This method is not thread-safe for any other concurrent calls.
public void Dispose()
@@ -434,10 +482,7 @@ private void ThrowIfDisposed()
{
if (_disposed)
{
- ThrowObjectDisposedException();
-
- [DoesNotReturn]
- static void ThrowObjectDisposedException() => throw new ObjectDisposedException(null, SR.CancellationTokenSource_Disposed);
+ ThrowHelper.ThrowObjectDisposedException(ExceptionResource.CancellationTokenSource_Disposed);
}
}
@@ -876,6 +921,25 @@ internal sealed class Registrations
/// The associated source.
public Registrations(CancellationTokenSource source) => Source = source;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)] // used in only two places, one of which is a hot path
+ private void Recycle(CallbackNode node)
+ {
+ Debug.Assert(_lock == 1);
+
+ // Clear out the unused node and put it on the singly-linked free list.
+ // The only field we don't clear out is the associated Registrations, as that's fixed
+ // throughout the node's lifetime.
+ node.Id = 0;
+ node.Callback = null;
+ node.CallbackState = null;
+ node.ExecutionContext = null;
+ node.SynchronizationContext = null;
+
+ node.Prev = null;
+ node.Next = FreeNodeList;
+ FreeNodeList = node;
+ }
+
/// Unregisters a callback.
/// The expected id of the registration.
/// The callback node.
@@ -925,17 +989,7 @@ public bool Unregister(long id, CallbackNode node)
node.Next.Prev = node.Prev;
}
- // Clear out the now unused node and put it on the singly-linked free list.
- // The only field we don't clear out is the associated Source, as that's fixed
- // throughout the nodes lifetime.
- node.Id = 0;
- node.Callback = null;
- node.CallbackState = null;
- node.ExecutionContext = null;
- node.SynchronizationContext = null;
- node.Prev = null;
- node.Next = FreeNodeList;
- FreeNodeList = node;
+ Recycle(node);
return true;
}
@@ -945,6 +999,30 @@ public bool Unregister(long id, CallbackNode node)
}
}
+ /// Moves all registrations to the free list.
+ public void UnregisterAll()
+ {
+ EnterLock();
+ try
+ {
+ // Null out all callbacks.
+ CallbackNode? node = Callbacks;
+ Callbacks = null;
+
+ // Reset and move each node that was in the callbacks list to the free list.
+ while (node != null)
+ {
+ CallbackNode? next = node.Next;
+ Recycle(node);
+ node = next;
+ }
+ }
+ finally
+ {
+ ExitLock();
+ }
+ }
+
///
/// Wait for a single callback to complete (or, more specifically, to not be running).
/// It is ok to call this method if the callback has already finished.
diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Timer.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Timer.cs
index 2ab4c1003e12..e2766f270c49 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Threading/Timer.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Timer.cs
@@ -206,6 +206,7 @@ private void FireNextTimers()
if (remaining <= 0)
{
// Timer is ready to fire.
+ timer._everQueued = true;
if (timer._period != Timeout.UnsignedInfinite)
{
@@ -476,6 +477,7 @@ internal sealed partial class TimerQueueTimer : IThreadPoolWorkItem
// instead of with a provided WaitHandle.
private int _callbacksRunning;
private bool _canceled;
+ internal bool _everQueued;
private object? _notifyWhenNoCallbacksRunning; // may be either WaitHandle or Task
internal TimerQueueTimer(TimerCallback timerCallback, object? state, uint dueTime, uint period, bool flowExecutionContext)
diff --git a/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs b/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs
index 128b59d30594..117e60fdd061 100644
--- a/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs
@@ -911,6 +911,8 @@ private static string GetResourceString(ExceptionResource resource)
return SR.Argument_SpansMustHaveSameLength;
case ExceptionResource.Argument_InvalidFlag:
return SR.Argument_InvalidFlag;
+ case ExceptionResource.CancellationTokenSource_Disposed:
+ return SR.CancellationTokenSource_Disposed;
default:
Debug.Fail("The enum value is not defined, please check the ExceptionResource Enum.");
return "";
@@ -1090,5 +1092,6 @@ internal enum ExceptionResource
Arg_TypeNotSupported,
Argument_SpansMustHaveSameLength,
Argument_InvalidFlag,
+ CancellationTokenSource_Disposed,
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.FullGlobalizationData.cs b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.FullGlobalizationData.cs
new file mode 100644
index 000000000000..34e1f5adf691
--- /dev/null
+++ b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.FullGlobalizationData.cs
@@ -0,0 +1,259 @@
+// 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;
+
+namespace System
+{
+ public sealed partial class TimeZoneInfo
+ {
+ private const string FallbackCultureName = "en-US";
+ private const string GmtId = "GMT";
+
+ // Some time zones may give better display names using their location names rather than their generic name.
+ // We can update this list as need arises.
+ private static readonly string[] s_ZonesThatUseLocationName = new[] {
+ "Europe/Minsk", // Prefer "Belarus Time" over "Moscow Standard Time (Minsk)"
+ "Europe/Moscow", // Prefer "Moscow Time" over "Moscow Standard Time"
+ "Europe/Simferopol", // Prefer "Simferopol Time" over "Moscow Standard Time (Simferopol)"
+ "Pacific/Apia", // Prefer "Samoa Time" over "Apia Time"
+ "Pacific/Pitcairn" // Prefer "Pitcairn Islands Time" over "Pitcairn Time"
+ };
+
+ // Main function that is called during construction to populate the three display names
+ private static void TryPopulateTimeZoneDisplayNamesFromGlobalizationData(string timeZoneId, TimeSpan baseUtcOffset, ref string? standardDisplayName, ref string? daylightDisplayName, ref string? displayName)
+ {
+ // Determine the culture to use
+ CultureInfo uiCulture = CultureInfo.CurrentUICulture;
+ if (uiCulture.Name.Length == 0)
+ uiCulture = CultureInfo.GetCultureInfo(FallbackCultureName); // ICU doesn't work nicely with InvariantCulture
+
+ // Attempt to populate the fields backing the StandardName, DaylightName, and DisplayName from globalization data.
+ GetDisplayName(timeZoneId, Interop.Globalization.TimeZoneDisplayNameType.Standard, uiCulture.Name, ref standardDisplayName);
+ GetDisplayName(timeZoneId, Interop.Globalization.TimeZoneDisplayNameType.DaylightSavings, uiCulture.Name, ref daylightDisplayName);
+ GetFullValueForDisplayNameField(timeZoneId, baseUtcOffset, uiCulture, ref displayName);
+ }
+
+ // Helper function to get the standard display name for the UTC static time zone instance
+ private static string GetUtcStandardDisplayName()
+ {
+ // Don't bother looking up the name for invariant or English cultures
+ CultureInfo uiCulture = CultureInfo.CurrentUICulture;
+ if (GlobalizationMode.Invariant || uiCulture.Name.Length == 0 || uiCulture.TwoLetterISOLanguageName == "en")
+ return InvariantUtcStandardDisplayName;
+
+ // Try to get a localized version of "Coordinated Universal Time" from the globalization data
+ string? standardDisplayName = null;
+ GetDisplayName(UtcId, Interop.Globalization.TimeZoneDisplayNameType.Standard, uiCulture.Name, ref standardDisplayName);
+
+ // Final safety check. Don't allow null or abbreviations
+ if (standardDisplayName == null || standardDisplayName == "GMT" || standardDisplayName == "UTC")
+ standardDisplayName = InvariantUtcStandardDisplayName;
+
+ return standardDisplayName;
+ }
+
+ // Helper function that retrieves various forms of time zone display names from ICU
+ private static unsafe void GetDisplayName(string timeZoneId, Interop.Globalization.TimeZoneDisplayNameType nameType, string uiCulture, ref string? displayName)
+ {
+ if (GlobalizationMode.Invariant)
+ {
+ return;
+ }
+
+ string? timeZoneDisplayName;
+ bool result = Interop.CallStringMethod(
+ (buffer, locale, id, type) =>
+ {
+ fixed (char* bufferPtr = buffer)
+ {
+ return Interop.Globalization.GetTimeZoneDisplayName(locale, id, type, bufferPtr, buffer.Length);
+ }
+ },
+ uiCulture,
+ timeZoneId,
+ nameType,
+ out timeZoneDisplayName);
+
+ if (!result && uiCulture != FallbackCultureName)
+ {
+ // Try to fallback using FallbackCultureName just in case we can make it work.
+ result = Interop.CallStringMethod(
+ (buffer, locale, id, type) =>
+ {
+ fixed (char* bufferPtr = buffer)
+ {
+ return Interop.Globalization.GetTimeZoneDisplayName(locale, id, type, bufferPtr, buffer.Length);
+ }
+ },
+ FallbackCultureName,
+ timeZoneId,
+ nameType,
+ out timeZoneDisplayName);
+ }
+
+ // If there is an unknown error, don't set the displayName field.
+ // It will be set to the abbreviation that was read out of the tzfile.
+ if (result && !string.IsNullOrEmpty(timeZoneDisplayName))
+ {
+ displayName = timeZoneDisplayName;
+ }
+ }
+
+ // Helper function that builds the value backing the DisplayName field from globalization data.
+ private static void GetFullValueForDisplayNameField(string timeZoneId, TimeSpan baseUtcOffset, CultureInfo uiCulture, ref string? displayName)
+ {
+ // There are a few diffent ways we might show the display name depending on the data.
+ // The algorithm used below should avoid duplicating the same words while still achieving the
+ // goal of providing a unique, discoverable, and intuitive name.
+
+ // Try to get the generic name for this time zone.
+ string? genericName = null;
+ GetDisplayName(timeZoneId, Interop.Globalization.TimeZoneDisplayNameType.Generic, uiCulture.Name, ref genericName);
+ if (genericName == null)
+ {
+ // We'll use the fallback display name value already set.
+ return;
+ }
+
+ // Get the base offset to prefix in front of the time zone.
+ // Only UTC and its aliases have "(UTC)", handled earlier. All other zones include an offset, even if it's zero.
+ string baseOffsetText = $"(UTC{(baseUtcOffset >= TimeSpan.Zero ? '+' : '-')}{baseUtcOffset:hh\\:mm})";
+
+ // Get the generic location name.
+ string? genericLocationName = null;
+ GetDisplayName(timeZoneId, Interop.Globalization.TimeZoneDisplayNameType.GenericLocation, uiCulture.Name, ref genericLocationName);
+
+ // Some edge cases only apply when the offset is +00:00.
+ if (baseUtcOffset == TimeSpan.Zero)
+ {
+ // GMT and its aliases will just use the equivalent of "Greenwich Mean Time".
+ string? gmtLocationName = null;
+ GetDisplayName(GmtId, Interop.Globalization.TimeZoneDisplayNameType.GenericLocation, uiCulture.Name, ref gmtLocationName);
+ if (genericLocationName == gmtLocationName)
+ {
+ displayName = $"{baseOffsetText} {genericName}";
+ return;
+ }
+
+ // Other zones with a zero offset and the equivalent of "Greenwich Mean Time" should only use the location name.
+ // For example, prefer "Iceland Time" over "Greenwich Mean Time (Reykjavik)".
+ string? gmtGenericName = null;
+ GetDisplayName(GmtId, Interop.Globalization.TimeZoneDisplayNameType.Generic, uiCulture.Name, ref gmtGenericName);
+ if (genericName == gmtGenericName)
+ {
+ displayName = $"{baseOffsetText} {genericLocationName}";
+ return;
+ }
+ }
+
+ if (genericLocationName == genericName)
+ {
+ // When the location name is the same as the generic name,
+ // then it is generally good enough to show by itself.
+
+ // *** Example (en-US) ***
+ // id = "America/Havana"
+ // baseOffsetText = "(UTC-05:00)"
+ // standardName = "Cuba Standard Time"
+ // genericName = "Cuba Time"
+ // genericLocationName = "Cuba Time"
+ // exemplarCityName = "Havana"
+ // displayName = "(UTC-05:00) Cuba Time"
+
+ displayName = $"{baseOffsetText} {genericLocationName}";
+ return;
+ }
+
+ // Prefer location names in some special cases.
+ if (StringArrayContains(timeZoneId, s_ZonesThatUseLocationName, StringComparison.OrdinalIgnoreCase))
+ {
+ displayName = $"{baseOffsetText} {genericLocationName}";
+ return;
+ }
+
+ // See if we should include the exemplar city name.
+ string exemplarCityName = GetExemplarCityName(timeZoneId, uiCulture.Name);
+ if (uiCulture.CompareInfo.IndexOf(genericName, exemplarCityName, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace) >= 0 && genericLocationName != null)
+ {
+ // When an exemplar city is already part of the generic name,
+ // there's no need to repeat it again so just use the generic name.
+
+ // *** Example (fr-FR) ***
+ // id = "Australia/Lord_Howe"
+ // baseOffsetText = "(UTC+10:30)"
+ // standardName = "heure normale de Lord Howe"
+ // genericName = "heure de Lord Howe"
+ // genericLocationName = "heure : Lord Howe"
+ // exemplarCityName = "Lord Howe"
+ // displayName = "(UTC+10:30) heure de Lord Howe"
+
+ displayName = $"{baseOffsetText} {genericName}";
+ }
+ else
+ {
+ // Finally, use the generic name and the exemplar city together.
+ // This provides an intuitive name and still disambiguates.
+
+ // *** Example (en-US) ***
+ // id = "Europe/Rome"
+ // baseOffsetText = "(UTC+01:00)"
+ // standardName = "Central European Standard Time"
+ // genericName = "Central European Time"
+ // genericLocationName = "Italy Time"
+ // exemplarCityName = "Rome"
+ // displayName = "(UTC+01:00) Central European Time (Rome)"
+
+ displayName = $"{baseOffsetText} {genericName} ({exemplarCityName})";
+ }
+ }
+
+ // Helper function that gets an exmplar city name either from ICU or from the IANA time zone ID itself
+ private static string GetExemplarCityName(string timeZoneId, string uiCultureName)
+ {
+ // First try to get the name through the localization data.
+ string? exemplarCityName = null;
+ GetDisplayName(timeZoneId, Interop.Globalization.TimeZoneDisplayNameType.ExemplarCity, uiCultureName, ref exemplarCityName);
+ if (!string.IsNullOrEmpty(exemplarCityName))
+ return exemplarCityName;
+
+ // Support for getting exemplar city names was added in ICU 51.
+ // We may have an older version. For example, in Helix we test on RHEL 7.5 which uses ICU 50.1.2.
+ // We'll fallback to using an English name generated from the time zone ID.
+ int i = timeZoneId.LastIndexOf('/');
+ return timeZoneId.Substring(i + 1).Replace('_', ' ');
+ }
+
+ // Helper function that returns an alternative ID using ICU data. Used primarily for converting from Windows IDs.
+ private static unsafe string? GetAlternativeId(string id)
+ {
+ if (!GlobalizationMode.Invariant)
+ {
+ if (id.Equals("utc", StringComparison.OrdinalIgnoreCase))
+ {
+ // Special case UTC, as previously ICU would convert it to "Etc/GMT" which is incorrect name for UTC.
+ return "Etc/UTC";
+ }
+
+ foreach (char c in id)
+ {
+ // ICU uses some characters as a separator and trim the id at that character.
+ // while we should fail if the Id contained one of these characters.
+ if (c == '\\' || c == '\n' || c == '\r')
+ {
+ return null;
+ }
+ }
+
+ char* buffer = stackalloc char[100];
+ int length = Interop.Globalization.WindowsIdToIanaId(id, buffer, 100);
+ if (length > 0)
+ {
+ return new string(buffer, 0, length);
+ }
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.GetDisplayName.cs b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.GetDisplayName.cs
deleted file mode 100644
index ba54330cf891..000000000000
--- a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.GetDisplayName.cs
+++ /dev/null
@@ -1,66 +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.Buffers;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
-using System.Globalization;
-using System.IO;
-using System.Text;
-using System.Threading;
-using System.Security;
-
-using Internal.IO;
-
-namespace System
-{
- public sealed partial class TimeZoneInfo
- {
- private static unsafe void GetDisplayName(string timeZoneId, Interop.Globalization.TimeZoneDisplayNameType nameType, string uiCulture, ref string? displayName)
- {
- if (GlobalizationMode.Invariant)
- {
- return;
- }
-
- string? timeZoneDisplayName;
- bool result = Interop.CallStringMethod(
- (buffer, locale, id, type) =>
- {
- fixed (char* bufferPtr = buffer)
- {
- return Interop.Globalization.GetTimeZoneDisplayName(locale, id, type, bufferPtr, buffer.Length);
- }
- },
- uiCulture,
- timeZoneId,
- nameType,
- out timeZoneDisplayName);
-
- if (!result && uiCulture != FallbackCultureName)
- {
- // Try to fallback using FallbackCultureName just in case we can make it work.
- result = Interop.CallStringMethod(
- (buffer, locale, id, type) =>
- {
- fixed (char* bufferPtr = buffer)
- {
- return Interop.Globalization.GetTimeZoneDisplayName(locale, id, type, bufferPtr, buffer.Length);
- }
- },
- FallbackCultureName,
- timeZoneId,
- nameType,
- out timeZoneDisplayName);
- }
-
- // If there is an unknown error, don't set the displayName field.
- // It will be set to the abbreviation that was read out of the tzfile.
- if (result && !string.IsNullOrEmpty(timeZoneDisplayName))
- {
- displayName = timeZoneDisplayName;
- }
- }
- }
-}
diff --git a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.MinimalGlobalizationData.cs b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.MinimalGlobalizationData.cs
new file mode 100644
index 000000000000..9da75786bed1
--- /dev/null
+++ b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.MinimalGlobalizationData.cs
@@ -0,0 +1,25 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System
+{
+ public sealed partial class TimeZoneInfo
+ {
+ private static void TryPopulateTimeZoneDisplayNamesFromGlobalizationData(string timeZoneId, TimeSpan baseUtcOffset, ref string? standardDisplayName, ref string? daylightDisplayName, ref string? displayName)
+ {
+ // Do nothing. We'll use the fallback values already set.
+ }
+
+ private static string GetUtcStandardDisplayName()
+ {
+ // Just use the invariant display name.
+ return InvariantUtcStandardDisplayName;
+ }
+
+ private static string? GetAlternativeId(string id)
+ {
+ // No alternative IDs in this target.
+ return null;
+ }
+ }
+}
diff --git a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs
index 5c8a9a755516..3bd7e2f569b2 100644
--- a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs
@@ -22,12 +22,10 @@ public sealed partial class TimeZoneInfo
private const string ZoneTabFileName = "zone.tab";
private const string TimeZoneEnvironmentVariable = "TZ";
private const string TimeZoneDirectoryEnvironmentVariable = "TZDIR";
- private const string FallbackCultureName = "en-US";
- private const string GmtId = "GMT";
// UTC aliases per https://github.com/unicode-org/cldr/blob/master/common/bcp47/timezone.xml
- // Hard-coded because we need to treat all aliases of UTC the same even when ICU is not available,
- // or when we get "GMT" returned from older ICU versions. (This list is not likely to change.)
+ // Hard-coded because we need to treat all aliases of UTC the same even when globalization data is not available.
+ // (This list is not likely to change.)
private static readonly string[] s_UtcAliases = new[] {
"Etc/UTC",
"Etc/UCT",
@@ -39,16 +37,6 @@ public sealed partial class TimeZoneInfo
"Zulu"
};
- // Some time zones may give better display names using their location names rather than their generic name.
- // We can update this list as need arises.
- private static readonly string[] s_ZonesThatUseLocationName = new[] {
- "Europe/Minsk", // Prefer "Belarus Time" over "Moscow Standard Time (Minsk)"
- "Europe/Moscow", // Prefer "Moscow Time" over "Moscow Standard Time"
- "Europe/Simferopol", // Prefer "Simferopol Time" over "Moscow Standard Time (Simferopol)"
- "Pacific/Apia", // Prefer "Samoa Time" over "Apia Time"
- "Pacific/Pitcairn" // Prefer "Pitcairn Islands Time" over "Pitcairn Time"
- };
-
private TimeZoneInfo(byte[] data, string id, bool dstDisabled)
{
_id = id;
@@ -114,20 +102,14 @@ private TimeZoneInfo(byte[] data, string id, bool dstDisabled)
}
}
- // Use abbrev as the fallback
+ // Set fallback values using abbreviations, base offset, and id
+ // These are expected in environments without time zone globalization data
_standardDisplayName = standardAbbrevName;
_daylightDisplayName = daylightAbbrevName ?? standardAbbrevName;
- _displayName = _standardDisplayName;
-
- // Determine the culture to use
- CultureInfo uiCulture = CultureInfo.CurrentUICulture;
- if (uiCulture.Name.Length == 0)
- uiCulture = CultureInfo.GetCultureInfo(FallbackCultureName); // ICU doesn't work nicely with InvariantCulture
+ _displayName = $"(UTC{(_baseUtcOffset >= TimeSpan.Zero ? '+' : '-')}{_baseUtcOffset:hh\\:mm}) {_id}";
- // Attempt to populate the fields backing the StandardName, DaylightName, and DisplayName from globalization data.
- GetDisplayName(_id, Interop.Globalization.TimeZoneDisplayNameType.Standard, uiCulture.Name, ref _standardDisplayName);
- GetDisplayName(_id, Interop.Globalization.TimeZoneDisplayNameType.DaylightSavings, uiCulture.Name, ref _daylightDisplayName);
- GetFullValueForDisplayNameField(_id, _baseUtcOffset, uiCulture, ref _displayName);
+ // Try to populate the display names from the globalization data
+ TryPopulateTimeZoneDisplayNamesFromGlobalizationData(_id, _baseUtcOffset, ref _standardDisplayName, ref _daylightDisplayName, ref _displayName);
// TZif supports seconds-level granularity with offsets but TimeZoneInfo only supports minutes since it aligns
// with DateTimeOffset, SQL Server, and the W3C XML Specification
@@ -145,133 +127,6 @@ private TimeZoneInfo(byte[] data, string id, bool dstDisabled)
ValidateTimeZoneInfo(_id, _baseUtcOffset, _adjustmentRules, out _supportsDaylightSavingTime);
}
- // Helper function that builds the value backing the DisplayName field from gloablization data.
- private static void GetFullValueForDisplayNameField(string timeZoneId, TimeSpan baseUtcOffset, CultureInfo uiCulture, ref string? displayName)
- {
- // There are a few diffent ways we might show the display name depending on the data.
- // The algorithm used below should avoid duplicating the same words while still achieving the
- // goal of providing a unique, discoverable, and intuitive name.
-
- // Get the base offset to prefix in front of the time zone.
- // Only UTC and its aliases have "(UTC)", handled earlier. All other zones include an offset, even if it's zero.
- string baseOffsetText = $"(UTC{(baseUtcOffset >= TimeSpan.Zero ? '+' : '-')}{baseUtcOffset:hh\\:mm})";
-
- // Try to get the generic name for this time zone.
- string? genericName = null;
- GetDisplayName(timeZoneId, Interop.Globalization.TimeZoneDisplayNameType.Generic, uiCulture.Name, ref genericName);
-
- if (genericName == null)
- {
- // When we can't get a generic name, use the offset and the ID.
- // It is not ideal, but at least it is non-ambiguous.
- // (Note, UTC was handled already above.)
- displayName = $"{baseOffsetText} {timeZoneId}";
- return;
- }
-
- // Get the generic location name.
- string? genericLocationName = null;
- GetDisplayName(timeZoneId, Interop.Globalization.TimeZoneDisplayNameType.GenericLocation, uiCulture.Name, ref genericLocationName);
-
- // Some edge cases only apply when the offset is +00:00.
- if (baseUtcOffset == TimeSpan.Zero)
- {
- // GMT and its aliases will just use the equivalent of "Greenwich Mean Time".
- string? gmtLocationName = null;
- GetDisplayName(GmtId, Interop.Globalization.TimeZoneDisplayNameType.GenericLocation, uiCulture.Name, ref gmtLocationName);
- if (genericLocationName == gmtLocationName)
- {
- displayName = $"{baseOffsetText} {genericName}";
- return;
- }
-
- // Other zones with a zero offset and the equivalent of "Greenwich Mean Time" should only use the location name.
- // For example, prefer "Iceland Time" over "Greenwich Mean Time (Reykjavik)".
- string? gmtGenericName = null;
- GetDisplayName(GmtId, Interop.Globalization.TimeZoneDisplayNameType.Generic, uiCulture.Name, ref gmtGenericName);
- if (genericName == gmtGenericName)
- {
- displayName = $"{baseOffsetText} {genericLocationName}";
- return;
- }
- }
-
- if (genericLocationName == genericName)
- {
- // When the location name is the same as the generic name,
- // then it is generally good enough to show by itself.
-
- // *** Example (en-US) ***
- // id = "America/Havana"
- // baseOffsetText = "(UTC-05:00)"
- // standardName = "Cuba Standard Time"
- // genericName = "Cuba Time"
- // genericLocationName = "Cuba Time"
- // exemplarCityName = "Havana"
- // displayName = "(UTC-05:00) Cuba Time"
-
- displayName = $"{baseOffsetText} {genericLocationName}";
- return;
- }
-
- // Prefer location names in some special cases.
- if (StringArrayContains(timeZoneId, s_ZonesThatUseLocationName, StringComparison.OrdinalIgnoreCase))
- {
- displayName = $"{baseOffsetText} {genericLocationName}";
- return;
- }
-
- // See if we should include the exemplar city name.
- string exemplarCityName = GetExemplarCityName(timeZoneId, uiCulture.Name);
- if (uiCulture.CompareInfo.IndexOf(genericName, exemplarCityName, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace) >= 0 && genericLocationName != null)
- {
- // When an exemplar city is already part of the generic name,
- // there's no need to repeat it again so just use the generic name.
-
- // *** Example (fr-FR) ***
- // id = "Australia/Lord_Howe"
- // baseOffsetText = "(UTC+10:30)"
- // standardName = "heure normale de Lord Howe"
- // genericName = "heure de Lord Howe"
- // genericLocationName = "heure : Lord Howe"
- // exemplarCityName = "Lord Howe"
- // displayName = "(UTC+10:30) heure de Lord Howe"
-
- displayName = $"{baseOffsetText} {genericName}";
- }
- else
- {
- // Finally, use the generic name and the exemplar city together.
- // This provides an intuitive name and still disambiguates.
-
- // *** Example (en-US) ***
- // id = "Europe/Rome"
- // baseOffsetText = "(UTC+01:00)"
- // standardName = "Central European Standard Time"
- // genericName = "Central European Time"
- // genericLocationName = "Italy Time"
- // exemplarCityName = "Rome"
- // displayName = "(UTC+01:00) Central European Time (Rome)"
-
- displayName = $"{baseOffsetText} {genericName} ({exemplarCityName})";
- }
- }
-
- private static string GetExemplarCityName(string timeZoneId, string uiCultureName)
- {
- // First try to get the name through the localization data.
- string? exemplarCityName = null;
- GetDisplayName(timeZoneId, Interop.Globalization.TimeZoneDisplayNameType.ExemplarCity, uiCultureName, ref exemplarCityName);
- if (!string.IsNullOrEmpty(exemplarCityName))
- return exemplarCityName;
-
- // Support for getting exemplar city names was added in ICU 51.
- // We may have an older version. For example, in Helix we test on RHEL 7.5 which uses ICU 50.1.2.
- // We'll fallback to using an English name generated from the time zone ID.
- int i = timeZoneId.LastIndexOf('/');
- return timeZoneId.Substring(i + 1).Replace('_', ' ');
- }
-
// The TransitionTime fields are not used when AdjustmentRule.NoDaylightTransitions == true.
// However, there are some cases in the past where DST = true, and the daylight savings offset
// now equals what the current BaseUtcOffset is. In that case, the AdjustmentRule.DaylightOffset
@@ -380,36 +235,6 @@ private static void PopulateAllSystemTimeZones(CachedData cachedData)
}
}
- private static unsafe string? GetAlternativeId(string id)
- {
- if (!GlobalizationMode.Invariant)
- {
- if (id.Equals("utc", StringComparison.OrdinalIgnoreCase))
- {
- //special case UTC as ICU will convert it to "Etc/GMT" which is incorrect name for UTC.
- return "Etc/UTC";
- }
- foreach (char c in id)
- {
- // ICU uses some characters as a separator and trim the id at that character.
- // while we should fail if the Id contained one of these characters.
- if (c == '\\' || c == '\n' || c == '\r')
- {
- return null;
- }
- }
-
- char* buffer = stackalloc char[100];
- int length = Interop.Globalization.WindowsIdToIanaId(id, buffer, 100);
- if (length > 0)
- {
- return new string(buffer, 0, length);
- }
- }
-
- return null;
- }
-
///
/// Helper function for retrieving the local system time zone.
/// May throw COMException, TimeZoneNotFoundException, InvalidTimeZoneException.
@@ -1979,24 +1804,5 @@ private static bool StringArrayContains(string value, string[] source, StringCom
return false;
}
-
- // Helper function to get the standard display name for the UTC static time zone instance
- private static string GetUtcStandardDisplayName()
- {
- // Don't bother looking up the name for invariant or English cultures
- CultureInfo uiCulture = CultureInfo.CurrentUICulture;
- if (GlobalizationMode.Invariant || uiCulture.Name.Length == 0 || uiCulture.TwoLetterISOLanguageName == "en")
- return InvariantUtcStandardDisplayName;
-
- // Try to get a localized version of "Coordinated Universal Time" from the globalization data
- string? standardDisplayName = null;
- GetDisplayName(UtcId, Interop.Globalization.TimeZoneDisplayNameType.Standard, uiCulture.Name, ref standardDisplayName);
-
- // Final safety check. Don't allow null or abbreviations
- if (standardDisplayName == null || standardDisplayName == "GMT" || standardDisplayName == "UTC")
- standardDisplayName = InvariantUtcStandardDisplayName;
-
- return standardDisplayName;
- }
}
}
diff --git a/src/libraries/System.Private.Xml/src/ILLink/ILLink.Suppressions.xml b/src/libraries/System.Private.Xml/src/ILLink/ILLink.Suppressions.xml
index 991377561048..40dbf4ac889e 100644
--- a/src/libraries/System.Private.Xml/src/ILLink/ILLink.Suppressions.xml
+++ b/src/libraries/System.Private.Xml/src/ILLink/ILLink.Suppressions.xml
@@ -313,23 +313,5 @@
memberM:System.Xml.Serialization.XmlSerializationWriterILGen.WriteText(System.Xml.Serialization.SourceInfo,System.Xml.Serialization.TextAccessor)
-
- ILLink
- IL2067
- member
- M:System.Xml.Xsl.Runtime.XmlExtensionFunction.#ctor(System.String,System.String,System.Int32,System.Type,System.Reflection.BindingFlags)
-
-
- ILLink
- IL2067
- member
- M:System.Xml.Xsl.Runtime.XmlExtensionFunctionTable.Bind(System.String,System.String,System.Int32,System.Type,System.Reflection.BindingFlags)
-
-
- ILLink
- IL2075
- member
- M:System.Xml.Xsl.XsltOld.XsltCompileContext.GetExtentionMethod(System.String,System.String,System.Xml.XPath.XPathResultType[],System.Object@)
-
diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReaderILGen.cs b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReaderILGen.cs
index e80a951c76d3..feb269c3d752 100644
--- a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReaderILGen.cs
+++ b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReaderILGen.cs
@@ -936,7 +936,7 @@ private void WritePrimitive(TypeMapping mapping, string source)
{
i++;
uniqueName = name + i.ToString(CultureInfo.InvariantCulture);
- m = Enums[uniqueName];
+ Enums.TryGetValue(uniqueName, out m);
}
}
Enums.Add(uniqueName, mapping);
diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/IlGen/GenerateHelper.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/IlGen/GenerateHelper.cs
index a3fb2822f6d1..e02699f4abe8 100644
--- a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/IlGen/GenerateHelper.cs
+++ b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/IlGen/GenerateHelper.cs
@@ -303,7 +303,11 @@ internal static class XmlILMethods
public static readonly MethodInfo GetDataSource = typeof(XmlQueryContext).GetMethod("GetDataSource")!;
public static readonly MethodInfo GetDefaultDataSource = typeof(XmlQueryContext).GetMethod("get_DefaultDataSource")!;
public static readonly MethodInfo GetParam = typeof(XmlQueryContext).GetMethod("GetParameter")!;
- public static readonly MethodInfo InvokeXsltLate = typeof(XmlQueryContext).GetMethod("InvokeXsltLateBoundFunction")!;
+ public static readonly MethodInfo InvokeXsltLate = GetInvokeXsltLateBoundFunction();
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
+ Justification = "Supressing warning about not having the RequiresUnreferencedCode attribute since this code path " +
+ "will only be emitting IL that will later be called by Transform() method which is already annotated as RequiresUnreferencedCode")]
+ private static MethodInfo GetInvokeXsltLateBoundFunction() => typeof(XmlQueryContext).GetMethod("InvokeXsltLateBoundFunction")!;
// XmlILIndex
public static readonly MethodInfo IndexAdd = typeof(XmlILIndex).GetMethod("Add")!;
diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlExtensionFunction.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlExtensionFunction.cs
index ef7ddb38c996..da2e1b645d43 100644
--- a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlExtensionFunction.cs
+++ b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlExtensionFunction.cs
@@ -27,7 +27,12 @@ public XmlExtensionFunctionTable()
_table = new Dictionary();
}
- public XmlExtensionFunction Bind(string name, string namespaceUri, int numArgs, Type objectType, BindingFlags flags)
+ public XmlExtensionFunction Bind(
+ string name,
+ string namespaceUri,
+ int numArgs,
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] Type objectType,
+ BindingFlags flags)
{
XmlExtensionFunction func;
@@ -89,7 +94,7 @@ public XmlExtensionFunction(string name, string namespaceUri, MethodInfo meth)
///
/// Constructor.
///
- public XmlExtensionFunction(string name, string namespaceUri, int numArgs, Type objectType, BindingFlags flags)
+ public XmlExtensionFunction(string name, string namespaceUri, int numArgs, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicMethods)] Type objectType, BindingFlags flags)
{
Init(name, namespaceUri, numArgs, objectType, flags);
}
diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlQueryContext.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlQueryContext.cs
index 752a94d36ec1..c696d59abe04 100644
--- a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlQueryContext.cs
+++ b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlQueryContext.cs
@@ -12,6 +12,8 @@
using System.Xml.Schema;
using System.Xml.XPath;
using System.Runtime.Versioning;
+using System.Diagnostics.CodeAnalysis;
+using System.Xml.Xsl.Xslt;
namespace System.Xml.Xsl.Runtime
{
@@ -222,6 +224,8 @@ public object GetParameter(string localName, string namespaceUri)
///
/// Return the extension object that is mapped to the specified namespace, or null if no object is mapped.
///
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
+ Justification = XsltArgumentList.ExtensionObjectSuppresion)]
public object GetLateBoundObject(string namespaceUri)
{
return (_argList != null) ? _argList.GetExtensionObject(namespaceUri) : null;
@@ -230,6 +234,7 @@ public object GetLateBoundObject(string namespaceUri)
///
/// Return true if the late bound object identified by "namespaceUri" contains a method that matches "name".
///
+ [RequiresUnreferencedCode(Scripts.ExtensionFunctionCannotBeStaticallyAnalyzed)]
public bool LateBoundFunctionExists(string name, string namespaceUri)
{
object instance;
@@ -248,6 +253,7 @@ public bool LateBoundFunctionExists(string name, string namespaceUri)
/// Get a late-bound extension object from the external argument list. Bind to a method on the object and invoke it,
/// passing "args" as arguments.
///
+ [RequiresUnreferencedCode(Scripts.ExtensionFunctionCannotBeStaticallyAnalyzed)]
public IList InvokeXsltLateBoundFunction(string name, string namespaceUri, IList[] args)
{
object instance;
diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlQueryRuntime.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlQueryRuntime.cs
index ce2e8f1ccbe9..4a490b3128ff 100644
--- a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlQueryRuntime.cs
+++ b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlQueryRuntime.cs
@@ -6,11 +6,13 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reflection;
using System.Xml.Schema;
using System.Xml.XPath;
using System.Xml.Xsl.IlGen;
+using System.Xml.Xsl.Xslt;
using MS.Internal.Xml.XPath;
namespace System.Xml.Xsl.Runtime
@@ -273,6 +275,7 @@ public object GetEarlyBoundObject(int index)
///
/// Return true if the early bound object identified by "namespaceUri" contains a method that matches "name".
///
+ [RequiresUnreferencedCode(Scripts.ExtensionFunctionCannotBeStaticallyAnalyzed)]
public bool EarlyBoundFunctionExists(string name, string namespaceUri)
{
if (_earlyInfo == null)
diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XsltLibrary.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XsltLibrary.cs
index 0c8018bbb1ba..31c779d6abd6 100644
--- a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XsltLibrary.cs
+++ b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XsltLibrary.cs
@@ -10,6 +10,7 @@
using System.Xml.XPath;
using System.Xml.Xsl.Xslt;
using System.ComponentModel;
+using System.Diagnostics.CodeAnalysis;
namespace System.Xml.Xsl.Runtime
{
@@ -59,7 +60,11 @@ internal static class XsltMethods
// XSLT functions and helper methods (non-static)
public static readonly MethodInfo CheckScriptNamespace = typeof(XsltLibrary).GetMethod("CheckScriptNamespace");
- public static readonly MethodInfo FunctionAvailable = typeof(XsltLibrary).GetMethod("FunctionAvailable");
+ public static readonly MethodInfo FunctionAvailable = GetFunctionAvailableMethod();
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
+ Justification = "Supressing warning about not having the RequiresUnreferencedCode attribute since this code path " +
+ "will only be emitting IL that will later be called by Transform() method which is already annotated as RequiresUnreferencedCode")]
+ private static MethodInfo GetFunctionAvailableMethod() => typeof(XsltLibrary).GetMethod("FunctionAvailable");
public static readonly MethodInfo ElementAvailable = typeof(XsltLibrary).GetMethod("ElementAvailable");
public static readonly MethodInfo RegisterDecimalFormat = typeof(XsltLibrary).GetMethod("RegisterDecimalFormat");
public static readonly MethodInfo RegisterDecimalFormatter = typeof(XsltLibrary).GetMethod("RegisterDecimalFormatter");
@@ -110,6 +115,7 @@ public bool ElementAvailable(XmlQualifiedName name)
}
// Spec: http://www.w3.org/TR/xslt#function-function-available
+ [RequiresUnreferencedCode(Scripts.ExtensionFunctionCannotBeStaticallyAnalyzed)]
public bool FunctionAvailable(XmlQualifiedName name)
{
if (_functionsAvail == null)
@@ -130,6 +136,7 @@ public bool FunctionAvailable(XmlQualifiedName name)
return result;
}
+ [RequiresUnreferencedCode(Scripts.ExtensionFunctionCannotBeStaticallyAnalyzed)]
private bool FunctionAvailableHelper(XmlQualifiedName name)
{
// Is this an XPath or an XSLT function?
diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Xslt/QilGeneratorEnv.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Xslt/QilGeneratorEnv.cs
index 7918c2995e69..a9a2e410c1aa 100644
--- a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Xslt/QilGeneratorEnv.cs
+++ b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Xslt/QilGeneratorEnv.cs
@@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.Xml.Schema;
using System.Xml.XPath;
using System.Xml.Xsl.Qil;
@@ -95,6 +96,9 @@ QilNode IXPathEnvironment.ResolveVariable(string prefix, string name)
}
// NOTE: DO NOT call QilNode.Clone() while executing this method since fixup nodes cannot be cloned
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
+ Justification = "Suppressing the warning for the ResolveFunction call on the Scripts since " +
+ "Scripts functionality is not supported by .NET Core")]
QilNode IXPathEnvironment.ResolveFunction(string prefix, string name, IList args, IFocus env)
{
Debug.Assert(!args.IsReadOnly, "Writable collection expected");
diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Xslt/Scripts.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Xslt/Scripts.cs
index 0f74a98c23da..72ec06504aa6 100644
--- a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Xslt/Scripts.cs
+++ b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Xslt/Scripts.cs
@@ -16,6 +16,7 @@ internal sealed class Scripts
private readonly Compiler _compiler;
private readonly TrimSafeDictionary _nsToType = new TrimSafeDictionary();
private readonly XmlExtensionFunctionTable _extFuncs = new XmlExtensionFunctionTable();
+ internal const string ExtensionFunctionCannotBeStaticallyAnalyzed = "The extension function referenced will be called from the stylesheet which cannot be statically analyzed.";
public Scripts(Compiler compiler)
{
@@ -27,6 +28,7 @@ public TrimSafeDictionary ScriptClasses
get { return _nsToType; }
}
+ [RequiresUnreferencedCode(ExtensionFunctionCannotBeStaticallyAnalyzed)]
public XmlExtensionFunction? ResolveFunction(string name, string ns, int numArgs, IErrorHelper errorHelper)
{
Type? type;
diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Xslt/XslAstAnalyzer.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Xslt/XslAstAnalyzer.cs
index 963f3411cea7..482b95131294 100644
--- a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Xslt/XslAstAnalyzer.cs
+++ b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Xslt/XslAstAnalyzer.cs
@@ -1054,6 +1054,9 @@ public XslFlags Variable(string prefix, string name)
return XslFlags.None;
}
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
+ Justification = "Supressing warning about not having the RequiresUnreferencedCode attribute since xsl Scripts are " +
+ "not supported in .NET Core")]
public XslFlags Function(string prefix, string name, IList args)
{
_typeDonor = null;
diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XsltOld/Processor.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XsltOld/Processor.cs
index 4a8075b0dcf6..7eec61431623 100644
--- a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XsltOld/Processor.cs
+++ b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XsltOld/Processor.cs
@@ -6,6 +6,7 @@ namespace System.Xml.Xsl.XsltOld
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
+ using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Reflection;
@@ -247,6 +248,8 @@ parameter is float || parameter is decimal
return parameter;
}
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
+ Justification = XsltArgumentList.ExtensionObjectSuppresion)]
internal object? GetExtensionObject(string nsUri)
{
return _args.GetExtensionObject(nsUri);
diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XsltOld/XsltCompileContext.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XsltOld/XsltCompileContext.cs
index ef58b3d968f2..af038b5711cf 100644
--- a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XsltOld/XsltCompileContext.cs
+++ b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XsltOld/XsltCompileContext.cs
@@ -183,6 +183,8 @@ public override bool PreserveWhitespace(XPathNavigator node)
}
private const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static;
+ [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2075:RequiresUnreferencedCode",
+ Justification = XsltArgumentList.ExtensionObjectSuppresion)]
private IXsltContextFunction? GetExtentionMethod(string ns, string name, XPathResultType[]? argTypes, out object? extension)
{
FuncExtension? result = null;
diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xslt/XsltArgumentList.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xslt/XsltArgumentList.cs
index 34ed4a5367fd..76045522c308 100644
--- a/src/libraries/System.Private.Xml/src/System/Xml/Xslt/XsltArgumentList.cs
+++ b/src/libraries/System.Private.Xml/src/System/Xml/Xslt/XsltArgumentList.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections;
+using System.Diagnostics.CodeAnalysis;
namespace System.Xml.Xsl
{
@@ -16,6 +17,10 @@ public class XsltArgumentList
{
private readonly Hashtable _parameters = new Hashtable();
private readonly Hashtable _extensions = new Hashtable();
+ private const string ExtensionObjectWarning = @"The stylesheet may have calls to methods of the extension object passed in which cannot be statically analyzed " +
+ "by the trimmer. Ensure all methods that may be called are preserved.";
+ internal const string ExtensionObjectSuppresion = @"In order for this code path to be hit, a previous call to XsltArgumentList.AddExtensionObject is " +
+ "required. That method is already annotated as unsafe and throwing a warning, so we can suppress here.";
// Used for reporting xsl:message's during execution
internal XsltMessageEncounteredEventHandler? xsltMessageEncountered;
@@ -27,6 +32,7 @@ public XsltArgumentList() { }
return _parameters[new XmlQualifiedName(name, namespaceUri)];
}
+ [RequiresUnreferencedCode(ExtensionObjectWarning)]
public object? GetExtensionObject(string namespaceUri)
{
return _extensions[namespaceUri];
@@ -43,6 +49,7 @@ public void AddParam(string name, string namespaceUri, object parameter)
_parameters.Add(qname, parameter);
}
+ [RequiresUnreferencedCode(ExtensionObjectWarning)]
public void AddExtensionObject(string namespaceUri, object extension)
{
CheckArgumentNull(namespaceUri, nameof(namespaceUri));
diff --git a/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj b/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj
index 2417558b7857..e099ac354b03 100644
--- a/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj
+++ b/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj
@@ -1,4 +1,4 @@
-
+trueen-US
@@ -15,9 +15,11 @@
+ Link="Common\Interop\Windows\Interop.Libraries.cs"
+ Condition="'$(TargetFramework)' != '$(NetCoreAppCurrent)' "/>
+ Link="Common\Interop\Windows\kernel32\Interop.ReadFile_SafeHandle_IntPtr.cs"
+ Condition="'$(TargetFramework)' != '$(NetCoreAppCurrent)' "/>
@@ -102,8 +104,9 @@
-
+
+
diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/MemoryBlocks/StreamMemoryBlockProvider.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/MemoryBlocks/StreamMemoryBlockProvider.cs
index 7581e90f0cb4..1c9f68da95e0 100644
--- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/MemoryBlocks/StreamMemoryBlockProvider.cs
+++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/MemoryBlocks/StreamMemoryBlockProvider.cs
@@ -76,9 +76,11 @@ internal static unsafe NativeHeapMemoryBlock ReadMemoryBlockNoLock(Stream stream
{
stream.Seek(start, SeekOrigin.Begin);
- if (!isFileStream || !FileStreamReadLightUp.TryReadFile(stream, block.Pointer, start, size))
+ int bytesRead = 0;
+
+ if (!isFileStream || (bytesRead = FileStreamReadLightUp.ReadFile(stream, block.Pointer, size)) != size)
{
- stream.CopyTo(block.Pointer, size);
+ stream.CopyTo(block.Pointer + bytesRead, size - bytesRead);
}
fault = false;
diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/FileStreamReadLightUp.netcoreapp.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/FileStreamReadLightUp.netcoreapp.cs
new file mode 100644
index 000000000000..aabc6739c715
--- /dev/null
+++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/FileStreamReadLightUp.netcoreapp.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.IO;
+
+namespace System.Reflection.Internal
+{
+ internal static class FileStreamReadLightUp
+ {
+ internal static bool IsFileStream(Stream stream) => stream is FileStream;
+
+ internal static unsafe int ReadFile(Stream stream, byte* buffer, int size)
+ => stream.Read(new Span(buffer, size));
+ }
+}
diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/FileStreamReadLightUp.netstandard1.1.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/FileStreamReadLightUp.netstandard1.1.cs
index 1bcc69e7a54c..774def66573f 100644
--- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/FileStreamReadLightUp.netstandard1.1.cs
+++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/FileStreamReadLightUp.netstandard1.1.cs
@@ -86,43 +86,29 @@ internal static SafeHandle GetSafeFileHandle(Stream stream)
return handle;
}
- internal static unsafe bool TryReadFile(Stream stream, byte* buffer, long start, int size)
+ internal static unsafe int ReadFile(Stream stream, byte* buffer, int size)
{
if (readFileNotAvailable)
{
- return false;
+ return 0;
}
SafeHandle handle = GetSafeFileHandle(stream);
if (handle == null)
{
- return false;
+ return 0;
}
- int result;
- int bytesRead;
-
try
{
- result = Interop.Kernel32.ReadFile(handle, buffer, size, out bytesRead, IntPtr.Zero);
+ int result = Interop.Kernel32.ReadFile(handle, buffer, size, out int bytesRead, IntPtr.Zero);
+ return result == 0 ? 0 : bytesRead;
}
catch
{
readFileNotAvailable = true;
- return false;
+ return 0;
}
-
- if (result == 0 || bytesRead != size)
- {
- // We used to throw here, but this is where we land if the FileStream was
- // opened with useAsync: true, which is currently the default on .NET Core.
- // https://github.com/dotnet/corefx/pull/987 filed to look in to how best to
- // handle this, but in the meantime, we'll fall back to the slower code path
- // just as in the case where the native API is unavailable in the current platform.
- return false;
- }
-
- return true;
}
}
}
diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/FileStreamReadLightUp.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/FileStreamReadLightUp.netstandard2.0.cs
similarity index 61%
rename from src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/FileStreamReadLightUp.cs
rename to src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/FileStreamReadLightUp.netstandard2.0.cs
index f64be71469b1..2416a723f6c0 100644
--- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/FileStreamReadLightUp.cs
+++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/FileStreamReadLightUp.netstandard2.0.cs
@@ -1,7 +1,6 @@
// 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.IO;
using System.Runtime.InteropServices;
@@ -9,12 +8,7 @@ namespace System.Reflection.Internal
{
internal static class FileStreamReadLightUp
{
- private static bool IsReadFileAvailable =>
-#if NETCOREAPP
- OperatingSystem.IsWindows();
-#else
- Path.DirectorySeparatorChar == '\\';
-#endif
+ private static bool IsReadFileAvailable => Path.DirectorySeparatorChar == '\\';
internal static bool IsFileStream(Stream stream) => stream is FileStream;
@@ -42,32 +36,21 @@ internal static class FileStreamReadLightUp
return handle;
}
- internal static unsafe bool TryReadFile(Stream stream, byte* buffer, long start, int size)
+ internal static unsafe int ReadFile(Stream stream, byte* buffer, int size)
{
if (!IsReadFileAvailable)
{
- return false;
+ return 0;
}
SafeHandle? handle = GetSafeFileHandle(stream);
if (handle == null)
{
- return false;
+ return 0;
}
int result = Interop.Kernel32.ReadFile(handle, buffer, size, out int bytesRead, IntPtr.Zero);
-
- if (result == 0 || bytesRead != size)
- {
- // We used to throw here, but this is where we land if the FileStream was
- // opened with useAsync: true, which is currently the default on .NET Core.
- // https://github.com/dotnet/corefx/pull/987 filed to look in to how best to
- // handle this, but in the meantime, we'll fall back to the slower code path
- // just as in the case where the native API is unavailable in the current platform.
- return false;
- }
-
- return true;
+ return result == 0 ? 0 : bytesRead;
}
}
}
diff --git a/src/libraries/System.Reflection/tests/System.Reflection.Tests.csproj b/src/libraries/System.Reflection/tests/System.Reflection.Tests.csproj
index 5b4ff2785839..deceb65e37f3 100644
--- a/src/libraries/System.Reflection/tests/System.Reflection.Tests.csproj
+++ b/src/libraries/System.Reflection/tests/System.Reflection.Tests.csproj
@@ -71,4 +71,8 @@
+
+
+ <__ExcludeFromBundle Include="TestAssembly.dll" />
+
diff --git a/src/libraries/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.il b/src/libraries/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.il
index c746a05cfab9..f7d5718f456a 100644
--- a/src/libraries/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.il
+++ b/src/libraries/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.il
@@ -28,6 +28,10 @@
01 00 0b 53 65 72 76 69 63 65 61 62 6c 65 04 54
72 75 65 00 00
) // "Serviceable", "True"
+ .custom instance void [CORE_ASSEMBLY]System.Reflection.AssemblyMetadataAttribute::.ctor(string, string) = (
+ 01 00 0b 49 73 54 72 69 6d 6d 61 62 6c 65 04 54
+ 72 75 65 00 00
+ ) // "IsTrimmable", "True"
.custom instance void [CORE_ASSEMBLY]System.Reflection.AssemblyCopyrightAttribute::.ctor(string) = ( 01 00 2F C2 A9 20 4D 69 63 72 6F 73 6F 66 74 20 // ../.. Microsoft
43 6F 72 70 6F 72 61 74 69 6F 6E 2E 20 20 41 6C // Corporation. Al
6C 20 72 69 67 68 74 73 20 72 65 73 65 72 76 65 // l rights reserve
diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/System.Runtime.Serialization.Xml.Tests.csproj b/src/libraries/System.Runtime.Serialization.Xml/tests/System.Runtime.Serialization.Xml.Tests.csproj
index 3080bd813ac9..3992b33bcfa3 100644
--- a/src/libraries/System.Runtime.Serialization.Xml/tests/System.Runtime.Serialization.Xml.Tests.csproj
+++ b/src/libraries/System.Runtime.Serialization.Xml/tests/System.Runtime.Serialization.Xml.Tests.csproj
@@ -15,10 +15,8 @@
-
-
+
+
@@ -29,6 +27,7 @@
+
diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/XmlSerializerTests.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/XmlSerializerTests.cs
new file mode 100644
index 000000000000..089e45de1131
--- /dev/null
+++ b/src/libraries/System.Runtime.Serialization.Xml/tests/XmlSerializerTests.cs
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.IO;
+using System.Xml;
+using System.Xml.Serialization;
+using Xunit;
+
+public static class XmlSerializerTests
+{
+
+ public const string FakeNS = "http://example.com/XmlSerializerTests";
+
+ [Fact]
+ public static void FlagEnums_With_Different_Namespaces()
+ {
+ StringWriter sw = new StringWriter();
+ XmlTextWriter xml = new XmlTextWriter(sw);
+
+ TwoClasses twoClasses = new TwoClasses
+ {
+ First = new FirstClass { TestingEnumValues = TestEnum.First },
+ Second = new SecondClass { TestingEnumValues = TestEnum.Second }
+ };
+
+ // 43675 - This line throws with inconsistent Flag.type/namespace usage
+ XmlSerializer ser = new XmlSerializer(typeof(TwoClasses));
+
+ ser.Serialize(xml, twoClasses);
+ string s = sw.ToString();
+
+ Assert.Contains("enumtest", s);
+ }
+
+ [Flags]
+ public enum TestEnum
+ {
+ First = 1,
+ Second = 2
+ }
+
+ public class FirstClass
+ {
+ [XmlAttribute("enumtest")]
+ public TestEnum TestingEnumValues;
+ }
+
+ public class SecondClass
+ {
+ [XmlAttribute("enumtest", Namespace = XmlSerializerTests.FakeNS)]
+ public TestEnum TestingEnumValues;
+ }
+
+ public class TwoClasses
+ {
+ public TwoClasses() { }
+
+ [XmlElement("first")]
+ public FirstClass First;
+
+ [XmlElement("second", Namespace = XmlSerializerTests.FakeNS)]
+ public SecondClass Second;
+ }
+
+}
diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs
index ef66619698d1..0bfd76c940dc 100644
--- a/src/libraries/System.Runtime/ref/System.Runtime.cs
+++ b/src/libraries/System.Runtime/ref/System.Runtime.cs
@@ -3699,6 +3699,8 @@ protected StringComparer() { }
public static System.StringComparer FromComparison(System.StringComparison comparisonType) { throw null; }
public int GetHashCode(object obj) { throw null; }
public abstract int GetHashCode(string obj);
+ public static bool IsWellKnownCultureAwareComparer(System.Collections.Generic.IEqualityComparer? comparer, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Globalization.CompareInfo? compareInfo, out System.Globalization.CompareOptions compareOptions) { throw null; }
+ public static bool IsWellKnownOrdinalComparer(System.Collections.Generic.IEqualityComparer? comparer, out bool ignoreCase) { throw null; }
}
public enum StringComparison
{
@@ -9114,7 +9116,7 @@ public sealed partial class AsyncIteratorStateMachineAttribute : System.Runtime.
{
public AsyncIteratorStateMachineAttribute(System.Type stateMachineType) : base (default(System.Type)) { }
}
- [System.AttributeUsageAttribute(System.AttributeTargets.Class | System.AttributeTargets.Delegate | System.AttributeTargets.Enum | System.AttributeTargets.Interface | System.AttributeTargets.Struct, Inherited=false, AllowMultiple=false)]
+ [System.AttributeUsageAttribute(System.AttributeTargets.Class | System.AttributeTargets.Delegate | System.AttributeTargets.Enum | System.AttributeTargets.Interface | System.AttributeTargets.Method | System.AttributeTargets.Struct, Inherited=false, AllowMultiple=false)]
public sealed partial class AsyncMethodBuilderAttribute : System.Attribute
{
public AsyncMethodBuilderAttribute(System.Type builderType) { }
@@ -9524,6 +9526,33 @@ public sealed partial class ModuleInitializerAttribute : System.Attribute
{
public ModuleInitializerAttribute() { }
}
+ public partial struct PoolingAsyncValueTaskMethodBuilder
+ {
+ private object _dummy;
+ private int _dummyPrimitive;
+ public System.Threading.Tasks.ValueTask Task { get { throw null; } }
+ public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : System.Runtime.CompilerServices.INotifyCompletion where TStateMachine : System.Runtime.CompilerServices.IAsyncStateMachine { }
+ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : System.Runtime.CompilerServices.ICriticalNotifyCompletion where TStateMachine : System.Runtime.CompilerServices.IAsyncStateMachine { }
+ public static System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder Create() { throw null; }
+ public void SetException(System.Exception exception) { }
+ public void SetResult() { }
+ public void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine stateMachine) { }
+ public void Start(ref TStateMachine stateMachine) where TStateMachine : System.Runtime.CompilerServices.IAsyncStateMachine { }
+ }
+ public partial struct PoolingAsyncValueTaskMethodBuilder
+ {
+ private TResult _result;
+ private object _dummy;
+ private int _dummyPrimitive;
+ public System.Threading.Tasks.ValueTask Task { get { throw null; } }
+ public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : System.Runtime.CompilerServices.INotifyCompletion where TStateMachine : System.Runtime.CompilerServices.IAsyncStateMachine { }
+ public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : System.Runtime.CompilerServices.ICriticalNotifyCompletion where TStateMachine : System.Runtime.CompilerServices.IAsyncStateMachine { }
+ public static System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder Create() { throw null; }
+ public void SetException(System.Exception exception) { }
+ public void SetResult(TResult result) { }
+ public void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine stateMachine) { }
+ public void Start(ref TStateMachine stateMachine) where TStateMachine : System.Runtime.CompilerServices.IAsyncStateMachine { }
+ }
[System.AttributeUsageAttribute(System.AttributeTargets.Method, AllowMultiple=false, Inherited=false)]
public sealed partial class PreserveBaseOverridesAttribute : System.Attribute
{
@@ -9753,6 +9782,7 @@ internal ExceptionDispatchInfo() { }
public System.Exception SourceException { get { throw null; } }
public static System.Runtime.ExceptionServices.ExceptionDispatchInfo Capture(System.Exception source) { throw null; }
public static System.Exception SetCurrentStackTrace(System.Exception source) { throw null; }
+ public static System.Exception SetRemoteStackTrace(System.Exception source, string stackTrace) { throw null; }
[System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute]
public void Throw() => throw null;
[System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute]
@@ -11020,6 +11050,7 @@ public void CancelAfter(System.TimeSpan delay) { }
public static System.Threading.CancellationTokenSource CreateLinkedTokenSource(params System.Threading.CancellationToken[] tokens) { throw null; }
public void Dispose() { }
protected virtual void Dispose(bool disposing) { }
+ public bool TryReset() { throw null; }
}
public enum LazyThreadSafetyMode
{
diff --git a/src/libraries/System.Runtime/tests/System/ActivatorTests.Generic.cs b/src/libraries/System.Runtime/tests/System/ActivatorTests.Generic.cs
index 2ba5c521ae87..1593cd0936ed 100644
--- a/src/libraries/System.Runtime/tests/System/ActivatorTests.Generic.cs
+++ b/src/libraries/System.Runtime/tests/System/ActivatorTests.Generic.cs
@@ -53,7 +53,7 @@ public void CreateInstanceT_StructWithPrivateDefaultConstructor_ThrowsMissingMet
Assert.Throws(() => Activator.CreateInstance());
[Fact]
- public void CreateInstanceT_StructWithoutDefaultConstructor_ThrowsMissingMethodException() =>
+ public void CreateInstanceT_StructWithoutDefaultConstructor_InvokesConstructor() =>
Activator.CreateInstance();
[Fact]
diff --git a/src/libraries/System.Runtime/tests/System/ExceptionTests.cs b/src/libraries/System.Runtime/tests/System/ExceptionTests.cs
index 3bec61d7f73a..fb83278ab318 100644
--- a/src/libraries/System.Runtime/tests/System/ExceptionTests.cs
+++ b/src/libraries/System.Runtime/tests/System/ExceptionTests.cs
@@ -61,7 +61,7 @@ public static void Exception_GetBaseException()
}
[Fact]
- public static void Exception_TargetSite_Jit()
+ public static void Exception_TargetSite()
{
bool caught = false;
@@ -78,6 +78,32 @@ public static void Exception_TargetSite_Jit()
Assert.True(caught);
}
+
+ static void RethrowException()
+ {
+ try
+ {
+ ThrowException();
+ }
+ catch
+ {
+ throw;
+ }
+ }
+
+ [Fact]
+ public static void Exception_TargetSite_OtherMethod()
+ {
+ Exception ex = Assert.ThrowsAny(() => ThrowException());
+ Assert.Equal(nameof(ThrowException), ex.TargetSite.Name);
+ }
+
+ [Fact]
+ public static void Exception_TargetSite_Rethrow()
+ {
+ Exception ex = Assert.ThrowsAny(() => RethrowException());
+ Assert.Equal(nameof(ThrowException), ex.TargetSite.Name);
+ }
[Fact]
[ActiveIssue("https://github.com/mono/mono/issues/15140", TestRuntimes.Mono)]
diff --git a/src/libraries/System.Runtime/tests/System/Runtime/ExceptionServices/ExceptionDispatchInfoTests.cs b/src/libraries/System.Runtime/tests/System/Runtime/ExceptionServices/ExceptionDispatchInfoTests.cs
index 820eceed5b36..e293a1814f29 100644
--- a/src/libraries/System.Runtime/tests/System/Runtime/ExceptionServices/ExceptionDispatchInfoTests.cs
+++ b/src/libraries/System.Runtime/tests/System/Runtime/ExceptionServices/ExceptionDispatchInfoTests.cs
@@ -1,7 +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.ComponentModel;
+using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
using Xunit;
@@ -29,40 +29,59 @@ public static void StaticThrow_UpdatesStackTraceAppropriately()
}
[Fact]
- [ActiveIssue("https://github.com/dotnet/runtimelab/issues/831" /* NativeAot */)]
- public static void SetCurrentStackTrace_Invalid_Throws()
+ public static void SetCurrentOrRemoteStackTrace_Invalid_Throws()
{
Exception e;
// Null argument
e = null;
AssertExtensions.Throws("source", () => ExceptionDispatchInfo.SetCurrentStackTrace(e));
+ AssertExtensions.Throws("source", () => ExceptionDispatchInfo.SetRemoteStackTrace(e, "Hello"));
+ AssertExtensions.Throws("stackTrace", () => ExceptionDispatchInfo.SetRemoteStackTrace(new Exception(), stackTrace: null));
// Previously set current stack
e = new Exception();
ExceptionDispatchInfo.SetCurrentStackTrace(e);
Assert.Throws(() => ExceptionDispatchInfo.SetCurrentStackTrace(e));
+ Assert.Throws(() => ExceptionDispatchInfo.SetRemoteStackTrace(e, "Hello"));
// Previously thrown
e = new Exception();
try { throw e; } catch { }
Assert.Throws(() => ExceptionDispatchInfo.SetCurrentStackTrace(e));
+ Assert.Throws(() => ExceptionDispatchInfo.SetRemoteStackTrace(e, "Hello"));
}
[Fact]
- [ActiveIssue("https://github.com/dotnet/runtimelab/issues/831" /* NativeAot */)]
public static void SetCurrentStackTrace_IncludedInExceptionStackTrace()
{
Exception e;
e = new Exception();
ABCDEFGHIJKLMNOPQRSTUVWXYZ(e);
- Assert.Contains(nameof(ABCDEFGHIJKLMNOPQRSTUVWXYZ), e.StackTrace);
+ Assert.Contains(nameof(ABCDEFGHIJKLMNOPQRSTUVWXYZ), e.StackTrace, StringComparison.Ordinal);
e = new Exception();
ABCDEFGHIJKLMNOPQRSTUVWXYZ(e);
try { throw e; } catch { }
- Assert.Contains(nameof(ABCDEFGHIJKLMNOPQRSTUVWXYZ), e.StackTrace);
+ Assert.Contains(nameof(ABCDEFGHIJKLMNOPQRSTUVWXYZ), e.StackTrace, StringComparison.Ordinal);
+ }
+
+ [Fact]
+ public static void SetRemoteStackTrace_IncludedInExceptionStackTrace()
+ {
+ Exception e;
+
+ e = new Exception();
+ Assert.Same(e, ExceptionDispatchInfo.SetRemoteStackTrace(e, "pumpkin-anaconda-maritime")); // 3 randomly selected words
+ Assert.Contains("pumpkin-anaconda-maritime", e.StackTrace, StringComparison.Ordinal);
+ Assert.DoesNotContain("pumpkin-anaconda-maritime", new StackTrace(e).ToString(), StringComparison.Ordinal); // we shouldn't attempt to parse it in a StackTrace object
+
+ e = new Exception();
+ Assert.Same(e, ExceptionDispatchInfo.SetRemoteStackTrace(e, "pumpkin-anaconda-maritime"));
+ try { throw e; } catch { }
+ Assert.Contains("pumpkin-anaconda-maritime", e.StackTrace, StringComparison.Ordinal);
+ Assert.DoesNotContain("pumpkin-anaconda-maritime", new StackTrace(e).ToString(), StringComparison.Ordinal);
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
diff --git a/src/libraries/System.Runtime/tests/System/StringComparerTests.cs b/src/libraries/System.Runtime/tests/System/StringComparerTests.cs
index 364ecdfb2602..3027c870855b 100644
--- a/src/libraries/System.Runtime/tests/System/StringComparerTests.cs
+++ b/src/libraries/System.Runtime/tests/System/StringComparerTests.cs
@@ -1,7 +1,9 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Collections.Generic;
using System.Globalization;
+using System.Reflection;
using Xunit;
namespace System.Tests
@@ -135,5 +137,116 @@ public void CreateCultureOptions_CreatesValidComparer()
Assert.Equal(1, c.Compare("42", null));
Assert.Throws(() => c.Compare(42, "84"));
}
+
+ [Fact]
+ public void IsWellKnownOrdinalComparer_TestCases()
+ {
+ CompareInfo ci_enUS = CompareInfo.GetCompareInfo("en-US");
+
+ // First, instantiate and test the comparers directly
+
+ RunTest(null, false, false);
+ RunTest(EqualityComparer.Default, true, false); // EC.Default is Ordinal-equivalent
+ RunTest(EqualityComparer.Default, false, false); // EC.Default isn't a string comparer
+ RunTest(StringComparer.Ordinal, true, false);
+ RunTest(StringComparer.OrdinalIgnoreCase, true, true);
+ RunTest(StringComparer.InvariantCulture, false, false); // not ordinal
+ RunTest(StringComparer.InvariantCultureIgnoreCase, false, false); // not ordinal
+ RunTest(GetNonRandomizedComparer("WrappedAroundDefaultComparer"), true, false); // EC.Default is Ordinal-equivalent
+ RunTest(GetNonRandomizedComparer("WrappedAroundStringComparerOrdinal"), true, false);
+ RunTest(GetNonRandomizedComparer("WrappedAroundStringComparerOrdinalIgnoreCase"), true, true);
+ RunTest(new CustomStringComparer(), false, false); // not an inbox comparer
+ RunTest(ci_enUS.GetStringComparer(CompareOptions.None), false, false); // linguistic
+ RunTest(ci_enUS.GetStringComparer(CompareOptions.Ordinal), true, false);
+ RunTest(ci_enUS.GetStringComparer(CompareOptions.OrdinalIgnoreCase), true, true);
+
+ // Then, make sure that this API works with common collection types
+
+ RunTest(new Dictionary().Comparer, true, false);
+ RunTest(new Dictionary(StringComparer.Ordinal).Comparer, true, false);
+ RunTest(new Dictionary(StringComparer.OrdinalIgnoreCase).Comparer, true, true);
+ RunTest(new Dictionary(StringComparer.InvariantCulture).Comparer, false, false);
+ RunTest(new Dictionary(StringComparer.InvariantCultureIgnoreCase).Comparer, false, false);
+
+ RunTest(new HashSet().Comparer, true, false);
+ RunTest(new HashSet(StringComparer.Ordinal).Comparer, true, false);
+ RunTest(new HashSet(StringComparer.OrdinalIgnoreCase).Comparer, true, true);
+ RunTest(new HashSet(StringComparer.InvariantCulture).Comparer, false, false);
+ RunTest(new HashSet(StringComparer.InvariantCultureIgnoreCase).Comparer, false, false);
+
+ static void RunTest(IEqualityComparer comparer, bool expectedIsOrdinal, bool expectedIgnoreCase)
+ {
+ Assert.Equal(expectedIsOrdinal, StringComparer.IsWellKnownOrdinalComparer(comparer, out bool actualIgnoreCase));
+ Assert.Equal(expectedIgnoreCase, actualIgnoreCase);
+ }
+ }
+
+ [Fact]
+ public void IsWellKnownCultureAwareComparer_TestCases()
+ {
+ CompareInfo ci_enUS = CompareInfo.GetCompareInfo("en-US");
+ CompareInfo ci_inv = CultureInfo.InvariantCulture.CompareInfo;
+
+ // First, instantiate and test the comparers directly
+
+ RunTest(null, null, default);
+ RunTest(EqualityComparer.Default, null, default); // EC.Default is not culture-aware
+ RunTest(EqualityComparer.Default, null, default); // EC.Default isn't a string comparer
+ RunTest(StringComparer.Ordinal, null, default);
+ RunTest(StringComparer.OrdinalIgnoreCase, null, default);
+ RunTest(StringComparer.InvariantCulture, ci_inv, CompareOptions.None);
+ RunTest(StringComparer.InvariantCultureIgnoreCase, ci_inv, CompareOptions.IgnoreCase);
+ RunTest(GetNonRandomizedComparer("WrappedAroundDefaultComparer"), null, default); // EC.Default is Ordinal-equivalent
+ RunTest(GetNonRandomizedComparer("WrappedAroundStringComparerOrdinal"), null, default);
+ RunTest(GetNonRandomizedComparer("WrappedAroundStringComparerOrdinalIgnoreCase"), null, default);
+ RunTest(new CustomStringComparer(), null, default); // not an inbox comparer
+ RunTest(ci_enUS.GetStringComparer(CompareOptions.None), ci_enUS, CompareOptions.None);
+ RunTest(ci_enUS.GetStringComparer(CompareOptions.IgnoreCase | CompareOptions.IgnoreKanaType), ci_enUS, CompareOptions.IgnoreCase | CompareOptions.IgnoreKanaType);
+ RunTest(ci_enUS.GetStringComparer(CompareOptions.Ordinal), null, default); // not linguistic
+ RunTest(ci_enUS.GetStringComparer(CompareOptions.OrdinalIgnoreCase), null, default); // not linguistic
+ RunTest(StringComparer.Create(CultureInfo.InvariantCulture, false), ci_inv, CompareOptions.None);
+ RunTest(StringComparer.Create(CultureInfo.InvariantCulture, true), ci_inv, CompareOptions.IgnoreCase);
+ RunTest(StringComparer.Create(CultureInfo.InvariantCulture, CompareOptions.IgnoreSymbols), ci_inv, CompareOptions.IgnoreSymbols);
+
+ // Then, make sure that this API works with common collection types
+
+ RunTest(new Dictionary().Comparer, null, default);
+ RunTest(new Dictionary(StringComparer.Ordinal).Comparer, null, default);
+ RunTest(new Dictionary(StringComparer.OrdinalIgnoreCase).Comparer, null, default);
+ RunTest(new Dictionary(StringComparer.InvariantCulture).Comparer, ci_inv, CompareOptions.None);
+ RunTest(new Dictionary(StringComparer.InvariantCultureIgnoreCase).Comparer, ci_inv, CompareOptions.IgnoreCase);
+
+ RunTest(new HashSet().Comparer, null, default);
+ RunTest(new HashSet(StringComparer.Ordinal).Comparer, null, default);
+ RunTest(new HashSet(StringComparer.OrdinalIgnoreCase).Comparer, null, default);
+ RunTest(new HashSet(StringComparer.InvariantCulture).Comparer, ci_inv, CompareOptions.None);
+ RunTest(new HashSet(StringComparer.InvariantCultureIgnoreCase).Comparer, ci_inv, CompareOptions.IgnoreCase);
+
+ static void RunTest(IEqualityComparer comparer, CompareInfo expectedCompareInfo, CompareOptions expectedCompareOptions)
+ {
+ bool actualReturnValue = StringComparer.IsWellKnownCultureAwareComparer(comparer, out CompareInfo actualCompareInfo, out CompareOptions actualCompareOptions);
+ Assert.Equal(expectedCompareInfo != null, actualReturnValue);
+ Assert.Equal(expectedCompareInfo, actualCompareInfo);
+ Assert.Equal(expectedCompareOptions, actualCompareOptions);
+ }
+ }
+
+ private static IEqualityComparer GetNonRandomizedComparer(string name)
+ {
+ Type nonRandomizedComparerType = typeof(StringComparer).Assembly.GetType("System.Collections.Generic.NonRandomizedStringEqualityComparer");
+ Assert.NotNull(nonRandomizedComparerType);
+
+ FieldInfo fi = nonRandomizedComparerType.GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
+ Assert.NotNull(fi);
+
+ return (IEqualityComparer)fi.GetValue(null);
+ }
+
+ private class CustomStringComparer : StringComparer
+ {
+ public override int Compare(string x, string y) => throw new NotImplementedException();
+ public override bool Equals(string x, string y) => throw new NotImplementedException();
+ public override int GetHashCode(string obj) => throw new NotImplementedException();
+ }
}
}
diff --git a/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs b/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs
index 05ae478a9d54..0e8390632acf 100644
--- a/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs
+++ b/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs
@@ -2469,7 +2469,7 @@ public static void GetSystemTimeZones_AllTimeZonesHaveOffsetInValidRange()
[InlineData("<+00>0<+01>,A/0,J365/25", 0, 0, false)]
public static void NJulianRuleTest(string posixRule, int dayNumber, int monthNumber, bool shouldSucceed)
{
- string zoneFilePath = Path.GetTempPath() + "dotnet_tz";
+ string zoneFilePath = Path.GetTempPath() + Path.GetRandomFileName();
using (FileStream fs = new FileStream(zoneFilePath, FileMode.Create))
{
fs.Write(timeZoneFileContents.AsSpan());
diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSigner.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSigner.cs
index d3d1cc650e85..fbe270792bc8 100644
--- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSigner.cs
+++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSigner.cs
@@ -258,6 +258,7 @@ internal SignerInfoAsn Sign(
X509Chain chain = new X509Chain();
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;
+ chain.ChainPolicy.VerificationTime = Certificate!.NotBefore;
if (!chain.Build(Certificate!))
{
@@ -265,7 +266,18 @@ internal SignerInfoAsn Sign(
{
if (status.Status == X509ChainStatusFlags.PartialChain)
{
- throw new CryptographicException(SR.Cryptography_Cms_IncompleteCertChain);
+ if (chain.ChainElements.Count == 0)
+ {
+ // On Android, we will fail with PartialChain to build a cert chain
+ // even if the failure is an untrusted root cert since the underlying platform
+ // does not provide a way to distinguish the failure.
+ // In that case, just use the provided cert.
+ certs.Add(Certificate!);
+ }
+ else
+ {
+ throw new CryptographicException(SR.Cryptography_Cms_IncompleteCertChain);
+ }
}
}
}
diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/Native/Helpers.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/Native/Helpers.cs
index 5a7b3ea8ef3e..afec7590d3e9 100644
--- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/Native/Helpers.cs
+++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/Native/Helpers.cs
@@ -2,10 +2,10 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System;
-using System.Text;
using System.Diagnostics;
-using System.Security.Cryptography;
using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Text;
namespace Internal.Cryptography.Pal.Native
{
@@ -73,11 +73,12 @@ public static byte[] ValueAsAscii(this Oid oid)
}
public unsafe delegate void DecodedObjectReceiver(void* pvDecodedObject, int cbDecodedObject);
+ public unsafe delegate TResult DecodedObjectReceiver(void* pvDecodedObject, int cbDecodedObject);
- public static void DecodeObject(
+ public static TResult DecodeObject(
this byte[] encoded,
CryptDecodeObjectStructType lpszStructType,
- DecodedObjectReceiver receiver)
+ DecodedObjectReceiver receiver)
{
unsafe
{
@@ -109,14 +110,14 @@ public static void DecodeObject(
throw Marshal.GetLastWin32Error().ToCryptographicException();
}
- receiver(decoded, cb);
+ return receiver(decoded, cb);
}
}
- public static void DecodeObject(
+ public static TResult DecodeObject(
this byte[] encoded,
string lpszStructType,
- DecodedObjectReceiver receiver)
+ DecodedObjectReceiver receiver)
{
unsafe
{
@@ -148,7 +149,7 @@ public static void DecodeObject(
throw Marshal.GetLastWin32Error().ToCryptographicException();
}
- receiver(decoded, cb);
+ return receiver(decoded, cb);
}
}
diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/X509Pal.CustomExtensions.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/X509Pal.CustomExtensions.cs
index 57883ba6d909..f7f1c5a5ebb2 100644
--- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/X509Pal.CustomExtensions.cs
+++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/X509Pal.CustomExtensions.cs
@@ -41,14 +41,12 @@ public void DecodeX509KeyUsageExtension(byte[] encoded, out X509KeyUsageFlags ke
{
unsafe
{
- uint keyUsagesAsUint = 0;
- encoded.DecodeObject(
+ uint keyUsagesAsUint = encoded.DecodeObject(
CryptDecodeObjectStructType.X509_KEY_USAGE,
- delegate (void* pvDecoded, int cbDecoded)
+ static delegate (void* pvDecoded, int cbDecoded)
{
Debug.Assert(cbDecoded >= sizeof(CRYPT_BIT_BLOB));
CRYPT_BIT_BLOB* pBlob = (CRYPT_BIT_BLOB*)pvDecoded;
- keyUsagesAsUint = 0;
byte* pbData = pBlob->pbData;
if (pbData != null)
@@ -58,13 +56,13 @@ public void DecodeX509KeyUsageExtension(byte[] encoded, out X509KeyUsageFlags ke
switch (pBlob->cbData)
{
case 1:
- keyUsagesAsUint = *pbData;
- break;
+ return *pbData;
case 2:
- keyUsagesAsUint = *(ushort*)(pbData);
- break;
+ return *(ushort*)(pbData);
}
}
+
+ return 0u;
}
);
keyUsages = (X509KeyUsageFlags)keyUsagesAsUint;
@@ -95,25 +93,16 @@ public void DecodeX509BasicConstraintsExtension(byte[] encoded, out bool certifi
{
unsafe
{
- bool localCertificateAuthority = false;
- bool localHasPathLengthConstraint = false;
- int localPathLengthConstraint = 0;
-
- encoded.DecodeObject(
+ (certificateAuthority, hasPathLengthConstraint, pathLengthConstraint) = encoded.DecodeObject(
CryptDecodeObjectStructType.X509_BASIC_CONSTRAINTS,
- delegate (void* pvDecoded, int cbDecoded)
+ static delegate (void* pvDecoded, int cbDecoded)
{
Debug.Assert(cbDecoded >= sizeof(CERT_BASIC_CONSTRAINTS_INFO));
CERT_BASIC_CONSTRAINTS_INFO* pBasicConstraints = (CERT_BASIC_CONSTRAINTS_INFO*)pvDecoded;
- localCertificateAuthority = (pBasicConstraints->SubjectType.pbData[0] & CERT_BASIC_CONSTRAINTS_INFO.CERT_CA_SUBJECT_FLAG) != 0;
- localHasPathLengthConstraint = pBasicConstraints->fPathLenConstraint != 0;
- localPathLengthConstraint = pBasicConstraints->dwPathLenConstraint;
- }
- );
-
- certificateAuthority = localCertificateAuthority;
- hasPathLengthConstraint = localHasPathLengthConstraint;
- pathLengthConstraint = localPathLengthConstraint;
+ return ((pBasicConstraints->SubjectType.pbData[0] & CERT_BASIC_CONSTRAINTS_INFO.CERT_CA_SUBJECT_FLAG) != 0,
+ pBasicConstraints->fPathLenConstraint != 0,
+ pBasicConstraints->dwPathLenConstraint);
+ });
}
}
@@ -121,25 +110,16 @@ public void DecodeX509BasicConstraints2Extension(byte[] encoded, out bool certif
{
unsafe
{
- bool localCertificateAuthority = false;
- bool localHasPathLengthConstraint = false;
- int localPathLengthConstraint = 0;
-
- encoded.DecodeObject(
+ (certificateAuthority, hasPathLengthConstraint, pathLengthConstraint) = encoded.DecodeObject(
CryptDecodeObjectStructType.X509_BASIC_CONSTRAINTS2,
- delegate (void* pvDecoded, int cbDecoded)
+ static delegate (void* pvDecoded, int cbDecoded)
{
Debug.Assert(cbDecoded >= sizeof(CERT_BASIC_CONSTRAINTS2_INFO));
CERT_BASIC_CONSTRAINTS2_INFO* pBasicConstraints2 = (CERT_BASIC_CONSTRAINTS2_INFO*)pvDecoded;
- localCertificateAuthority = pBasicConstraints2->fCA != 0;
- localHasPathLengthConstraint = pBasicConstraints2->fPathLenConstraint != 0;
- localPathLengthConstraint = pBasicConstraints2->dwPathLenConstraint;
- }
- );
-
- certificateAuthority = localCertificateAuthority;
- hasPathLengthConstraint = localHasPathLengthConstraint;
- pathLengthConstraint = localPathLengthConstraint;
+ return (pBasicConstraints2->fCA != 0,
+ pBasicConstraints2->fPathLenConstraint != 0,
+ pBasicConstraints2->dwPathLenConstraint);
+ });
}
}
@@ -163,14 +143,14 @@ public byte[] EncodeX509EnhancedKeyUsageExtension(OidCollection usages)
public void DecodeX509EnhancedKeyUsageExtension(byte[] encoded, out OidCollection usages)
{
- OidCollection localUsages = new OidCollection();
-
unsafe
{
- encoded.DecodeObject(
+ usages = encoded.DecodeObject(
CryptDecodeObjectStructType.X509_ENHANCED_KEY_USAGE,
- delegate (void* pvDecoded, int cbDecoded)
+ static delegate (void* pvDecoded, int cbDecoded)
{
+ var localUsages = new OidCollection();
+
Debug.Assert(cbDecoded >= sizeof(CERT_ENHKEY_USAGE));
CERT_ENHKEY_USAGE* pEnhKeyUsage = (CERT_ENHKEY_USAGE*)pvDecoded;
int count = pEnhKeyUsage->cUsageIdentifier;
@@ -181,11 +161,10 @@ public void DecodeX509EnhancedKeyUsageExtension(byte[] encoded, out OidCollectio
Oid oid = new Oid(oidValue);
localUsages.Add(oid);
}
- }
- );
- }
- usages = localUsages;
+ return localUsages;
+ });
+ }
}
public byte[] EncodeX509SubjectKeyIdentifierExtension(ReadOnlySpan subjectKeyIdentifier)
@@ -204,17 +183,14 @@ public void DecodeX509SubjectKeyIdentifierExtension(byte[] encoded, out byte[] s
{
unsafe
{
- byte[] localSubjectKeyIdentifier = null!;
- encoded.DecodeObject(
+ subjectKeyIdentifier = encoded.DecodeObject(
Oids.SubjectKeyIdentifier,
- delegate (void* pvDecoded, int cbDecoded)
+ static delegate (void* pvDecoded, int cbDecoded)
{
Debug.Assert(cbDecoded >= sizeof(CRYPTOAPI_BLOB));
CRYPTOAPI_BLOB* pBlob = (CRYPTOAPI_BLOB*)pvDecoded;
- localSubjectKeyIdentifier = pBlob->ToByteArray();
- }
- );
- subjectKeyIdentifier = localSubjectKeyIdentifier;
+ return pBlob->ToByteArray();
+ });
}
}
diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/X509Pal.PublicKey.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/X509Pal.PublicKey.cs
index dd11ea04d083..19bce7dfa75f 100644
--- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/X509Pal.PublicKey.cs
+++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/X509Pal.PublicKey.cs
@@ -283,46 +283,32 @@ private static byte[] ConstructDSSPublicKeyCspBlob(byte[] encodedKeyValue, byte[
{
unsafe
{
- byte[]? decodedKeyValue = null;
-
- encodedKeyValue.DecodeObject(
+ return encodedKeyValue.DecodeObject(
CryptDecodeObjectStructType.X509_DSS_PUBLICKEY,
- delegate (void* pvDecoded, int cbDecoded)
+ static delegate (void* pvDecoded, int cbDecoded)
{
Debug.Assert(cbDecoded >= sizeof(CRYPTOAPI_BLOB));
CRYPTOAPI_BLOB* pBlob = (CRYPTOAPI_BLOB*)pvDecoded;
- decodedKeyValue = pBlob->ToByteArray();
- }
- );
-
- return decodedKeyValue;
+ return pBlob->ToByteArray();
+ });
}
}
private static void DecodeDssParameters(byte[] encodedParameters, out byte[] p, out byte[] q, out byte[] g)
{
- byte[] pLocal = null!;
- byte[] qLocal = null!;
- byte[] gLocal = null!;
-
unsafe
{
- encodedParameters.DecodeObject(
+ (p, q, g) = encodedParameters.DecodeObject(
CryptDecodeObjectStructType.X509_DSS_PARAMETERS,
delegate (void* pvDecoded, int cbDecoded)
{
Debug.Assert(cbDecoded >= sizeof(CERT_DSS_PARAMETERS));
CERT_DSS_PARAMETERS* pCertDssParameters = (CERT_DSS_PARAMETERS*)pvDecoded;
- pLocal = pCertDssParameters->p.ToByteArray();
- qLocal = pCertDssParameters->q.ToByteArray();
- gLocal = pCertDssParameters->g.ToByteArray();
- }
- );
+ return (pCertDssParameters->p.ToByteArray(),
+ pCertDssParameters->q.ToByteArray(),
+ pCertDssParameters->g.ToByteArray());
+ });
}
-
- p = pLocal;
- q = qLocal;
- g = gLocal;
}
private static bool HasExplicitParameters(SafeBCryptKeyHandle bcryptHandle)
diff --git a/src/libraries/System.Text.Json/src/Resources/Strings.resx b/src/libraries/System.Text.Json/src/Resources/Strings.resx
index 217b5220ab1f..c6039fdeba14 100644
--- a/src/libraries/System.Text.Json/src/Resources/Strings.resx
+++ b/src/libraries/System.Text.Json/src/Resources/Strings.resx
@@ -554,4 +554,7 @@
Unable to assign 'null' to the property or field of type '{0}'.
-
+
+ The converter '{0}' cannot return an instance of JsonConverterFactory.
+
+
\ No newline at end of file
diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterFactory.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterFactory.cs
index 404ea47449c6..ed6f50c8591b 100644
--- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterFactory.cs
+++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterFactory.cs
@@ -65,6 +65,11 @@ internal JsonConverter GetConverterInternal(Type typeToConvert, JsonSerializerOp
ThrowHelper.ThrowInvalidOperationException_SerializerConverterFactoryReturnsNull(GetType());
}
+ if (converter is JsonConverterFactory)
+ {
+ ThrowHelper.ThrowInvalidOperationException_SerializerConverterFactoryReturnsJsonConverterFactorty(GetType());
+ }
+
return converter!;
}
diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs b/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs
index cee333582020..34868bbf4ede 100644
--- a/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs
+++ b/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs
@@ -188,6 +188,12 @@ public static void ThrowInvalidOperationException_SerializerConverterFactoryRetu
throw new InvalidOperationException(SR.Format(SR.SerializerConverterFactoryReturnsNull, converterType));
}
+ [DoesNotReturn]
+ public static void ThrowInvalidOperationException_SerializerConverterFactoryReturnsJsonConverterFactorty(Type converterType)
+ {
+ throw new InvalidOperationException(SR.Format(SR.SerializerConverterFactoryReturnsJsonConverterFactory, converterType));
+ }
+
[DoesNotReturn]
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowInvalidOperationException_MultiplePropertiesBindToConstructorParameters(
diff --git a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.BadConverters.cs b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.BadConverters.cs
index 4a6cf3dd4220..b62d8556a977 100644
--- a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.BadConverters.cs
+++ b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.BadConverters.cs
@@ -188,6 +188,28 @@ public static void ConverterThatReturnsNullFail()
Assert.Contains(typeof(ConverterFactoryThatReturnsNull).ToString(), ex.Message);
}
+ private class ConverterFactoryThatReturnsJsonConverterFactory : JsonConverterFactory
+ {
+ public override bool CanConvert(Type type) => true;
+
+ public override JsonConverter CreateConverter(Type type, JsonSerializerOptions options) => new ConverterFactoryThatReturnsJsonConverterFactory();
+ }
+
+ [Fact]
+ public static void CustomJsonConverterFactoryThatReturnsJsonConverterFactoryFail()
+ {
+ JsonSerializerOptions options = new()
+ {
+ Converters = { new ConverterFactoryThatReturnsJsonConverterFactory() }
+ };
+
+ InvalidOperationException ex = Assert.Throws(() => JsonSerializer.Serialize(1, options));
+ Assert.Contains(typeof(ConverterFactoryThatReturnsJsonConverterFactory).ToString(), ex.Message);
+
+ ex = Assert.Throws(() => JsonSerializer.Deserialize("1", options));
+ Assert.Contains(typeof(ConverterFactoryThatReturnsJsonConverterFactory).ToString(), ex.Message);
+ }
+
private class Level1
{
public Level1()
diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Replace.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Replace.cs
index f94730510072..b3dfbcb4ac57 100644
--- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Replace.cs
+++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Replace.cs
@@ -174,7 +174,7 @@ private static string Replace(MatchEvaluator evaluator, Regex regex, string inpu
if (!regex.RightToLeft)
{
- regex.Run(input, startat, ref state, (ref (SegmentStringBuilder segments, MatchEvaluator evaluator, int prevat, string input, int count) state, Match match) =>
+ regex.Run(input, startat, ref state, static (ref (SegmentStringBuilder segments, MatchEvaluator evaluator, int prevat, string input, int count) state, Match match) =>
{
state.segments.Add(state.input.AsMemory(state.prevat, match.Index - state.prevat));
state.prevat = match.Index + match.Length;
@@ -193,11 +193,11 @@ private static string Replace(MatchEvaluator evaluator, Regex regex, string inpu
{
state.prevat = input.Length;
- regex.Run(input, startat, ref state, (ref (SegmentStringBuilder segments, MatchEvaluator evaluator, int prevat, string input, int count) state, Match match) =>
+ regex.Run(input, startat, ref state, static (ref (SegmentStringBuilder segments, MatchEvaluator evaluator, int prevat, string input, int count) state, Match match) =>
{
state.segments.Add(state.input.AsMemory(match.Index + match.Length, state.prevat - match.Index - match.Length));
state.prevat = match.Index;
- state.segments.Add(evaluator(match).AsMemory());
+ state.segments.Add(state.evaluator(match).AsMemory());
return --state.count != 0;
}, reuseMatchObject: false);
diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Split.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Split.cs
index ac3c4b32fc88..f223c4e6ed97 100644
--- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Split.cs
+++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Split.cs
@@ -89,7 +89,7 @@ private static string[] Split(Regex regex, string input, int count, int startat)
if (!regex.RightToLeft)
{
- regex.Run(input, startat, ref state, (ref (List results, int prevat, string input, int count) state, Match match) =>
+ regex.Run(input, startat, ref state, static (ref (List results, int prevat, string input, int count) state, Match match) =>
{
state.results.Add(state.input.Substring(state.prevat, match.Index - state.prevat));
state.prevat = match.Index + match.Length;
@@ -117,7 +117,7 @@ private static string[] Split(Regex regex, string input, int count, int startat)
{
state.prevat = input.Length;
- regex.Run(input, startat, ref state, (ref (List results, int prevat, string input, int count) state, Match match) =>
+ regex.Run(input, startat, ref state, static (ref (List results, int prevat, string input, int count) state, Match match) =>
{
state.results.Add(state.input.Substring(match.Index + match.Length, state.prevat - match.Index - match.Length));
state.prevat = match.Index;
diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCharClass.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCharClass.cs
index 3dc776fe6047..a569614032f0 100644
--- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCharClass.cs
+++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCharClass.cs
@@ -547,7 +547,7 @@ public static string ConvertOldStringsToClass(string set, string category)
strLength -= 2;
}
- return string.Create(strLength, (set, category, startsWithNulls), (span, state) =>
+ return string.Create(strLength, (set, category, startsWithNulls), static (span, state) =>
{
int index;
diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs
index 7316eb8a1073..c06b5af67c63 100644
--- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs
+++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs
@@ -1368,7 +1368,7 @@ protected void GenerateFindFirstChar()
{
// Create a string to store the lookup table we use to find the offset.
Debug.Assert(_boyerMoorePrefix.Pattern.Length <= char.MaxValue, "RegexBoyerMoore should have limited the size allowed.");
- string negativeLookup = string.Create(negativeRange, (thisRef: this, beforefirst), (span, state) =>
+ string negativeLookup = string.Create(negativeRange, (thisRef: this, beforefirst), static (span, state) =>
{
// Store the offsets into the string. RightToLeft has negative offsets, so to support it with chars (unsigned), we negate
// the values to be stored in the string, and then at run time after looking up the offset in the string, negate it again.
@@ -5256,7 +5256,7 @@ void EmitCharInClass()
// Generate the lookup table to store 128 answers as bits. We use a const string instead of a byte[] / static
// data property because it lets IL emit handle all the details for us.
- string bitVectorString = string.Create(8, (charClass, invariant), (dest, state) => // String length is 8 chars == 16 bytes == 128 bits.
+ string bitVectorString = string.Create(8, (charClass, invariant), static (dest, state) => // String length is 8 chars == 16 bytes == 128 bits.
{
for (int i = 0; i < 128; i++)
{
diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexParser.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexParser.cs
index fae6d582421b..8885ae485f49 100644
--- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexParser.cs
+++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexParser.cs
@@ -2134,7 +2134,7 @@ private void AddConcatenate(int pos, int cch, bool isReplacement)
if (cch > 1)
{
string str = UseOptionI() && !isReplacement ?
- string.Create(cch, (_pattern, _culture, pos, cch), (span, state) => state._pattern.AsSpan(state.pos, state.cch).ToLower(span, state._culture)) :
+ string.Create(cch, (_pattern, _culture, pos, cch), static (span, state) => state._pattern.AsSpan(state.pos, state.cch).ToLower(span, state._culture)) :
_pattern.Substring(pos, cch);
node = new RegexNode(RegexNode.Multi, _options, str);
diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/SegmentStringBuilder.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/SegmentStringBuilder.cs
index 87b729712046..eb19c8574858 100644
--- a/src/libraries/System.Text.RegularExpressions/src/System/Text/SegmentStringBuilder.cs
+++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/SegmentStringBuilder.cs
@@ -74,7 +74,7 @@ public override string ToString()
length += span[i].Length;
}
- string result = string.Create(length, this, (dest, builder) =>
+ string result = string.Create(length, this, static (dest, builder) =>
{
Span> localSpan = builder.AsSpan();
for (int i = 0; i < localSpan.Length; i++)
diff --git a/src/libraries/System.Threading.Channels/ref/System.Threading.Channels.cs b/src/libraries/System.Threading.Channels/ref/System.Threading.Channels.cs
index 6422594f03a0..8c093689cb84 100644
--- a/src/libraries/System.Threading.Channels/ref/System.Threading.Channels.cs
+++ b/src/libraries/System.Threading.Channels/ref/System.Threading.Channels.cs
@@ -23,6 +23,7 @@ public static partial class Channel
{
public static System.Threading.Channels.Channel CreateBounded(int capacity) { throw null; }
public static System.Threading.Channels.Channel CreateBounded(System.Threading.Channels.BoundedChannelOptions options) { throw null; }
+ public static System.Threading.Channels.Channel CreateBounded(BoundedChannelOptions options, Action? itemDropped) { throw null; }
public static System.Threading.Channels.Channel CreateUnbounded() { throw null; }
public static System.Threading.Channels.Channel CreateUnbounded(System.Threading.Channels.UnboundedChannelOptions options) { throw null; }
}
diff --git a/src/libraries/System.Threading.Channels/src/System/Threading/Channels/BoundedChannel.cs b/src/libraries/System.Threading.Channels/src/System/Threading/Channels/BoundedChannel.cs
index c8e074649365..bc7b18fd3488 100644
--- a/src/libraries/System.Threading.Channels/src/System/Threading/Channels/BoundedChannel.cs
+++ b/src/libraries/System.Threading.Channels/src/System/Threading/Channels/BoundedChannel.cs
@@ -15,6 +15,8 @@ internal sealed class BoundedChannel : Channel, IDebugEnumerable
{
/// The mode used when the channel hits its bound.
private readonly BoundedChannelFullMode _mode;
+ /// The delegate that will be invoked when the channel hits its bound and an item is dropped from the channel.
+ private readonly Action? _itemDropped;
/// Task signaled when the channel has completed.
private readonly TaskCompletionSource _completion;
/// The maximum capacity of the channel.
@@ -40,12 +42,14 @@ internal sealed class BoundedChannel : Channel, IDebugEnumerable
/// The positive bounded capacity for the channel.
/// The mode used when writing to a full channel.
/// Whether to force continuations to be executed asynchronously.
- internal BoundedChannel(int bufferedCapacity, BoundedChannelFullMode mode, bool runContinuationsAsynchronously)
+ /// Delegate that will be invoked when an item is dropped from the channel. See .
+ internal BoundedChannel(int bufferedCapacity, BoundedChannelFullMode mode, bool runContinuationsAsynchronously, Action? itemDropped)
{
Debug.Assert(bufferedCapacity > 0);
_bufferedCapacity = bufferedCapacity;
_mode = mode;
_runContinuationsAsynchronously = runContinuationsAsynchronously;
+ _itemDropped = itemDropped;
_completion = new TaskCompletionSource(runContinuationsAsynchronously ? TaskCreationOptions.RunContinuationsAsynchronously : TaskCreationOptions.None);
Reader = new BoundedChannelReader(this);
Writer = new BoundedChannelWriter(this);
@@ -332,8 +336,12 @@ public override bool TryWrite(T item)
AsyncOperation? waitingReadersTail = null;
BoundedChannel parent = _parent;
- lock (parent.SyncObj)
+
+ bool releaseLock = false;
+ try
{
+ Monitor.Enter(parent.SyncObj, ref releaseLock);
+
parent.AssertInvariants();
// If we're done writing, nothing more to do.
@@ -393,24 +401,35 @@ public override bool TryWrite(T item)
{
// The channel is full. Just ignore the item being added
// but say we added it.
+ Monitor.Exit(parent.SyncObj);
+ releaseLock = false;
+ parent._itemDropped?.Invoke(item);
return true;
}
else
{
// The channel is full, and we're in a dropping mode.
- // Drop either the oldest or the newest and write the new item.
- if (parent._mode == BoundedChannelFullMode.DropNewest)
- {
- parent._items.DequeueTail();
- }
- else
- {
+ // Drop either the oldest or the newest
+ T droppedItem = parent._mode == BoundedChannelFullMode.DropNewest ?
+ parent._items.DequeueTail() :
parent._items.DequeueHead();
- }
+
parent._items.EnqueueTail(item);
+
+ Monitor.Exit(parent.SyncObj);
+ releaseLock = false;
+ parent._itemDropped?.Invoke(droppedItem);
+
return true;
}
}
+ finally
+ {
+ if (releaseLock)
+ {
+ Monitor.Exit(parent.SyncObj);
+ }
+ }
// We either wrote the item already, or we're transferring it to the blocked reader we grabbed.
if (blockedReader != null)
@@ -492,8 +511,12 @@ public override ValueTask WriteAsync(T item, CancellationToken cancellationToken
AsyncOperation? waitingReadersTail = null;
BoundedChannel parent = _parent;
- lock (parent.SyncObj)
+
+ bool releaseLock = false;
+ try
{
+ Monitor.Enter(parent.SyncObj, ref releaseLock);
+
parent.AssertInvariants();
// If we're done writing, trying to write is an error.
@@ -569,24 +592,35 @@ public override ValueTask WriteAsync(T item, CancellationToken cancellationToken
{
// The channel is full and we're in ignore mode.
// Ignore the item but say we accepted it.
+ Monitor.Exit(parent.SyncObj);
+ releaseLock = false;
+ parent._itemDropped?.Invoke(item);
return default;
}
else
{
// The channel is full, and we're in a dropping mode.
// Drop either the oldest or the newest and write the new item.
- if (parent._mode == BoundedChannelFullMode.DropNewest)
- {
- parent._items.DequeueTail();
- }
- else
- {
+ T droppedItem = parent._mode == BoundedChannelFullMode.DropNewest ?
+ parent._items.DequeueTail() :
parent._items.DequeueHead();
- }
+
parent._items.EnqueueTail(item);
+
+ Monitor.Exit(parent.SyncObj);
+ releaseLock = false;
+ parent._itemDropped?.Invoke(droppedItem);
+
return default;
}
}
+ finally
+ {
+ if (releaseLock)
+ {
+ Monitor.Exit(parent.SyncObj);
+ }
+ }
// We either wrote the item already, or we're transfering it to the blocked reader we grabbed.
if (blockedReader != null)
diff --git a/src/libraries/System.Threading.Channels/src/System/Threading/Channels/Channel.cs b/src/libraries/System.Threading.Channels/src/System/Threading/Channels/Channel.cs
index f377993ec03d..156489276902 100644
--- a/src/libraries/System.Threading.Channels/src/System/Threading/Channels/Channel.cs
+++ b/src/libraries/System.Threading.Channels/src/System/Threading/Channels/Channel.cs
@@ -35,21 +35,31 @@ public static Channel CreateBounded(int capacity)
throw new ArgumentOutOfRangeException(nameof(capacity));
}
- return new BoundedChannel(capacity, BoundedChannelFullMode.Wait, runContinuationsAsynchronously: true);
+ return new BoundedChannel(capacity, BoundedChannelFullMode.Wait, runContinuationsAsynchronously: true, itemDropped: null);
}
- /// Creates a channel with the specified maximum capacity.
+ /// Creates a channel subject to the provided options.
/// Specifies the type of data in the channel.
/// Options that guide the behavior of the channel.
/// The created channel.
public static Channel CreateBounded(BoundedChannelOptions options)
+ {
+ return CreateBounded(options, itemDropped: null);
+ }
+
+ /// Creates a channel subject to the provided options.
+ /// Specifies the type of data in the channel.
+ /// Options that guide the behavior of the channel.
+ /// Delegate that will be called when item is being dropped from channel. See .
+ /// The created channel.
+ public static Channel CreateBounded(BoundedChannelOptions options, Action? itemDropped)
{
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
- return new BoundedChannel(options.Capacity, options.FullMode, !options.AllowSynchronousContinuations);
+ return new BoundedChannel(options.Capacity, options.FullMode, !options.AllowSynchronousContinuations, itemDropped);
}
}
}
diff --git a/src/libraries/System.Threading.Channels/tests/BoundedChannelTests.cs b/src/libraries/System.Threading.Channels/tests/BoundedChannelTests.cs
index 4c8989d83c4d..6eb1d3fe8e73 100644
--- a/src/libraries/System.Threading.Channels/tests/BoundedChannelTests.cs
+++ b/src/libraries/System.Threading.Channels/tests/BoundedChannelTests.cs
@@ -1,6 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Collections.Generic;
+using System.Linq;
using System.Threading.Tasks;
using Microsoft.DotNet.XUnitExtensions;
using Xunit;
@@ -17,6 +19,17 @@ protected override Channel CreateFullChannel()
return c;
}
+ public static IEnumerable ChannelDropModes()
+ {
+ foreach (BoundedChannelFullMode mode in Enum.GetValues(typeof(BoundedChannelFullMode)))
+ {
+ if (mode != BoundedChannelFullMode.Wait)
+ {
+ yield return new object[] { mode };
+ }
+ }
+ }
+
[Fact]
public void Count_IncrementsDecrementsAsExpected()
{
@@ -249,6 +262,216 @@ public void WriteAsync_TryRead_Many_Ignore(int bufferedCapacity)
Assert.Equal(0, result);
}
+ [Fact]
+ public void DroppedDelegateNotCalledOnWaitMode_SyncWrites()
+ {
+ bool dropDelegateCalled = false;
+
+ Channel c = Channel.CreateBounded(new BoundedChannelOptions(1) { FullMode = BoundedChannelFullMode.Wait },
+ item =>
+ {
+ dropDelegateCalled = true;
+ });
+
+ Assert.True(c.Writer.TryWrite(1));
+ Assert.False(c.Writer.TryWrite(1));
+
+ Assert.False(dropDelegateCalled);
+ }
+
+ [Fact]
+ public async Task DroppedDelegateNotCalledOnWaitMode_AsyncWrites()
+ {
+ bool dropDelegateCalled = false;
+
+ Channel c = Channel.CreateBounded(new BoundedChannelOptions(1) { FullMode = BoundedChannelFullMode.Wait },
+ item =>
+ {
+ dropDelegateCalled = true;
+ });
+
+ // First async write should pass
+ await c.Writer.WriteAsync(1);
+
+ // Second write should wait
+ var secondWriteTask = c.Writer.WriteAsync(2);
+ Assert.False(secondWriteTask.IsCompleted);
+
+ // Read from channel to free up space
+ var readItem = await c.Reader.ReadAsync();
+ // Second write should complete
+ await secondWriteTask;
+
+ // No dropped delegate should be called
+ Assert.False(dropDelegateCalled);
+ }
+
+ [Theory]
+ [MemberData(nameof(ChannelDropModes))]
+ public void DroppedDelegateIsNull_SyncWrites(BoundedChannelFullMode boundedChannelFullMode)
+ {
+ Channel c = Channel.CreateBounded(new BoundedChannelOptions(1) { FullMode = boundedChannelFullMode }, itemDropped: null);
+
+ Assert.True(c.Writer.TryWrite(5));
+ Assert.True(c.Writer.TryWrite(5));
+ }
+
+ [Theory]
+ [MemberData(nameof(ChannelDropModes))]
+ public async Task DroppedDelegateIsNull_AsyncWrites(BoundedChannelFullMode boundedChannelFullMode)
+ {
+ Channel c = Channel.CreateBounded(new BoundedChannelOptions(1) { FullMode = boundedChannelFullMode }, itemDropped: null);
+
+ await c.Writer.WriteAsync(5);
+ await c.Writer.WriteAsync(5);
+ }
+
+ [Theory]
+ [MemberData(nameof(ChannelDropModes))]
+ public void DroppedDelegateCalledOnChannelFull_SyncWrites(BoundedChannelFullMode boundedChannelFullMode)
+ {
+ var droppedItems = new HashSet();
+
+ void AddDroppedItem(int itemDropped)
+ {
+ Assert.True(droppedItems.Add(itemDropped));
+ }
+
+ const int channelCapacity = 10;
+ var c = Channel.CreateBounded(new BoundedChannelOptions(channelCapacity)
+ {
+ FullMode = boundedChannelFullMode
+ }, AddDroppedItem);
+
+ for (int i = 0; i < channelCapacity; i++)
+ {
+ Assert.True(c.Writer.TryWrite(i));
+ }
+
+ // No dropped delegate should be called while channel is not full
+ Assert.Empty(droppedItems);
+
+ for (int i = channelCapacity; i < channelCapacity + 10; i++)
+ {
+ Assert.True(c.Writer.TryWrite(i));
+ }
+
+ // Assert expected number of dropped items delegate calls
+ Assert.Equal(10, droppedItems.Count);
+ }
+
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
+ [MemberData(nameof(ChannelDropModes))]
+ public void DroppedDelegateCalledAfterLockReleased_SyncWrites(BoundedChannelFullMode boundedChannelFullMode)
+ {
+ Channel c = null;
+ bool dropDelegateCalled = false;
+
+ c = Channel.CreateBounded(new BoundedChannelOptions(1)
+ {
+ FullMode = boundedChannelFullMode
+ }, (droppedItem) =>
+ {
+ if (dropDelegateCalled)
+ {
+ // Prevent infinite callbacks being called
+ return;
+ }
+
+ dropDelegateCalled = true;
+
+ // Dropped delegate should not be called while holding the channel lock.
+ // Verify this by trying to write into the channel from different thread.
+ // If lock is held during callback, this should effecitvely cause deadlock.
+ var mres = new ManualResetEventSlim();
+ ThreadPool.QueueUserWorkItem(delegate
+ {
+ c.Writer.TryWrite(3);
+ mres.Set();
+ });
+
+ mres.Wait();
+ });
+
+ Assert.True(c.Writer.TryWrite(1));
+ Assert.True(c.Writer.TryWrite(2));
+
+ Assert.True(dropDelegateCalled);
+ }
+
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
+ [MemberData(nameof(ChannelDropModes))]
+ public async Task DroppedDelegateCalledAfterLockReleased_AsyncWrites(BoundedChannelFullMode boundedChannelFullMode)
+ {
+ Channel c = null;
+ bool dropDelegateCalled = false;
+
+ c = Channel.CreateBounded(new BoundedChannelOptions(1)
+ {
+ FullMode = boundedChannelFullMode
+ }, (droppedItem) =>
+ {
+ if (dropDelegateCalled)
+ {
+ // Prevent infinite callbacks being called
+ return;
+ }
+
+ dropDelegateCalled = true;
+
+ // Dropped delegate should not be called while holding the channel synchronisation lock.
+ // Verify this by trying to write into the channel from different thread.
+ // If lock is held during callback, this should effecitvely cause deadlock.
+ var mres = new ManualResetEventSlim();
+ ThreadPool.QueueUserWorkItem(delegate
+ {
+ c.Writer.TryWrite(11);
+ mres.Set();
+ });
+
+ mres.Wait();
+ });
+
+ await c.Writer.WriteAsync(1);
+ await c.Writer.WriteAsync(2);
+
+ Assert.True(dropDelegateCalled);
+ }
+
+ [Theory]
+ [MemberData(nameof(ChannelDropModes))]
+ public async Task DroppedDelegateCalledOnChannelFull_AsyncWrites(BoundedChannelFullMode boundedChannelFullMode)
+ {
+ var droppedItems = new HashSet();
+
+ void AddDroppedItem(int itemDropped)
+ {
+ Assert.True(droppedItems.Add(itemDropped));
+ }
+
+ const int channelCapacity = 10;
+ var c = Channel.CreateBounded(new BoundedChannelOptions(channelCapacity)
+ {
+ FullMode = boundedChannelFullMode
+ }, AddDroppedItem);
+
+ for (int i = 0; i < channelCapacity; i++)
+ {
+ await c.Writer.WriteAsync(i);
+ }
+
+ // No dropped delegate should be called while channel is not full
+ Assert.Empty(droppedItems);
+
+ for (int i = channelCapacity; i < channelCapacity + 10; i++)
+ {
+ await c.Writer.WriteAsync(i);
+ }
+
+ // Assert expected number of dropped items delegate calls
+ Assert.Equal(10, droppedItems.Count);
+ }
+
[Fact]
public async Task CancelPendingWrite_Reading_DataTransferredFromCorrectWriter()
{
diff --git a/src/libraries/System.Threading.Tasks.Extensions/tests/AsyncValueTaskMethodBuilderTests.cs b/src/libraries/System.Threading.Tasks.Extensions/tests/AsyncValueTaskMethodBuilderTests.cs
index d929d30d22d6..e515a1ff0a7e 100644
--- a/src/libraries/System.Threading.Tasks.Extensions/tests/AsyncValueTaskMethodBuilderTests.cs
+++ b/src/libraries/System.Threading.Tasks.Extensions/tests/AsyncValueTaskMethodBuilderTests.cs
@@ -555,69 +555,6 @@ static async ValueTask ValueTaskAsync(int i)
}));
}
- [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
- [InlineData("1", null)]
- [InlineData("true", null)]
- [InlineData("true", "1")]
- [InlineData("true", "100")]
- [InlineData("false", null)]
- [InlineData("false", "100")]
- public void PoolingAsyncValueTasksBuilder_ObjectsPooled(string poolingEnvVar, string limitEnvVar)
- {
- // Use RemoteExecutor to launch a process with the right environment variables set
- var psi = new ProcessStartInfo();
- psi.Environment.Add("DOTNET_SYSTEM_THREADING_POOLASYNCVALUETASKS", poolingEnvVar);
- if (limitEnvVar != null)
- {
- psi.Environment.Add("DOTNET_SYSTEM_THREADING_POOLASYNCVALUETASKSLIMIT", limitEnvVar);
- }
-
- RemoteExecutor.Invoke(async expectReuse =>
- {
- var boxes = new ConcurrentQueue();
- var valueTasks = new ValueTask[10];
- int total = 0;
-
- // Invoke a bunch of ValueTask methods, some in parallel,
- // and track a) their results and b) what boxing object is used.
- for (int rep = 0; rep < 3; rep++)
- {
- for (int i = 0; i < valueTasks.Length; i++)
- {
- valueTasks[i] = ComputeAsync(i + 1, boxes);
- }
- foreach (ValueTask vt in valueTasks)
- {
- total += await vt;
- }
- }
-
- // Make sure we got the right total, and that if we expected pooling,
- // we at least pooled one object.
- Assert.Equal(330, total);
- if (expectReuse == "1" || expectReuse == "true")
- {
- Assert.InRange(boxes.Distinct().Count(), 1, boxes.Count - 1);
- }
- }, (poolingEnvVar == "1" || poolingEnvVar == "true").ToString(), new RemoteInvokeOptions() { StartInfo = psi }).Dispose();
-
- static async ValueTask ComputeAsync(int input, ConcurrentQueue boxes)
- {
- await RecursiveValueTaskAsync(3, boxes);
- return input * 2;
- }
-
- static async ValueTask RecursiveValueTaskAsync(int depth, ConcurrentQueue boxes)
- {
- boxes.Enqueue(await GetStateMachineData.FetchAsync());
- if (depth > 0)
- {
- await Task.Delay(1);
- await RecursiveValueTaskAsync(depth - 1, boxes);
- }
- }
- }
-
private struct DelegateStateMachine : IAsyncStateMachine
{
internal Action MoveNextDelegate;
diff --git a/src/libraries/System.Threading.Tasks.Extensions/tests/PoolingAsyncValueTaskMethodBuilderTests.cs b/src/libraries/System.Threading.Tasks.Extensions/tests/PoolingAsyncValueTaskMethodBuilderTests.cs
new file mode 100644
index 000000000000..c2e83881ce5b
--- /dev/null
+++ b/src/libraries/System.Threading.Tasks.Extensions/tests/PoolingAsyncValueTaskMethodBuilderTests.cs
@@ -0,0 +1,579 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks.Sources.Tests;
+using Microsoft.DotNet.RemoteExecutor;
+using Xunit;
+
+namespace System.Threading.Tasks.Tests
+{
+ public class PoolingAsyncValueTaskMethodBuilderTests
+ {
+ [Fact]
+ public void Create_ReturnsDefaultInstance() // implementation detail being verified
+ {
+ Assert.Equal(default, PoolingAsyncValueTaskMethodBuilder.Create());
+ Assert.Equal(default, PoolingAsyncValueTaskMethodBuilder.Create());
+ }
+
+ [Fact]
+ public void NonGeneric_SetResult_BeforeAccessTask_ValueTaskIsDefault()
+ {
+ PoolingAsyncValueTaskMethodBuilder b = PoolingAsyncValueTaskMethodBuilder.Create();
+
+ b.SetResult();
+
+ Assert.Equal(default, b.Task);
+ }
+
+ [Fact]
+ public void Generic_SetResult_BeforeAccessTask_ValueTaskContainsValue()
+ {
+ PoolingAsyncValueTaskMethodBuilder b = PoolingAsyncValueTaskMethodBuilder.Create();
+
+ b.SetResult(42);
+
+ ValueTask vt = b.Task;
+ Assert.Equal(vt, b.Task);
+ Assert.Equal(new ValueTask(42), vt);
+ }
+
+ [Fact]
+ public void NonGeneric_SetResult_AfterAccessTask_ValueTaskContainsValue()
+ {
+ PoolingAsyncValueTaskMethodBuilder b = PoolingAsyncValueTaskMethodBuilder.Create();
+
+ ValueTask vt = b.Task;
+ Assert.NotEqual(default, vt);
+ Assert.Equal(vt, b.Task);
+
+ b.SetResult();
+
+ Assert.Equal(vt, b.Task);
+ Assert.True(vt.IsCompletedSuccessfully);
+ }
+
+ [Fact]
+ public void Generic_SetResult_AfterAccessTask_ValueTaskContainsValue()
+ {
+ PoolingAsyncValueTaskMethodBuilder b = PoolingAsyncValueTaskMethodBuilder.Create();
+
+ ValueTask vt = b.Task;
+ Assert.NotEqual(default, vt);
+ Assert.Equal(vt, b.Task);
+
+ b.SetResult(42);
+
+ Assert.Equal(vt, b.Task);
+ Assert.True(vt.IsCompletedSuccessfully);
+ Assert.Equal(42, vt.Result);
+ }
+
+ [Fact]
+ public void NonGeneric_SetException_BeforeAccessTask_FaultsTask()
+ {
+ PoolingAsyncValueTaskMethodBuilder b = PoolingAsyncValueTaskMethodBuilder.Create();
+
+ var e = new FormatException();
+ b.SetException(e);
+
+ ValueTask vt = b.Task;
+ Assert.Equal(vt, b.Task);
+ Assert.True(vt.IsFaulted);
+ Assert.Same(e, Assert.Throws(() => vt.GetAwaiter().GetResult()));
+ }
+
+ [Fact]
+ public void Generic_SetException_BeforeAccessTask_FaultsTask()
+ {
+ PoolingAsyncValueTaskMethodBuilder b = PoolingAsyncValueTaskMethodBuilder.Create();
+
+ var e = new FormatException();
+ b.SetException(e);
+
+ ValueTask vt = b.Task;
+ Assert.Equal(vt, b.Task);
+ Assert.True(vt.IsFaulted);
+ Assert.Same(e, Assert.Throws(() => vt.GetAwaiter().GetResult()));
+ }
+
+ [Fact]
+ public void NonGeneric_SetException_AfterAccessTask_FaultsTask()
+ {
+ PoolingAsyncValueTaskMethodBuilder b = PoolingAsyncValueTaskMethodBuilder.Create();
+
+ ValueTask vt = b.Task;
+ Assert.Equal(vt, b.Task);
+
+ var e = new FormatException();
+ b.SetException(e);
+
+ Assert.Equal(vt, b.Task);
+ Assert.True(vt.IsFaulted);
+ Assert.Same(e, Assert.Throws(() => vt.GetAwaiter().GetResult()));
+ }
+
+ [Fact]
+ public void Generic_SetException_AfterAccessTask_FaultsTask()
+ {
+ PoolingAsyncValueTaskMethodBuilder b = PoolingAsyncValueTaskMethodBuilder.Create();
+
+ ValueTask vt = b.Task;
+ Assert.Equal(vt, b.Task);
+
+ var e = new FormatException();
+ b.SetException(e);
+
+ Assert.Equal(vt, b.Task);
+ Assert.True(vt.IsFaulted);
+ Assert.Same(e, Assert.Throws(() => vt.GetAwaiter().GetResult()));
+ }
+
+ [Fact]
+ public void NonGeneric_SetException_OperationCanceledException_CancelsTask()
+ {
+ PoolingAsyncValueTaskMethodBuilder b = PoolingAsyncValueTaskMethodBuilder.Create();
+
+ ValueTask vt = b.Task;
+ Assert.Equal(vt, b.Task);
+
+ var e = new OperationCanceledException();
+ b.SetException(e);
+
+ Assert.Equal(vt, b.Task);
+ Assert.True(vt.IsCanceled);
+ Assert.Same(e, Assert.Throws(() => vt.GetAwaiter().GetResult()));
+ }
+
+ [Fact]
+ public void Generic_SetException_OperationCanceledException_CancelsTask()
+ {
+ PoolingAsyncValueTaskMethodBuilder b = PoolingAsyncValueTaskMethodBuilder.Create();
+
+ ValueTask vt = b.Task;
+ Assert.Equal(vt, b.Task);
+
+ var e = new OperationCanceledException();
+ b.SetException(e);
+
+ Assert.Equal(vt, b.Task);
+ Assert.True(vt.IsCanceled);
+ Assert.Same(e, Assert.Throws(() => vt.GetAwaiter().GetResult()));
+ }
+
+ [Fact]
+ public void NonGeneric_SetExceptionWithNullException_Throws()
+ {
+ PoolingAsyncValueTaskMethodBuilder b = PoolingAsyncValueTaskMethodBuilder.Create();
+ AssertExtensions.Throws("exception", () => b.SetException(null));
+ }
+
+ [Fact]
+ public void Generic_SetExceptionWithNullException_Throws()
+ {
+ PoolingAsyncValueTaskMethodBuilder b = PoolingAsyncValueTaskMethodBuilder.Create();
+ AssertExtensions.Throws("exception", () => b.SetException(null));
+ }
+
+ [Fact]
+ public void NonGeneric_Start_InvokesMoveNext()
+ {
+ PoolingAsyncValueTaskMethodBuilder b = PoolingAsyncValueTaskMethodBuilder.Create();
+
+ int invokes = 0;
+ var dsm = new DelegateStateMachine { MoveNextDelegate = () => invokes++ };
+ b.Start(ref dsm);
+
+ Assert.Equal(1, invokes);
+ }
+
+ [Fact]
+ public void Generic_Start_InvokesMoveNext()
+ {
+ PoolingAsyncValueTaskMethodBuilder b = PoolingAsyncValueTaskMethodBuilder.Create();
+
+ int invokes = 0;
+ var dsm = new DelegateStateMachine { MoveNextDelegate = () => invokes++ };
+ b.Start(ref dsm);
+
+ Assert.Equal(1, invokes);
+ }
+
+ [Theory]
+ [InlineData(1, false)]
+ [InlineData(2, false)]
+ [InlineData(1, true)]
+ [InlineData(2, true)]
+ public void NonGeneric_AwaitOnCompleted_ForcesTaskCreation(int numAwaits, bool awaitUnsafe)
+ {
+ PoolingAsyncValueTaskMethodBuilder b = PoolingAsyncValueTaskMethodBuilder.Create();
+
+ var dsm = new DelegateStateMachine();
+ TaskAwaiter t = new TaskCompletionSource().Task.GetAwaiter();
+
+ Assert.InRange(numAwaits, 1, int.MaxValue);
+ for (int i = 1; i <= numAwaits; i++)
+ {
+ if (awaitUnsafe)
+ {
+ b.AwaitUnsafeOnCompleted(ref t, ref dsm);
+ }
+ else
+ {
+ b.AwaitOnCompleted(ref t, ref dsm);
+ }
+ }
+
+ b.SetResult();
+
+ ValueTask vt = b.Task;
+ Assert.NotEqual(default, vt);
+ Assert.True(vt.IsCompletedSuccessfully);
+ }
+
+ [Theory]
+ [InlineData(1, false)]
+ [InlineData(2, false)]
+ [InlineData(1, true)]
+ [InlineData(2, true)]
+ public void Generic_AwaitOnCompleted_ForcesTaskCreation(int numAwaits, bool awaitUnsafe)
+ {
+ PoolingAsyncValueTaskMethodBuilder b = PoolingAsyncValueTaskMethodBuilder.Create();
+
+ var dsm = new DelegateStateMachine();
+ TaskAwaiter t = new TaskCompletionSource().Task.GetAwaiter();
+
+ Assert.InRange(numAwaits, 1, int.MaxValue);
+ for (int i = 1; i <= numAwaits; i++)
+ {
+ if (awaitUnsafe)
+ {
+ b.AwaitUnsafeOnCompleted(ref t, ref dsm);
+ }
+ else
+ {
+ b.AwaitOnCompleted(ref t, ref dsm);
+ }
+ }
+
+ b.SetResult(42);
+
+ ValueTask vt = b.Task;
+ Assert.NotEqual(default, vt);
+ Assert.True(vt.IsCompletedSuccessfully);
+ Assert.Equal(42, vt.Result);
+ }
+
+ [Fact]
+ public void NonGeneric_SetStateMachine_InvalidArgument_ThrowsException()
+ {
+ PoolingAsyncValueTaskMethodBuilder b = PoolingAsyncValueTaskMethodBuilder.Create();
+ AssertExtensions.Throws("stateMachine", () => b.SetStateMachine(null));
+ }
+
+ [Fact]
+ public void Generic_SetStateMachine_InvalidArgument_ThrowsException()
+ {
+ PoolingAsyncValueTaskMethodBuilder b = PoolingAsyncValueTaskMethodBuilder.Create();
+ AssertExtensions.Throws("stateMachine", () => b.SetStateMachine(null));
+ }
+
+ [Fact]
+ public void NonGeneric_Start_ExecutionContextChangesInMoveNextDontFlowOut()
+ {
+ var al = new AsyncLocal { Value = 0 };
+ int calls = 0;
+
+ var dsm = new DelegateStateMachine
+ {
+ MoveNextDelegate = () =>
+ {
+ al.Value++;
+ calls++;
+ }
+ };
+
+ dsm.MoveNext();
+ Assert.Equal(1, al.Value);
+ Assert.Equal(1, calls);
+
+ dsm.MoveNext();
+ Assert.Equal(2, al.Value);
+ Assert.Equal(2, calls);
+
+ PoolingAsyncValueTaskMethodBuilder b = PoolingAsyncValueTaskMethodBuilder.Create();
+ b.Start(ref dsm);
+ Assert.Equal(2, al.Value); // change should not be visible
+ Assert.Equal(3, calls);
+
+ // Make sure we've not caused the Task to be allocated
+ b.SetResult();
+ Assert.Equal(default, b.Task);
+ }
+
+ [Fact]
+ public void Generic_Start_ExecutionContextChangesInMoveNextDontFlowOut()
+ {
+ var al = new AsyncLocal { Value = 0 };
+ int calls = 0;
+
+ var dsm = new DelegateStateMachine
+ {
+ MoveNextDelegate = () =>
+ {
+ al.Value++;
+ calls++;
+ }
+ };
+
+ dsm.MoveNext();
+ Assert.Equal(1, al.Value);
+ Assert.Equal(1, calls);
+
+ dsm.MoveNext();
+ Assert.Equal(2, al.Value);
+ Assert.Equal(2, calls);
+
+ PoolingAsyncValueTaskMethodBuilder b = PoolingAsyncValueTaskMethodBuilder.Create();
+ b.Start(ref dsm);
+ Assert.Equal(2, al.Value); // change should not be visible
+ Assert.Equal(3, calls);
+
+ // Make sure we've not caused the Task to be allocated
+ b.SetResult(42);
+ Assert.Equal(new ValueTask(42), b.Task);
+ }
+
+ [ActiveIssue("https://github.com/dotnet/roslyn/issues/51999")]
+ [Theory]
+ [InlineData(0)]
+ [InlineData(1)]
+ [InlineData(2)]
+ [InlineData(10)]
+ public static async Task NonGeneric_UsedWithAsyncMethod_CompletesSuccessfully(int yields)
+ {
+ StrongBox result;
+
+ result = new StrongBox();
+ await ValueTaskReturningAsyncMethod(42, result);
+ Assert.Equal(42 + yields, result.Value);
+
+ result = new StrongBox();
+ await ValueTaskReturningAsyncMethod(84, result);
+ Assert.Equal(84 + yields, result.Value);
+
+ [AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder))]
+ async ValueTask ValueTaskReturningAsyncMethod(int result, StrongBox output)
+ {
+ for (int i = 0; i < yields; i++)
+ {
+ await Task.Yield();
+ result++;
+ }
+ output.Value = result;
+ }
+ }
+
+ [ActiveIssue("https://github.com/dotnet/roslyn/issues/51999")]
+ [Theory]
+ [InlineData(0)]
+ [InlineData(1)]
+ [InlineData(2)]
+ [InlineData(10)]
+ public static async Task Generic_UsedWithAsyncMethod_CompletesSuccessfully(int yields)
+ {
+ Assert.Equal(42 + yields, await ValueTaskReturningAsyncMethod(42));
+ Assert.Equal(84 + yields, await ValueTaskReturningAsyncMethod(84));
+
+ [AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder))]
+ async ValueTask ValueTaskReturningAsyncMethod(int result)
+ {
+ for (int i = 0; i < yields; i++)
+ {
+ await Task.Yield();
+ result++;
+ }
+ return result;
+ }
+ }
+
+ [ActiveIssue("https://github.com/dotnet/roslyn/issues/51999")]
+ [Fact]
+ public static async Task AwaitTasksAndValueTasks_InTaskAndValueTaskMethods()
+ {
+ for (int i = 0; i < 2; i++)
+ {
+ await ValueTaskReturningMethod();
+ Assert.Equal(18, await ValueTaskInt32ReturningMethod());
+ }
+
+ [AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder))]
+ async ValueTask ValueTaskReturningMethod()
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ // Complete
+ await Task.CompletedTask;
+ await Task.FromResult(42);
+ await new ValueTask();
+ await Assert.ThrowsAsync(async () => await new ValueTask(Task.FromException(new FormatException())));
+ await Assert.ThrowsAsync(async () => await new ValueTask(ManualResetValueTaskSourceFactory.Completed(0, new FormatException()), 0));
+ Assert.Equal(42, await new ValueTask(42));
+ Assert.Equal(42, await new ValueTask(Task.FromResult(42)));
+ Assert.Equal(42, await new ValueTask(ManualResetValueTaskSourceFactory.Completed(42, null), 0));
+ await Assert.ThrowsAsync(async () => await new ValueTask(Task.FromException(new FormatException())));
+ await Assert.ThrowsAsync(async () => await new ValueTask(ManualResetValueTaskSourceFactory.Completed(0, new FormatException()), 0));
+
+ // Incomplete
+ await Assert.ThrowsAsync(async () => await new ValueTask(Task.Delay(1).ContinueWith(_ => throw new FormatException())));
+ await Assert.ThrowsAsync(async () => await new ValueTask(ManualResetValueTaskSourceFactory.Delay(1, 0, new FormatException()), 0));
+ Assert.Equal(42, await new ValueTask(Task.Delay(1).ContinueWith(_ => 42)));
+ Assert.Equal(42, await new ValueTask(ManualResetValueTaskSourceFactory.Delay(1, 42, null), 0));
+ await Assert.ThrowsAsync(async () => await new ValueTask(Task.Delay(1).ContinueWith(_ => throw new FormatException())));
+ await Assert.ThrowsAsync(async () => await new ValueTask(ManualResetValueTaskSourceFactory.Delay(1, 0, new FormatException()), 0));
+ await Task.Yield();
+ }
+ }
+
+ [AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder))]
+ async ValueTask ValueTaskInt32ReturningMethod()
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ // Complete
+ await Task.CompletedTask;
+ await Task.FromResult(42);
+ await new ValueTask();
+ await Assert.ThrowsAsync(async () => await new ValueTask(Task.FromException(new FormatException())));
+ await Assert.ThrowsAsync(async () => await new ValueTask(ManualResetValueTaskSourceFactory.Completed(0, new FormatException()), 0));
+ Assert.Equal(42, await new ValueTask(42));
+ Assert.Equal(42, await new ValueTask(Task.FromResult(42)));
+ Assert.Equal(42, await new ValueTask(ManualResetValueTaskSourceFactory.Completed(42, null), 0));
+ await Assert.ThrowsAsync(async () => await new ValueTask(Task.FromException(new FormatException())));
+ await Assert.ThrowsAsync(async () => await new ValueTask(ManualResetValueTaskSourceFactory.Completed(0, new FormatException()), 0));
+
+ // Incomplete
+ await Assert.ThrowsAsync(async () => await new ValueTask(Task.Delay(1).ContinueWith(_ => throw new FormatException())));
+ await Assert.ThrowsAsync(async () => await new ValueTask(ManualResetValueTaskSourceFactory.Delay(1, 0, new FormatException()), 0));
+ Assert.Equal(42, await new ValueTask(Task.Delay(1).ContinueWith(_ => 42)));
+ Assert.Equal(42, await new ValueTask(ManualResetValueTaskSourceFactory.Delay(1, 42, null), 0));
+ await Assert.ThrowsAsync(async () => await new ValueTask(Task.Delay(1).ContinueWith(_ => throw new FormatException())));
+ await Assert.ThrowsAsync(async () => await new ValueTask(ManualResetValueTaskSourceFactory.Delay(1, 0, new FormatException()), 0));
+ await Task.Yield();
+ }
+ return 18;
+ }
+ }
+
+ [ActiveIssue("https://github.com/dotnet/roslyn/issues/51999")]
+ [Fact]
+ public async Task NonGeneric_ConcurrentBuilders_WorkCorrectly()
+ {
+ await Task.WhenAll(Enumerable.Range(0, Environment.ProcessorCount).Select(async _ =>
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ await ValueTaskAsync();
+
+ [AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder))]
+ static async ValueTask ValueTaskAsync()
+ {
+ await Task.Delay(1);
+ }
+ }
+ }));
+ }
+
+ [ActiveIssue("https://github.com/dotnet/roslyn/issues/51999")]
+ [Fact]
+ public async Task Generic_ConcurrentBuilders_WorkCorrectly()
+ {
+ await Task.WhenAll(Enumerable.Range(0, Environment.ProcessorCount).Select(async _ =>
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ Assert.Equal(42 + i, await ValueTaskAsync(i));
+
+ [AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder))]
+ static async ValueTask ValueTaskAsync(int i)
+ {
+ await Task.Delay(1);
+ return 42 + i;
+ }
+ }
+ }));
+ }
+
+ [ActiveIssue("https://github.com/dotnet/roslyn/issues/51999")]
+ [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
+ [InlineData(null)]
+ [InlineData("1")]
+ [InlineData("100")]
+ public void PoolingAsyncValueTasksBuilder_ObjectsPooled(string limitEnvVar)
+ {
+ // Use RemoteExecutor to launch a process with the right environment variables set
+ var psi = new ProcessStartInfo();
+ if (limitEnvVar != null)
+ {
+ psi.Environment.Add("DOTNET_SYSTEM_THREADING_POOLINGASYNCVALUETASKSCACHESIZE", limitEnvVar);
+ }
+
+ RemoteExecutor.Invoke(async () =>
+ {
+ var boxes = new ConcurrentQueue();
+ var valueTasks = new ValueTask[10];
+ int total = 0;
+
+ // Invoke a bunch of ValueTask methods, some in parallel,
+ // and track a) their results and b) what boxing object is used.
+ for (int rep = 0; rep < 3; rep++)
+ {
+ for (int i = 0; i < valueTasks.Length; i++)
+ {
+ valueTasks[i] = ComputeAsync(i + 1, boxes);
+ }
+ foreach (ValueTask vt in valueTasks)
+ {
+ total += await vt;
+ }
+ }
+
+ // Make sure we got the right total, and that if we expected pooling,
+ // we at least pooled one object.
+ Assert.Equal(330, total);
+ Assert.InRange(boxes.Distinct().Count(), 1, boxes.Count - 1);
+ }, new RemoteInvokeOptions() { StartInfo = psi }).Dispose();
+
+ [AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder))]
+ static async ValueTask ComputeAsync(int input, ConcurrentQueue boxes)
+ {
+ await RecursiveValueTaskAsync(3, boxes);
+ return input * 2;
+ }
+
+ [AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder))]
+ static async ValueTask RecursiveValueTaskAsync(int depth, ConcurrentQueue boxes)
+ {
+ boxes.Enqueue(await GetStateMachineData.FetchAsync());
+ if (depth > 0)
+ {
+ await Task.Delay(1);
+ await RecursiveValueTaskAsync(depth - 1, boxes);
+ }
+ }
+ }
+
+ private struct DelegateStateMachine : IAsyncStateMachine
+ {
+ internal Action MoveNextDelegate;
+ public void MoveNext() => MoveNextDelegate?.Invoke();
+
+ public void SetStateMachine(IAsyncStateMachine stateMachine) { }
+ }
+ }
+}
diff --git a/src/libraries/System.Threading.Tasks.Extensions/tests/System.Threading.Tasks.Extensions.Tests.csproj b/src/libraries/System.Threading.Tasks.Extensions/tests/System.Threading.Tasks.Extensions.Tests.csproj
index 6a7215d2b5cb..3cf17c52a2fc 100644
--- a/src/libraries/System.Threading.Tasks.Extensions/tests/System.Threading.Tasks.Extensions.Tests.csproj
+++ b/src/libraries/System.Threading.Tasks.Extensions/tests/System.Threading.Tasks.Extensions.Tests.csproj
@@ -8,6 +8,7 @@
+
diff --git a/src/libraries/System.Threading.Tasks/tests/CancellationTokenTests.cs b/src/libraries/System.Threading.Tasks/tests/CancellationTokenTests.cs
index 8ba430cbbe5f..63a37468eb3d 100644
--- a/src/libraries/System.Threading.Tasks/tests/CancellationTokenTests.cs
+++ b/src/libraries/System.Threading.Tasks/tests/CancellationTokenTests.cs
@@ -1049,6 +1049,7 @@ public static void CancellationTokenSourceWithTimer()
cts.Dispose();
}
+
[Fact]
public static void CancellationTokenSourceWithTimer_Negative()
{
@@ -1076,6 +1077,54 @@ public static void CancellationTokenSourceWithTimer_Negative()
Assert.Throws(() => { cts.CancelAfter(reasonableTimeSpan); });
}
+ [Fact]
+ public static void CancellationTokenSource_TryReset_ReturnsFalseIfAlreadyCanceled()
+ {
+ var cts = new CancellationTokenSource();
+ cts.Cancel();
+ Assert.False(cts.TryReset());
+ Assert.True(cts.IsCancellationRequested);
+ }
+
+ [Fact]
+ public static void CancellationTokenSource_TryReset_ReturnsTrueIfNotCanceledAndNoTimer()
+ {
+ var cts = new CancellationTokenSource();
+ Assert.True(cts.TryReset());
+ Assert.True(cts.TryReset());
+ }
+
+ [Fact]
+ public static void CancellationTokenSource_TryReset_ReturnsTrueIfNotCanceledAndTimerHasntFired()
+ {
+ var cts = new CancellationTokenSource();
+ cts.CancelAfter(TimeSpan.FromDays(1));
+ Assert.True(cts.TryReset());
+ }
+
+ [Fact]
+ public static void CancellationTokenSource_TryReset_UnregistersAll()
+ {
+ bool registration1Invoked = false;
+ bool registration2Invoked = false;
+
+ var cts = new CancellationTokenSource();
+ CancellationTokenRegistration ctr1 = cts.Token.Register(() => registration1Invoked = true);
+ Assert.True(cts.TryReset());
+ CancellationTokenRegistration ctr2 = cts.Token.Register(() => registration2Invoked = true);
+
+ cts.Cancel();
+
+ Assert.False(registration1Invoked);
+ Assert.True(registration2Invoked);
+
+ Assert.False(ctr1.Unregister());
+ Assert.False(ctr2.Unregister());
+
+ Assert.Equal(cts.Token, ctr1.Token);
+ Assert.Equal(cts.Token, ctr2.Token);
+ }
+
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
public static void EnlistWithSyncContext_BeforeCancel()
{
diff --git a/src/libraries/System.Xml.ReaderWriter/ref/System.Xml.ReaderWriter.cs b/src/libraries/System.Xml.ReaderWriter/ref/System.Xml.ReaderWriter.cs
index b5d4ab5dc931..479251eab451 100644
--- a/src/libraries/System.Xml.ReaderWriter/ref/System.Xml.ReaderWriter.cs
+++ b/src/libraries/System.Xml.ReaderWriter/ref/System.Xml.ReaderWriter.cs
@@ -2817,9 +2817,11 @@ public partial class XsltArgumentList
{
public XsltArgumentList() { }
public event System.Xml.Xsl.XsltMessageEncounteredEventHandler XsltMessageEncountered { add { } remove { } }
+ [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The stylesheet may have calls to methods of the extension object passed in which cannot be statically analyzed by the trimmer. Ensure all methods that may be called are preserved.")]
public void AddExtensionObject(string namespaceUri, object extension) { }
public void AddParam(string name, string namespaceUri, object parameter) { }
public void Clear() { }
+ [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The stylesheet may have calls to methods of the extension object passed in which cannot be statically analyzed by the trimmer. Ensure all methods that may be called are preserved.")]
public object? GetExtensionObject(string namespaceUri) { throw null; }
public object? GetParam(string name, string namespaceUri) { throw null; }
public object? RemoveExtensionObject(string namespaceUri) { throw null; }
diff --git a/src/libraries/libraries-packages.proj b/src/libraries/libraries-packages.proj
index b8fde0c0adb1..9af91645ebef 100644
--- a/src/libraries/libraries-packages.proj
+++ b/src/libraries/libraries-packages.proj
@@ -4,7 +4,7 @@
BuildAllProjects=true$(AdditionalBuildTargetFrameworks);package-$(Configuration)
-
+
$(NuGetPackageRoot)microsoft.dotnet.build.tasks.packaging\$(MicrosoftDotNetBuildTasksPackagingVersion)\tools\$(PackagingTaskAssembly)netcoreapp3.1\
@@ -14,8 +14,10 @@
-
-
+
+
diff --git a/src/libraries/shims/ApiCompatBaseline.PreviousNetCoreApp.txt b/src/libraries/shims/ApiCompatBaseline.PreviousNetCoreApp.txt
index c9cd20297935..401f0a5f0ba1 100644
--- a/src/libraries/shims/ApiCompatBaseline.PreviousNetCoreApp.txt
+++ b/src/libraries/shims/ApiCompatBaseline.PreviousNetCoreApp.txt
@@ -23,4 +23,5 @@ CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'System.Ru
CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' changed from '[AttributeUsageAttribute(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Enum | AttributeTargets.Event | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Module | AttributeTargets.Property | AttributeTargets.Struct, AllowMultiple=true, Inherited=false)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Enum | AttributeTargets.Event | AttributeTargets.Field | AttributeTargets.Interface | AttributeTargets.Method | AttributeTargets.Module | AttributeTargets.Property | AttributeTargets.Struct, AllowMultiple=true, Inherited=false)]' in the implementation.
Compat issues with assembly System.Security.Cryptography.Algorithms:
CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Security.Cryptography.CryptoConfig' in the contract but not the implementation.
-Total Issues: 15
+CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'System.Runtime.CompilerServices.AsyncMethodBuilderAttribute' changed from '[AttributeUsageAttribute(AttributeTargets.Class | AttributeTargets.Delegate | AttributeTargets.Enum | AttributeTargets.Interface | AttributeTargets.Struct, Inherited=false, AllowMultiple=false)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Class | AttributeTargets.Delegate | AttributeTargets.Enum | AttributeTargets.Interface | AttributeTargets.Method | AttributeTargets.Struct, Inherited=false, AllowMultiple=false)]' in the implementation.
+Total Issues: 16
diff --git a/src/libraries/shims/ApiCompatBaseline.netcoreapp.netstandardOnly.txt b/src/libraries/shims/ApiCompatBaseline.netcoreapp.netstandardOnly.txt
index b5e47f7d9647..2510e64f1e5c 100644
--- a/src/libraries/shims/ApiCompatBaseline.netcoreapp.netstandardOnly.txt
+++ b/src/libraries/shims/ApiCompatBaseline.netcoreapp.netstandardOnly.txt
@@ -195,4 +195,5 @@ CannotRemoveAttribute : Attribute 'System.ComponentModel.BrowsableAttribute' exi
CannotRemoveAttribute : Attribute 'System.ComponentModel.CategoryAttribute' exists on 'System.Timers.Timer.Elapsed' in the contract but not the implementation.
CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'System.Xml.Serialization.XmlAnyAttributeAttribute' changed from '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple=false)]' in the implementation.
CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'System.Xml.Serialization.XmlNamespaceDeclarationsAttribute' changed from '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple=false)]' in the implementation.
-Total Issues: 196
+CannotChangeAttribute : Attribute 'System.AttributeUsageAttribute' on 'System.Runtime.CompilerServices.AsyncMethodBuilderAttribute' changed from '[AttributeUsageAttribute(AttributeTargets.Class | AttributeTargets.Delegate | AttributeTargets.Enum | AttributeTargets.Interface | AttributeTargets.Struct, Inherited=false, AllowMultiple=false)]' in the contract to '[AttributeUsageAttribute(AttributeTargets.Class | AttributeTargets.Delegate | AttributeTargets.Enum | AttributeTargets.Interface | AttributeTargets.Method | AttributeTargets.Struct, Inherited=false, AllowMultiple=false)]' in the implementation.
+Total Issues: 198
diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj
index 55fdbc13f9f1..2157714a38f4 100644
--- a/src/libraries/tests.proj
+++ b/src/libraries/tests.proj
@@ -12,7 +12,7 @@
falsefalse
-
+
@@ -56,6 +56,7 @@
+
@@ -68,6 +69,11 @@
+
+
+
+
+
@@ -107,17 +113,17 @@
-
+
-
+
-
+
-
+
@@ -320,6 +326,12 @@
+
+
+
+
+
+
-
+
-
-
+
diff --git a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj
index 5f18659ee173..6faf1e8ca4f7 100644
--- a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -40,7 +40,7 @@
enable
- MONO;NETCOREAPP;SYSTEM_PRIVATE_CORELIB;FEATURE_POOLASYNCVALUETASKS
+ MONO;NETCOREAPP;SYSTEM_PRIVATE_CORELIBtruetrue
diff --git a/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml b/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml
index f066b8f010d4..a04c78e98cc0 100644
--- a/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml
+++ b/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml
@@ -23,7 +23,7 @@
-
+
@@ -61,7 +61,7 @@
-
+
@@ -125,7 +125,7 @@
-
+
@@ -156,13 +156,13 @@
-
+
-
+
@@ -195,13 +195,12 @@
-
+
-
@@ -214,15 +213,12 @@
-
-
-
-
+
@@ -386,7 +382,7 @@
-
+
@@ -448,7 +444,7 @@
-
+
@@ -457,7 +453,7 @@
-
+
@@ -537,13 +533,13 @@
-
+
-
+
@@ -566,7 +562,8 @@
-
+
+
@@ -585,7 +582,7 @@
-
+
@@ -608,7 +605,7 @@
-
+
@@ -651,5 +648,9 @@
+
+
+
+
diff --git a/src/mono/System.Private.CoreLib/src/System/Exception.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Exception.Mono.cs
index 5e369825827b..490a19699e9f 100644
--- a/src/mono/System.Private.CoreLib/src/System/Exception.Mono.cs
+++ b/src/mono/System.Private.CoreLib/src/System/Exception.Mono.cs
@@ -2,10 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections;
-using System.Reflection;
using System.Diagnostics;
+using System.Reflection;
using System.Runtime.InteropServices;
-using System.Text;
namespace System
{
@@ -102,22 +101,17 @@ internal void RestoreDispatchState(in DispatchState state)
_stackTraceString = null;
}
- [StackTraceHidden]
- internal void SetCurrentStackTrace()
+ // Returns true if setting the _remoteStackTraceString field is legal, false if not (immutable exception).
+ // A false return value means the caller should early-exit the operation.
+ // Can also throw InvalidOperationException if a stack trace is already set or if object has been thrown.
+ private bool CanSetRemoteStackTrace()
{
- // Check to see if the exception already has a stack set in it.
if (_traceIPs != null || _stackTraceString != null || _remoteStackTraceString != null)
{
ThrowHelper.ThrowInvalidOperationException();
}
- // Store the current stack trace into the "remote" stack trace, which was originally introduced to support
- // remoting of exceptions cross app-domain boundaries, and is thus concatenated into Exception.StackTrace
- // when it's retrieved.
- var sb = new StringBuilder(256);
- new StackTrace(fNeedFileInfo: true).ToString(Diagnostics.StackTrace.TraceFormat.TrailingNewLine, sb);
- sb.AppendLine(SR.Exception_EndStackTraceFromPreviousThrow);
- _remoteStackTraceString = sb.ToString();
+ return true; // mono runtime doesn't have immutable agile exceptions, always return true
}
private string? CreateSourceName()
@@ -149,7 +143,6 @@ internal void SetCurrentStackTrace()
private static IDictionary CreateDataContainer() => new ListDictionaryInternal();
private static string? SerializationWatsonBuckets => null;
- private string? SerializationRemoteStackTraceString => _remoteStackTraceString;
private string? SerializationStackTraceString => GetStackTrace(true);
}
}
diff --git a/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs b/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs
index 7e54e26fe994..f58b2d5bd4cc 100644
--- a/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs
+++ b/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs
@@ -1835,11 +1835,15 @@ public override Type[] GetGenericParameterConstraints()
return constraints ?? Type.EmptyTypes;
}
- internal static object CreateInstanceForAnotherGenericParameter([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type genericType, RuntimeType genericArgument)
+ internal static object CreateInstanceForAnotherGenericParameter(
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type genericType,
+ RuntimeType genericArgument)
{
var gt = (RuntimeType)MakeGenericType(genericType, new Type[] { genericArgument });
RuntimeConstructorInfo? ctor = gt.GetDefaultConstructor();
- if (ctor is null)
+
+ // CreateInstanceForAnotherGenericParameter requires type to have a public parameterless constructor so it can be annotated for trimming without preserving private constructors.
+ if (ctor is null || !ctor.IsPublic)
throw new MissingMethodException(SR.Format(SR.Arg_NoDefCTor, gt));
return ctor.InternalInvoke(null, null, wrapExceptions: true)!;
diff --git a/src/mono/mono/metadata/CMakeLists.txt b/src/mono/mono/metadata/CMakeLists.txt
index f5281ab0bf7a..4b56d07c4405 100644
--- a/src/mono/mono/metadata/CMakeLists.txt
+++ b/src/mono/mono/metadata/CMakeLists.txt
@@ -94,6 +94,7 @@ set(metadata_common_sources
icall-eventpipe.c
image.c
image-internals.h
+ jit-info.h
jit-info.c
loader.c
lock-tracer.c
diff --git a/src/mono/mono/metadata/appdomain.c b/src/mono/mono/metadata/appdomain.c
index bbb920968126..11b20d7fc84f 100644
--- a/src/mono/mono/metadata/appdomain.c
+++ b/src/mono/mono/metadata/appdomain.c
@@ -605,13 +605,7 @@ mono_domain_try_type_resolve_name (MonoDomain *domain, MonoAssembly *assembly, M
gboolean
mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
{
- gboolean res;
- MonoMemoryManager *memory_manager = mono_mem_manager_get_ambient ();
-
- mono_mem_manager_lock (memory_manager);
- res = mono_mempool_contains_addr (memory_manager->mp, vtable_slot);
- mono_mem_manager_unlock (memory_manager);
- return res;
+ return mono_mem_manager_mp_contains_addr (mono_mem_manager_get_ambient (), vtable_slot);
}
gboolean
diff --git a/src/mono/mono/metadata/domain-internals.h b/src/mono/mono/metadata/domain-internals.h
index 05aafc20417e..9465be28d7b6 100644
--- a/src/mono/mono/metadata/domain-internals.h
+++ b/src/mono/mono/metadata/domain-internals.h
@@ -32,214 +32,6 @@ G_BEGIN_DECLS
*/
extern gboolean mono_dont_free_domains;
-typedef struct _MonoJitInfoTable MonoJitInfoTable;
-typedef struct _MonoJitInfoTableChunk MonoJitInfoTableChunk;
-
-#define MONO_JIT_INFO_TABLE_CHUNK_SIZE 64
-
-struct _MonoJitInfoTableChunk
-{
- int refcount;
- volatile int num_elements;
- volatile gint8 *last_code_end;
- MonoJitInfo *next_tombstone;
- MonoJitInfo * volatile data [MONO_JIT_INFO_TABLE_CHUNK_SIZE];
-};
-
-struct _MonoJitInfoTable
-{
- MonoDomain *domain;
- int num_chunks;
- int num_valid;
- MonoJitInfoTableChunk *chunks [MONO_ZERO_LEN_ARRAY];
-};
-
-#define MONO_SIZEOF_JIT_INFO_TABLE (sizeof (struct _MonoJitInfoTable) - MONO_ZERO_LEN_ARRAY * SIZEOF_VOID_P)
-
-typedef GArray MonoAotModuleInfoTable;
-
-typedef struct {
- guint32 flags;
- gint32 exvar_offset;
- gpointer try_start;
- gpointer try_end;
- gpointer handler_start;
- /*
- * For LLVM compiled code, this is the index of the il clause
- * associated with this handler.
- */
- int clause_index;
- uint32_t try_offset;
- uint32_t try_len;
- uint32_t handler_offset;
- uint32_t handler_len;
- union {
- MonoClass *catch_class;
- gpointer filter;
- gpointer handler_end;
- } data;
-} MonoJitExceptionInfo;
-
-/*
- * Contains information about the type arguments for generic shared methods.
- */
-typedef struct {
- gboolean is_gsharedvt;
-} MonoGenericSharingContext;
-
-/* Simplified DWARF location list entry */
-typedef struct {
- /* Whenever the value is in a register */
- gboolean is_reg;
- /*
- * If is_reg is TRUE, the register which contains the value. Otherwise
- * the base register.
- */
- int reg;
- /*
- * If is_reg is FALSE, the offset of the stack location relative to 'reg'.
- * Otherwise, 0.
- */
- int offset;
- /*
- * Offsets of the PC interval where the value is in this location.
- */
- int from, to;
-} MonoDwarfLocListEntry;
-
-typedef struct
-{
- MonoGenericSharingContext *generic_sharing_context;
- int nlocs;
- MonoDwarfLocListEntry *locations;
- gint32 this_offset;
- guint8 this_reg;
- gboolean has_this:1;
- gboolean this_in_reg:1;
-} MonoGenericJitInfo;
-
-/*
-A try block hole is used to represent a non-contiguous part of
-of a segment of native code protected by a given .try block.
-Usually, a try block is defined as a contiguous segment of code.
-But in some cases it's needed to have some parts of it to not be protected.
-For example, given "try {} finally {}", the code in the .try block to call
-the finally part looks like:
-
-try {
- ...
- call finally_block
- adjust stack
- jump outside try block
- ...
-} finally {
- ...
-}
-
-The instructions between the call and the jump should not be under the try block since they happen
-after the finally block executes, which means if an async exceptions happens at that point we would
-execute the finally clause twice. So, to avoid this, we introduce a hole in the try block to signal
-that those instructions are not protected.
-*/
-typedef struct
-{
- guint32 offset;
- guint16 clause;
- guint16 length;
-} MonoTryBlockHoleJitInfo;
-
-typedef struct
-{
- guint16 num_holes;
- MonoTryBlockHoleJitInfo holes [MONO_ZERO_LEN_ARRAY];
-} MonoTryBlockHoleTableJitInfo;
-
-typedef struct
-{
- guint32 stack_size;
- guint32 epilog_size;
-} MonoArchEHJitInfo;
-
-typedef struct {
- /* Relative to code_start */
- int thunks_offset;
- int thunks_size;
-} MonoThunkJitInfo;
-
-typedef struct {
- guint8 *unw_info;
- int unw_info_len;
-} MonoUnwindJitInfo;
-
-typedef enum {
- JIT_INFO_NONE = 0,
- JIT_INFO_HAS_GENERIC_JIT_INFO = (1 << 0),
- JIT_INFO_HAS_TRY_BLOCK_HOLES = (1 << 1),
- JIT_INFO_HAS_ARCH_EH_INFO = (1 << 2),
- JIT_INFO_HAS_THUNK_INFO = (1 << 3),
- /*
- * If this is set, the unwind info is stored in the structure, instead of being pointed to by the
- * 'unwind_info' field.
- */
- JIT_INFO_HAS_UNWIND_INFO = (1 << 4)
-} MonoJitInfoFlags;
-
-G_ENUM_FUNCTIONS (MonoJitInfoFlags)
-
-struct _MonoJitInfo {
- /* NOTE: These first two elements (method and
- next_jit_code_hash) must be in the same order and at the
- same offset as in RuntimeMethod, because of the jit_code_hash
- internal hash table in MonoDomain. */
- union {
- MonoMethod *method;
- MonoImage *image;
- MonoAotModule *aot_info;
- MonoTrampInfo *tramp_info;
- } d;
- union {
- MonoJitInfo *next_jit_code_hash;
- MonoJitInfo *next_tombstone;
- } n;
- gpointer code_start;
- guint32 unwind_info;
- int code_size;
- guint32 num_clauses:15;
- gboolean has_generic_jit_info:1;
- gboolean has_try_block_holes:1;
- gboolean has_arch_eh_info:1;
- gboolean has_thunk_info:1;
- gboolean has_unwind_info:1;
- gboolean from_aot:1;
- gboolean from_llvm:1;
- gboolean dbg_attrs_inited:1;
- gboolean dbg_hidden:1;
- /* Whenever this jit info was loaded in async context */
- gboolean async:1;
- gboolean dbg_step_through:1;
- gboolean dbg_non_user_code:1;
- /*
- * Whenever this jit info refers to a trampoline.
- * d.tramp_info contains additional data in this case.
- */
- gboolean is_trampoline:1;
- /* Whenever this jit info refers to an interpreter method */
- gboolean is_interp:1;
-
- /* FIXME: Embed this after the structure later*/
- gpointer gc_info; /* Currently only used by SGen */
-
- gpointer seq_points;
-
- MonoJitExceptionInfo clauses [MONO_ZERO_LEN_ARRAY];
- /* There is an optional MonoGenericJitInfo after the clauses */
- /* There is an optional MonoTryBlockHoleTableJitInfo after MonoGenericJitInfo clauses*/
- /* There is an optional MonoArchEHJitInfo after MonoTryBlockHoleTableJitInfo */
- /* There is an optional MonoThunkJitInfo after MonoArchEHJitInfo */
-};
-
-#define MONO_SIZEOF_JIT_INFO (offsetof (struct _MonoJitInfo, clauses))
-
struct _MonoAppContext {
MonoObject obj;
gint32 domain_id;
@@ -255,13 +47,6 @@ typedef struct _MonoThunkFreeList {
typedef struct _MonoJitCodeHash MonoJitCodeHash;
struct _MonoDomain {
- /*
- * This lock must never be taken before the loader lock,
- * i.e. if both are taken by the same thread, the loader lock
- * must taken first.
- */
- MonoCoopMutex lock;
-
/*
* keep all the managed objects close to each other for the precise GC
* For the Boehm GC we additionally keep close also other GC-tracked pointers.
@@ -320,9 +105,6 @@ mono_domain_assemblies_unlock (MonoDomain *domain)
typedef MonoDomain* (*MonoLoadFunc) (const char *filename, const char *runtime_version);
-void mono_domain_lock (MonoDomain *domain);
-void mono_domain_unlock (MonoDomain *domain);
-
void
mono_install_runtime_load (MonoLoadFunc func);
@@ -335,65 +117,12 @@ mono_runtime_quit_internal (void);
void
mono_close_exe_image (void);
-void
-mono_jit_info_tables_init (void);
-
-int
-mono_jit_info_size (MonoJitInfoFlags flags, int num_clauses, int num_holes);
-
-void
-mono_jit_info_init (MonoJitInfo *ji, MonoMethod *method, guint8 *code, int code_size,
- MonoJitInfoFlags flags, int num_clauses, int num_holes);
-
-MonoJitInfoTable *
-mono_jit_info_table_new (void);
-
-void
-mono_jit_info_table_free (MonoJitInfoTable *table);
-
-void
-mono_jit_info_table_add (MonoJitInfo *ji);
-
-void
-mono_jit_info_table_remove (MonoJitInfo *ji);
-
-void
-mono_jit_info_add_aot_module (MonoImage *image, gpointer start, gpointer end);
-
-MonoGenericJitInfo*
-mono_jit_info_get_generic_jit_info (MonoJitInfo *ji);
-
-MonoGenericSharingContext*
-mono_jit_info_get_generic_sharing_context (MonoJitInfo *ji);
-
-void
-mono_jit_info_set_generic_sharing_context (MonoJitInfo *ji, MonoGenericSharingContext *gsctx);
-
void
mono_domain_unset (void);
void
mono_domain_set_internal_with_options (MonoDomain *domain, gboolean migrate_exception);
-MonoTryBlockHoleTableJitInfo*
-mono_jit_info_get_try_block_hole_table_info (MonoJitInfo *ji);
-
-MonoArchEHJitInfo*
-mono_jit_info_get_arch_eh_info (MonoJitInfo *ji);
-
-MonoThunkJitInfo*
-mono_jit_info_get_thunk_info (MonoJitInfo *ji);
-
-MonoUnwindJitInfo*
-mono_jit_info_get_unwind_info (MonoJitInfo *ji);
-
-/*
- * Installs a new function which is used to return a MonoJitInfo for a method inside
- * an AOT module.
- */
-typedef MonoJitInfo *(*MonoJitInfoFindInAot) (MonoDomain *domain, MonoImage *image, gpointer addr);
-void mono_install_jit_info_find_in_aot (MonoJitInfoFindInAot func);
-
void
mono_jit_code_hash_init (MonoInternalHashTable *jit_code_hash);
diff --git a/src/mono/mono/metadata/domain.c b/src/mono/mono/metadata/domain.c
index 88e45e8bcd97..c887af37f1f8 100644
--- a/src/mono/mono/metadata/domain.c
+++ b/src/mono/mono/metadata/domain.c
@@ -47,6 +47,7 @@
#include
#include
#include
+#include
#include
#include
#include "external-only.h"
@@ -315,8 +316,6 @@ mono_domain_create (void)
domain->domain_assemblies = NULL;
- mono_coop_mutex_init_recursive (&domain->lock);
-
mono_coop_mutex_init_recursive (&domain->assemblies_lock);
mono_appdomains_lock ();
@@ -1256,18 +1255,6 @@ mono_get_runtime_info (void)
return current_runtime;
}
-void
-mono_domain_lock (MonoDomain *domain)
-{
- mono_locks_coop_acquire (&domain->lock, DomainLock);
-}
-
-void
-mono_domain_unlock (MonoDomain *domain)
-{
- mono_locks_coop_release (&domain->lock, DomainLock);
-}
-
GPtrArray*
mono_domain_get_assemblies (MonoDomain *domain)
{
diff --git a/src/mono/mono/metadata/exception.c b/src/mono/mono/metadata/exception.c
index fd43f641b08a..5e57b278e83d 100644
--- a/src/mono/mono/metadata/exception.c
+++ b/src/mono/mono/metadata/exception.c
@@ -23,6 +23,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/src/mono/mono/metadata/jit-info.c b/src/mono/mono/metadata/jit-info.c
index 9ce62822ffd6..84bac024bb55 100644
--- a/src/mono/mono/metadata/jit-info.c
+++ b/src/mono/mono/metadata/jit-info.c
@@ -17,6 +17,7 @@
#include
#include