diff --git a/.vsconfig b/.vsconfig
index b0c6f21fd92d5c..62cee7a8ded460 100755
--- a/.vsconfig
+++ b/.vsconfig
@@ -1,53 +1,55 @@
{
"version": "1.0",
"components": [
- "Microsoft.VisualStudio.Component.CoreEditor",
- "Microsoft.VisualStudio.Workload.CoreEditor",
- "Microsoft.NetCore.Component.SDK",
- "Microsoft.VisualStudio.Component.NuGet",
- "Microsoft.Net.Component.4.6.1.TargetingPack",
"Microsoft.VisualStudio.Component.Roslyn.Compiler",
"Microsoft.VisualStudio.Component.Roslyn.LanguageServices",
- "Microsoft.VisualStudio.Component.FSharp",
- "Microsoft.NetCore.Component.DevelopmentTools",
+ "Microsoft.Component.MSBuild",
+ "Microsoft.Net.Component.4.5.2.TargetingPack",
+ "Microsoft.VisualStudio.Component.SQL.LocalDB.Runtime",
+ "Microsoft.VisualStudio.Component.SQL.CLR",
+ "Microsoft.VisualStudio.Component.CoreEditor",
+ "Microsoft.VisualStudio.Workload.CoreEditor",
"Microsoft.Net.Component.4.8.SDK",
"Microsoft.Net.Component.4.7.2.TargetingPack",
"Microsoft.Net.ComponentGroup.DevelopmentPrerequisites",
- "Microsoft.Component.MSBuild",
"Microsoft.VisualStudio.Component.TextTemplating",
- "Microsoft.VisualStudio.Component.SQL.LocalDB.Runtime",
- "Microsoft.VisualStudio.Component.SQL.CLR",
+ "Microsoft.VisualStudio.Component.NuGet",
"Microsoft.VisualStudio.Component.ManagedDesktop.Core",
- "Microsoft.Net.Component.4.5.2.TargetingPack",
- "Microsoft.Net.Component.4.5.TargetingPack",
- "Microsoft.VisualStudio.Component.IntelliCode",
- "Microsoft.Net.Component.4.TargetingPack",
- "Microsoft.Net.Component.4.5.1.TargetingPack",
- "Microsoft.Net.Component.4.6.TargetingPack",
- "Microsoft.Net.ComponentGroup.TargetingPacks.Common",
+ "Microsoft.NetCore.Component.SDK",
+ "Microsoft.VisualStudio.Component.FSharp",
+ "Microsoft.ComponentGroup.ClickOnce.Publish",
+ "Microsoft.NetCore.Component.DevelopmentTools",
+ "Microsoft.Net.Component.4.8.TargetingPack",
+ "Microsoft.Net.Component.4.6.1.TargetingPack",
"Microsoft.VisualStudio.Component.DiagnosticTools",
+ "Microsoft.VisualStudio.Component.IntelliCode",
"Microsoft.Net.Component.4.6.2.TargetingPack",
- "Microsoft.Net.ComponentGroup.4.6.2.DeveloperTools",
"Microsoft.Net.Component.4.7.TargetingPack",
- "Microsoft.Net.ComponentGroup.4.7.DeveloperTools",
- "Microsoft.Net.Component.4.8.TargetingPack",
+ "Microsoft.VisualStudio.Component.ClassDesigner",
+ "Microsoft.VisualStudio.Component.GraphDocument",
+ "Microsoft.VisualStudio.Component.CodeMap",
"Microsoft.VisualStudio.Component.VC.CoreIde",
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
- "Microsoft.VisualStudio.Component.Windows10SDK.18362",
+ "Microsoft.VisualStudio.Component.Windows10SDK.19041",
"Microsoft.VisualStudio.Component.ManagedDesktop.Prerequisites",
"Microsoft.ComponentGroup.Blend",
"Microsoft.VisualStudio.Component.FSharp.Desktop",
"Microsoft.VisualStudio.ComponentGroup.MSIX.Packaging",
"Microsoft.VisualStudio.Workload.ManagedDesktop",
"Microsoft.VisualStudio.Component.VC.Redist.14.Latest",
+ "Microsoft.VisualStudio.ComponentGroup.ArchitectureTools.Native",
"Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Core",
+ "Microsoft.VisualStudio.Component.VC.Tools.ARM64",
"Microsoft.VisualStudio.Component.VC.CLI.Support",
"Microsoft.VisualStudio.Workload.NativeDesktop",
- "Microsoft.VisualStudio.Component.VC.Tools.ARM64",
"Microsoft.VisualStudio.Component.VC.Tools.ARM",
+ "Microsoft.Net.ComponentGroup.TargetingPacks.Common",
+ "Microsoft.Net.Component.4.6.TargetingPack",
"Microsoft.VisualStudio.Component.Git",
"Microsoft.VisualStudio.Component.LinqToSql",
+ "Microsoft.NetCore.Component.Runtime.3.1",
+ "Microsoft.NetCore.Component.Runtime.5.0",
"Microsoft.Net.Component.4.6.2.SDK",
"Microsoft.Net.Component.4.7.SDK"
]
-}
+}
\ No newline at end of file
diff --git a/Directory.Build.props b/Directory.Build.props
index cc4715cfad4f06..88779ccdac0290 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -280,6 +280,9 @@
Properties
false
+
+ true
diff --git a/eng/Subsets.props b/eng/Subsets.props
index f9bde27cb97770..f26f40c7d7a052 100644
--- a/eng/Subsets.props
+++ b/eng/Subsets.props
@@ -35,14 +35,24 @@
<_subset Condition="'$(Subset)' == ''">+$(DefaultSubsets)+
+
+
+ CoreCLR
+ Mono
+
+
Mono
Mono
- CoreCLR
+ $(PrimaryRuntimeFlavor)
clr.native+linuxdac+clr.corelib+clr.tools+clr.nativecorelib+clr.packages
+
+ clr.iltools+clr.packages
mono.llvm+
mono.llvm+
@@ -58,8 +68,8 @@
host.native+host.tools
$(DefaultHostSubsets)+host.pkg+host.tests
-
- host.native
+
+ host.native
packs.product
$(DefaultPacksSubsets)+packs.tests
@@ -225,7 +235,7 @@
-
+
@@ -317,16 +327,16 @@
-
+
-
-
-
+
+
+
-
+
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 2f2190618a1115..9d351471f4b163 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -4,7 +4,7 @@
https://github.com/dotnet/icu
08293141bc33a81b7e58120535079d8eac36519f
-
+
https://github.com/dotnet/msquic
d7db669b70f4dd67ec001c192f9809c218cab88b
@@ -54,9 +54,9 @@
https://github.com/dotnet/arcade
89806f0b9e93ad2bbe32c654412835c0801a2032
-
+
https://github.com/dotnet/arcade
- 89806f0b9e93ad2bbe32c654412835c0801a2032
+ 6224d1b573b73caaa84176bd83dabe75f202cdc7
https://github.com/dotnet/arcade
@@ -186,9 +186,9 @@
https://github.com/dotnet/runtime
f7e4c261815c66fde2c1e750b744f193e236c17e
-
+
https://github.com/mono/linker
- 6eae01980dc694107bdee0bc723d75a0dd601f0e
+ b888d672e11588e2bbca1cd3eeaee30d53416897
https://github.com/dotnet/xharness
diff --git a/eng/Versions.props b/eng/Versions.props
index ecd7f036d099fc..bf0541aa321cbb 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -17,8 +17,8 @@
release
true
-
- 4.0.0-3.21367.2
+
+ 4.0.0-3.21376.12
true
false
false
@@ -62,7 +62,7 @@
6.0.0-beta.21370.12
6.0.0-beta.21370.12
6.0.0-beta.21370.12
- 6.0.0-beta.21370.12
+ 6.0.0-beta.21372.16
6.0.0-beta.21370.12
6.0.0-beta.21370.12
6.0.0-beta.21370.12
@@ -143,7 +143,7 @@
These are used as reference assemblies only, so they must not take a ProdCon/source-build
version. Insert "RefOnly" to avoid assignment via PVP.
-->
- 16.9.0
+ 16.10.0
$(RefOnlyMicrosoftBuildVersion)
$(RefOnlyMicrosoftBuildVersion)
$(RefOnlyMicrosoftBuildVersion)
@@ -166,12 +166,12 @@
5.0.0-preview-20201009.2
- 6.0.100-preview.6.21370.1
+ 6.0.100-preview.6.21376.2
$(MicrosoftNETILLinkTasksVersion)
6.0.0-rc.1.21369.1
- 6.0.0-preview.7.21357.1
+ 6.0.0-preview.7.21376.1
11.1.0-alpha.1.21369.1
11.1.0-alpha.1.21369.1
diff --git a/eng/pipelines/common/restore-internal-tools.yml b/eng/pipelines/common/restore-internal-tools.yml
index 848c9800c167c9..d289d82b53505c 100644
--- a/eng/pipelines/common/restore-internal-tools.yml
+++ b/eng/pipelines/common/restore-internal-tools.yml
@@ -7,6 +7,7 @@ steps:
- script: $(Build.SourcesDirectory)$(dir)build$(scriptExt)
-ci
-restore
+ -configuration $(_BuildConfig)
-projects $(Build.SourcesDirectory)/eng/common/internal/Tools.csproj
/bl:$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)/RestoreInternal.binlog
/v:normal
diff --git a/eng/pipelines/common/templates/runtimes/run-test-job.yml b/eng/pipelines/common/templates/runtimes/run-test-job.yml
index fb1a3b55f9afc9..96b85e61bf94cd 100644
--- a/eng/pipelines/common/templates/runtimes/run-test-job.yml
+++ b/eng/pipelines/common/templates/runtimes/run-test-job.yml
@@ -486,6 +486,9 @@ jobs:
gcSimulatorTests: true
scenarios:
- normal
+ ${{ if in(parameters.testGroup, 'gc-standalone') }}:
+ scenarios:
+ - gcstandalone
${{ if in(parameters.testGroup, 'jitelthookenabled') }}:
scenarios:
- jitelthookenabled
diff --git a/eng/pipelines/coreclr/ci.yml b/eng/pipelines/coreclr/ci.yml
index 117f645186fb94..c4cbf06a14bde6 100644
--- a/eng/pipelines/coreclr/ci.yml
+++ b/eng/pipelines/coreclr/ci.yml
@@ -151,20 +151,6 @@ jobs:
displayNameArgs: R2R_CG2
liveLibrariesBuildConfig: Release
-#
-# Crossgen-comparison jobs
-#
-- template: /eng/pipelines/common/platform-matrix.yml
- parameters:
- jobTemplate: /eng/pipelines/coreclr/templates/crossgen-comparison-job.yml
- buildConfig: release
- platforms:
- # Currently failing globally, should be uncommented once the tracking bug gets fixed:
- # https://github.com/dotnet/runtime/issues/1282
- # - Linux_arm
- helixQueueGroup: ci
- helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml
-
#
# Formatting
#
diff --git a/eng/pipelines/coreclr/gc-standalone.yml b/eng/pipelines/coreclr/gc-standalone.yml
new file mode 100644
index 00000000000000..4d309290705328
--- /dev/null
+++ b/eng/pipelines/coreclr/gc-standalone.yml
@@ -0,0 +1,49 @@
+trigger: none
+
+schedules:
+- cron: "0 5 * * *"
+ displayName: Mon through Sun at 9:00 PM (UTC-8:00)
+ branches:
+ include:
+ - main
+ always: true
+
+jobs:
+
+- template: /eng/pipelines/common/platform-matrix.yml
+ parameters:
+ jobTemplate: /eng/pipelines/common/build-coreclr-and-libraries-job.yml
+ buildConfig: checked
+ platforms:
+ - Linux_arm64
+ - windows_arm64
+ - windows_x64
+ - CoreClrTestBuildHost # Either OSX_x64 or Linux_x64
+ jobParameters:
+ testGroup: gc-standalone
+
+- template: /eng/pipelines/common/platform-matrix.yml
+ parameters:
+ jobTemplate: /eng/pipelines/common/templates/runtimes/build-test-job.yml
+ buildConfig: checked
+ platforms:
+ - CoreClrTestBuildHost # Either OSX_x64 or Linux_x64
+ jobParameters:
+ testGroup: gc-standalone
+ liveLibrariesBuildConfig: Release
+
+- template: /eng/pipelines/common/platform-matrix.yml
+ parameters:
+ jobTemplate: /eng/pipelines/common/templates/runtimes/run-test-job.yml
+ buildConfig: checked
+ platforms:
+ - Linux_arm64
+ - Linux_x64
+ - windows_arm64
+ - windows_x64
+ helixQueueGroup: ci
+ helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml
+ jobParameters:
+ testGroup: gc-standalone
+ displayNameArgs: GCStandAlone
+ liveLibrariesBuildConfig: Release
diff --git a/eng/pipelines/coreclr/release-tests.yml b/eng/pipelines/coreclr/release-tests.yml
index 485389ccf33375..bfa51bd287826d 100644
--- a/eng/pipelines/coreclr/release-tests.yml
+++ b/eng/pipelines/coreclr/release-tests.yml
@@ -72,17 +72,3 @@ jobs:
readyToRun: true
displayNameArgs: R2R
-#
-# Crossgen-comparison jobs
-#
-- template: /eng/pipelines/common/platform-matrix.yml
- parameters:
- jobTemplate: /eng/pipelines/coreclr/templates/crossgen-comparison-job.yml
- buildConfig: release
- platforms:
- - Linux_arm
- helixQueueGroup: ci
- helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml
- jobParameters:
- testGroup: outerloop
- liveLibrariesBuildConfig: Release
diff --git a/eng/pipelines/coreclr/templates/crossgen-comparison-job.yml b/eng/pipelines/coreclr/templates/crossgen-comparison-job.yml
deleted file mode 100644
index 282dcee588e5d8..00000000000000
--- a/eng/pipelines/coreclr/templates/crossgen-comparison-job.yml
+++ /dev/null
@@ -1,203 +0,0 @@
-parameters:
- buildConfig: ''
- archType: ''
- osGroup: ''
- osSubgroup: ''
- container: ''
- helixQueues: ''
- runtimeVariant: ''
- crossBuild: false
- crossrootfsDir: ''
- dependOnEvaluatePaths: false
- stagedBuild: false
- variables: {}
- pool: ''
-
- # When set to a non-empty value (Debug / Release), it determines libraries
- # build configuration to use for the tests. Setting this property implies
- # a dependency of this job on the appropriate libraries build and is used
- # to construct the name of the Azure artifact representing libraries build
- # to use for building the tests.
- liveLibrariesBuildConfig: ''
-
-### Crossgen-comparison job
-###
-### Ensure that the output of cross-architecture, e.g. x64-hosted-arm-targeting,
-### crossgen matches that of native, e.g. arm-hosted-arm-targeting, crossgen.
-
-jobs:
-- template: xplat-pipeline-job.yml
- parameters:
- buildConfig: ${{ parameters.buildConfig }}
- archType: ${{ parameters.archType }}
- osGroup: ${{ parameters.osGroup }}
- osSubgroup: ${{ parameters.osSubgroup }}
- stagedBuild: ${{ parameters.stagedBuild }}
- runtimeVariant: ${{ parameters.runtimeVariant }}
- liveLibrariesBuildConfig: ${{ parameters.liveLibrariesBuildConfig }}
- helixType: 'test/crossgen-comparison/'
- pool: ${{ parameters.pool }}
- dependOnEvaluatePaths: ${{ parameters.dependOnEvaluatePaths }}
-
- # Compute job name from template parameters
- name: ${{ format('test_crossgen_comparison_{0}{1}_{1}_{2}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
- displayName: ${{ format('Test crossgen-comparison {0}{1} {2} {3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
-
- crossBuild: ${{ parameters.crossBuild }}
- crossrootfsDir: ${{ parameters.crossrootfsDir }}
-
- variables:
- - ${{ if eq(variables['System.TeamProject'], 'internal') }}:
- - group: DotNet-HelixApi-Access
- - name: hostArchType
- value: x64
- - name: targetFlavor
- value: $(osGroup).$(archType).$(buildConfigUpper)
- - name: crossFlavor
- value: $(osGroup).$(hostArchType)_$(archType).$(buildConfigUpper)
- - ${{ if ne(parameters.osGroup, 'windows') }}:
- - name: artifactsDirectory
- value: $(Build.SourcesDirectory)/artifacts
- - name: binDirectory
- value: $(artifactsDirectory)/bin
- - name: productDirectory
- value: $(binDirectory)/coreclr
- - name: workItemDirectory
- value: $(artifactsDirectory)/tests/coreclr/$(targetFlavor)/Tests/Core_Root
- - ${{ if eq(parameters.osGroup, 'windows') }}:
- - name: artifactsDirectory
- value: $(Build.SourcesDirectory)\artifacts
- - name: binDirectory
- value: $(artifactsDirectory)\bin
- - name: productDirectory
- value: $(binDirectory)\coreclr
- - name: workItemDirectory
- value: $(artifactsDirectory)\tests\coreclr\$(targetFlavor)\Tests\Core_Root
-
- - ${{ parameters.variables }}
-
- # 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.liveLibrariesBuildConfig, '') }}:
- - ${{ format('libraries_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.liveLibrariesBuildConfig) }}
-
- # Run all steps in the container.
- # Note that the containers are defined in platform-matrix.yml
- container: ${{ parameters.container }}
- timeoutInMinutes: 180 # 3 hrs
-
- steps:
-
- # Download product build
- - template: /eng/pipelines/common/download-artifact-step.yml
- parameters:
- unpackFolder: $(buildProductRootFolderPath)
- artifactFileName: '$(buildProductArtifactName)$(archiveExtension)'
- artifactName: '$(buildProductArtifactName)'
- displayName: 'product build'
-
- # Optionally download live-built libraries
- - ${{ if ne(parameters.liveLibrariesBuildConfig, '') }}:
- - template: /eng/pipelines/common/download-artifact-step.yml
- parameters:
- unpackFolder: $(librariesDownloadDir)
- cleanUnpackFolder: false
- artifactFileName: '$(librariesBuildArtifactName)$(archiveExtension)'
- artifactName: '$(librariesBuildArtifactName)'
- displayName: 'live-built libraries'
-
- # Populate Core_Root
- - script: $(Build.SourcesDirectory)/src/tests/build$(scriptExt) $(buildConfig) $(archType) $(crossArg) generatelayoutonly
- displayName: Populate Core_Root
-
- # Create directories and ensure crossgen is executable
- - ${{ if ne(parameters.osGroup, 'windows') }}:
- - script: |
- chmod +x $(workItemDirectory)/crossgen
- mkdir -p $(workItemDirectory)/log/$(crossFlavor)
- displayName: Create directories and ensure crossgen is executable
- - ${{ if eq(parameters.osGroup, 'windows') }}:
- - script: |
- mkdir $(workItemDirectory)\log\$(crossFlavor)
- displayName: Create directories
-
- # Create baseline output on the host (x64) machine
- - task: PythonScript@0
- displayName: Create cross-platform crossgen baseline
- inputs:
- scriptSource: 'filePath'
- scriptPath: $(Build.SourcesDirectory)/src/tests/Common/scripts/crossgen_comparison.py
- pythonInterpreter: /usr/bin/python3
- ${{ if ne(parameters.osGroup, 'windows') }}:
- arguments:
- crossgen_framework
- --crossgen $(productDirectory)/$(targetFlavor)/$(hostArchType)/crossgen
- --il_corelib $(productDirectory)/$(targetFlavor)/IL/System.Private.CoreLib.dll
- --core_root $(workItemDirectory)
- --result_dir $(workItemDirectory)/log/$(crossFlavor)
- ${{ if eq(parameters.osGroup, 'windows') }}:
- arguments:
- crossgen_framework
- --crossgen $(productDirectory)\$(targetFlavor)\$(hostArchType)\crossgen
- --il_corelib $(productDirectory)\$(targetFlavor)\IL\System.Private.CoreLib.dll
- --core_root $(workItemDirectory)
- --result_dir $(workItemDirectory)\log\$(crossFlavor)
-
- # Dump contents and payload information
- - ${{ if ne(parameters.osGroup, 'windows') }}:
- - script: |
- ls $(workItemDirectory)
- du -sh $(workItemDirectory)
- displayName: Dump contents and payload information
- - ${{ if eq(parameters.osGroup, 'windows') }}:
- - script: |
- dir $(workItemDirectory)
- displayName: Dump contents and payload information
-
- # Send payload to Helix where the native output is generated and compared to the baseline
- - template: /eng/common/templates/steps/send-to-helix.yml
- parameters:
- DisplayNamePrefix: Run native crossgen and compare output to baseline
- HelixSource: $(_HelixSource)
- HelixType: 'test/crossgen-comparison/'
- ${{ if eq(variables['System.TeamProject'], 'internal') }}:
- HelixAccessToken: $(HelixApiAccessToken)
- HelixTargetQueues: ${{ join(' ', parameters.helixQueues) }}
- ${{ if ne(variables['System.TeamProject'], 'internal') }}:
- Creator: $(Creator)
- WorkItemTimeout: 3:00 # 3 hours
- WorkItemDirectory: '$(workItemDirectory)'
- CorrelationPayloadDirectory: '$(Build.SourcesDirectory)/src/tests/Common/scripts'
- ${{ if ne(parameters.osName, 'windows') }}:
- WorkItemCommand:
- chmod +x $HELIX_WORKITEM_PAYLOAD/crossgen;
- mkdir -p $HELIX_WORKITEM_PAYLOAD/log/$(targetFlavor);
- python3 -u $HELIX_CORRELATION_PAYLOAD/crossgen_comparison.py crossgen_framework
- --crossgen $HELIX_WORKITEM_PAYLOAD/crossgen
- --il_corelib $HELIX_WORKITEM_PAYLOAD/IL/System.Private.CoreLib.dll
- --core_root $HELIX_WORKITEM_PAYLOAD
- --result_dir $HELIX_WORKITEM_PAYLOAD/log/$(targetFlavor);
- python3 -u $HELIX_CORRELATION_PAYLOAD/crossgen_comparison.py compare
- --base_dir $HELIX_WORKITEM_PAYLOAD/log/$(crossFlavor)
- --diff_dir $HELIX_WORKITEM_PAYLOAD/log/$(targetFlavor)
- ${{ if eq(parameters.osName, 'windows') }}:
- WorkItemCommand:
- mkdir %HELIX_WORKITEM_PAYLOAD%\log\$(targetFlavor);
- python3 -u %HELIX_CORRELATION_PAYLOAD%\crossgen_comparison.py crossgen_framework
- --crossgen %HELIX_WORKITEM_PAYLOAD%\crossgen
- --il_corelib %HELIX_WORKITEM_PAYLOAD%\IL\System.Private.CoreLib.dll
- --core_root %HELIX_WORKITEM_PAYLOAD%
- --result_dir %HELIX_WORKITEM_PAYLOAD%\log\$(targetFlavor);
- python3 -u %HELIX_CORRELATION_PAYLOAD%\crossgen_comparison.py compare
- --base_dir %HELIX_WORKITEM_PAYLOAD%\log\$(crossFlavor)
- --diff_dir %HELIX_WORKITEM_PAYLOAD%\log\$(targetFlavor)
-
- # Publish log
- - task: PublishPipelineArtifact@1
- displayName: Publish log
- inputs:
- pathtoPublish: $(workItemDirectory)/log
- artifactName: ${{ format('Testlog_crossgen_comparison_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
- continueOnError: true
- condition: always()
diff --git a/eng/pipelines/coreclr/templates/xplat-pipeline-job.yml b/eng/pipelines/coreclr/templates/xplat-pipeline-job.yml
index e3200502b7060d..712bd74057c4f3 100644
--- a/eng/pipelines/coreclr/templates/xplat-pipeline-job.yml
+++ b/eng/pipelines/coreclr/templates/xplat-pipeline-job.yml
@@ -129,7 +129,8 @@ jobs:
value: ''
# 'innerloop' and 'clrinterpreter' jobs run the Priority 0 tests; everything else runs the Priority 1 tests.
- - ${{ if and(ne(parameters.testGroup, 'innerloop'), ne(parameters.testGroup, 'clrinterpreter')) }}:
+ # 'gc-standalone' is forced to run pri0 as well to start with.
+ - ${{ if and(ne(parameters.testGroup, 'innerloop'), ne(parameters.testGroup, 'clrinterpreter'), ne(parameters.testGroup, 'gc-standalone')) }}:
- ${{ if ne(parameters.osGroup, 'windows') }}:
- name: priorityArg
value: 'priority1'
diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml
index fdeeecdaa82936..2ae339930ef6bb 100644
--- a/eng/pipelines/runtime.yml
+++ b/eng/pipelines/runtime.yml
@@ -899,25 +899,6 @@ jobs:
- windows_x86
- Linux_x64
-#
-# Crossgen-comparison jobs
-# Only when CoreCLR is changed
-#
-- template: /eng/pipelines/common/platform-matrix.yml
- parameters:
- jobTemplate: /eng/pipelines/coreclr/templates/crossgen-comparison-job.yml
- buildConfig: checked
- platforms:
- - Linux_arm
- helixQueueGroup: pr
- helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml
- jobParameters:
- liveLibrariesBuildConfig: Release
- condition: >-
- or(
- eq(dependencies.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true),
- eq(variables['isFullMatrix'], true))
-
#
# CoreCLR Test builds using live libraries release build
# Only when CoreCLR is changed
diff --git a/eng/testing/ILLinkDescriptors/ILLink.Descriptors.Castle.xml b/eng/testing/ILLinkDescriptors/ILLink.Descriptors.Castle.xml
index d9aa664cee8d81..7a8084b4d633bc 100644
--- a/eng/testing/ILLinkDescriptors/ILLink.Descriptors.Castle.xml
+++ b/eng/testing/ILLinkDescriptors/ILLink.Descriptors.Castle.xml
@@ -2,7 +2,6 @@
-
diff --git a/src/coreclr/.nuget/coreclr-packages.proj b/src/coreclr/.nuget/coreclr-packages.proj
index 1347e06d5ff0a0..5d6391b6124e22 100644
--- a/src/coreclr/.nuget/coreclr-packages.proj
+++ b/src/coreclr/.nuget/coreclr-packages.proj
@@ -5,12 +5,15 @@
-
+
-
+
+
+
+
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/CastHelpers.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/CastHelpers.cs
index cb8800994aa787..a31f67b4ebbff2 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/CastHelpers.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/CastHelpers.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
+using System.Numerics;
using System.Runtime.InteropServices;
using System.Threading;
@@ -45,10 +46,10 @@ private static int KeyToBucket(ref int tableData, nuint source, nuint target)
int hashShift = HashShift(ref tableData);
#if TARGET_64BIT
- ulong hash = (((ulong)source << 32) | ((ulong)source >> 32)) ^ (ulong)target;
+ ulong hash = BitOperations.RotateLeft((ulong)source, 32) ^ (ulong)target;
return (int)((hash * 11400714819323198485ul) >> hashShift);
#else
- uint hash = (((uint)source >> 16) | ((uint)source << 16)) ^ (uint)target;
+ uint hash = BitOperations.RotateLeft((uint)source, 16) ^ (uint)target;
return (int)((hash * 2654435769u) >> hashShift);
#endif
}
diff --git a/src/coreclr/classlibnative/bcltype/system.cpp b/src/coreclr/classlibnative/bcltype/system.cpp
index eece2220c63a91..bf5cd0fc75309a 100644
--- a/src/coreclr/classlibnative/bcltype/system.cpp
+++ b/src/coreclr/classlibnative/bcltype/system.cpp
@@ -195,6 +195,8 @@ INT32 QCALLTYPE SystemNative::GetProcessorCount()
// managed string object buffer. This buffer is not always used, see comments in
// the method below.
WCHAR g_szFailFastBuffer[256];
+WCHAR *g_pFailFastBuffer = g_szFailFastBuffer;
+
#define FAIL_FAST_STATIC_BUFFER_LENGTH (sizeof(g_szFailFastBuffer) / sizeof(WCHAR))
// This is the common code for FailFast processing that is wrapped by the two
@@ -243,7 +245,7 @@ void SystemNative::GenericFailFast(STRINGREF refMesgString, EXCEPTIONREF refExce
// Another option would seem to be to implement a new frame type that
// protects object references as pinned, but that seems like overkill for
// just this problem.
- WCHAR *pszMessage = NULL;
+ WCHAR *pszMessageBuffer = NULL;
DWORD cchMessage = (gc.refMesgString == NULL) ? 0 : gc.refMesgString->GetStringLength();
WCHAR * errorSourceString = NULL;
@@ -262,32 +264,44 @@ void SystemNative::GenericFailFast(STRINGREF refMesgString, EXCEPTIONREF refExce
if (cchMessage < FAIL_FAST_STATIC_BUFFER_LENGTH)
{
- pszMessage = g_szFailFastBuffer;
+ // The static buffer can be used only once to avoid race condition with other threads
+ pszMessageBuffer = InterlockedExchangeT(&g_pFailFastBuffer, NULL);
}
- else
+
+ if (pszMessageBuffer == NULL)
{
// We can fail here, but we can handle the fault.
CONTRACT_VIOLATION(FaultViolation);
- pszMessage = new (nothrow) WCHAR[cchMessage + 1];
- if (pszMessage == NULL)
+ pszMessageBuffer = new (nothrow) WCHAR[cchMessage + 1];
+ if (pszMessageBuffer == NULL)
{
// Truncate the message to what will fit in the static buffer.
cchMessage = FAIL_FAST_STATIC_BUFFER_LENGTH - 1;
- pszMessage = g_szFailFastBuffer;
+ pszMessageBuffer = InterlockedExchangeT(&g_pFailFastBuffer, NULL);
}
}
- if (cchMessage > 0)
- memcpyNoGCRefs(pszMessage, gc.refMesgString->GetBuffer(), cchMessage * sizeof(WCHAR));
- pszMessage[cchMessage] = W('\0');
+ const WCHAR *pszMessage;
+ if (pszMessageBuffer != NULL)
+ {
+ if (cchMessage > 0)
+ memcpyNoGCRefs(pszMessageBuffer, gc.refMesgString->GetBuffer(), cchMessage * sizeof(WCHAR));
+ pszMessageBuffer[cchMessage] = W('\0');
+ pszMessage = pszMessageBuffer;
+ }
+ else
+ {
+ pszMessage = W("There is not enough memory to print the supplied FailFast message.");
+ cchMessage = (DWORD)wcslen(pszMessage);
+ }
if (cchMessage == 0) {
WszOutputDebugString(W("CLR: Managed code called FailFast without specifying a reason.\r\n"));
}
else {
- WszOutputDebugString(W("CLR: Managed code called FailFast, saying \""));
+ WszOutputDebugString(W("CLR: Managed code called FailFast.\r\n"));
WszOutputDebugString(pszMessage);
- WszOutputDebugString(W("\"\r\n"));
+ WszOutputDebugString(W("\r\n"));
}
LPCWSTR argExceptionString = NULL;
diff --git a/src/coreclr/crossgen-corelib.proj b/src/coreclr/crossgen-corelib.proj
index 6d675a2a59e247..655fc3281eb2ef 100644
--- a/src/coreclr/crossgen-corelib.proj
+++ b/src/coreclr/crossgen-corelib.proj
@@ -66,6 +66,7 @@
$(DotNetCli) $([MSBuild]::NormalizePath('$(BinDir)', 'dotnet-pgo', 'dotnet-pgo.dll')) merge
$(DotNetPgoCmd) -o:$(MergedMibcPath)
$(DotNetPgoCmd) @(OptimizationMibcFiles->'-i:%(Identity)', ' ')
+ $(DotNetPgoCmd) --inherit-timestamp
diff --git a/src/coreclr/debug/createdump/crashinfo.cpp b/src/coreclr/debug/createdump/crashinfo.cpp
index 807036fd200822..151a11d68a75d7 100644
--- a/src/coreclr/debug/createdump/crashinfo.cpp
+++ b/src/coreclr/debug/createdump/crashinfo.cpp
@@ -361,8 +361,9 @@ bool
CrashInfo::UnwindAllThreads(IXCLRDataProcess* pClrDataProcess)
{
ReleaseHolder pSos = nullptr;
- pClrDataProcess->QueryInterface(__uuidof(ISOSDacInterface), (void**)&pSos);
-
+ if (pClrDataProcess != nullptr) {
+ pClrDataProcess->QueryInterface(__uuidof(ISOSDacInterface), (void**)&pSos);
+ }
// For each native and managed thread
for (ThreadInfo* thread : m_threads)
{
diff --git a/src/coreclr/debug/createdump/crashinfo.h b/src/coreclr/debug/createdump/crashinfo.h
index 199144e17540ec..ca8f77994ac751 100644
--- a/src/coreclr/debug/createdump/crashinfo.h
+++ b/src/coreclr/debug/createdump/crashinfo.h
@@ -106,12 +106,12 @@ class CrashInfo : public ICLRDataEnumMemoryRegionsCallback,
inline const std::string& Name() const { return m_name; }
inline const ModuleInfo* MainModule() const { return m_mainModule; }
- inline const std::vector Threads() const { return m_threads; }
- inline const std::set ModuleMappings() const { return m_moduleMappings; }
- inline const std::set OtherMappings() const { return m_otherMappings; }
- inline const std::set MemoryRegions() const { return m_memoryRegions; }
+ inline const std::vector& Threads() const { return m_threads; }
+ inline const std::set& ModuleMappings() const { return m_moduleMappings; }
+ inline const std::set& OtherMappings() const { return m_otherMappings; }
+ inline const std::set& MemoryRegions() const { return m_memoryRegions; }
#ifndef __APPLE__
- inline const std::vector AuxvEntries() const { return m_auxvEntries; }
+ inline const std::vector& AuxvEntries() const { return m_auxvEntries; }
inline size_t GetAuxvSize() const { return m_auxvEntries.size() * sizeof(elf_aux_entry); }
#endif
diff --git a/src/coreclr/jit/codegen.h b/src/coreclr/jit/codegen.h
index 65cf32b02020d5..6a78dc35154394 100644
--- a/src/coreclr/jit/codegen.h
+++ b/src/coreclr/jit/codegen.h
@@ -1155,7 +1155,10 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void genConsumeHWIntrinsicOperands(GenTreeHWIntrinsic* tree);
#endif // FEATURE_HW_INTRINSICS
void genEmitGSCookieCheck(bool pushReg);
- void genSetRegToIcon(regNumber reg, ssize_t val, var_types type = TYP_INT, insFlags flags = INS_FLAGS_DONT_CARE);
+ void genSetRegToIcon(regNumber reg,
+ ssize_t val,
+ var_types type = TYP_INT,
+ insFlags flags = INS_FLAGS_DONT_CARE DEBUGARG(GenTreeFlags gtFlags = GTF_EMPTY));
void genCodeForShift(GenTree* tree);
#if defined(TARGET_X86) || defined(TARGET_ARM)
@@ -1490,7 +1493,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
regNumber reg,
ssize_t imm,
insFlags flags = INS_FLAGS_DONT_CARE DEBUGARG(size_t targetHandle = 0)
- DEBUGARG(unsigned gtFlags = 0));
+ DEBUGARG(GenTreeFlags gtFlags = GTF_EMPTY));
void instGen_Compare_Reg_To_Zero(emitAttr size, regNumber reg);
diff --git a/src/coreclr/jit/codegenarm.cpp b/src/coreclr/jit/codegenarm.cpp
index 4cd5f03b57e513..7c8c75ff9a6208 100644
--- a/src/coreclr/jit/codegenarm.cpp
+++ b/src/coreclr/jit/codegenarm.cpp
@@ -159,7 +159,7 @@ void CodeGen::genEHCatchRet(BasicBlock* block)
void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size,
regNumber reg,
ssize_t imm,
- insFlags flags DEBUGARG(size_t targetHandle) DEBUGARG(unsigned gtFlags))
+ insFlags flags DEBUGARG(size_t targetHandle) DEBUGARG(GenTreeFlags gtFlags))
{
// reg cannot be a FP register
assert(!genIsValidFloatReg(reg));
diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp
index fa7e8fd99fd17e..2428c33fee6f78 100644
--- a/src/coreclr/jit/codegenarm64.cpp
+++ b/src/coreclr/jit/codegenarm64.cpp
@@ -1594,7 +1594,7 @@ void CodeGen::genEHCatchRet(BasicBlock* block)
void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size,
regNumber reg,
ssize_t imm,
- insFlags flags DEBUGARG(size_t targetHandle) DEBUGARG(unsigned gtFlags))
+ insFlags flags DEBUGARG(size_t targetHandle) DEBUGARG(GenTreeFlags gtFlags))
{
// reg cannot be a FP register
assert(!genIsValidFloatReg(reg));
diff --git a/src/coreclr/jit/codegenarmarch.cpp b/src/coreclr/jit/codegenarmarch.cpp
index 292df210aab226..1953f93e076b9a 100644
--- a/src/coreclr/jit/codegenarmarch.cpp
+++ b/src/coreclr/jit/codegenarmarch.cpp
@@ -560,7 +560,7 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
//------------------------------------------------------------------------
// genSetRegToIcon: Generate code that will set the given register to the integer constant.
//
-void CodeGen::genSetRegToIcon(regNumber reg, ssize_t val, var_types type, insFlags flags)
+void CodeGen::genSetRegToIcon(regNumber reg, ssize_t val, var_types type, insFlags flags DEBUGARG(GenTreeFlags gtFlags))
{
// Reg cannot be a FP reg
assert(!genIsValidFloatReg(reg));
@@ -603,7 +603,7 @@ void CodeGen::genSetGSSecurityCookie(regNumber initReg, bool* pInitRegZeroed)
else
{
instGen_Set_Reg_To_Imm(EA_PTR_DSP_RELOC, initReg, (ssize_t)compiler->gsGlobalSecurityCookieAddr,
- INS_FLAGS_DONT_CARE DEBUGARG((size_t)THT_SetGSCookie) DEBUGARG(0));
+ INS_FLAGS_DONT_CARE DEBUGARG((size_t)THT_SetGSCookie) DEBUGARG(GTF_EMPTY));
GetEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, initReg, initReg, 0);
regSet.verifyRegUsed(initReg);
GetEmitter()->emitIns_S_R(INS_str, EA_PTRSIZE, initReg, compiler->lvaGSSecurityCookie, 0);
diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp
index b0f6aab8e30e3b..dcf1768c60a7dd 100644
--- a/src/coreclr/jit/codegencommon.cpp
+++ b/src/coreclr/jit/codegencommon.cpp
@@ -1799,7 +1799,7 @@ void CodeGen::genEmitGSCookieCheck(bool pushReg)
{
// Ngen case - GS cookie constant needs to be accessed through an indirection.
instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, regGSConst, (ssize_t)compiler->gsGlobalSecurityCookieAddr,
- INS_FLAGS_DONT_CARE DEBUGARG((size_t)THT_GSCookieCheck) DEBUGARG(0));
+ INS_FLAGS_DONT_CARE DEBUGARG((size_t)THT_GSCookieCheck) DEBUGARG(GTF_EMPTY));
GetEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, regGSConst, regGSConst, 0);
}
// Load this method's GS value from the stack frame
diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp
index e361a56ae4747c..529d1fe948799c 100644
--- a/src/coreclr/jit/codegenxarch.cpp
+++ b/src/coreclr/jit/codegenxarch.cpp
@@ -28,7 +28,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
* Generate code that will set the given register to the integer constant.
*/
-void CodeGen::genSetRegToIcon(regNumber reg, ssize_t val, var_types type, insFlags flags)
+void CodeGen::genSetRegToIcon(regNumber reg, ssize_t val, var_types type, insFlags flags DEBUGARG(GenTreeFlags gtFlags))
{
// Reg cannot be a FP reg
assert(!genIsValidFloatReg(reg));
@@ -45,7 +45,7 @@ void CodeGen::genSetRegToIcon(regNumber reg, ssize_t val, var_types type, insFla
else
{
// TODO-XArch-CQ: needs all the optimized cases
- GetEmitter()->emitIns_R_I(INS_mov, emitActualTypeSize(type), reg, val);
+ GetEmitter()->emitIns_R_I(INS_mov, emitActualTypeSize(type), reg, val DEBUGARG(gtFlags));
}
}
@@ -440,7 +440,7 @@ void CodeGen::genEHFinallyOrFilterRet(BasicBlock* block)
void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size,
regNumber reg,
ssize_t imm,
- insFlags flags DEBUGARG(size_t targetHandle) DEBUGARG(unsigned gtFlags))
+ insFlags flags DEBUGARG(size_t targetHandle) DEBUGARG(GenTreeFlags gtFlags))
{
// reg cannot be a FP register
assert(!genIsValidFloatReg(reg));
@@ -505,7 +505,7 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre
}
else
{
- genSetRegToIcon(targetReg, cnsVal, targetType);
+ genSetRegToIcon(targetReg, cnsVal, targetType, INS_FLAGS_DONT_CARE DEBUGARG(tree->gtFlags));
}
}
break;
diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp
index 21e37879eed7ec..36dbf617a70f86 100644
--- a/src/coreclr/jit/emit.cpp
+++ b/src/coreclr/jit/emit.cpp
@@ -3904,6 +3904,114 @@ void emitter::emitRecomputeIGoffsets()
#endif
}
+//----------------------------------------------------------------------------------------
+// emitDispCommentForHandle:
+// Displays a comment for a handle, e.g. displays a raw string for GTF_ICON_STR_HDL
+// or a class name for GTF_ICON_CLASS_HDL
+//
+// Arguments:
+// handle - a constant value to display a comment for
+// flags - a flag that the describes the handle
+//
+void emitter::emitDispCommentForHandle(size_t handle, GenTreeFlags flag)
+{
+#ifdef DEBUG
+ if (handle == 0)
+ {
+ return;
+ }
+
+#ifdef TARGET_XARCH
+ const char* commentPrefix = " ;";
+#else
+ const char* commentPrefix = " //";
+#endif
+
+ flag &= GTF_ICON_HDL_MASK;
+ const char* str = nullptr;
+
+ if (flag == GTF_ICON_STR_HDL)
+ {
+ const WCHAR* wstr = emitComp->eeGetCPString(handle);
+ // NOTE: eGetCPString always returns nullptr on Linux/ARM
+ if (wstr == nullptr)
+ {
+ str = "string handle";
+ }
+ else
+ {
+ const size_t actualLen = wcslen(wstr);
+ const size_t maxLength = 63;
+ const size_t newLen = min(maxLength, actualLen);
+
+ // +1 for null terminator
+ WCHAR buf[maxLength + 1] = {0};
+ wcsncpy(buf, wstr, newLen);
+ for (size_t i = 0; i < newLen; i++)
+ {
+ // Escape \n and \r symbols
+ if (buf[i] == L'\n' || buf[i] == L'\r')
+ {
+ buf[i] = L' ';
+ }
+ }
+ if (actualLen > maxLength)
+ {
+ // Append "..." for long strings
+ buf[maxLength - 3] = L'.';
+ buf[maxLength - 2] = L'.';
+ buf[maxLength - 1] = L'.';
+ }
+ printf("%s \"%S\"", commentPrefix, buf);
+ }
+ }
+ else if (flag == GTF_ICON_CLASS_HDL)
+ {
+ str = emitComp->eeGetClassName(reinterpret_cast(handle));
+ }
+#ifndef TARGET_XARCH
+ // These are less useful for xarch:
+ else if (flag == GTF_ICON_CONST_PTR)
+ {
+ str = "const ptr";
+ }
+ else if (flag == GTF_ICON_GLOBAL_PTR)
+ {
+ str = "global ptr";
+ }
+ else if (flag == GTF_ICON_FIELD_HDL)
+ {
+ str = emitComp->eeGetFieldName(reinterpret_cast(handle));
+ }
+ else if (flag == GTF_ICON_STATIC_HDL)
+ {
+ str = "static handle";
+ }
+ else if (flag == GTF_ICON_METHOD_HDL)
+ {
+ str = emitComp->eeGetMethodFullName(reinterpret_cast(handle));
+ }
+ else if (flag == GTF_ICON_FTN_ADDR)
+ {
+ str = "function address";
+ }
+ else if (flag == GTF_ICON_TOKEN_HDL)
+ {
+ str = "token handle";
+ }
+ else
+ {
+ str = "unknown";
+ }
+#endif // TARGET_XARCH
+
+ if (str != nullptr)
+ {
+ printf("%s %s", commentPrefix, str);
+ }
+#endif // DEBUG
+}
+
/*****************************************************************************
* Bind targets of relative jumps to choose the smallest possible encoding.
* X86 and AMD64 have a small and large encoding.
@@ -8735,11 +8843,7 @@ const char* emitter::emitOffsetToLabel(unsigned offs)
if (ig->igOffs == offs)
{
- // Found it!
- sprintf_s(buf[curBuf], TEMP_BUFFER_LEN, "%s", emitLabelString(ig));
- retbuf = buf[curBuf];
- curBuf = (curBuf + 1) % 4;
- return retbuf;
+ return emitLabelString(ig);
}
else if (ig->igOffs > offs)
{
diff --git a/src/coreclr/jit/emit.h b/src/coreclr/jit/emit.h
index ef67148ea962a3..4776f14648221c 100644
--- a/src/coreclr/jit/emit.h
+++ b/src/coreclr/jit/emit.h
@@ -510,6 +510,8 @@ class emitter
void emitRecomputeIGoffsets();
+ void emitDispCommentForHandle(size_t handle, GenTreeFlags flags);
+
/************************************************************************/
/* The following describes a single instruction */
/************************************************************************/
@@ -545,7 +547,7 @@ class emitter
size_t idSize; // size of the instruction descriptor
unsigned idVarRefOffs; // IL offset for LclVar reference
size_t idMemCookie; // for display of method name (also used by switch table)
- unsigned idFlags; // for determining type of handle in idMemCookie
+ GenTreeFlags idFlags; // for determining type of handle in idMemCookie
bool idFinallyCall; // Branch instruction is a call to finally
bool idCatchRet; // Instruction is for a catch 'return'
CORINFO_SIG_INFO* idCallSig; // Used to report native call site signatures to the EE
diff --git a/src/coreclr/jit/emitarm.cpp b/src/coreclr/jit/emitarm.cpp
index 387b0bb8f5d573..b8a730a31a7488 100644
--- a/src/coreclr/jit/emitarm.cpp
+++ b/src/coreclr/jit/emitarm.cpp
@@ -1711,8 +1711,11 @@ void emitter::emitIns_R(instruction ins, emitAttr attr, regNumber reg)
* Add an instruction referencing a register and a constant.
*/
-void emitter::emitIns_R_I(
- instruction ins, emitAttr attr, regNumber reg, target_ssize_t imm, insFlags flags /* = INS_FLAGS_DONT_CARE */)
+void emitter::emitIns_R_I(instruction ins,
+ emitAttr attr,
+ regNumber reg,
+ target_ssize_t imm,
+ insFlags flags /* = INS_FLAGS_DONT_CARE */ DEBUGARG(GenTreeFlags gtFlags))
{
insFormat fmt = IF_NONE;
@@ -2016,6 +2019,7 @@ void emitter::emitIns_R_I(
id->idInsSize(isz);
id->idInsFlags(sf);
id->idReg1(reg);
+ INDEBUG(id->idDebugOnlyInfo()->idFlags = gtFlags);
dispIns(id);
appendToCurIG(id);
diff --git a/src/coreclr/jit/emitarm.h b/src/coreclr/jit/emitarm.h
index ac6e4f139db7f8..6da0ceaa7ee262 100644
--- a/src/coreclr/jit/emitarm.h
+++ b/src/coreclr/jit/emitarm.h
@@ -220,8 +220,11 @@ void emitIns_I(instruction ins, emitAttr attr, target_ssize_t imm);
void emitIns_R(instruction ins, emitAttr attr, regNumber reg);
-void emitIns_R_I(
- instruction ins, emitAttr attr, regNumber reg, target_ssize_t imm, insFlags flags = INS_FLAGS_DONT_CARE);
+void emitIns_R_I(instruction ins,
+ emitAttr attr,
+ regNumber reg,
+ target_ssize_t imm,
+ insFlags flags = INS_FLAGS_DONT_CARE DEBUGARG(GenTreeFlags gtFlags = GTF_EMPTY));
void emitIns_MovRelocatableImmediate(instruction ins, emitAttr attr, regNumber reg, BYTE* addr);
void emitIns_Mov(instruction ins,
diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp
index 84c49d94723d43..771ce88ec849cb 100644
--- a/src/coreclr/jit/emitarm64.cpp
+++ b/src/coreclr/jit/emitarm64.cpp
@@ -3715,7 +3715,11 @@ void emitter::emitIns_R(instruction ins, emitAttr attr, regNumber reg)
* Add an instruction referencing a register and a constant.
*/
-void emitter::emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t imm, insOpts opt /* = INS_OPTS_NONE */)
+void emitter::emitIns_R_I(instruction ins,
+ emitAttr attr,
+ regNumber reg,
+ ssize_t imm,
+ insOpts opt /* = INS_OPTS_NONE */ DEBUGARG(GenTreeFlags gtFlags))
{
emitAttr size = EA_SIZE(attr);
emitAttr elemsize = EA_UNKNOWN;
@@ -3965,6 +3969,7 @@ void emitter::emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t
id->idInsOpt(opt);
id->idReg1(reg);
+ INDEBUG(id->idDebugOnlyInfo()->idFlags = gtFlags);
dispIns(id);
appendToCurIG(id);
@@ -8098,7 +8103,7 @@ void emitter::emitIns_R_AR(instruction ins, emitAttr attr, regNumber ireg, regNu
void emitter::emitIns_R_AI(instruction ins,
emitAttr attr,
regNumber ireg,
- ssize_t addr DEBUGARG(size_t targetHandle) DEBUGARG(unsigned gtFlags))
+ ssize_t addr DEBUGARG(size_t targetHandle) DEBUGARG(GenTreeFlags gtFlags))
{
assert(EA_IS_RELOC(attr));
emitAttr size = EA_SIZE(attr);
@@ -12257,7 +12262,6 @@ void emitter::emitDispIns(
ssize_t index2;
unsigned registerListSize;
const char* targetName;
- const WCHAR* stringLiteral;
case IF_BI_0A: // BI_0A ......iiiiiiiiii iiiiiiiiiiiiiiii simm26:00
case IF_BI_0B: // BI_0B ......iiiiiiiiii iiiiiiiiiii..... simm19:00
@@ -12363,9 +12367,8 @@ void emitter::emitDispIns(
case IF_LARGEADR:
assert(insOptsNone(id->idInsOpt()));
emitDispReg(id->idReg1(), size, true);
- imm = emitGetInsSC(id);
- targetName = nullptr;
- stringLiteral = nullptr;
+ imm = emitGetInsSC(id);
+ targetName = nullptr;
/* Is this actually a reference to a data section? */
if (fmt == IF_LARGEADR)
@@ -12398,8 +12401,7 @@ void emitter::emitDispIns(
{
printf("HIGH RELOC ");
emitDispImm((ssize_t)id->idAddr()->iiaAddr, false);
- size_t targetHandle = id->idDebugOnlyInfo()->idMemCookie;
- unsigned idFlags = id->idDebugOnlyInfo()->idFlags & GTF_ICON_HDL_MASK;
+ size_t targetHandle = id->idDebugOnlyInfo()->idMemCookie;
if (targetHandle == THT_IntializeArrayIntrinsics)
{
@@ -12413,53 +12415,6 @@ void emitter::emitDispIns(
{
targetName = "SetGlobalSecurityCookie";
}
- else if (idFlags == GTF_ICON_CONST_PTR)
- {
- targetName = "const ptr";
- }
- else if (idFlags == GTF_ICON_GLOBAL_PTR)
- {
- targetName = "global ptr";
- }
- else if (idFlags == GTF_ICON_STR_HDL)
- {
- stringLiteral = emitComp->eeGetCPString(targetHandle);
- // Note that eGetCPString isn't currently implemented on Linux/ARM
- // and instead always returns nullptr. However, use it here, so in
- // future, once it is is implemented, no changes will be needed here.
- if (stringLiteral == nullptr)
- {
- targetName = "String handle";
- }
- }
- else if (idFlags == GTF_ICON_FIELD_HDL)
- {
- targetName = emitComp->eeGetFieldName((CORINFO_FIELD_HANDLE)targetHandle);
- }
- else if (idFlags == GTF_ICON_STATIC_HDL)
- {
- targetName = "Static handle";
- }
- else if (idFlags == GTF_ICON_METHOD_HDL)
- {
- targetName = emitComp->eeGetMethodFullName((CORINFO_METHOD_HANDLE)targetHandle);
- }
- else if (idFlags == GTF_ICON_FTN_ADDR)
- {
- targetName = "Function address";
- }
- else if (idFlags == GTF_ICON_CLASS_HDL)
- {
- targetName = emitComp->eeGetClassName((CORINFO_CLASS_HANDLE)targetHandle);
- }
- else if (idFlags == GTF_ICON_TOKEN_HDL)
- {
- targetName = "Token handle";
- }
- else
- {
- targetName = "Unknown";
- }
}
else if (id->idIsBound())
{
@@ -12475,9 +12430,9 @@ void emitter::emitDispIns(
{
printf(" // [%s]", targetName);
}
- else if (stringLiteral != nullptr)
+ else
{
- printf(" // [%S]", stringLiteral);
+ emitDispCommentForHandle(id->idDebugOnlyInfo()->idMemCookie, id->idDebugOnlyInfo()->idFlags);
}
break;
diff --git a/src/coreclr/jit/emitarm64.h b/src/coreclr/jit/emitarm64.h
index b25659368c1d12..a5e98d24b569aa 100644
--- a/src/coreclr/jit/emitarm64.h
+++ b/src/coreclr/jit/emitarm64.h
@@ -728,7 +728,11 @@ void emitIns_I(instruction ins, emitAttr attr, ssize_t imm);
void emitIns_R(instruction ins, emitAttr attr, regNumber reg);
-void emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t imm, insOpts opt = INS_OPTS_NONE);
+void emitIns_R_I(instruction ins,
+ emitAttr attr,
+ regNumber reg,
+ ssize_t imm,
+ insOpts opt = INS_OPTS_NONE DEBUGARG(GenTreeFlags gtFlags = GTF_EMPTY));
void emitIns_R_F(instruction ins, emitAttr attr, regNumber reg, double immDbl, insOpts opt = INS_OPTS_NONE);
@@ -827,7 +831,7 @@ void emitIns_R_AR(instruction ins, emitAttr attr, regNumber ireg, regNumber reg,
void emitIns_R_AI(instruction ins,
emitAttr attr,
regNumber ireg,
- ssize_t disp DEBUGARG(size_t targetHandle = 0) DEBUGARG(unsigned gtFlags = 0));
+ ssize_t disp DEBUGARG(size_t targetHandle = 0) DEBUGARG(GenTreeFlags gtFlags = GTF_EMPTY));
void emitIns_AR_R(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs);
diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp
index 6e0de0d59e195b..dc55403d6dcf30 100644
--- a/src/coreclr/jit/emitxarch.cpp
+++ b/src/coreclr/jit/emitxarch.cpp
@@ -3965,7 +3965,7 @@ void emitter::emitIns_R(instruction ins, emitAttr attr, regNumber reg)
* Add an instruction referencing a register and a constant.
*/
-void emitter::emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t val)
+void emitter::emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t val DEBUGARG(GenTreeFlags gtFlags))
{
emitAttr size = EA_SIZE(attr);
@@ -4089,8 +4089,8 @@ void emitter::emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t
id->idIns(ins);
id->idInsFmt(fmt);
id->idReg1(reg);
-
id->idCodeSize(sz);
+ INDEBUG(id->idDebugOnlyInfo()->idFlags = gtFlags);
dispIns(id);
emitCurIGsize += sz;
@@ -8851,6 +8851,7 @@ void emitter::emitDispIns(
else
{
PRINT_CONSTANT:
+ ssize_t srcVal = val;
// Munge any pointers if we want diff-able disassembly
if (emitComp->opts.disDiffable)
{
@@ -8872,6 +8873,7 @@ void emitter::emitDispIns(
{ // (val < 0)
printf("-0x%IX", -val);
}
+ emitDispCommentForHandle(srcVal, id->idDebugOnlyInfo()->idFlags & GTF_ICON_HDL_MASK);
}
break;
diff --git a/src/coreclr/jit/emitxarch.h b/src/coreclr/jit/emitxarch.h
index f952a6f649f440..632fd95bcb1406 100644
--- a/src/coreclr/jit/emitxarch.h
+++ b/src/coreclr/jit/emitxarch.h
@@ -327,7 +327,7 @@ void emitIns_R(instruction ins, emitAttr attr, regNumber reg);
void emitIns_C(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE fdlHnd, int offs);
-void emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t val);
+void emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t val DEBUGARG(GenTreeFlags gtFlags = GTF_EMPTY));
void emitIns_Mov(instruction ins, emitAttr attr, regNumber dstReg, regNumber srgReg, bool canSkip);
diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp
index 8263c7db2bf946..30c38ff3d5550d 100644
--- a/src/coreclr/jit/optimizer.cpp
+++ b/src/coreclr/jit/optimizer.cpp
@@ -6117,7 +6117,7 @@ void Compiler::optRecordLoopMemoryDependence(GenTree* tree, BasicBlock* block, V
// we know of. Update the map.
//
JITDUMP(" ==> Updating loop memory dependence of [%06u] to " FMT_LP "\n", dspTreeID(tree), updateLoopNum);
- map->Set(tree, optLoopTable[updateLoopNum].lpEntry);
+ map->Set(tree, optLoopTable[updateLoopNum].lpEntry, NodeToLoopMemoryBlockMap::Overwrite);
}
//------------------------------------------------------------------------
diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp
index 86d0d5dae10de6..bd5821697a824e 100644
--- a/src/coreclr/jit/valuenum.cpp
+++ b/src/coreclr/jit/valuenum.cpp
@@ -2125,7 +2125,7 @@ ValueNum ValueNumStore::VNForFunc(var_types typ, VNFunc func, ValueNum arg0VN, V
//
// Return Value: - Returns the ValueNum associated with 'func'('arg0VN','arg1VN','arg2VN','arg3VN')
//
-// Note: Currently the only four operand func is the VNF_PtrToArrElem operation
+// Note: Currently the only four operand funcs are VNF_PtrToArrElem and VNF_MapStore.
//
ValueNum ValueNumStore::VNForFunc(
var_types typ, VNFunc func, ValueNum arg0VN, ValueNum arg1VN, ValueNum arg2VN, ValueNum arg3VN)
@@ -2282,7 +2282,7 @@ ValueNum ValueNumStore::VNForMapSelectWork(
else
{
// Give up if we've run out of budget.
- if (--(*pBudget) <= 0)
+ if (*pBudget == 0)
{
// We have to use 'nullptr' for the basic block here, because subsequent expressions
// in different blocks may find this result in the VNFunc2Map -- other expressions in
@@ -2293,6 +2293,9 @@ ValueNum ValueNumStore::VNForMapSelectWork(
return res;
}
+ // Reduce our budget by one
+ (*pBudget)--;
+
// If it's recursive, stop the recursion.
if (SelectIsBeingEvaluatedRecursively(arg0VN, arg1VN))
{
@@ -2329,9 +2332,9 @@ ValueNum ValueNumStore::VNForMapSelectWork(
assert(funcApp.m_args[1] != arg1VN); // we already checked this above.
#if FEATURE_VN_TRACE_APPLY_SELECTORS
JITDUMP(" AX2: " FMT_VN " != " FMT_VN " ==> select([" FMT_VN "]store(" FMT_VN ", " FMT_VN
- ", " FMT_VN "), " FMT_VN ") ==> select(" FMT_VN ", " FMT_VN ").\n",
+ ", " FMT_VN "), " FMT_VN ") ==> select(" FMT_VN ", " FMT_VN ") remaining budget is %d.\n",
arg1VN, funcApp.m_args[1], arg0VN, funcApp.m_args[0], funcApp.m_args[1], funcApp.m_args[2],
- arg1VN, funcApp.m_args[0], arg1VN);
+ arg1VN, funcApp.m_args[0], arg1VN, *pBudget);
#endif
// This is the equivalent of the recursive tail call:
// return VNForMapSelect(vnk, typ, funcApp.m_args[0], arg1VN);
@@ -4351,8 +4354,9 @@ var_types ValueNumStore::TypeOfVN(ValueNum vn)
}
//------------------------------------------------------------------------
-// LoopOfVN: If the given value number is VNF_MemOpaque or VNF_MapStore, return
-// the loop number where the memory update occurs, otherwise returns MAX_LOOP_NUM.
+// LoopOfVN: If the given value number is VNF_MemOpaque, VNF_MapStore, or
+// VNF_MemoryPhiDef, return the loop number where the memory update occurs,
+// otherwise returns MAX_LOOP_NUM.
//
// Arguments:
// vn - Value number to query
@@ -4374,6 +4378,11 @@ BasicBlock::loopNumber ValueNumStore::LoopOfVN(ValueNum vn)
{
return (BasicBlock::loopNumber)funcApp.m_args[3];
}
+ else if (funcApp.m_func == VNF_PhiMemoryDef)
+ {
+ BasicBlock* const block = reinterpret_cast(ConstantValue(funcApp.m_args[0]));
+ return block->bbNatLoopNum;
+ }
}
return BasicBlock::MAX_LOOP_NUM;
diff --git a/src/coreclr/pal/src/cruntime/filecrt.cpp b/src/coreclr/pal/src/cruntime/filecrt.cpp
index 6a14a9cd6f5677..78aab0c4d16181 100644
--- a/src/coreclr/pal/src/cruntime/filecrt.cpp
+++ b/src/coreclr/pal/src/cruntime/filecrt.cpp
@@ -229,11 +229,16 @@ CorUnix::InternalOpen(
va_end(ap);
}
+ do
+ {
#if OPEN64_IS_USED_INSTEAD_OF_OPEN
nRet = open64(szPath, nFlags, mode);
#else
nRet = open(szPath, nFlags, mode);
#endif
+ }
+ while ((nRet == -1) && (errno == EINTR));
+
return nRet;
}
diff --git a/src/coreclr/tools/Common/Internal/Text/Utf8String.cs b/src/coreclr/tools/Common/Internal/Text/Utf8String.cs
index cc1b045bb19a96..9b44102c582c5a 100644
--- a/src/coreclr/tools/Common/Internal/Text/Utf8String.cs
+++ b/src/coreclr/tools/Common/Internal/Text/Utf8String.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System;
+using System.Numerics;
using System.Runtime.CompilerServices;
using System.Text;
@@ -42,38 +43,31 @@ public override bool Equals(object obj)
return (obj is Utf8String) && Equals((Utf8String)obj);
}
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static int _rotl(int value, int shift)
- {
- // This is expected to be optimized into a single rotl instruction
- return (int)(((uint)value << shift) | ((uint)value >> (32 - shift)));
- }
-
public unsafe override int GetHashCode()
{
int length = _value.Length;
- int hash = length;
+ uint hash = (uint)length;
fixed (byte* ap = _value)
{
byte* a = ap;
while (length >= 4)
{
- hash = (hash + _rotl(hash, 5)) ^ *(int*)a;
+ hash = (hash + BitOperations.RotateLeft(hash, 5)) ^ *(uint*)a;
a += 4; length -= 4;
}
if (length >= 2)
{
- hash = (hash + _rotl(hash, 5)) ^ *(short*)a;
+ hash = (hash + BitOperations.RotateLeft(hash, 5)) ^ *(ushort*)a;
a += 2; length -= 2;
}
if (length > 0)
{
- hash = (hash + _rotl(hash, 5)) ^ *a;
+ hash = (hash + BitOperations.RotateLeft(hash, 5)) ^ *a;
}
- hash += _rotl(hash, 7);
- hash += _rotl(hash, 15);
- return hash;
+ hash += BitOperations.RotateLeft(hash, 7);
+ hash += BitOperations.RotateLeft(hash, 15);
+ return (int)hash;
}
}
diff --git a/src/coreclr/tools/Directory.Build.props b/src/coreclr/tools/Directory.Build.props
index e699ed222e7072..b8e4a4e912df23 100644
--- a/src/coreclr/tools/Directory.Build.props
+++ b/src/coreclr/tools/Directory.Build.props
@@ -4,7 +4,6 @@
false
false
false
- true
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs
index 079ef257595a70..b9671aa4850223 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs
@@ -230,8 +230,8 @@ internal struct ArgLocDesc
public bool m_fRequires64BitAlignment; // ARM - True if the argument should always be aligned (in registers or on the stack
- public int m_idxStack; // First stack slot used (or -1)
- public int m_cStack; // Count of stack slots used (or 0)
+ public int m_byteStackIndex; // Stack offset in bytes (or -1)
+ public int m_byteStackSize; // Stack size in bytes
// Initialize to represent a non-placed argument (no register or stack slots referenced).
public void Init()
@@ -240,8 +240,8 @@ public void Init()
m_cFloatReg = 0;
m_idxGenReg = -1;
m_cGenReg = 0;
- m_idxStack = -1;
- m_cStack = 0;
+ m_byteStackIndex = -1;
+ m_byteStackSize = 0;
m_fRequires64BitAlignment = false;
}
@@ -531,6 +531,7 @@ private uint SizeOfArgStack()
if (!_SIZE_OF_ARG_STACK_COMPUTED)
ForceSigWalk();
Debug.Assert(_SIZE_OF_ARG_STACK_COMPUTED);
+ Debug.Assert((_nSizeOfArgStack % _transitionBlock.PointerSize) == 0);
return (uint)_nSizeOfArgStack;
}
@@ -550,6 +551,7 @@ public int SizeOfFrameArgumentArray()
size += (uint)_transitionBlock.SizeOfArgumentRegisters;
}
+ Debug.Assert((size % _transitionBlock.PointerSize) == 0);
return (int)size;
}
@@ -784,14 +786,14 @@ public int GetNextOffset()
{
case CallingConventions.StdCall:
_numRegistersUsed = ArchitectureConstants.NUM_ARGUMENT_REGISTERS;
- _curOfs = TransitionBlock.GetOffsetOfArgs() + numRegistersUsed * _transitionBlock.PointerSize + initialArgOffset;
+ _ofsStack = TransitionBlock.GetOffsetOfArgs() + numRegistersUsed * _transitionBlock.PointerSize + initialArgOffset;
break;
case CallingConventions.ManagedStatic:
case CallingConventions.ManagedInstance:
_numRegistersUsed = numRegistersUsed;
// DESKTOP BEHAVIOR _curOfs = (int)(TransitionBlock.GetOffsetOfArgs() + SizeOfArgStack());
- _curOfs = (int)(TransitionBlock.GetOffsetOfArgs() + initialArgOffset);
+ _ofsStack= (int)(TransitionBlock.GetOffsetOfArgs() + initialArgOffset);
break;
default:
@@ -801,9 +803,9 @@ public int GetNextOffset()
#endif
_x86NumRegistersUsed = numRegistersUsed;
#if PROJECTN
- _x86CurOfs = (int)(_transitionBlock.OffsetOfArgs + initialArgOffset);
+ _x86OfsStack = (int)(_transitionBlock.OffsetOfArgs + initialArgOffset);
#else
- _x86CurOfs = (int)(_transitionBlock.OffsetOfArgs + SizeOfArgStack());
+ _x86OfsStack = (int)(_transitionBlock.OffsetOfArgs + SizeOfArgStack());
#endif
break;
@@ -822,14 +824,14 @@ public int GetNextOffset()
case TargetArchitecture.ARM:
_armIdxGenReg = numRegistersUsed;
- _armIdxStack = 0;
+ _armOfsStack = 0;
_armWFPRegs = 0;
break;
case TargetArchitecture.ARM64:
_arm64IdxGenReg = numRegistersUsed;
- _arm64IdxStack = 0;
+ _arm64OfsStack = 0;
_arm64IdxFPReg = 0;
break;
@@ -879,11 +881,11 @@ public int GetNextOffset()
}
#if PROJECTN
- argOfs = _x86CurOfs;
- _x86CurOfs += _transitionBlock.StackElemSize(argSize);
+ argOfs = _x86OfsStack;
+ _x86OfsStack += _transitionBlock.StackElemSize(argSize);
#else
- _x86CurOfs -= _transitionBlock.StackElemSize(argSize);
- argOfs = _x86CurOfs;
+ _x86OfsStack -= _transitionBlock.StackElemSize(argSize);
+ argOfs = _x86OfsStack;
#endif
Debug.Assert(argOfs >= _transitionBlock.OffsetOfArgs);
return argOfs;
@@ -988,7 +990,7 @@ public int GetNextOffset()
_fX64UnixArgInRegisters = false;
argOfs = _transitionBlock.OffsetOfArgs + _x64UnixIdxStack * 8;
- int cArgSlots = cbArg / _transitionBlock.StackElemSize();
+ int cArgSlots = cbArg / _transitionBlock.PointerSize;
_x64UnixIdxStack += cArgSlots;
return argOfs;
@@ -1081,7 +1083,7 @@ public int GetNextOffset()
_armRequires64BitAlignment = fRequiresAlign64Bit;
int cbArg = _transitionBlock.StackElemSize(argSize);
- int cArgSlots = cbArg / 4;
+ Debug.Assert((cbArg % _transitionBlock.PointerSize) == 0);
// Ignore floating point argument placement in registers if we're dealing with a vararg function (the ABI
// specifies this so that vararg processing on the callee side is simplified).
@@ -1127,13 +1129,13 @@ public int GetNextOffset()
// Doubles or HFAs containing doubles need the stack aligned appropriately.
if (fRequiresAlign64Bit)
- _armIdxStack = ALIGN_UP(_armIdxStack, 2);
+ _armOfsStack = ALIGN_UP(_armOfsStack, _transitionBlock.PointerSize * 2);
// Indicate the stack location of the argument to the caller.
- int argOfsInner = _transitionBlock.OffsetOfArgs + _armIdxStack * 4;
+ int argOfsInner = _transitionBlock.OffsetOfArgs + _armOfsStack;
// Record the stack usage.
- _armIdxStack += cArgSlots;
+ _armOfsStack += cbArg;
return argOfsInner;
}
@@ -1154,10 +1156,10 @@ public int GetNextOffset()
int argOfsInner = _transitionBlock.OffsetOfArgumentRegisters + _armIdxGenReg * 4;
int cRemainingRegs = 4 - _armIdxGenReg;
- if (cArgSlots <= cRemainingRegs)
+ if (cbArg <= cRemainingRegs * _transitionBlock.PointerSize)
{
// Mark the registers just allocated as used.
- _armIdxGenReg += cArgSlots;
+ _armIdxGenReg += ALIGN_UP(cbArg, _transitionBlock.PointerSize) / _transitionBlock.PointerSize;
return argOfsInner;
}
@@ -1168,9 +1170,9 @@ public int GetNextOffset()
_armIdxGenReg = 4;
- if (_armIdxStack == 0)
+ if (_armOfsStack == 0)
{
- _armIdxStack += cArgSlots - cRemainingRegs;
+ _armOfsStack += cbArg - cRemainingRegs * _transitionBlock.PointerSize;
return argOfsInner;
}
}
@@ -1179,13 +1181,13 @@ public int GetNextOffset()
{
// The argument requires 64-bit alignment. If it is going to be passed on the stack, align
// the next stack slot. See step C.6 in the algorithm in the ABI spec.
- _armIdxStack = ALIGN_UP(_armIdxStack, 2);
+ _armOfsStack = ALIGN_UP(_armOfsStack, _transitionBlock.PointerSize * 2);
}
- argOfs = _transitionBlock.OffsetOfArgs + _armIdxStack * 4;
+ argOfs = _transitionBlock.OffsetOfArgs + _armOfsStack;
// Advance the stack pointer over the argument just placed.
- _armIdxStack += cArgSlots;
+ _armOfsStack += cbArg;
return argOfs;
}
@@ -1193,6 +1195,7 @@ public int GetNextOffset()
case TargetArchitecture.ARM64:
{
int cFPRegs = 0;
+ bool isFloatHFA = false;
switch (argType)
{
@@ -1216,6 +1219,10 @@ public int GetNextOffset()
_argLocDescForStructInRegs.m_idxFloatReg = _arm64IdxFPReg;
int haElementSize = _argTypeHandle.GetHomogeneousAggregateElementSize();
+ if (haElementSize == 4)
+ {
+ isFloatHFA = true;
+ }
cFPRegs = argSize / haElementSize;
_argLocDescForStructInRegs.m_cFloatReg = cFPRegs;
@@ -1241,8 +1248,8 @@ public int GetNextOffset()
break;
}
- int cbArg = _transitionBlock.StackElemSize(argSize);
- int cArgSlots = cbArg / _transitionBlock.StackElemSize();
+ bool isValueType = (argType == CorElementType.ELEMENT_TYPE_VALUETYPE);
+ int cbArg = _transitionBlock.StackElemSize(argSize, isValueType, isFloatHFA);
if (cFPRegs > 0 && !IsVarArg)
{
@@ -1260,12 +1267,15 @@ public int GetNextOffset()
}
else
{
+ Debug.Assert(_transitionBlock.IsAppleArm64ABI || (cbArg % _transitionBlock.PointerSize) == 0);
+
+ int regSlots = ALIGN_UP(cbArg, _transitionBlock.PointerSize) / _transitionBlock.PointerSize;
// Only x0-x7 are valid argument registers (x8 is always the return buffer)
- if (_arm64IdxGenReg + cArgSlots <= 8)
+ if (_arm64IdxGenReg + regSlots <= 8)
{
// The entirety of the arg fits in the register slots.
int argOfsInner = _transitionBlock.OffsetOfArgumentRegisters + _arm64IdxGenReg * 8;
- _arm64IdxGenReg += cArgSlots;
+ _arm64IdxGenReg += regSlots;
return argOfsInner;
}
else if (_context.Target.IsWindows && IsVarArg && (_arm64IdxGenReg < 8))
@@ -1275,9 +1285,9 @@ public int GetNextOffset()
// into x0-x7, and any remaining stack arguments are placed normally.
int argOfsInner = _transitionBlock.OffsetOfArgumentRegisters + _arm64IdxGenReg * 8;
- // Increase m_idxStack to account for the space used for the remainder of the arg after
- // register slots are filled.
- _arm64IdxStack += (_arm64IdxGenReg + cArgSlots - 8);
+ // Increase m_ofsStack to account for the space used for the remainder of the arg after
+ // registers are filled.
+ _arm64OfsStack += cbArg + (_arm64IdxGenReg - 8) * _transitionBlock.PointerSize;
// We used up the remaining reg slots.
_arm64IdxGenReg = 8;
@@ -1291,8 +1301,27 @@ public int GetNextOffset()
}
}
- argOfs = _transitionBlock.OffsetOfArgs + _arm64IdxStack * 8;
- _arm64IdxStack += cArgSlots;
+ if (_transitionBlock.IsAppleArm64ABI)
+ {
+ int alignment;
+ if (!isValueType)
+ {
+ Debug.Assert((cbArg & (cbArg - 1)) == 0);
+ alignment = cbArg;
+ }
+ else if (isFloatHFA)
+ {
+ alignment = 4;
+ }
+ else
+ {
+ alignment = 8;
+ }
+ _arm64OfsStack = ALIGN_UP(_arm64OfsStack, alignment);
+ }
+
+ argOfs = _transitionBlock.OffsetOfArgs + _arm64OfsStack;
+ _arm64OfsStack += cbArg;
return argOfs;
}
@@ -1321,6 +1350,21 @@ public int GetArgSize()
return _argSize;
}
+ public bool IsValueType()
+ {
+ return (_argType == CorElementType.ELEMENT_TYPE_VALUETYPE);
+ }
+
+ public bool IsFloatHfa()
+ {
+ if (IsValueType() && !IsVarArg && _argTypeHandle.IsHomogeneousAggregate())
+ {
+ int hfaElementSize = _argTypeHandle.GetHomogeneousAggregateElementSize();
+ return hfaElementSize == 4;
+ }
+ return false;
+ }
+
private void ForceSigWalk()
{
// This can be only used before the actual argument iteration started
@@ -1445,14 +1489,15 @@ private void ForceSigWalk()
{
// All stack arguments take just one stack slot on AMD64 because of arguments bigger
// than a stack slot are passed by reference.
- stackElemSize = _transitionBlock.StackElemSize();
+ stackElemSize = _transitionBlock.PointerSize;
}
}
else
{
- stackElemSize = _transitionBlock.StackElemSize(GetArgSize());
+ stackElemSize = _transitionBlock.StackElemSize(GetArgSize(), IsValueType(), IsFloatHfa());
+
if (IsArgPassedByRef())
- stackElemSize = _transitionBlock.StackElemSize();
+ stackElemSize = _transitionBlock.PointerSize;
}
int endOfs = ofs + stackElemSize;
@@ -1477,6 +1522,9 @@ private void ForceSigWalk()
}
}
+ // arg stack size is rounded to the pointer size on all platforms.
+ nSizeOfArgStack = ALIGN_UP(nSizeOfArgStack, _transitionBlock.PointerSize);
+
// Cache the result
_nSizeOfArgStack = nSizeOfArgStack;
_SIZE_OF_ARG_STACK_COMPUTED = true;
@@ -1497,12 +1545,14 @@ private void ForceSigWalk()
pLoc.m_fRequires64BitAlignment = _armRequires64BitAlignment;
- int cSlots = (GetArgSize() + 3) / 4;
+ int byteArgSize = GetArgSize();
if (_transitionBlock.IsFloatArgumentRegisterOffset(argOffset))
{
- pLoc.m_idxFloatReg = (argOffset - _transitionBlock.OffsetOfFloatArgumentRegisters) / 4;
- pLoc.m_cFloatReg = cSlots;
+ int floatRegOfsInBytes = argOffset - _transitionBlock.OffsetOfFloatArgumentRegisters;
+ Debug.Assert((floatRegOfsInBytes % _transitionBlock.FloatRegisterSize) == 0);
+ pLoc.m_idxFloatReg = floatRegOfsInBytes / _transitionBlock.FloatRegisterSize;
+ pLoc.m_cFloatReg = ALIGN_UP(byteArgSize, _transitionBlock.FloatRegisterSize) / _transitionBlock.FloatRegisterSize;
return pLoc;
}
@@ -1510,22 +1560,22 @@ private void ForceSigWalk()
{
pLoc.m_idxGenReg = _transitionBlock.GetArgumentIndexFromOffset(argOffset);
- if (cSlots <= (4 - pLoc.m_idxGenReg))
+ if (byteArgSize <= (4 - pLoc.m_idxGenReg) * _transitionBlock.PointerSize)
{
- pLoc.m_cGenReg = (short)cSlots;
+ pLoc.m_cGenReg = (short)(ALIGN_UP(byteArgSize, _transitionBlock.PointerSize) / _transitionBlock.PointerSize);
}
else
{
pLoc.m_cGenReg = (short)(4 - pLoc.m_idxGenReg);
- pLoc.m_idxStack = 0;
- pLoc.m_cStack = cSlots - pLoc.m_cGenReg;
+ pLoc.m_byteStackIndex = 0;
+ pLoc.m_byteStackSize = _transitionBlock.StackElemSize(byteArgSize) - pLoc.m_cGenReg * _transitionBlock.PointerSize;
}
}
else
{
- pLoc.m_idxStack = _transitionBlock.GetArgumentIndexFromOffset(argOffset) - 4;
- pLoc.m_cStack = cSlots;
+ pLoc.m_byteStackIndex = _transitionBlock.GetStackArgumentByteIndexFromOffset(argOffset);
+ pLoc.m_byteStackSize = _transitionBlock.StackElemSize(byteArgSize);
}
return pLoc;
}
@@ -1538,8 +1588,9 @@ private void ForceSigWalk()
if (_transitionBlock.IsFloatArgumentRegisterOffset(argOffset))
{
- // Dividing by 16 as size of each register in FloatArgumentRegisters is 16 bytes.
- pLoc.m_idxFloatReg = (argOffset - _transitionBlock.OffsetOfFloatArgumentRegisters) / 16;
+ int floatRegOfsInBytes = argOffset - _transitionBlock.OffsetOfFloatArgumentRegisters;
+ Debug.Assert((floatRegOfsInBytes % _transitionBlock.FloatRegisterSize) == 0);
+ pLoc.m_idxFloatReg = floatRegOfsInBytes / _transitionBlock.FloatRegisterSize;
if (!_argTypeHandle.IsNull() && _argTypeHandle.IsHomogeneousAggregate())
{
@@ -1553,24 +1604,24 @@ private void ForceSigWalk()
return pLoc;
}
- int cSlots = (GetArgSize() + 7) / 8;
+ int byteArgSize = GetArgSize();
// Composites greater than 16bytes are passed by reference
TypeHandle dummy;
if (GetArgType(out dummy) == CorElementType.ELEMENT_TYPE_VALUETYPE && GetArgSize() > _transitionBlock.EnregisteredParamTypeMaxSize)
{
- cSlots = 1;
+ byteArgSize = _transitionBlock.PointerSize;
}
if (!_transitionBlock.IsStackArgumentOffset(argOffset))
{
pLoc.m_idxGenReg = _transitionBlock.GetArgumentIndexFromOffset(argOffset);
- pLoc.m_cGenReg = (short)cSlots;
+ pLoc.m_cGenReg = (short)(ALIGN_UP(byteArgSize, _transitionBlock.PointerSize) / _transitionBlock.PointerSize);
}
else
{
- pLoc.m_idxStack = _transitionBlock.GetStackArgumentIndexFromOffset(argOffset);
- pLoc.m_cStack = cSlots;
+ pLoc.m_byteStackIndex = _transitionBlock.GetStackArgumentByteIndexFromOffset(argOffset);
+ pLoc.m_byteStackSize = _transitionBlock.StackElemSize(byteArgSize, IsValueType(), IsFloatHfa());
}
return pLoc;
}
@@ -1595,8 +1646,9 @@ private void ForceSigWalk()
if (_transitionBlock.IsFloatArgumentRegisterOffset(argOffset))
{
- // Dividing by 8 as size of each register in FloatArgumentRegisters is 8 bytes.
- pLoc.m_idxFloatReg = (argOffset - _transitionBlock.OffsetOfFloatArgumentRegisters) / 8;
+ int floatRegOfsInBytes = argOffset - _transitionBlock.OffsetOfFloatArgumentRegisters;
+ Debug.Assert((floatRegOfsInBytes % _transitionBlock.FloatRegisterSize) == 0);
+ pLoc.m_idxFloatReg = floatRegOfsInBytes / _transitionBlock.FloatRegisterSize;
pLoc.m_cFloatReg = 1;
}
else if (!_transitionBlock.IsStackArgumentOffset(argOffset))
@@ -1606,14 +1658,13 @@ private void ForceSigWalk()
}
else
{
- pLoc.m_idxStack = (argOffset - _transitionBlock.OffsetOfArgs) / 8;
- int argOnStackSize;
- int stackElemSize = _transitionBlock.StackElemSize();
+ pLoc.m_byteStackIndex = _transitionBlock.GetStackArgumentByteIndexFromOffset(argOffset);
+ int argSizeInBytes;
if (IsArgPassedByRef())
- argOnStackSize = stackElemSize;
+ argSizeInBytes = _transitionBlock.PointerSize;
else
- argOnStackSize = GetArgSize();
- pLoc.m_cStack = (argOnStackSize + stackElemSize - 1) / stackElemSize;
+ argSizeInBytes = GetArgSize();
+ pLoc.m_byteStackSize = _transitionBlock.StackElemSize(argSizeInBytes);
}
return pLoc;
}
@@ -1641,7 +1692,7 @@ private void ForceSigWalk()
private TypeHandle _argTypeHandleOfByRefParam;
private bool _argForceByRef;
- private int _x86CurOfs; // Current position of the stack iterator
+ private int _x86OfsStack; // Current position of the stack iterator
private int _x86NumRegistersUsed;
private int _x64UnixIdxGenReg;
@@ -1651,13 +1702,13 @@ private void ForceSigWalk()
private int _x64WindowsCurOfs; // Current position of the stack iterator
private int _armIdxGenReg; // Next general register to be assigned a value
- private int _armIdxStack; // Next stack slot to be assigned a value
+ private int _armOfsStack; // Offset of next stack location to be assigned a value
private ushort _armWFPRegs; // Bitmask of available floating point argument registers (s0-s15/d0-d7)
private bool _armRequires64BitAlignment; // Cached info about the current arg
private int _arm64IdxGenReg; // Next general register to be assigned a value
- private int _arm64IdxStack; // Next stack slot to be assigned a value
+ private int _arm64OfsStack; // Offset of next stack location to be assigned a value
private int _arm64IdxFPReg; // Next FP register to be assigned a value
// These are enum flags in CallingConventions.h, but that's really ugly in C#, so I've changed them to bools.
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs
index 667bae1742abf6..a044a42b1d2dd1 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs
@@ -39,7 +39,9 @@ public static TransitionBlock FromTarget(TargetDetails target)
}
case TargetArchitecture.ARM64:
- return Arm64TransitionBlock.Instance;
+ return target.OperatingSystem == TargetOS.OSX ?
+ AppleArm64TransitionBlock.Instance :
+ Arm64TransitionBlock.Instance;
default:
throw new NotImplementedException(target.Architecture.ToString());
@@ -66,12 +68,13 @@ public static TransitionBlock FromTarget(TargetDetails target)
public virtual bool IsArmelABI => false;
public virtual bool IsArmhfABI => false;
+ public virtual bool IsAppleArm64ABI => false;
public abstract int PointerSize { get; }
- public int StackElemSize() => PointerSize;
+ public abstract int FloatRegisterSize { get; }
- public int StackElemSize(int size) => (((size) + StackElemSize() - 1) & -StackElemSize());
+ public abstract int StackElemSize(int parmSize, bool isValueType = false, bool isFloatHfa = false);
public abstract int NumArgumentRegisters { get; }
@@ -108,7 +111,7 @@ public static TransitionBlock FromTarget(TargetDetails target)
///
/// Default implementation of ThisOffset; X86TransitionBlock provides a slightly different implementation.
///
- public virtual int ThisOffset { get { return OffsetOfArgumentRegisters; } }
+ public virtual int ThisOffset { get { return OffsetOfArgumentRegisters; } }
///
/// Recalculate pos in GC ref map to actual offset. This is the default implementation for all architectures
@@ -134,6 +137,7 @@ public bool IsStackArgumentOffset(int offset)
public bool IsArgumentRegisterOffset(int offset)
{
+ Debug.Assert(!IsX64UnixABI || offset != StructInRegsOffset);
int ofsArgRegs = OffsetOfArgumentRegisters;
return offset >= ofsArgRegs && offset < (int)(ofsArgRegs + SizeOfArgumentRegisters);
@@ -142,13 +146,21 @@ public bool IsArgumentRegisterOffset(int offset)
public int GetArgumentIndexFromOffset(int offset)
{
Debug.Assert(!IsX86);
- return ((offset - OffsetOfArgumentRegisters) / PointerSize);
+ offset -= OffsetOfArgumentRegisters;
+ Debug.Assert((offset % PointerSize) == 0);
+ return offset / PointerSize;
}
public int GetStackArgumentIndexFromOffset(int offset)
{
Debug.Assert(!IsX86);
- return (offset - OffsetOfArgs) / StackElemSize();
+ return (offset - OffsetOfArgs) / PointerSize;
+ }
+
+ public int GetStackArgumentByteIndexFromOffset(int offset)
+ {
+ Debug.Assert(!IsX86);
+ return offset - OffsetOfArgs;
}
///
@@ -397,6 +409,11 @@ public void ComputeReturnValueTreatment(CorElementType type, TypeHandle thRetTyp
}
}
+ public static int ALIGN_UP(int input, int align_to)
+ {
+ return (input + (align_to - 1)) & ~(align_to - 1);
+ }
+
public const int InvalidOffset = -1;
public sealed class X86Constants
@@ -412,6 +429,7 @@ private sealed class X86TransitionBlock : TransitionBlock
public override TargetArchitecture Architecture => TargetArchitecture.X86;
public override int PointerSize => 4;
+ public override int FloatRegisterSize => throw new NotImplementedException();
public override int NumArgumentRegisters => 2;
public override int NumCalleeSavedRegisters => 4;
@@ -450,6 +468,12 @@ public override int GetRetBuffArgOffset(bool hasThis)
return hasThis ? X86Constants.OffsetOfEdx : X86Constants.OffsetOfEcx;
#endif
}
+
+ public override int StackElemSize(int parmSize, bool isValueType = false, bool isFloatHfa = false)
+ {
+ int stackSlotSize = 4;
+ return ALIGN_UP(parmSize, stackSlotSize);
+ }
}
public const int SizeOfM128A = 16;
@@ -461,6 +485,7 @@ internal abstract class X64TransitionBlock : TransitionBlock
{
public override TargetArchitecture Architecture => TargetArchitecture.X64;
public override int PointerSize => 8;
+ public override int FloatRegisterSize => 16;
public override bool IsArgPassedByRef(TypeHandle th)
{
@@ -475,6 +500,11 @@ public override bool IsVarArgPassedByRef(int size)
}
public override int GetRetBuffArgOffset(bool hasThis) => OffsetOfArgumentRegisters + (hasThis ? PointerSize : 0);
+ public sealed override int StackElemSize(int parmSize, bool isValueType = false, bool isFloatHfa = false)
+ {
+ int stackSlotSize = 8;
+ return ALIGN_UP(parmSize, stackSlotSize);
+ }
}
private sealed class X64WindowsTransitionBlock : X64TransitionBlock
@@ -521,6 +551,7 @@ private class Arm32TransitionBlock : TransitionBlock
public sealed override TargetArchitecture Architecture => TargetArchitecture.ARM;
public sealed override int PointerSize => 4;
+ public override int FloatRegisterSize => 4;
// R0, R1, R2, R3
public sealed override int NumArgumentRegisters => 4;
// R4, R5, R6, R7, R8, R9, R10, R11, R14
@@ -538,6 +569,12 @@ private class Arm32TransitionBlock : TransitionBlock
public sealed override bool IsArgPassedByRef(TypeHandle th) => false;
public sealed override int GetRetBuffArgOffset(bool hasThis) => OffsetOfArgumentRegisters + (hasThis ? PointerSize : 0);
+
+ public sealed override int StackElemSize(int parmSize, bool isValueType = false, bool isFloatHfa = false)
+ {
+ int stackSlotSize = 4;
+ return ALIGN_UP(parmSize, stackSlotSize);
+ }
}
private class Arm32ElTransitionBlock : Arm32TransitionBlock
@@ -548,12 +585,12 @@ private class Arm32ElTransitionBlock : Arm32TransitionBlock
public override bool IsArmelABI => true;
}
- private sealed class Arm64TransitionBlock : TransitionBlock
+ private class Arm64TransitionBlock : TransitionBlock
{
public static TransitionBlock Instance = new Arm64TransitionBlock();
-
public override TargetArchitecture Architecture => TargetArchitecture.ARM64;
public override int PointerSize => 8;
+ public override int FloatRegisterSize => 16;
// X0 .. X7
public override int NumArgumentRegisters => 8;
// X29, X30, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28
@@ -581,6 +618,37 @@ public override bool IsArgPassedByRef(TypeHandle th)
public override int GetRetBuffArgOffset(bool hasThis) => OffsetOfX8Register;
public override bool IsRetBuffPassedAsFirstArg => false;
+
+ public override int StackElemSize(int parmSize, bool isValueType = false, bool isFloatHfa = false)
+ {
+ int stackSlotSize = 8;
+ return ALIGN_UP(parmSize, stackSlotSize);
+ }
+ }
+
+ private sealed class AppleArm64TransitionBlock : Arm64TransitionBlock
+ {
+ public new static TransitionBlock Instance = new AppleArm64TransitionBlock();
+ public override bool IsAppleArm64ABI => true;
+
+ public sealed override int StackElemSize(int parmSize, bool isValueType = false, bool isFloatHfa = false)
+ {
+ if (!isValueType)
+ {
+ // The primitive types' sizes are expected to be powers of 2.
+ Debug.Assert((parmSize & (parmSize - 1)) == 0);
+ // No padding/alignment for primitive types.
+ return parmSize;
+ }
+ if (isFloatHfa)
+ {
+ Debug.Assert((parmSize % 4) == 0);
+ // float hfa is not considered a struct type and passed with 4-byte alignment.
+ return parmSize;
+ }
+
+ return base.StackElemSize(parmSize, isValueType, isFloatHfa);
+ }
}
}
}
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ProfileDataManager.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ProfileDataManager.cs
index 0685f3e00c97da..07dfaa54da8ef4 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ProfileDataManager.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ProfileDataManager.cs
@@ -45,7 +45,11 @@ public ProfileDataManager(Logger logger,
{
// Parse MIbc Data
- string onlyParseItemsDefinedInAssembly = nonLocalGenericsHome == null ? inputModules.First().Assembly.GetName().Name : null;
+ string onlyParseItemsDefinedInAssembly = null;
+ if (nonLocalGenericsHome == null && !compilationGroup.IsCompositeBuildMode)
+ {
+ onlyParseItemsDefinedInAssembly = inputModules.First().Assembly.GetName().Name;
+ }
HashSet versionBubbleModuleStrings = new HashSet();
foreach (ModuleDesc versionBubbleModule in versionBubble)
{
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunHashCode.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunHashCode.cs
index 19a643476ecd1d..e506bb8b3b6ef8 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunHashCode.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunHashCode.cs
@@ -3,6 +3,7 @@
using System;
using System.Diagnostics;
+using System.Numerics;
using System.Text;
using Internal.TypeSystem;
@@ -219,7 +220,7 @@ public static int ModuleNameHashCode(ModuleDesc module)
/// Number of bits
private static int RotateLeft(int value, int bitCount)
{
- return unchecked((int)(((uint)value << bitCount) | ((uint)value >> (32 - bitCount))));
+ return (int)BitOperations.RotateLeft((uint)value, bitCount);
}
private static uint XXHash32_MixEmptyState()
@@ -231,7 +232,7 @@ private static uint XXHash32_MixEmptyState()
private static uint XXHash32_QueueRound(uint hash, uint queuedValue)
{
- return ((uint)RotateLeft((int)(hash + queuedValue * 3266489917U/*Prime3*/), 17)) * 668265263U/*Prime4*/;
+ return (BitOperations.RotateLeft((hash + queuedValue * 3266489917U/*Prime3*/), 17)) * 668265263U/*Prime4*/;
}
private static uint XXHash32_MixFinal(uint hash)
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 e3da2dc734fef5..6a325a5844c816 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
@@ -1142,6 +1142,10 @@ private CorInfoHelpFunc getNewHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken,
pHasSideEffects = type.HasFinalizer;
+ // If the type isn't within the version bubble, it could gain a finalizer. Always treat it as if it has a finalizer
+ if (!pHasSideEffects && !_compilation.NodeFactory.CompilationModuleGroup.VersionsWithType(type))
+ pHasSideEffects = true;
+
return CorInfoHelpFunc.CORINFO_HELP_NEWFAST;
}
diff --git a/src/coreclr/tools/dotnet-pgo/CommandLineOptions.cs b/src/coreclr/tools/dotnet-pgo/CommandLineOptions.cs
index 3da9ded70632f7..a2e3a82f37fdb6 100644
--- a/src/coreclr/tools/dotnet-pgo/CommandLineOptions.cs
+++ b/src/coreclr/tools/dotnet-pgo/CommandLineOptions.cs
@@ -45,6 +45,7 @@ internal class CommandLineOptions
public bool DumpMibc = false;
public FileInfo InputFileToDump;
public List CompareMibc;
+ public bool InheritTimestamp;
public string[] HelpArgs = Array.Empty();
@@ -265,6 +266,8 @@ void HelpOption()
}
}
+ syntax.DefineOption(name: "inherit-timestamp", value: ref InheritTimestamp, help: "If specified, set the output's timestamp to the max timestamp of the input files");
+
VerbosityOption();
CompressedOption();
HelpOption();
diff --git a/src/coreclr/tools/dotnet-pgo/Program.cs b/src/coreclr/tools/dotnet-pgo/Program.cs
index 32b42394b6afe9..77113377c478dd 100644
--- a/src/coreclr/tools/dotnet-pgo/Program.cs
+++ b/src/coreclr/tools/dotnet-pgo/Program.cs
@@ -378,7 +378,14 @@ static int InnerMergeMain(CommandLineOptions commandLineOptions)
ProfileData.MergeProfileData(ref partialNgen, mergedProfileData, MIbcProfileParser.ParseMIbcFile(tsc, peReader, assemblyNamesInBubble, onlyDefinedInAssembly: null));
}
- return MibcEmitter.GenerateMibcFile(tsc, commandLineOptions.OutputFileName, mergedProfileData.Values, commandLineOptions.ValidateOutputFile, commandLineOptions.Uncompressed);
+ int result = MibcEmitter.GenerateMibcFile(tsc, commandLineOptions.OutputFileName, mergedProfileData.Values, commandLineOptions.ValidateOutputFile, commandLineOptions.Uncompressed);
+ if (result == 0 && commandLineOptions.InheritTimestamp)
+ {
+ commandLineOptions.OutputFileName.CreationTimeUtc = commandLineOptions.InputFilesToMerge.Max(fi => fi.CreationTimeUtc);
+ commandLineOptions.OutputFileName.LastWriteTimeUtc = commandLineOptions.InputFilesToMerge.Max(fi => fi.LastWriteTimeUtc);
+ }
+
+ return result;
}
finally
{
@@ -999,13 +1006,23 @@ static int InnerProcessTraceFileMain(CommandLineOptions commandLineOptions)
{
foreach (FileInfo fileReference in commandLineOptions.Reference)
{
- if (!File.Exists(fileReference.FullName))
+ try
{
- PrintError($"Unable to find reference '{fileReference.FullName}'");
- filePathError = true;
+ if (!File.Exists(fileReference.FullName))
+ {
+ PrintError($"Unable to find reference '{fileReference.FullName}'");
+ filePathError = true;
+ }
+ else
+ tsc.GetModuleFromPath(fileReference.FullName);
+ }
+ catch (Internal.TypeSystem.TypeSystemException.BadImageFormatException)
+ {
+ // Ignore BadImageFormat in order to allow users to use '-r *.dll'
+ // in a folder with native dynamic libraries (which have the same extension on Windows).
+
+ // We don't need to log a warning here - it's already logged in GetModuleFromPath
}
- else
- tsc.GetModuleFromPath(fileReference.FullName);
}
}
diff --git a/src/coreclr/vm/ClrEtwAll.man b/src/coreclr/vm/ClrEtwAll.man
index 1841981ba3d7c5..826c790a6953f9 100644
--- a/src/coreclr/vm/ClrEtwAll.man
+++ b/src/coreclr/vm/ClrEtwAll.man
@@ -7249,7 +7249,7 @@
diff --git a/src/coreclr/vm/amd64/AsmHelpers.asm b/src/coreclr/vm/amd64/AsmHelpers.asm
index 172b800f3feac2..0fd77a277f58b3 100644
--- a/src/coreclr/vm/amd64/AsmHelpers.asm
+++ b/src/coreclr/vm/amd64/AsmHelpers.asm
@@ -432,13 +432,15 @@ endif ; _DEBUG
NESTED_ENTRY OnHijackTripThread, _TEXT
; Don't fiddle with this unless you change HijackFrame::UpdateRegDisplay
- ; and HijackObjectArgs
+ ; and HijackArgs
+ mov rdx, rsp
push rax ; make room for the real return address (Rip)
+ push rdx
PUSH_CALLEE_SAVED_REGISTERS
push_vol_reg rax
mov rcx, rsp
- alloc_stack 30h ; make extra room for xmm0
+ alloc_stack 38h ; make extra room for xmm0, argument home slots and align the SP
save_xmm128_postrsp xmm0, 20h
@@ -448,9 +450,10 @@ NESTED_ENTRY OnHijackTripThread, _TEXT
movdqa xmm0, [rsp + 20h]
- add rsp, 30h
+ add rsp, 38h
pop rax
POP_CALLEE_SAVED_REGISTERS
+ pop rdx
ret ; return to the correct place, adjusted by our caller
NESTED_END OnHijackTripThread, _TEXT
diff --git a/src/coreclr/vm/amd64/cgenamd64.cpp b/src/coreclr/vm/amd64/cgenamd64.cpp
index d00f7b74df0d48..af91cc3a525f37 100644
--- a/src/coreclr/vm/amd64/cgenamd64.cpp
+++ b/src/coreclr/vm/amd64/cgenamd64.cpp
@@ -286,7 +286,11 @@ void HijackFrame::UpdateRegDisplay(const PREGDISPLAY pRD)
pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary.
pRD->pCurrentContext->Rip = m_ReturnAddress;
+#ifdef TARGET_WINDOWS
+ pRD->pCurrentContext->Rsp = m_Args->Rsp;
+#else
pRD->pCurrentContext->Rsp = PTR_TO_MEMBER_TADDR(HijackArgs, m_Args, Rip) + sizeof(void *);
+#endif
UpdateRegDisplayFromCalleeSavedRegisters(pRD, &(m_Args->Regs));
diff --git a/src/coreclr/vm/amd64/cgencpu.h b/src/coreclr/vm/amd64/cgencpu.h
index 6300876fa330e3..93797a4e84910e 100644
--- a/src/coreclr/vm/amd64/cgencpu.h
+++ b/src/coreclr/vm/amd64/cgencpu.h
@@ -465,7 +465,7 @@ struct HijackArgs
ULONG64 Rax;
ULONG64 ReturnValue[1];
};
-#else // FEATURE_MULTIREG_RETURN
+#else // !FEATURE_MULTIREG_RETURN
union
{
struct
@@ -475,8 +475,11 @@ struct HijackArgs
};
ULONG64 ReturnValue[2];
};
-#endif // TARGET_UNIX
+#endif // !FEATURE_MULTIREG_RETURN
CalleeSavedRegisters Regs;
+#ifdef TARGET_WINDOWS
+ ULONG64 Rsp;
+#endif
union
{
ULONG64 Rip;
diff --git a/src/coreclr/vm/excep.cpp b/src/coreclr/vm/excep.cpp
index 7ee6baad9a4a63..74a1f9f6be7822 100644
--- a/src/coreclr/vm/excep.cpp
+++ b/src/coreclr/vm/excep.cpp
@@ -7186,6 +7186,52 @@ LONG WINAPI CLRVectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo)
}
}
+#ifdef TARGET_AMD64
+
+#ifndef STATUS_RETURN_ADDRESS_HIJACK_ATTEMPT
+#define STATUS_RETURN_ADDRESS_HIJACK_ATTEMPT ((DWORD)0x80000033L)
+#endif
+
+ if (pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_RETURN_ADDRESS_HIJACK_ATTEMPT)
+ {
+ HijackArgs hijackArgs;
+ hijackArgs.Rax = pExceptionInfo->ContextRecord->Rax;
+ hijackArgs.Rsp = pExceptionInfo->ContextRecord->Rsp;
+
+ bool areCetShadowStacksEnabled = Thread::AreCetShadowStacksEnabled();
+ if (areCetShadowStacksEnabled)
+ {
+ // When the CET is enabled, the return address is still on stack, so we need to set the Rsp as
+ // if it was popped.
+ hijackArgs.Rsp += 8;
+ }
+ hijackArgs.Rip = 0 ; // The OnHijackWorker sets this
+ #define CALLEE_SAVED_REGISTER(regname) hijackArgs.Regs.regname = pExceptionInfo->ContextRecord->regname;
+ ENUM_CALLEE_SAVED_REGISTERS();
+ #undef CALLEE_SAVED_REGISTER
+
+ OnHijackWorker(&hijackArgs);
+
+ #define CALLEE_SAVED_REGISTER(regname) pExceptionInfo->ContextRecord->regname = hijackArgs.Regs.regname;
+ ENUM_CALLEE_SAVED_REGISTERS();
+ #undef CALLEE_SAVED_REGISTER
+ pExceptionInfo->ContextRecord->Rax = hijackArgs.Rax;
+
+ if (areCetShadowStacksEnabled)
+ {
+ // The context refers to the return instruction
+ // Set the return address on the stack to the original one
+ *(size_t *)pExceptionInfo->ContextRecord->Rsp = hijackArgs.ReturnAddress;
+ }
+ else
+ {
+ // The context refers to the location after the return was processed
+ pExceptionInfo->ContextRecord->Rip = hijackArgs.ReturnAddress;
+ }
+
+ return EXCEPTION_CONTINUE_EXECUTION;
+ }
+#endif
// We need to unhijack the thread here if it is not unhijacked already. On x86 systems,
// we do this in Thread::StackWalkFramesEx, but on amd64 systems we have the OS walk the
diff --git a/src/coreclr/vm/interoplibinterface.cpp b/src/coreclr/vm/interoplibinterface.cpp
index b027d6b9d4bbdc..b9b02ebb5c6a60 100644
--- a/src/coreclr/vm/interoplibinterface.cpp
+++ b/src/coreclr/vm/interoplibinterface.cpp
@@ -161,7 +161,10 @@ namespace
~ExternalWrapperResultHolder()
{
if (Result.Context != NULL)
+ {
+ GCX_PREEMP();
InteropLib::Com::DestroyWrapperForExternal(Result.Context);
+ }
}
InteropLib::Com::ExternalWrapperResult* operator&()
{
@@ -285,9 +288,6 @@ namespace
// The collection should respect the supplied arguments.
// withFlags - If Flag_None, then ignore. Otherwise objects must have these flags.
// threadContext - The object must be associated with the supplied thread context.
- //
- // [TODO] Performance improvement should be made here to provide a custom IEnumerable
- // instead of a managed array.
OBJECTREF CreateManagedEnumerable(_In_ DWORD withFlags, _In_opt_ void* threadContext)
{
CONTRACT(OBJECTREF)
@@ -300,64 +300,61 @@ namespace
}
CONTRACT_END;
- DWORD objCount;
- DWORD objCountMax;
-
struct
{
PTRARRAYREF arrRef;
- PTRARRAYREF arrRefTmp;
} gc;
::ZeroMemory(&gc, sizeof(gc));
GCPROTECT_BEGIN(gc);
- {
- LockHolder lock(this);
- objCountMax = _hashMap.GetCount();
- }
+ CQuickArrayList localList;
- // Allocate the max number of objects needed.
- gc.arrRef = (PTRARRAYREF)AllocateObjectArray(objCountMax, g_pObjectClass);
-
- // Populate the array
+ // Determine objects to return
{
LockHolder lock(this);
- Iterator curr = _hashMap.Begin();
Iterator end = _hashMap.End();
-
- ExternalObjectContext* inst;
- for (objCount = 0; curr != end && objCount < objCountMax; objCount++, curr++)
+ for (Iterator curr = _hashMap.Begin(); curr != end; ++curr)
{
- inst = *curr;
+ ExternalObjectContext* inst = *curr;
// Only add objects that are in the correct thread
// context and have the appropriate flags set.
if (inst->ThreadContext == threadContext
&& (withFlags == ExternalObjectContext::Flags_None || inst->IsSet(withFlags)))
{
- // Separate the wrapper from the tracker runtime prior to
- // passing this onto the caller. This call is okay to make
- // even if the instance isn't from the tracker runtime.
- InteropLib::Com::SeparateWrapperFromTrackerRuntime(inst);
- gc.arrRef->SetAt(objCount, inst->GetObjectRef());
+ localList.Push(inst);
STRESS_LOG1(LF_INTEROP, LL_INFO100, "Add EOC to Enumerable: 0x%p\n", inst);
}
}
}
- // Make the array the correct size
- if (objCount < objCountMax)
- {
- gc.arrRefTmp = (PTRARRAYREF)AllocateObjectArray(objCount, g_pObjectClass);
-
- SIZE_T elementSize = gc.arrRef->GetComponentSize();
+ // Allocate enumerable type to return.
+ gc.arrRef = (PTRARRAYREF)AllocateObjectArray((DWORD)localList.Size(), g_pObjectClass);
- void *src = gc.arrRef->GetDataPtr();
- void *dest = gc.arrRefTmp->GetDataPtr();
+ // Insert objects into enumerable.
+ // The ExternalObjectContexts in the hashmap are only
+ // removed and associated objects collected during a GC. Since
+ // this code is running in Cooperative mode they will never
+ // be null.
+ for (SIZE_T i = 0; i < localList.Size(); i++)
+ {
+ ExternalObjectContext* inst = localList[i];
+ gc.arrRef->SetAt(i, inst->GetObjectRef());
+ }
- _ASSERTE(sizeof(Object*) == elementSize && "Assumption invalidated in memmoveGCRefs() usage");
- memmoveGCRefs(dest, src, objCount * elementSize);
- gc.arrRef = gc.arrRefTmp;
+ {
+ // Separate the wrapper from the tracker runtime prior to
+ // passing them onto the caller. This call is okay to make
+ // even if the instance isn't from the tracker runtime.
+ // We switch to Preemptive mode since seperating a wrapper
+ // requires us to call out to non-runtime code which could
+ // call back into the runtime and/or trigger a GC.
+ GCX_PREEMP();
+ for (SIZE_T i = 0; i < localList.Size(); i++)
+ {
+ ExternalObjectContext* inst = localList[i];
+ InteropLib::Com::SeparateWrapperFromTrackerRuntime(inst);
+ }
}
GCPROTECT_END();
@@ -656,12 +653,15 @@ namespace
OBJECTHANDLE instHandle = GetAppDomain()->CreateTypedHandle(gc.instRef, InstanceHandleType);
// Call the InteropLib and create the associated managed object wrapper.
- hr = InteropLib::Com::CreateWrapperForObject(
- instHandle,
- vtableCount,
- vtables,
- flags,
- &newWrapper);
+ {
+ GCX_PREEMP();
+ hr = InteropLib::Com::CreateWrapperForObject(
+ instHandle,
+ vtableCount,
+ vtables,
+ flags,
+ &newWrapper);
+ }
if (FAILED(hr))
{
DestroyHandleCommon(instHandle, InstanceHandleType);
@@ -809,7 +809,6 @@ namespace
sizeof(ExternalObjectContext),
&resultHolder);
}
-
if (FAILED(hr))
COMPlusThrowHR(hr);
@@ -1461,14 +1460,18 @@ void ComWrappersNative::DestroyManagedObjectComWrapper(_In_ void* wrapper)
CONTRACTL
{
NOTHROW;
- GC_NOTRIGGER;
+ GC_TRIGGERS;
MODE_ANY;
PRECONDITION(wrapper != NULL);
}
CONTRACTL_END;
STRESS_LOG1(LF_INTEROP, LL_INFO100, "Destroying MOW: 0x%p\n", wrapper);
- InteropLib::Com::DestroyWrapperForObject(wrapper);
+
+ {
+ GCX_PREEMP();
+ InteropLib::Com::DestroyWrapperForObject(wrapper);
+ }
}
void ComWrappersNative::DestroyExternalComObjectContext(_In_ void* contextRaw)
@@ -1476,7 +1479,7 @@ void ComWrappersNative::DestroyExternalComObjectContext(_In_ void* contextRaw)
CONTRACTL
{
NOTHROW;
- GC_NOTRIGGER;
+ GC_TRIGGERS;
MODE_ANY;
PRECONDITION(contextRaw != NULL);
}
@@ -1488,7 +1491,11 @@ void ComWrappersNative::DestroyExternalComObjectContext(_In_ void* contextRaw)
#endif
STRESS_LOG1(LF_INTEROP, LL_INFO100, "Destroying EOC: 0x%p\n", contextRaw);
- InteropLib::Com::DestroyWrapperForExternal(contextRaw);
+
+ {
+ GCX_PREEMP();
+ InteropLib::Com::DestroyWrapperForExternal(contextRaw);
+ }
}
void ComWrappersNative::MarkExternalComObjectContextCollected(_In_ void* contextRaw)
diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp
index 8bdc5f0c2a892b..1007f0b28c6e63 100644
--- a/src/coreclr/vm/methodtable.cpp
+++ b/src/coreclr/vm/methodtable.cpp
@@ -7950,7 +7950,8 @@ MethodTable::MethodData::ProcessMap(
UINT32 cTypeIDs,
MethodTable * pMT,
UINT32 iCurrentChainDepth,
- MethodDataEntry * rgWorkingData)
+ MethodDataEntry * rgWorkingData,
+ size_t cWorkingData)
{
LIMITED_METHOD_CONTRACT;
@@ -7961,10 +7962,8 @@ MethodTable::MethodData::ProcessMap(
if (it.Entry()->GetTypeID() == rgTypeIDs[nTypeIDIndex])
{
UINT32 curSlot = it.Entry()->GetSlotNumber();
- // If we're processing an interface, or it's for a virtual, or it's for a non-virtual
- // for the most derived type, we want to process the entry. In other words, we
- // want to ignore non-virtuals for parent classes.
- if ((curSlot < pMT->GetNumVirtuals()) || (iCurrentChainDepth == 0))
+ // This if check is defensive, and should never fail
+ if (curSlot < cWorkingData)
{
MethodDataEntry * pCurEntry = &rgWorkingData[curSlot];
if (!pCurEntry->IsDeclInit() && !pCurEntry->IsImplInit())
@@ -8331,7 +8330,7 @@ MethodTable::MethodDataInterfaceImpl::PopulateNextLevel()
if (m_cDeclTypeIDs != 0)
{ // We got the TypeIDs from TypeLoader, use them
- ProcessMap(m_rgDeclTypeIDs, m_cDeclTypeIDs, pMTCur, iChainDepth, GetEntryData());
+ ProcessMap(m_rgDeclTypeIDs, m_cDeclTypeIDs, pMTCur, iChainDepth, GetEntryData(), GetNumVirtuals());
}
else
{ // We should decode all interface duplicates of code:m_pDecl
@@ -8348,7 +8347,7 @@ MethodTable::MethodDataInterfaceImpl::PopulateNextLevel()
INDEBUG(dbg_fInterfaceFound = TRUE);
DispatchMapTypeID declTypeID = DispatchMapTypeID::InterfaceClassID(it.GetIndex());
- ProcessMap(&declTypeID, 1, pMTCur, iChainDepth, GetEntryData());
+ ProcessMap(&declTypeID, 1, pMTCur, iChainDepth, GetEntryData(), GetNumVirtuals());
}
}
// The interface code:m_Decl should be found at least once in the interface map of code:m_pImpl,
diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h
index df712a378d4ece..816da7ee0f339b 100644
--- a/src/coreclr/vm/methodtable.h
+++ b/src/coreclr/vm/methodtable.h
@@ -3242,7 +3242,8 @@ public :
UINT32 cTypeIDs,
MethodTable * pMT,
UINT32 cCurrentChainDepth,
- MethodDataEntry * rgWorkingData);
+ MethodDataEntry * rgWorkingData,
+ size_t cWorkingData);
}; // class MethodData
typedef ::Holder < MethodData *, MethodData::HolderAcquire, MethodData::HolderRelease > MethodDataHolder;
diff --git a/src/coreclr/vm/syncblk.h b/src/coreclr/vm/syncblk.h
index 6fb565c1aa4018..3b79753069976e 100644
--- a/src/coreclr/vm/syncblk.h
+++ b/src/coreclr/vm/syncblk.h
@@ -823,19 +823,24 @@ class InteropSyncBlockInfo
if (m_managedObjectComWrapperMap == NULL)
return;
- CrstHolder lock(&m_managedObjectComWrapperLock);
-
- if (callback != NULL)
+ CQuickArrayList localList;
{
- ManagedObjectComWrapperByIdMap::Iterator iter = m_managedObjectComWrapperMap->Begin();
- while (iter != m_managedObjectComWrapperMap->End())
+ CrstHolder lock(&m_managedObjectComWrapperLock);
+ if (callback != NULL)
{
- callback(iter->Value());
- ++iter;
+ ManagedObjectComWrapperByIdMap::Iterator iter = m_managedObjectComWrapperMap->Begin();
+ while (iter != m_managedObjectComWrapperMap->End())
+ {
+ localList.Push(iter->Value());
+ ++iter;
+ }
}
+
+ m_managedObjectComWrapperMap->RemoveAll();
}
- m_managedObjectComWrapperMap->RemoveAll();
+ for (SIZE_T i = 0; i < localList.Size(); i++)
+ callback(localList[i]);
}
using EnumWrappersCallback = bool(void* mocw, void* cxt);
diff --git a/src/coreclr/vm/threadsuspend.cpp b/src/coreclr/vm/threadsuspend.cpp
index 02e4747fceaf10..8359706d948f70 100644
--- a/src/coreclr/vm/threadsuspend.cpp
+++ b/src/coreclr/vm/threadsuspend.cpp
@@ -28,6 +28,10 @@ CLREvent* ThreadSuspend::g_pGCSuspendEvent = NULL;
ThreadSuspend::SUSPEND_REASON ThreadSuspend::m_suspendReason;
+#if defined(TARGET_WINDOWS) && defined(TARGET_AMD64)
+void* ThreadSuspend::g_returnAddressHijackTarget = NULL;
+#endif
+
// If you add any thread redirection function, make sure the debugger can 1) recognize the redirection
// function, and 2) retrieve the original CONTEXT. See code:Debugger.InitializeHijackFunctionAddress and
// code:DacDbiInterfaceImpl.RetrieveHijackedContext.
@@ -4678,7 +4682,17 @@ void Thread::HijackThread(ReturnKind returnKind, ExecutionState *esb)
CONTRACTL_END;
_ASSERTE(IsValidReturnKind(returnKind));
+
VOID *pvHijackAddr = reinterpret_cast(OnHijackTripThread);
+
+#if defined(TARGET_WINDOWS) && defined(TARGET_AMD64)
+ void* returnAddressHijackTarget = ThreadSuspend::GetReturnAddressHijackTarget();
+ if (returnAddressHijackTarget != NULL)
+ {
+ pvHijackAddr = returnAddressHijackTarget;
+ }
+#endif // TARGET_WINDOWS && TARGET_AMD64
+
#ifdef TARGET_X86
if (returnKind == RT_Float)
{
@@ -5975,9 +5989,26 @@ bool Thread::InjectActivation(ActivationReason reason)
// Initialize thread suspension support
void ThreadSuspend::Initialize()
{
-#if defined(FEATURE_HIJACK) && defined(TARGET_UNIX)
+#ifdef FEATURE_HIJACK
+#if defined(TARGET_UNIX)
::PAL_SetActivationFunction(HandleSuspensionForInterruptedThread, CheckActivationSafePoint);
-#endif
+#elif defined(TARGET_WINDOWS) && defined(TARGET_AMD64)
+ // Only versions of Windows that have the special user mode APC have a correct implementation of the return address hijack handling
+ if (Thread::UseSpecialUserModeApc())
+ {
+ HMODULE hModNtdll = WszLoadLibrary(W("ntdll.dll"));
+ if (hModNtdll != NULL)
+ {
+ typedef ULONG_PTR (NTAPI *PFN_RtlGetReturnAddressHijackTarget)();
+ PFN_RtlGetReturnAddressHijackTarget pfnRtlGetReturnAddressHijackTarget = (PFN_RtlGetReturnAddressHijackTarget)GetProcAddress(hModNtdll, "RtlGetReturnAddressHijackTarget");
+ if (pfnRtlGetReturnAddressHijackTarget != NULL)
+ {
+ g_returnAddressHijackTarget = (void*)pfnRtlGetReturnAddressHijackTarget();
+ }
+ }
+ }
+#endif // TARGET_WINDOWS && TARGET_AMD64
+#endif // FEATURE_HIJACK
}
#ifdef _DEBUG
diff --git a/src/coreclr/vm/threadsuspend.h b/src/coreclr/vm/threadsuspend.h
index f36b39f4f7f7a8..9274327682a6b9 100644
--- a/src/coreclr/vm/threadsuspend.h
+++ b/src/coreclr/vm/threadsuspend.h
@@ -194,6 +194,10 @@ class ThreadSuspend
private:
static CLREvent * g_pGCSuspendEvent;
+#if defined(TARGET_WINDOWS) && defined(TARGET_AMD64)
+ static void* g_returnAddressHijackTarget;
+#endif // TARGET_WINDOWS && TARGET_AMD64
+
// This is true iff we're currently in the process of suspending threads. Once the
// threads have been suspended, this is false. This is set via an instance of
// SuspendRuntimeInProgressHolder placed in SuspendRuntime, SysStartSuspendForDebug,
@@ -247,6 +251,13 @@ class ThreadSuspend
return g_pSuspensionThread;
}
+#if defined(TARGET_WINDOWS) && defined(TARGET_AMD64)
+ static void* GetReturnAddressHijackTarget()
+ {
+ return g_returnAddressHijackTarget;
+ }
+#endif // TARGET_WINDOWS && TARGET_AMD64
+
private:
static LONG m_DebugWillSyncCount;
};
diff --git a/src/installer/pkg/projects/Microsoft.NETCore.DotNetAppHost/Microsoft.NETCore.DotNetAppHost.pkgproj b/src/installer/pkg/projects/Microsoft.NETCore.DotNetAppHost/Microsoft.NETCore.DotNetAppHost.pkgproj
index 73768455ceddc5..8f078c7c1bb6e9 100644
--- a/src/installer/pkg/projects/Microsoft.NETCore.DotNetAppHost/Microsoft.NETCore.DotNetAppHost.pkgproj
+++ b/src/installer/pkg/projects/Microsoft.NETCore.DotNetAppHost/Microsoft.NETCore.DotNetAppHost.pkgproj
@@ -6,13 +6,15 @@
-
+
+
+
diff --git a/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.targets b/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.targets
index c570a22277456e..61c12cb71a854d 100644
--- a/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.targets
+++ b/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.targets
@@ -8,7 +8,7 @@
-
+
diff --git a/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Host.sfxproj b/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Host.sfxproj
index ab948eb5ddbae7..f32e7eb5e853bc 100644
--- a/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Host.sfxproj
+++ b/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Host.sfxproj
@@ -2,7 +2,7 @@
- true
+ true
AppHostPack
true
dotnet-apphost-pack
@@ -21,13 +21,15 @@
-
+
+
+
diff --git a/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.props b/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.props
index 3fe16b05bacc05..87aaf9d263ced2 100644
--- a/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.props
+++ b/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.props
@@ -15,7 +15,7 @@
The .NET Shared Framework
-
+
Mono
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 c69491f5044a0b..90f8d4ad2a28f0 100644
--- a/src/installer/pkg/sfx/bundle/Microsoft.NETCore.App.Bundle.bundleproj
+++ b/src/installer/pkg/sfx/bundle/Microsoft.NETCore.App.Bundle.bundleproj
@@ -5,7 +5,7 @@
Name, used to generate the bundle upgrade code. Must stay the same to allow bundles in a given
product band to upgrade in place.
-->
- true
+ true
false
.NET Core Shared Framework Bundle Installer
$(MSBuildProjectDirectory)
diff --git a/src/installer/pkg/sfx/installers/dotnet-host.proj b/src/installer/pkg/sfx/installers/dotnet-host.proj
index 0963a7b89d8cca..953b0f4f8522f9 100644
--- a/src/installer/pkg/sfx/installers/dotnet-host.proj
+++ b/src/installer/pkg/sfx/installers/dotnet-host.proj
@@ -1,6 +1,6 @@
- true
+ true
true
dotnet-host
dotnet-host-internal
diff --git a/src/installer/pkg/sfx/installers/dotnet-hostfxr.proj b/src/installer/pkg/sfx/installers/dotnet-hostfxr.proj
index 0edd1eaa9853d2..2c5fa5d8188867 100644
--- a/src/installer/pkg/sfx/installers/dotnet-hostfxr.proj
+++ b/src/installer/pkg/sfx/installers/dotnet-hostfxr.proj
@@ -1,6 +1,6 @@
- true
+ true
true
dotnet-hostfxr-internal
dotnet-hostfxr
diff --git a/src/installer/tests/HostActivation.Tests/MultiArchInstallLocation.cs b/src/installer/tests/HostActivation.Tests/MultiArchInstallLocation.cs
index 3206cd74d15593..120b899cff451b 100644
--- a/src/installer/tests/HostActivation.Tests/MultiArchInstallLocation.cs
+++ b/src/installer/tests/HostActivation.Tests/MultiArchInstallLocation.cs
@@ -205,6 +205,38 @@ public void InstallLocationFile_ReallyLongInstallPathIsParsedCorrectly()
}
}
+ [Fact]
+ [SkipOnPlatform(TestPlatforms.Windows, "This test targets the install_location config file which is only used on Linux and macOS.")]
+ public void InstallLocationFile_MissingFile()
+ {
+ var fixture = sharedTestState.PortableAppFixture.Copy();
+
+ var appExe = fixture.TestProject.AppExe;
+ string testArtifactsPath = SharedFramework.CalculateUniqueTestDirectory(Path.Combine(TestArtifact.TestArtifactsPath, "missingInstallLocation"));
+ using (new TestArtifact(testArtifactsPath))
+ using (var testOnlyProductBehavior = TestOnlyProductBehavior.Enable(appExe))
+ {
+ Directory.CreateDirectory(testArtifactsPath);
+
+ string directory = Path.Combine(testArtifactsPath, "installLocationOverride");
+ Directory.CreateDirectory(directory);
+ string nonExistentLocationFile = Path.Combine(directory, "install_location");
+ string defaultInstallLocation = Path.Combine(testArtifactsPath, "defaultInstallLocation");
+
+ Command.Create(appExe)
+ .CaptureStdErr()
+ .EnvironmentVariable(
+ Constants.TestOnlyEnvironmentVariables.InstallLocationFilePath,
+ nonExistentLocationFile)
+ .EnvironmentVariable(
+ Constants.TestOnlyEnvironmentVariables.DefaultInstallPath,
+ defaultInstallLocation)
+ .DotNetRoot(null)
+ .Execute()
+ .Should().NotHaveStdErrContaining("The install_location file");
+ }
+ }
+
public class SharedTestState : IDisposable
{
public string BaseDirectory { get; }
diff --git a/src/installer/tests/HostActivation.Tests/PortableAppActivation.cs b/src/installer/tests/HostActivation.Tests/PortableAppActivation.cs
index fa3e03bd972016..1abb3ad75b9697 100644
--- a/src/installer/tests/HostActivation.Tests/PortableAppActivation.cs
+++ b/src/installer/tests/HostActivation.Tests/PortableAppActivation.cs
@@ -340,6 +340,37 @@ public void AppHost_FrameworkDependent_GlobalLocation_Succeeds(bool useRegistere
}
}
+ [Fact]
+ public void RuntimeConfig_FilePath_Breaks_MAX_PATH_Threshold()
+ {
+ var project = sharedTestState.PortableAppFixture_Published
+ .Copy();
+
+ var appExeName = Path.GetFileName(project.TestProject.AppExe);
+ var outputDir = project.TestProject.OutputDirectory;
+
+ // Move the portable app to a path such that the length of the executable's fullpath
+ // is just 1 char behind MAX_PATH (260) so that the runtimeconfig(.dev).json files
+ // break this threshold. This will cause hostfxr to normalize these paths -- here we
+ // are checking that the updated paths are used.
+ var tmp = Path.GetTempPath();
+ var dirName = new string('a', 259 - tmp.Length - appExeName.Length - 1);
+ var newDir = Path.Combine(tmp, dirName);
+ var appExe = Path.Combine(newDir, appExeName);
+ Debug.Assert(appExe.Length == 259);
+ Directory.CreateDirectory(newDir);
+ foreach (var file in Directory.GetFiles(outputDir, "*.*", SearchOption.TopDirectoryOnly))
+ File.Copy(file, Path.Combine(newDir, Path.GetFileName(file)), true);
+
+ Command.Create(appExe)
+ .DotNetRoot(project.BuiltDotnet.BinPath)
+ .EnableTracingAndCaptureOutputs()
+ .MultilevelLookup(false)
+ .Execute()
+ .Should().Pass()
+ .And.HaveStdOutContaining("Hello World");
+ }
+
[Fact]
public void ComputedTPADoesntEndWithPathSeparator()
{
@@ -707,7 +738,7 @@ public SharedTestState()
PortableAppFixture_Published = new TestProjectFixture("PortableApp", RepoDirectories)
.EnsureRestored()
- .PublishProject();
+ .PublishProject(extraArgs: "/p:UseAppHost=true");
MockApp = new TestApp(SharedFramework.CalculateUniqueTestDirectory(Path.Combine(TestArtifact.TestArtifactsPath, "portableAppActivation")), "App");
Directory.CreateDirectory(MockApp.Location);
diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/QPackEncoder.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/QPackEncoder.cs
index 1f2275ebb15ff3..fb6e690b01ddc6 100644
--- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/QPackEncoder.cs
+++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Http3/QPack/QPackEncoder.cs
@@ -317,7 +317,7 @@ private static void EncodeValueStringPart(string s, Span buffer)
if (ch > 127)
{
- throw new QPackEncodingException("ASCII header value.");
+ throw new QPackEncodingException(SR.net_http_request_invalid_char_encoding);
}
buffer[i] = (byte)ch;
@@ -402,4 +402,4 @@ private static bool EncodeHeaderBlockPrefix(Span destination, out int byte
return true;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/SR.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/SR.cs
index 2e67f3463b02d9..3f1f91e905554c 100644
--- a/src/libraries/Common/src/System/Net/Http/aspnetcore/SR.cs
+++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/SR.cs
@@ -1,5 +1,5 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// 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;
diff --git a/src/libraries/Common/src/System/Net/Security/CertificateValidation.Unix.cs b/src/libraries/Common/src/System/Net/Security/CertificateValidation.Unix.cs
index e03cd4088d5b49..57bc4b9e23220e 100644
--- a/src/libraries/Common/src/System/Net/Security/CertificateValidation.Unix.cs
+++ b/src/libraries/Common/src/System/Net/Security/CertificateValidation.Unix.cs
@@ -12,7 +12,7 @@ internal static class CertificateValidation
{
private static readonly IdnMapping s_idnMapping = new IdnMapping();
- internal static SslPolicyErrors BuildChainAndVerifyProperties(X509Chain chain, X509Certificate2 remoteCertificate, bool checkCertName, string? hostName)
+ internal static SslPolicyErrors BuildChainAndVerifyProperties(X509Chain chain, X509Certificate2 remoteCertificate, bool checkCertName, bool isServer, string? hostName)
{
SslPolicyErrors errors = chain.Build(remoteCertificate) ?
SslPolicyErrors.None :
diff --git a/src/libraries/Common/src/System/Net/Security/CertificateValidation.Windows.cs b/src/libraries/Common/src/System/Net/Security/CertificateValidation.Windows.cs
new file mode 100644
index 00000000000000..41d127639484b8
--- /dev/null
+++ b/src/libraries/Common/src/System/Net/Security/CertificateValidation.Windows.cs
@@ -0,0 +1,90 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.Win32.SafeHandles;
+using System.Diagnostics;
+using System.Net.Security;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.X509Certificates;
+using System.Security.Principal;
+
+namespace System.Net
+{
+ internal static partial class CertificateValidation
+ {
+ internal static SslPolicyErrors BuildChainAndVerifyProperties(X509Chain chain, X509Certificate2 remoteCertificate, bool checkCertName, bool isServer, string? hostName)
+ {
+ SslPolicyErrors sslPolicyErrors = SslPolicyErrors.None;
+
+ bool chainBuildResult = chain.Build(remoteCertificate);
+ if (!chainBuildResult // Build failed on handle or on policy.
+ && chain.SafeHandle!.DangerousGetHandle() == IntPtr.Zero) // Build failed to generate a valid handle.
+ {
+ throw new CryptographicException(Marshal.GetLastPInvokeError());
+ }
+
+ if (checkCertName)
+ {
+ unsafe
+ {
+ uint status = 0;
+
+ var eppStruct = new Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA()
+ {
+ cbSize = (uint)sizeof(Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA),
+ // Authenticate the remote party: (e.g. when operating in server mode, authenticate the client).
+ dwAuthType = isServer ? Interop.Crypt32.AuthType.AUTHTYPE_CLIENT : Interop.Crypt32.AuthType.AUTHTYPE_SERVER,
+ fdwChecks = 0,
+ pwszServerName = null
+ };
+
+ var cppStruct = new Interop.Crypt32.CERT_CHAIN_POLICY_PARA()
+ {
+ cbSize = (uint)sizeof(Interop.Crypt32.CERT_CHAIN_POLICY_PARA),
+ dwFlags = 0,
+ pvExtraPolicyPara = &eppStruct
+ };
+
+ fixed (char* namePtr = hostName)
+ {
+ eppStruct.pwszServerName = namePtr;
+ cppStruct.dwFlags |=
+ (Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_ALL &
+ ~Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG);
+
+ SafeX509ChainHandle chainContext = chain.SafeHandle!;
+ status = Verify(chainContext, ref cppStruct);
+ if (status == Interop.Crypt32.CertChainPolicyErrors.CERT_E_CN_NO_MATCH)
+ {
+ sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch;
+ }
+ }
+ }
+ }
+
+ if (!chainBuildResult)
+ {
+ sslPolicyErrors |= SslPolicyErrors.RemoteCertificateChainErrors;
+ }
+
+ return sslPolicyErrors;
+ }
+
+ private static unsafe uint Verify(SafeX509ChainHandle chainContext, ref Interop.Crypt32.CERT_CHAIN_POLICY_PARA cpp)
+ {
+ Interop.Crypt32.CERT_CHAIN_POLICY_STATUS status = default;
+ status.cbSize = (uint)sizeof(Interop.Crypt32.CERT_CHAIN_POLICY_STATUS);
+
+ bool errorCode =
+ Interop.Crypt32.CertVerifyCertificateChainPolicy(
+ (IntPtr)Interop.Crypt32.CertChainPolicy.CERT_CHAIN_POLICY_SSL,
+ chainContext,
+ ref cpp,
+ ref status);
+
+ if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(chainContext, $"CertVerifyCertificateChainPolicy returned: {errorCode}. Status: {status.dwError}");
+ return status.dwError;
+ }
+ }
+}
diff --git a/src/libraries/Common/src/System/Text/Json/PooledByteBufferWriter.cs b/src/libraries/Common/src/System/Text/Json/PooledByteBufferWriter.cs
index 80e7bc26ae36da..8694a785ad3a58 100644
--- a/src/libraries/Common/src/System/Text/Json/PooledByteBufferWriter.cs
+++ b/src/libraries/Common/src/System/Text/Json/PooledByteBufferWriter.cs
@@ -86,8 +86,9 @@ public void Dispose()
}
ClearHelper();
- ArrayPool.Shared.Return(_rentedBuffer);
+ byte[] toReturn = _rentedBuffer;
_rentedBuffer = null!;
+ ArrayPool.Shared.Return(toReturn);
}
public void Advance(int count)
diff --git a/src/libraries/Common/tests/StreamConformanceTests/StreamConformanceTests.csproj b/src/libraries/Common/tests/StreamConformanceTests/StreamConformanceTests.csproj
index b5dfa854512bfc..6959f41279b178 100644
--- a/src/libraries/Common/tests/StreamConformanceTests/StreamConformanceTests.csproj
+++ b/src/libraries/Common/tests/StreamConformanceTests/StreamConformanceTests.csproj
@@ -4,7 +4,7 @@
$(NetCoreAppCurrent)
-
+
diff --git a/src/libraries/Common/tests/System/Net/Http/Http3LoopbackConnection.cs b/src/libraries/Common/tests/System/Net/Http/Http3LoopbackConnection.cs
index 555a54895e7e6f..ca53bbe2068257 100644
--- a/src/libraries/Common/tests/System/Net/Http/Http3LoopbackConnection.cs
+++ b/src/libraries/Common/tests/System/Net/Http/Http3LoopbackConnection.cs
@@ -189,13 +189,36 @@ public override async Task HandleRequestAsync(HttpStatusCode st
await stream.SendResponseAsync(statusCode, headers, content).ConfigureAwait(false);
- // closing the connection here causes bytes written to streams to go missing.
- // Regardless, we told the client we are closing so it shouldn't matter -- they should not use this connection anymore.
- //await CloseAsync(H3_NO_ERROR).ConfigureAwait(false);
+ await WaitForClientDisconnectAsync();
return request;
}
+ // Wait for the client to close the connection, e.g. after we send a GOAWAY, or after the HttpClient is disposed.
+ public async Task WaitForClientDisconnectAsync()
+ {
+ while (true)
+ {
+ Http3LoopbackStream stream;
+
+ try
+ {
+ stream = await AcceptRequestStreamAsync().ConfigureAwait(false);
+ }
+ catch (QuicConnectionAbortedException abortException) when (abortException.ErrorCode == H3_NO_ERROR)
+ {
+ break;
+ }
+
+ using (stream)
+ {
+ await stream.AbortAndWaitForShutdownAsync(H3_REQUEST_REJECTED);
+ }
+ }
+
+ await CloseAsync(H3_NO_ERROR);
+ }
+
public override async Task WaitForCancellationAsync(bool ignoreIncomingData = true, int requestId = 0)
{
await GetOpenRequest(requestId).WaitForCancellationAsync(ignoreIncomingData).ConfigureAwait(false);
diff --git a/src/libraries/Common/tests/System/Net/Http/Http3LoopbackStream.cs b/src/libraries/Common/tests/System/Net/Http/Http3LoopbackStream.cs
index b93807a0321466..a3d2c9a4215c2b 100644
--- a/src/libraries/Common/tests/System/Net/Http/Http3LoopbackStream.cs
+++ b/src/libraries/Common/tests/System/Net/Http/Http3LoopbackStream.cs
@@ -359,6 +359,13 @@ public async Task WaitForCancellationAsync(bool ignoreIncomingData = true)
}
}
+ public async Task AbortAndWaitForShutdownAsync(long errorCode)
+ {
+ _stream.AbortRead(errorCode);
+ _stream.AbortWrite(errorCode);
+ await _stream.ShutdownCompleted();
+ }
+
public async Task<(long? frameType, byte[] payload)> ReadFrameAsync()
{
long? frameType = await ReadIntegerAsync().ConfigureAwait(false);
diff --git a/src/libraries/Common/tests/System/Threading/Tasks/TaskTimeoutExtensions.cs b/src/libraries/Common/tests/System/Threading/Tasks/TaskTimeoutExtensions.cs
index 2efde1fef9ad58..2efa7af0d0e188 100644
--- a/src/libraries/Common/tests/System/Threading/Tasks/TaskTimeoutExtensions.cs
+++ b/src/libraries/Common/tests/System/Threading/Tasks/TaskTimeoutExtensions.cs
@@ -12,6 +12,9 @@ public static class TaskTimeoutExtensions
#region WaitAsync polyfills
// Test polyfills when targeting a platform that doesn't have these ConfigureAwait overloads on Task
+ public static Task WaitAsync(this Task task, int millisecondsTimeout) =>
+ WaitAsync(task, TimeSpan.FromMilliseconds(millisecondsTimeout), default);
+
public static Task WaitAsync(this Task task, TimeSpan timeout) =>
WaitAsync(task, timeout, default);
@@ -28,6 +31,9 @@ public async static Task WaitAsync(this Task task, TimeSpan timeout, Cancellatio
}
}
+ public static Task WaitAsync(this Task task, int millisecondsTimeout) =>
+ WaitAsync(task, TimeSpan.FromMilliseconds(millisecondsTimeout), default);
+
public static Task WaitAsync(this Task task, TimeSpan timeout) =>
WaitAsync(task, timeout, default);
@@ -48,6 +54,9 @@ public static async Task WaitAsync(this Task task, Ti
public static async Task WhenAllOrAnyFailed(this Task[] tasks, int millisecondsTimeout) =>
await tasks.WhenAllOrAnyFailed().WaitAsync(TimeSpan.FromMilliseconds(millisecondsTimeout));
+ public static async Task WhenAllOrAnyFailed(Task t1, Task t2, int millisecondsTimeout) =>
+ await new Task[] {t1, t2}.WhenAllOrAnyFailed(millisecondsTimeout);
+
public static async Task WhenAllOrAnyFailed(this Task[] tasks)
{
try
diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs
index 096616937019eb..cff5e2284cfb36 100644
--- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs
+++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs
@@ -20,6 +20,7 @@ public static partial class PlatformDetection
public static bool IsDebian => IsDistroAndVersion("debian");
public static bool IsAlpine => IsDistroAndVersion("alpine");
public static bool IsDebian8 => IsDistroAndVersion("debian", 8);
+ public static bool IsDebian9 => IsDistroAndVersion("debian", 9);
public static bool IsDebian10 => IsDistroAndVersion("debian", 10);
public static bool IsUbuntu1604 => IsDistroAndVersion("ubuntu", 16, 4);
public static bool IsUbuntu1704 => IsDistroAndVersion("ubuntu", 17, 4);
diff --git a/src/libraries/Directory.Build.targets b/src/libraries/Directory.Build.targets
index 87dda78fb5bc1e..5e28db1deeb28d 100644
--- a/src/libraries/Directory.Build.targets
+++ b/src/libraries/Directory.Build.targets
@@ -59,10 +59,6 @@
'$(DisableImplicitFrameworkReferences)' != 'true' and
'$(TargetFrameworkIdentifier)' == '.NETCoreApp' and
('$(IsReferenceAssembly)' == 'true' or '$(IsSourceProject)' == 'true')">true
-
-
- true
diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.csproj b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.csproj
index f85823f03e54cd..75ea735a625eae 100644
--- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.csproj
+++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.csproj
@@ -11,6 +11,6 @@
-
+
diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Specification.Tests/src/DependencyInjectionSpecificationTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Specification.Tests/src/DependencyInjectionSpecificationTests.cs
index 88235f9e50d755..8a4d73684b4188 100644
--- a/src/libraries/Microsoft.Extensions.DependencyInjection.Specification.Tests/src/DependencyInjectionSpecificationTests.cs
+++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Specification.Tests/src/DependencyInjectionSpecificationTests.cs
@@ -434,6 +434,14 @@ public void ScopedServices_FromCachedScopeFactory_CanBeResolvedAndDisposed()
}
}
+ [Fact]
+ public void ServiceProviderIsDisposable()
+ {
+ var provider = CreateServiceProvider(new TestServiceCollection());
+
+ Assert.IsAssignableFrom(provider);
+ }
+
[Fact]
public void DisposingScopeDisposesService()
{
@@ -469,13 +477,10 @@ public void DisposingScopeDisposesService()
Assert.True(transient2.Disposed);
Assert.False(singleton.Disposed);
- var disposableProvider = provider as IDisposable;
- if (disposableProvider != null)
- {
- disposableProvider.Dispose();
- Assert.True(singleton.Disposed);
- Assert.True(transient3.Disposed);
- }
+ (provider as IDisposable).Dispose();
+
+ Assert.True(singleton.Disposed);
+ Assert.True(transient3.Disposed);
}
[Fact]
@@ -490,7 +495,7 @@ public void SelfResolveThenDispose()
// Assert
Assert.NotNull(serviceProvider);
- (provider as IDisposable)?.Dispose();
+ (provider as IDisposable).Dispose();
}
[Fact]
@@ -790,7 +795,7 @@ public void DisposesInReverseOrderOfCreation()
var multipleServices = outer.MultipleServices.ToArray();
// Act
- ((IDisposable)serviceProvider).Dispose();
+ (serviceProvider as IDisposable).Dispose();
// Assert
Assert.Equal(outer, callback.Disposed[0]);
diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/StructureMap.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/StructureMap.cs
index f73bf039220e8f..59a6e00160ec56 100644
--- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/StructureMap.cs
+++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/StructureMap.cs
@@ -12,6 +12,9 @@ public class StructureMapDependencyInjectionSpecificationTests: SkippableDepende
public override string[] SkippedTests => new[]
{
+ "ServiceProviderIsDisposable",
+ "SelfResolveThenDispose",
+ "DisposingScopeDisposesService",
"DisposesInReverseOrderOfCreation",
"ResolvesMixedOpenClosedGenericsAsEnumerable"
};
diff --git a/src/libraries/Microsoft.Extensions.FileProviders.Physical/tests/PhysicalFileProviderTests.cs b/src/libraries/Microsoft.Extensions.FileProviders.Physical/tests/PhysicalFileProviderTests.cs
index b4e37df4f11636..96bf27b7b5acab 100644
--- a/src/libraries/Microsoft.Extensions.FileProviders.Physical/tests/PhysicalFileProviderTests.cs
+++ b/src/libraries/Microsoft.Extensions.FileProviders.Physical/tests/PhysicalFileProviderTests.cs
@@ -1515,6 +1515,7 @@ public void UsePollingFileWatcher_FileWatcherNotNull_ReturnsFalse()
[Theory]
[InlineData(false)]
[InlineData(true)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/56190", TestPlatforms.AnyUnix)]
public async Task UsePollingFileWatcher_UseActivePolling_HasChanged(bool useWildcard)
{
// Arrange
@@ -1541,6 +1542,7 @@ public async Task UsePollingFileWatcher_UseActivePolling_HasChanged(bool useWild
[Theory]
[InlineData(false)]
[InlineData(true)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/56190", TestPlatforms.AnyUnix)]
public void UsePollingFileWatcher_UseActivePolling_HasChanged_FileDeleted(bool useWildcard)
{
// Arrange
diff --git a/src/libraries/Microsoft.Extensions.FileProviders.Physical/tests/PhysicalFileProviderTests.netcoreapp.cs b/src/libraries/Microsoft.Extensions.FileProviders.Physical/tests/PhysicalFileProviderTests.netcoreapp.cs
index d8b332b6409f56..7ccfafb28180cd 100644
--- a/src/libraries/Microsoft.Extensions.FileProviders.Physical/tests/PhysicalFileProviderTests.netcoreapp.cs
+++ b/src/libraries/Microsoft.Extensions.FileProviders.Physical/tests/PhysicalFileProviderTests.netcoreapp.cs
@@ -14,6 +14,7 @@ public partial class PhysicalFileProviderTests
[Theory]
[InlineData(false)]
[InlineData(true)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/56190", TestPlatforms.AnyUnix)]
public async Task UsePollingFileWatcher_UseActivePolling_HasChanged_SymbolicLink(bool useWildcard)
{
// Arrange
@@ -44,6 +45,7 @@ public async Task UsePollingFileWatcher_UseActivePolling_HasChanged_SymbolicLink
[Theory]
[InlineData(false)]
[InlineData(true)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/56190", TestPlatforms.AnyUnix)]
public void UsePollingFileWatcher_UseActivePolling_HasChanged_SymbolicLink_TargetNotExists(bool useWildcard)
{
// Arrange
@@ -69,6 +71,7 @@ public void UsePollingFileWatcher_UseActivePolling_HasChanged_SymbolicLink_Targe
[InlineData(false, true)]
[InlineData(true, false)]
[InlineData(true, true)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/56190", TestPlatforms.AnyUnix)]
public async Task UsePollingFileWatcher_UseActivePolling_HasChanged_SymbolicLink_TargetChanged(bool useWildcard, bool linkWasBroken)
{
// Arrange
@@ -108,6 +111,7 @@ public async Task UsePollingFileWatcher_UseActivePolling_HasChanged_SymbolicLink
[Theory]
[InlineData(false)]
[InlineData(true)]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/56190", TestPlatforms.AnyUnix)]
public void UsePollingFileWatcher_UseActivePolling_HasChanged_SymbolicLink_TargetDeleted(bool useWildcard)
{
// Arrange
diff --git a/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/HostBuilderTests.cs b/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/HostBuilderTests.cs
index 1f35e1c15f4802..abe332ab9b9dd8 100644
--- a/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/HostBuilderTests.cs
+++ b/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/HostBuilderTests.cs
@@ -310,7 +310,6 @@ public void HostConfigParametersReadCorrectly()
}
[Fact]
- [ActiveIssue("https://github.com/dotnet/runtime/issues/52114", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)]
public void RelativeContentRootIsResolved()
{
using (var host = new HostBuilder()
diff --git a/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/HostTests.cs b/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/HostTests.cs
index 345fcbb7866507..7fe9ceca422bb2 100644
--- a/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/HostTests.cs
+++ b/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/HostTests.cs
@@ -21,7 +21,6 @@ namespace Microsoft.Extensions.Hosting.Tests
public partial class HostTests
{
[Fact]
- [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.MacCatalyst | TestPlatforms.tvOS, "Not supported on iOS, MacCatalyst, or tvOS.")]
public async Task StopAsyncWithCancellation()
{
var builder = new HostBuilder();
diff --git a/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/Internal/HostTests.cs b/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/Internal/HostTests.cs
index 989ea8c1caf46f..e98aa45666ad81 100644
--- a/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/Internal/HostTests.cs
+++ b/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/Internal/HostTests.cs
@@ -19,7 +19,6 @@
namespace Microsoft.Extensions.Hosting.Internal
{
- [ActiveIssue("https://github.com/dotnet/runtime/issues/52114", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)]
public class HostTests
{
[Fact]
@@ -678,7 +677,7 @@ public async Task HostPropagatesExceptionsThrownWithBackgroundServiceExceptionBe
[Fact]
public async Task HostStopsApplicationWithOneBackgroundServiceErrorAndOthersWithoutError()
- {
+ {
var wasOtherServiceStarted = false;
TaskCompletionSource throwingTcs = new();
diff --git a/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/OptionsBuilderExtensionsTests.cs b/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/OptionsBuilderExtensionsTests.cs
index 53153ac7f2909d..793bedf2003db9 100644
--- a/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/OptionsBuilderExtensionsTests.cs
+++ b/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/OptionsBuilderExtensionsTests.cs
@@ -26,7 +26,6 @@ public void ValidateOnStart_NullOptionsBuilder_Throws()
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/34582", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)]
- [ActiveIssue("https://github.com/dotnet/runtime/issues/52114", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)]
public async Task ValidateOnStart_ConfigureAndValidateThenCallValidateOnStart_ValidatesFailure()
{
var hostBuilder = CreateHostBuilder(services =>
@@ -50,7 +49,6 @@ public async Task ValidateOnStart_ConfigureAndValidateThenCallValidateOnStart_Va
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/34582", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)]
- [ActiveIssue("https://github.com/dotnet/runtime/issues/52114", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)]
public async Task ValidateOnStart_CallFirstThenConfigureAndValidate_ValidatesFailure()
{
var hostBuilder = CreateHostBuilder(services =>
@@ -74,7 +72,6 @@ public async Task ValidateOnStart_CallFirstThenConfigureAndValidate_ValidatesFai
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/34582", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)]
- [ActiveIssue("https://github.com/dotnet/runtime/issues/52114", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)]
public async Task ValidateOnStart_ErrorMessageSpecified_FailsWithCustomError()
{
var hostBuilder = CreateHostBuilder(services =>
@@ -105,7 +102,6 @@ internal class FakeSettings
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/34582", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)]
- [ActiveIssue("https://github.com/dotnet/runtime/issues/52114", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)]
public async Task ValidateOnStart_NamedOptions_ValidatesFailureOnStart()
{
var hostBuilder = CreateHostBuilder(services =>
@@ -134,7 +130,6 @@ public async Task ValidateOnStart_NamedOptions_ValidatesFailureOnStart()
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/34582", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)]
- [ActiveIssue("https://github.com/dotnet/runtime/issues/52114", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)]
private async Task ValidateOnStart_AddNamedOptionsMultipleTimesForSameType_BothGetTriggered()
{
bool firstOptionsBuilderTriggered = false;
@@ -181,7 +176,6 @@ private async Task ValidateOnStart_AddNamedOptionsMultipleTimesForSameType_BothG
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/34582", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)]
- [ActiveIssue("https://github.com/dotnet/runtime/issues/52114", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)]
private async Task ValidateOnStart_AddEagerValidation_DoesValidationWhenHostStartsWithNoFailure()
{
bool validateCalled = false;
@@ -193,7 +187,7 @@ private async Task ValidateOnStart_AddEagerValidation_DoesValidationWhenHostStar
.Configure(o => o.Boolean = true)
.Validate(o =>
{
- validateCalled = true;
+ validateCalled = true;
return o.Boolean;
}, "correct_configuration")
.ValidateOnStart();
@@ -209,7 +203,6 @@ private async Task ValidateOnStart_AddEagerValidation_DoesValidationWhenHostStar
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/34582", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)]
- [ActiveIssue("https://github.com/dotnet/runtime/issues/52114", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)]
private async Task ValidateOnStart_AddLazyValidation_SkipsValidationWhenHostStarts()
{
bool validateCalled = false;
@@ -227,7 +220,7 @@ private async Task ValidateOnStart_AddLazyValidation_SkipsValidationWhenHostStar
.Configure(o => o.Boolean = false)
.Validate(o =>
{
- validateCalled = true;
+ validateCalled = true;
return o.Boolean;
}, "bad_configuration");
});
@@ -243,7 +236,6 @@ private async Task ValidateOnStart_AddLazyValidation_SkipsValidationWhenHostStar
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/34582", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)]
- [ActiveIssue("https://github.com/dotnet/runtime/issues/52114", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)]
public async Task ValidateOnStart_AddBothLazyAndEagerValidationOnDifferentTypes_ValidatesWhenHostStartsOnlyForEagerValidations()
{
bool validateCalledForNested = false;
@@ -254,7 +246,7 @@ public async Task ValidateOnStart_AddBothLazyAndEagerValidationOnDifferentTypes_
// Lazy validation for NestedOptions
services.AddOptions()
.Configure(o => o.Integer = 11)
- .Validate(o =>
+ .Validate(o =>
{
validateCalledForNested = true;
return o.Integer > 12;
@@ -263,7 +255,7 @@ public async Task ValidateOnStart_AddBothLazyAndEagerValidationOnDifferentTypes_
// Eager validation for ComplexOptions
services.AddOptions()
.Configure(o => o.Boolean = false)
- .Validate(o =>
+ .Validate(o =>
{
validateCalledForComplexOptions = true;
return o.Boolean;
@@ -287,7 +279,6 @@ public async Task ValidateOnStart_AddBothLazyAndEagerValidationOnDifferentTypes_
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/34582", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)]
- [ActiveIssue("https://github.com/dotnet/runtime/issues/52114", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)]
public async Task ValidateOnStart_MultipleErrorsInOneValidationCall_ValidatesFailureWithMultipleErrors()
{
var hostBuilder = CreateHostBuilder(services =>
@@ -316,7 +307,6 @@ public async Task ValidateOnStart_MultipleErrorsInOneValidationCall_ValidatesFai
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/34582", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)]
- [ActiveIssue("https://github.com/dotnet/runtime/issues/52114", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)]
public async Task ValidateOnStart_MultipleErrorsInOneValidationCallUsingCustomErrors_FailuresContainCustomErrors()
{
var hostBuilder = CreateHostBuilder(services =>
diff --git a/src/libraries/Microsoft.NETCore.Platforms/tests/Microsoft.NETCore.Platforms.Tests.csproj b/src/libraries/Microsoft.NETCore.Platforms/tests/Microsoft.NETCore.Platforms.Tests.csproj
index d39b20d6d9f5e2..a2a273ed6e042f 100644
--- a/src/libraries/Microsoft.NETCore.Platforms/tests/Microsoft.NETCore.Platforms.Tests.csproj
+++ b/src/libraries/Microsoft.NETCore.Platforms/tests/Microsoft.NETCore.Platforms.Tests.csproj
@@ -8,6 +8,8 @@
+
+
diff --git a/src/libraries/System.ComponentModel.EventBasedAsync/tests/AsyncOperationFinalizerTests.cs b/src/libraries/System.ComponentModel.EventBasedAsync/tests/AsyncOperationFinalizerTests.cs
index 06707dcbec13b1..e7a42d50bdc20f 100644
--- a/src/libraries/System.ComponentModel.EventBasedAsync/tests/AsyncOperationFinalizerTests.cs
+++ b/src/libraries/System.ComponentModel.EventBasedAsync/tests/AsyncOperationFinalizerTests.cs
@@ -34,7 +34,9 @@ private void Completed()
Assert.True(tracker.OperationDidComplete);
}
- [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
+ private static bool IsPreciseGcSupportedAndRemoteExecutorSupported => PlatformDetection.IsPreciseGcSupported && RemoteExecutor.IsSupported;
+
+ [ConditionalFact(nameof(IsPreciseGcSupportedAndRemoteExecutorSupported))]
public void Finalizer_OperationNotCompleted_CompletesOperation()
{
RemoteExecutor.Invoke(() =>
diff --git a/src/libraries/System.ComponentModel.TypeConverter/tests/ILLink.Descriptors.xml b/src/libraries/System.ComponentModel.TypeConverter/tests/ILLink.Descriptors.xml
index 2c51716e8b55b2..50dadf97ed098b 100644
--- a/src/libraries/System.ComponentModel.TypeConverter/tests/ILLink.Descriptors.xml
+++ b/src/libraries/System.ComponentModel.TypeConverter/tests/ILLink.Descriptors.xml
@@ -8,7 +8,6 @@
-
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs
index ce68dcf98f8155..cc846b56efb4d8 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs
@@ -376,7 +376,7 @@ public void EventSourcePublishesMissingDataPoints()
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
[OuterLoop("Slow and has lots of console spew")]
- public void EventSourcePublishesEndEventsOnNewListener()
+ public void EventSourceRejectsNewListener()
{
using Meter meter = new Meter("TestMeter7");
Counter c = meter.CreateCounter("counter1", "hat", "Fooz!!");
@@ -395,11 +395,13 @@ public void EventSourcePublishesEndEventsOnNewListener()
listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
c.Add(12);
h.Record(26);
- listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
- // some alternate listener starts listening
+ // some alternate listener attempts to listen in the middle
using MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "ADifferentMeter");
- listener.WaitForEndInstrumentReporting(s_waitForEventTimeout, 4);
+ listener2.WaitForMultipleSessionsNotSupportedError(s_waitForEventTimeout);
+
+
+ listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
events = listener.Events.ToArray();
}
@@ -409,7 +411,6 @@ public void EventSourcePublishesEndEventsOnNewListener()
AssertGaugeEventsPresent(events, meter.Name, og.Name, "", og.Unit, "9", "18", "27");
AssertHistogramEventsPresent(events, meter.Name, h.Name, "", h.Unit, "0.5=19;0.95=19;0.99=19", "0.5=26;0.95=26;0.99=26");
AssertCollectStartStopEventsPresent(events, IntervalSecs, 3);
- AssertEndInstrumentReportingEventsPresent(events, c, oc, og, h);
}
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
@@ -646,6 +647,63 @@ public void EventSourceHandlesObservableCallbackException()
AssertCollectStartStopEventsPresent(events, IntervalSecs, 3);
}
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
+ [OuterLoop("Slow and has lots of console spew")]
+ public void EventSourceWorksWithSequentialListeners()
+ {
+ using Meter meter = new Meter("TestMeter16");
+ Counter c = meter.CreateCounter("counter1");
+ int counterState = 3;
+ ObservableCounter oc = meter.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; });
+ int gaugeState = 0;
+ ObservableGauge og = meter.CreateObservableGauge("observableGauge1", () => { gaugeState += 9; return gaugeState; });
+ Histogram h = meter.CreateHistogram("histogram1");
+
+ EventWrittenEventArgs[] events;
+ using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter16"))
+ {
+ listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+ c.Add(5);
+ h.Record(19);
+ listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+ c.Add(12);
+ h.Record(26);
+ listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+ events = listener.Events.ToArray();
+ }
+
+ AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h);
+ AssertInitialEnumerationCompleteEventPresent(events);
+ AssertCounterEventsPresent(events, meter.Name, c.Name, "", "", "5", "12");
+ AssertCounterEventsPresent(events, meter.Name, oc.Name, "", "", "", "7");
+ AssertGaugeEventsPresent(events, meter.Name, og.Name, "", "", "9", "18");
+ AssertHistogramEventsPresent(events, meter.Name, h.Name, "", "", "0.5=19;0.95=19;0.99=19", "0.5=26;0.95=26;0.99=26");
+ AssertCollectStartStopEventsPresent(events, IntervalSecs, 3);
+
+ // Now create a new listener and do everything a 2nd time. Because the listener above has been disposed the source should be
+ // free to accept a new connection.
+ events = null;
+ using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter16"))
+ {
+ listener.WaitForCollectionStop(s_waitForEventTimeout, 1);
+ c.Add(5);
+ h.Record(19);
+ listener.WaitForCollectionStop(s_waitForEventTimeout, 2);
+ c.Add(12);
+ h.Record(26);
+ listener.WaitForCollectionStop(s_waitForEventTimeout, 3);
+ events = listener.Events.ToArray();
+ }
+
+ AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h);
+ AssertInitialEnumerationCompleteEventPresent(events);
+ AssertCounterEventsPresent(events, meter.Name, c.Name, "", "", "5", "12");
+ AssertCounterEventsPresent(events, meter.Name, oc.Name, "", "", "", "7");
+ AssertGaugeEventsPresent(events, meter.Name, og.Name, "", "", "36", "45");
+ AssertHistogramEventsPresent(events, meter.Name, h.Name, "", "", "0.5=19;0.95=19;0.99=19", "0.5=26;0.95=26;0.99=26");
+ AssertCollectStartStopEventsPresent(events, IntervalSecs, 3);
+ }
+
private void AssertBeginInstrumentReportingEventsPresent(EventWrittenEventArgs[] events, params Instrument[] expectedInstruments)
{
var beginReportEvents = events.Where(e => e.EventName == "BeginInstrumentReporting").Select(e =>
@@ -961,10 +1019,20 @@ protected override void OnEventSourceCreated(EventSource eventSource)
}
}
+ public override void Dispose()
+ {
+ if (_source != null)
+ {
+ // workaround for https://github.com/dotnet/runtime/issues/56378
+ DisableEvents(_source);
+ }
+ base.Dispose();
+ }
+
protected override void OnEventWritten(EventWrittenEventArgs eventData)
{
string sessionId = eventData.Payload[0].ToString();
- if(sessionId != "" && sessionId != _sessionId)
+ if (eventData.EventName != "MultipleSessionsNotSupportedError" && sessionId != "" && sessionId != _sessionId)
{
return;
}
@@ -988,68 +1056,36 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData)
_autoResetEvent.Set();
}
- public void WaitForCollectionStop(TimeSpan timeout, int numStops)
- {
- DateTime startTime = DateTime.Now;
- DateTime stopTime = startTime + timeout;
- int initialStopCount = GetCountCollectionStops();
- while (true)
- {
- if (GetCountCollectionStops() >= numStops)
- {
- return;
- }
- TimeSpan remainingTime = stopTime - DateTime.Now;
- if (remainingTime.TotalMilliseconds < 0 || !_autoResetEvent.WaitOne(remainingTime))
- {
- int currentStopCount = GetCountCollectionStops();
- throw new TimeoutException("Timed out waiting for a StopCollection event. " +
- $"StartTime={startTime} stopTime={stopTime} initialStopCount={initialStopCount} currentStopCount={currentStopCount} targetStopCount={numStops}");
- }
- }
- }
+ public void WaitForCollectionStop(TimeSpan timeout, int numEvents) => WaitForEvent(timeout, numEvents, "CollectionStop");
+
+ public void WaitForEndInstrumentReporting(TimeSpan timeout, int numEvents) => WaitForEvent(timeout, numEvents, "EndInstrumentReporting");
+
+ public void WaitForEnumerationComplete(TimeSpan timeout) => WaitForEvent(timeout, 1, "InitialInstrumentEnumerationComplete");
- public void WaitForEndInstrumentReporting(TimeSpan timeout, int numEvents)
+ public void WaitForMultipleSessionsNotSupportedError(TimeSpan timeout) => WaitForEvent(timeout, 1, "MultipleSessionsNotSupportedError");
+
+ void WaitForEvent(TimeSpan timeout, int numEvents, string eventName)
{
DateTime startTime = DateTime.Now;
DateTime stopTime = startTime + timeout;
- int initialEventCount = GetCountEndInstrumentReporting();
+ int initialEventCount = GetCountEvents(eventName);
while (true)
{
- if (GetCountEndInstrumentReporting() >= numEvents)
+ if (GetCountEvents(eventName) >= numEvents)
{
return;
}
TimeSpan remainingTime = stopTime - DateTime.Now;
if (remainingTime.TotalMilliseconds < 0 || !_autoResetEvent.WaitOne(remainingTime))
{
- int currentEventCount = GetCountEndInstrumentReporting();
- throw new TimeoutException("Timed out waiting for a EndInstrumentReporting event. " +
+ int currentEventCount = GetCountEvents(eventName);
+ throw new TimeoutException($"Timed out waiting for a {eventName} event. " +
$"StartTime={startTime} stopTime={stopTime} initialEventCount={initialEventCount} currentEventCount={currentEventCount} targetEventCount={numEvents}");
}
}
}
- public void WaitForEnumerationComplete(TimeSpan timeout)
- {
- DateTime startTime = DateTime.Now;
- DateTime stopTime = startTime + timeout;
- int initialEventCount = GetCountEnumerationComplete();
- while (true)
- {
- if (GetCountEnumerationComplete() >= 1)
- {
- return;
- }
- TimeSpan remainingTime = stopTime - DateTime.Now;
- if (remainingTime.TotalMilliseconds < 0 || !_autoResetEvent.WaitOne(remainingTime))
- {
- int currentEventCount = GetCountEnumerationComplete();
- throw new TimeoutException("Timed out waiting for a EndInstrumentReporting event. " +
- $"StartTime={startTime} stopTime={stopTime} initialEventCount={initialEventCount} currentEventCount={currentEventCount}");
- }
- }
- }
+
private void AssertOnError()
{
@@ -1064,29 +1100,12 @@ private void AssertOnError()
}
}
- private int GetCountCollectionStops()
+ private int GetCountEvents(string eventName)
{
lock (this)
{
AssertOnError();
- return Events.Where(e => e.EventName == "CollectionStop").Count();
- }
- }
-
- private int GetCountEndInstrumentReporting()
- {
- lock (this)
- {
- AssertOnError();
- return Events.Where(e => e.EventName == "EndInstrumentReporting").Count();
- }
- }
-
- private int GetCountEnumerationComplete()
- {
- lock (this)
- {
- return Events.Where(e => e.EventName == "InitialInstrumentEnumerationComplete").Count();
+ return Events.Where(e => e.EventName == eventName).Count();
}
}
}
diff --git a/src/libraries/System.Diagnostics.EventLog/ref/System.Diagnostics.EventLog.csproj b/src/libraries/System.Diagnostics.EventLog/ref/System.Diagnostics.EventLog.csproj
index 2631550443e3a7..ca4c77c50b5d52 100644
--- a/src/libraries/System.Diagnostics.EventLog/ref/System.Diagnostics.EventLog.csproj
+++ b/src/libraries/System.Diagnostics.EventLog/ref/System.Diagnostics.EventLog.csproj
@@ -10,7 +10,7 @@
-
+
@@ -19,4 +19,4 @@
-
\ No newline at end of file
+
diff --git a/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj b/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj
index abc273f110fa35..1bf0c43270e42e 100644
--- a/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj
+++ b/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj
@@ -12,7 +12,7 @@
true
-
+
diff --git a/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs b/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs
index 223972940e800c..38062773cb3671 100644
--- a/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs
+++ b/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs
@@ -30,10 +30,13 @@ private static bool IsAdmin_IsNotNano_RemoteExecutorIsSupported
=> PlatformDetection.IsWindowsAndElevated && PlatformDetection.IsNotWindowsNanoServer && RemoteExecutor.IsSupported;
[Fact]
- [ActiveIssue("https://github.com/dotnet/runtime/issues/51386", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)]
public void TestEnvironmentProperty()
{
- Assert.NotEqual(0, new Process().StartInfo.Environment.Count);
+ // Whole list of environment variables can no longer be accessed on non-OSX apple platforms
+ if (!PlatformDetection.IsiOS && !PlatformDetection.IstvOS && !PlatformDetection.IsMacCatalyst)
+ {
+ Assert.NotEqual(0, new Process().StartInfo.Environment.Count);
+ }
ProcessStartInfo psi = new ProcessStartInfo();
@@ -41,7 +44,11 @@ public void TestEnvironmentProperty()
// with current environmental variables.
IDictionary environment = psi.Environment;
- Assert.NotEqual(0, environment.Count);
+ // Whole list of environment variables can no longer be accessed on non-OSX apple platforms
+ if (!PlatformDetection.IsiOS && !PlatformDetection.IstvOS && !PlatformDetection.IsMacCatalyst)
+ {
+ Assert.NotEqual(0, environment.Count);
+ }
int countItems = environment.Count;
@@ -772,7 +779,6 @@ public void Verbs_GetUnix_ReturnsEmpty()
[PlatformSpecific(TestPlatforms.AnyUnix)] // Test case is specific to Unix
[Fact]
- [ActiveIssue("https://github.com/dotnet/runtime/issues/51386", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)]
public void TestEnvironmentVariablesPropertyUnix()
{
ProcessStartInfo psi = new ProcessStartInfo();
@@ -782,7 +788,11 @@ public void TestEnvironmentVariablesPropertyUnix()
StringDictionary environmentVariables = psi.EnvironmentVariables;
- Assert.NotEqual(0, environmentVariables.Count);
+ // Whole list of environment variables can no longer be accessed on non-OSX apple platforms
+ if (!PlatformDetection.IsiOS && !PlatformDetection.IstvOS && !PlatformDetection.IsMacCatalyst)
+ {
+ Assert.NotEqual(0, environmentVariables.Count);
+ }
int CountItems = environmentVariables.Count;
diff --git a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWriteEventToListener.cs b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWriteEventToListener.cs
index a35237468cf297..d7c7046ab693ed 100644
--- a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWriteEventToListener.cs
+++ b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWriteEventToListener.cs
@@ -448,5 +448,49 @@ public void Test_EventSourceCreatedEvents_AfterListener()
TestUtilities.CheckNoEventSourcesRunning("Stop");
}
+
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void Test_EventListenerThrows_ExceptionIsNotRethrownToCaller(bool setThrowOnEventWriteErrorsFlag)
+ {
+ TestUtilities.CheckNoEventSourcesRunning("Start");
+
+ using (var log = new EventSourceTest(throwOnEventWriteErrors: setThrowOnEventWriteErrorsFlag))
+ {
+ using (var listener = new EventListenerListener())
+ {
+ listener.EventSourceSynchronousEnable(log);
+
+ var thrownException = new Exception("Oops");
+ string outOfBandMessage = null;
+
+ listener.EventWritten += (_, e) =>
+ {
+ if (e.EventId == 0)
+ {
+ outOfBandMessage = e.Message;
+ }
+
+ throw thrownException;
+ };
+
+ try
+ {
+ log.Event0();
+ Assert.False(setThrowOnEventWriteErrorsFlag);
+ }
+ catch (EventSourceException ex)
+ {
+ Assert.True(setThrowOnEventWriteErrorsFlag);
+ Assert.Same(thrownException, ex.InnerException);
+ }
+
+ Assert.Contains(thrownException.Message, outOfBandMessage);
+ }
+ }
+
+ TestUtilities.CheckNoEventSourcesRunning("Stop");
+ }
}
}
diff --git a/src/libraries/System.Diagnostics.Tracing/tests/CustomEventSources/EventSourceTest.cs b/src/libraries/System.Diagnostics.Tracing/tests/CustomEventSources/EventSourceTest.cs
index 5cbd28b2a13328..7a6734e33ca3de 100644
--- a/src/libraries/System.Diagnostics.Tracing/tests/CustomEventSources/EventSourceTest.cs
+++ b/src/libraries/System.Diagnostics.Tracing/tests/CustomEventSources/EventSourceTest.cs
@@ -26,8 +26,9 @@ namespace SdtEventSources
[EventSource(Guid = "69e2aa3e-083b-5014-cad4-3e511a0b94cf", Name = "EventSourceTest")]
public sealed class EventSourceTest : EventSource
{
- public EventSourceTest(bool useSelfDescribingEvents = false)
- : base(true)
+ public EventSourceTest(bool useSelfDescribingEvents = false, bool throwOnEventWriteErrors = false)
+ : base((useSelfDescribingEvents ? EventSourceSettings.EtwSelfDescribingEventFormat : EventSourceSettings.EtwManifestEventFormat)
+ | (throwOnEventWriteErrors ? EventSourceSettings.ThrowOnEventWriteErrors : 0))
{ }
protected override void OnEventCommand(EventCommandEventArgs command)
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Icon.Windows.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Icon.Windows.cs
index 4acd6376e4c437..73e65b379fe573 100644
--- a/src/libraries/System.Drawing.Common/src/System/Drawing/Icon.Windows.cs
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Icon.Windows.cs
@@ -188,14 +188,17 @@ void ISerializable.GetObjectData(SerializationInfo si, StreamingContext context)
filePath.CopyTo(0, buffer, 0, filePath.Length);
buffer[filePath.Length] = '\0';
+ IntPtr hIcon;
fixed (char* b = buffer)
{
- IntPtr hIcon = Interop.Shell32.ExtractAssociatedIcon(NativeMethods.NullHandleRef, b, ref index);
- ArrayPool.Shared.Return(buffer);
- if (hIcon != IntPtr.Zero)
- {
- return new Icon(hIcon, true);
- }
+ hIcon = Interop.Shell32.ExtractAssociatedIcon(NativeMethods.NullHandleRef, b, ref index);
+ }
+
+ ArrayPool.Shared.Return(buffer);
+
+ if (hIcon != IntPtr.Zero)
+ {
+ return new Icon(hIcon, true);
}
return null;
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/ImageAnimator.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/ImageAnimator.cs
index 49ce7c0b598584..fdc6d751440a3d 100644
--- a/src/libraries/System.Drawing.Common/src/System/Drawing/ImageAnimator.cs
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/ImageAnimator.cs
@@ -35,6 +35,12 @@ namespace System.Drawing
///
public sealed partial class ImageAnimator
{
+ // We use a timer to apply an animation tick speeds of something a bit shorter than 50ms
+ // such that if the requested frame rate is about 20 frames per second, we will rarely skip
+ // a frame entirely. Sometimes we'll show a few more frames if available, but we will never
+ // show more than 25 frames a second and that's OK.
+ internal const int AnimationDelayMS = 40;
+
///
/// A list of images to be animated.
///
@@ -387,7 +393,7 @@ private static void AnimateImages()
while (true)
{
- Thread.Sleep(40);
+ Thread.Sleep(AnimationDelayMS);
// Because Thread.Sleep is not accurate, capture how much time has actually elapsed during the animation
long timeElapsed = stopwatch.ElapsedMilliseconds;
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/ImageInfo.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/ImageInfo.cs
index 24b041395580a0..a5eed455409732 100644
--- a/src/libraries/System.Drawing.Common/src/System/Drawing/ImageInfo.cs
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/ImageInfo.cs
@@ -29,6 +29,7 @@ private sealed class ImageInfo
private readonly bool _animated;
private EventHandler? _onFrameChangedHandler;
private readonly long[]? _frameEndTimes;
+ private long _totalAnimationTime;
private long _frameTimer;
public ImageInfo(Image image)
@@ -66,7 +67,21 @@ public ImageInfo(Image image)
}
// Frame delays are stored in 1/100ths of a second; convert to milliseconds while accumulating
- _frameEndTimes[f] = (lastEndTime += (BitConverter.ToInt32(values, i) * 10));
+ // Per spec, a frame delay can be 0 which is treated as a single animation tick
+ int delay = BitConverter.ToInt32(values, i) * 10;
+ lastEndTime += delay > 0 ? delay : ImageAnimator.AnimationDelayMS;
+
+ // Guard against overflows
+ if (lastEndTime < _totalAnimationTime)
+ {
+ lastEndTime = _totalAnimationTime;
+ }
+ else
+ {
+ _totalAnimationTime = lastEndTime;
+ }
+
+ _frameEndTimes[f] = lastEndTime;
}
}
@@ -95,24 +110,12 @@ public ImageInfo(Image image)
///
/// Whether the image supports animation.
///
- public bool Animated
- {
- get
- {
- return _animated;
- }
- }
+ public bool Animated => _animated;
///
/// The current frame has changed but the image has not yet been updated.
///
- public bool FrameDirty
- {
- get
- {
- return _frameDirty;
- }
- }
+ public bool FrameDirty => _frameDirty;
public EventHandler? FrameChangedHandler
{
@@ -127,15 +130,15 @@ public EventHandler? FrameChangedHandler
}
///
- /// The total animation time of the image, in milliseconds.
+ /// The total animation time of the image in milliseconds, or 0 if not animated.
///
- private long TotalAnimationTime => Animated ? _frameEndTimes![_frameCount - 1] : 0;
+ private long TotalAnimationTime => Animated ? _totalAnimationTime : 0;
///
/// Whether animation should progress, respecting the image's animation support
/// and if there are animation frames or loops remaining.
///
- private bool ShouldAnimate => Animated ? (_loopCount == 0 || _loop <= _loopCount) : false;
+ private bool ShouldAnimate => TotalAnimationTime > 0 ? (_loopCount == 0 || _loop <= _loopCount) : false;
///
/// Advance the animation by the specified number of milliseconds. If the advancement
@@ -195,13 +198,7 @@ public void AdvanceAnimationBy(long milliseconds)
///
/// The image this object wraps.
///
- internal Image Image
- {
- get
- {
- return _image;
- }
- }
+ internal Image Image => _image;
///
/// Selects the current frame as the active frame in the image.
diff --git a/src/libraries/System.Drawing.Common/tests/System/Drawing/ImageAnimator.ManualTests.cs b/src/libraries/System.Drawing.Common/tests/System/Drawing/ImageAnimator.ManualTests.cs
index 63cb4e3f9329ed..84d9da6d2c1a38 100644
--- a/src/libraries/System.Drawing.Common/tests/System/Drawing/ImageAnimator.ManualTests.cs
+++ b/src/libraries/System.Drawing.Common/tests/System/Drawing/ImageAnimator.ManualTests.cs
@@ -43,6 +43,7 @@ public void AnimateAndCaptureFrames()
"animated-timer-10fps-repeat-infinite.gif",
"animated-timer-100fps-repeat-2.gif",
"animated-timer-100fps-repeat-infinite.gif",
+ "animated-timer-0-delay-all-frames.gif",
};
Dictionary handlers = new();
diff --git a/src/libraries/System.Globalization/tests/Invariant/Invariant.Tests.csproj b/src/libraries/System.Globalization/tests/Invariant/Invariant.Tests.csproj
index 6979cd759d0ec1..b142e220e9d433 100644
--- a/src/libraries/System.Globalization/tests/Invariant/Invariant.Tests.csproj
+++ b/src/libraries/System.Globalization/tests/Invariant/Invariant.Tests.csproj
@@ -4,6 +4,7 @@
true
true
true
+ false
diff --git a/src/libraries/System.Globalization/tests/Invariant/runtimeconfig.template.json b/src/libraries/System.Globalization/tests/Invariant/runtimeconfig.template.json
deleted file mode 100644
index 076d8498455740..00000000000000
--- a/src/libraries/System.Globalization/tests/Invariant/runtimeconfig.template.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "configProperties": {
- "System.Globalization.Invariant": true,
- "System.Globalization.PredefinedCulturesOnly": false
- }
-}
\ No newline at end of file
diff --git a/src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFile.Extract.cs b/src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFile.Extract.cs
index 50e1717fc08a86..eb908ed66f0179 100644
--- a/src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFile.Extract.cs
+++ b/src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFile.Extract.cs
@@ -28,8 +28,7 @@ public static partial class ZipFile
/// and file names must be less than 260 characters.
/// The path specified by sourceArchive or destinationDirectoryName is invalid,
/// (for example, it is on an unmapped drive).
- /// The directory specified by destinationDirectoryName already exists.
- /// -or- An I/O error has occurred. -or- An archive entry?s name is zero-length, contains only whitespace, or contains one or
+ /// An I/O error has occurred. -or- An archive entry's name is zero-length, contains only whitespace, or contains one or
/// more invalid characters as defined by InvalidPathChars. -or- Extracting an archive entry would result in a file destination that is outside the destination directory (for example, because of parent directory accessors). -or- An archive entry has the same name as an already extracted entry from the same archive.
/// The caller does not have the required permission.
/// sourceArchive or destinationDirectoryName is in an invalid format.
@@ -61,8 +60,7 @@ public static void ExtractToDirectory(string sourceArchiveFileName, string desti
/// and file names must be less than 260 characters.
/// The path specified by sourceArchive or destinationDirectoryName is invalid,
/// (for example, it is on an unmapped drive).
- /// The directory specified by destinationDirectoryName already exists.
- /// -or- An I/O error has occurred. -or- An archive entry?s name is zero-length, contains only whitespace, or contains one or
+ /// An I/O error has occurred. -or- An archive entry's name is zero-length, contains only whitespace, or contains one or
/// more invalid characters as defined by InvalidPathChars. -or- Extracting an archive entry would result in a file destination that is outside the destination directory (for example, because of parent directory accessors). -or- An archive entry has the same name as an already extracted entry from the same archive.
/// The caller does not have the required permission.
/// sourceArchive or destinationDirectoryName is in an invalid format.
@@ -95,8 +93,7 @@ public static void ExtractToDirectory(string sourceArchiveFileName, string desti
/// and file names must be less than 260 characters.
/// The path specified by sourceArchive or destinationDirectoryName is invalid,
/// (for example, it is on an unmapped drive).
- /// The directory specified by destinationDirectoryName already exists.
- /// -or- An I/O error has occurred. -or- An archive entry?s name is zero-length, contains only whitespace, or contains one or
+ /// An I/O error has occurred. -or- An archive entry's name is zero-length, contains only whitespace, or contains one or
/// more invalid characters as defined by InvalidPathChars. -or- Extracting an archive entry would result in a file destination that is outside the destination directory (for example, because of parent directory accessors). -or- An archive entry has the same name as an already extracted entry from the same archive.
/// The caller does not have the required permission.
/// sourceArchive or destinationDirectoryName is in an invalid format.
@@ -150,8 +147,7 @@ public static void ExtractToDirectory(string sourceArchiveFileName, string desti
/// and file names must be less than 260 characters.
/// The path specified by sourceArchive or destinationDirectoryName is invalid,
/// (for example, it is on an unmapped drive).
- /// The directory specified by destinationDirectoryName already exists.
- /// -or- An I/O error has occurred. -or- An archive entry?s name is zero-length, contains only whitespace, or contains one or
+ /// An I/O error has occurred. -or- An archive entry's name is zero-length, contains only whitespace, or contains one or
/// more invalid characters as defined by InvalidPathChars. -or- Extracting an archive entry would result in a file destination that is outside the destination directory (for example, because of parent directory accessors). -or- An archive entry has the same name as an already extracted entry from the same archive.
/// The caller does not have the required permission.
/// sourceArchive or destinationDirectoryName is in an invalid format.
diff --git a/src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFileExtensions.ZipArchiveEntry.Extract.cs b/src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFileExtensions.ZipArchiveEntry.Extract.cs
index a74aca915faaf6..5d800c1f62ca71 100644
--- a/src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFileExtensions.ZipArchiveEntry.Extract.cs
+++ b/src/libraries/System.IO.Compression.ZipFile/src/System/IO/Compression/ZipFileExtensions.ZipArchiveEntry.Extract.cs
@@ -19,8 +19,7 @@ public static partial class ZipFileExtensions
/// For example, on Windows-based platforms, paths must be less than 248 characters, and file names must be less than 260 characters.
/// The path specified in destinationFileName is invalid (for example, it is on
/// an unmapped drive).
- /// destinationFileName already exists.
- /// -or- An I/O error has occurred. -or- The entry is currently open for writing.
+ /// An I/O error has occurred. -or- The entry is currently open for writing.
/// -or- The entry has been deleted from the archive.
/// destinationFileName is in an invalid format
/// -or- The ZipArchive that this entry belongs to was opened in a write-only mode.
@@ -48,8 +47,7 @@ public static void ExtractToFile(this ZipArchiveEntry source, string destination
/// For example, on Windows-based platforms, paths must be less than 248 characters, and file names must be less than 260 characters.
/// The path specified in destinationFileName is invalid
/// (for example, it is on an unmapped drive).
- /// destinationFileName exists and overwrite is false.
- /// -or- An I/O error has occurred.
+ /// An I/O error has occurred.
/// -or- The entry is currently open for writing.
/// -or- The entry has been deleted from the archive.
/// destinationFileName is in an invalid format
@@ -81,7 +79,14 @@ public static void ExtractToFile(this ZipArchiveEntry source, string destination
ExtractExternalAttributes(fs, source);
}
- File.SetLastWriteTime(destinationFileName, source.LastWriteTime.DateTime);
+ try
+ {
+ File.SetLastWriteTime(destinationFileName, source.LastWriteTime.DateTime);
+ }
+ catch (UnauthorizedAccessException)
+ {
+ // some OSes like Android (#35374) might not support setting the last write time, the extraction should not fail because of that
+ }
}
static partial void ExtractExternalAttributes(FileStream fs, ZipArchiveEntry entry);
diff --git a/src/libraries/System.IO.FileSystem/tests/RandomAccess/Read.cs b/src/libraries/System.IO.FileSystem/tests/RandomAccess/Read.cs
index 9559e7cebc12f5..509914ecd4b0d0 100644
--- a/src/libraries/System.IO.FileSystem/tests/RandomAccess/Read.cs
+++ b/src/libraries/System.IO.FileSystem/tests/RandomAccess/Read.cs
@@ -51,6 +51,20 @@ public void CanUseStackAllocatedMemory(FileOptions options)
}
}
+ [Theory]
+ [MemberData(nameof(GetSyncAsyncOptions))]
+ public void ReadFromBeyondEndOfFileReturnsZero(FileOptions options)
+ {
+ string filePath = GetTestFilePath();
+ File.WriteAllBytes(filePath, new byte[100]);
+
+ using (SafeFileHandle handle = File.OpenHandle(filePath, FileMode.Open, options: options))
+ {
+ long eof = RandomAccess.GetLength(handle);
+ Assert.Equal(0, RandomAccess.Read(handle, new byte[1], fileOffset: eof + 1));
+ }
+ }
+
[Theory]
[MemberData(nameof(GetSyncAsyncOptions))]
public void ReadsBytesFromGivenFileAtGivenOffset(FileOptions options)
diff --git a/src/libraries/System.IO.FileSystem/tests/RandomAccess/ReadAsync.cs b/src/libraries/System.IO.FileSystem/tests/RandomAccess/ReadAsync.cs
index f23cd8f92f6ac9..fe8f8b1111f2db 100644
--- a/src/libraries/System.IO.FileSystem/tests/RandomAccess/ReadAsync.cs
+++ b/src/libraries/System.IO.FileSystem/tests/RandomAccess/ReadAsync.cs
@@ -56,6 +56,20 @@ public async Task ReadToAnEmptyBufferReturnsZeroAsync(FileOptions options)
}
}
+ [Theory]
+ [MemberData(nameof(GetSyncAsyncOptions))]
+ public async Task ReadFromBeyondEndOfFileReturnsZeroAsync(FileOptions options)
+ {
+ string filePath = GetTestFilePath();
+ File.WriteAllBytes(filePath, new byte[100]);
+
+ using (SafeFileHandle handle = File.OpenHandle(filePath, FileMode.Open, options: options))
+ {
+ long eof = RandomAccess.GetLength(handle);
+ Assert.Equal(0, await RandomAccess.ReadAsync(handle, new byte[1], fileOffset: eof + 1));
+ }
+ }
+
[Theory]
[MemberData(nameof(GetSyncAsyncOptions))]
public async Task HappyPath(FileOptions options)
diff --git a/src/libraries/System.IO.FileSystem/tests/RandomAccess/ReadScatter.cs b/src/libraries/System.IO.FileSystem/tests/RandomAccess/ReadScatter.cs
index 7f51ea6e8478e2..0aa60632696188 100644
--- a/src/libraries/System.IO.FileSystem/tests/RandomAccess/ReadScatter.cs
+++ b/src/libraries/System.IO.FileSystem/tests/RandomAccess/ReadScatter.cs
@@ -46,6 +46,20 @@ public void ReadToAnEmptyBufferReturnsZero(FileOptions options)
}
}
+ [Theory]
+ [MemberData(nameof(GetSyncAsyncOptions))]
+ public void ReadFromBeyondEndOfFileReturnsZero(FileOptions options)
+ {
+ string filePath = GetTestFilePath();
+ File.WriteAllBytes(filePath, new byte[100]);
+
+ using (SafeFileHandle handle = File.OpenHandle(filePath, FileMode.Open, options: options))
+ {
+ long eof = RandomAccess.GetLength(handle);
+ Assert.Equal(0, RandomAccess.Read(handle, new Memory[] { new byte[1] }, fileOffset: eof + 1));
+ }
+ }
+
[Theory]
[MemberData(nameof(GetSyncAsyncOptions))]
public void ReadsBytesFromGivenFileAtGivenOffset(FileOptions options)
diff --git a/src/libraries/System.IO.FileSystem/tests/RandomAccess/ReadScatterAsync.cs b/src/libraries/System.IO.FileSystem/tests/RandomAccess/ReadScatterAsync.cs
index 250d9c316777da..0a9be6c433678e 100644
--- a/src/libraries/System.IO.FileSystem/tests/RandomAccess/ReadScatterAsync.cs
+++ b/src/libraries/System.IO.FileSystem/tests/RandomAccess/ReadScatterAsync.cs
@@ -66,6 +66,20 @@ public async Task ReadToAnEmptyBufferReturnsZeroAsync(FileOptions options)
}
}
+ [Theory]
+ [MemberData(nameof(GetSyncAsyncOptions))]
+ public async Task ReadFromBeyondEndOfFileReturnsZeroAsync(FileOptions options)
+ {
+ string filePath = GetTestFilePath();
+ File.WriteAllBytes(filePath, new byte[100]);
+
+ using (SafeFileHandle handle = File.OpenHandle(filePath, FileMode.Open, options: options))
+ {
+ long eof = RandomAccess.GetLength(handle);
+ Assert.Equal(0, await RandomAccess.ReadAsync(handle, new Memory[] { new byte[1] }, fileOffset: eof + 1));
+ }
+ }
+
[Theory]
[MemberData(nameof(GetSyncAsyncOptions))]
public async Task ReadsBytesFromGivenFileAtGivenOffsetAsync(FileOptions options)
diff --git a/src/libraries/System.IO.FileSystem/tests/RandomAccess/Write.cs b/src/libraries/System.IO.FileSystem/tests/RandomAccess/Write.cs
index 8a687dc6012dec..d78bd0c686d1d6 100644
--- a/src/libraries/System.IO.FileSystem/tests/RandomAccess/Write.cs
+++ b/src/libraries/System.IO.FileSystem/tests/RandomAccess/Write.cs
@@ -50,6 +50,22 @@ public void CanUseStackAllocatedMemory(FileOptions options)
Assert.Equal(stackAllocated.ToArray(), File.ReadAllBytes(filePath));
}
+ [Theory]
+ [MemberData(nameof(GetSyncAsyncOptions))]
+ public void WriteBeyondEndOfFileExtendsTheFile(FileOptions options)
+ {
+ string filePath = GetTestFilePath();
+
+ using (SafeFileHandle handle = File.OpenHandle(filePath, FileMode.CreateNew, FileAccess.Write, options: options))
+ {
+ Assert.Equal(0, RandomAccess.GetLength(handle));
+ RandomAccess.Write(handle, new byte[1] { 1 }, fileOffset: 1);
+ Assert.Equal(2, RandomAccess.GetLength(handle));
+ }
+
+ Assert.Equal(new byte[] { 0, 1 }, File.ReadAllBytes(filePath));
+ }
+
[Theory]
[MemberData(nameof(GetSyncAsyncOptions))]
public void WritesBytesFromGivenBufferToGivenFileAtGivenOffset(FileOptions options)
diff --git a/src/libraries/System.IO.FileSystem/tests/RandomAccess/WriteAsync.cs b/src/libraries/System.IO.FileSystem/tests/RandomAccess/WriteAsync.cs
index 37003283982060..b816bc8541592e 100644
--- a/src/libraries/System.IO.FileSystem/tests/RandomAccess/WriteAsync.cs
+++ b/src/libraries/System.IO.FileSystem/tests/RandomAccess/WriteAsync.cs
@@ -52,6 +52,22 @@ public async Task WriteUsingEmptyBufferReturnsAsync(FileOptions options)
}
}
+ [Theory]
+ [MemberData(nameof(GetSyncAsyncOptions))]
+ public async Task WriteBeyondEndOfFileExtendsTheFileAsync(FileOptions options)
+ {
+ string filePath = GetTestFilePath();
+
+ using (SafeFileHandle handle = File.OpenHandle(filePath, FileMode.CreateNew, FileAccess.Write, options: options))
+ {
+ Assert.Equal(0, RandomAccess.GetLength(handle));
+ await RandomAccess.WriteAsync(handle, new byte[1] { 1 }, fileOffset: 1);
+ Assert.Equal(2, RandomAccess.GetLength(handle));
+ }
+
+ Assert.Equal(new byte[] { 0, 1 }, await File.ReadAllBytesAsync(filePath));
+ }
+
[Theory]
[MemberData(nameof(GetSyncAsyncOptions))]
public async Task WritesBytesFromGivenBufferToGivenFileAtGivenOffsetAsync(FileOptions options)
diff --git a/src/libraries/System.IO.FileSystem/tests/RandomAccess/WriteGather.cs b/src/libraries/System.IO.FileSystem/tests/RandomAccess/WriteGather.cs
index 0f28b7c9c68b65..2edc72eb867c52 100644
--- a/src/libraries/System.IO.FileSystem/tests/RandomAccess/WriteGather.cs
+++ b/src/libraries/System.IO.FileSystem/tests/RandomAccess/WriteGather.cs
@@ -47,6 +47,22 @@ public void WriteUsingEmptyBufferReturns(FileOptions options)
}
}
+ [Theory]
+ [MemberData(nameof(GetSyncAsyncOptions))]
+ public void WriteBeyondEndOfFileExtendsTheFile(FileOptions options)
+ {
+ string filePath = GetTestFilePath();
+
+ using (SafeFileHandle handle = File.OpenHandle(filePath, FileMode.CreateNew, FileAccess.Write, options: options))
+ {
+ Assert.Equal(0, RandomAccess.GetLength(handle));
+ RandomAccess.Write(handle, new ReadOnlyMemory[] { new byte[1] { 1 } }, fileOffset: 1);
+ Assert.Equal(2, RandomAccess.GetLength(handle));
+ }
+
+ Assert.Equal(new byte[] { 0, 1 }, File.ReadAllBytes(filePath));
+ }
+
[Theory]
[MemberData(nameof(GetSyncAsyncOptions))]
public void WritesBytesFromGivenBuffersToGivenFileAtGivenOffset(FileOptions options)
diff --git a/src/libraries/System.IO.FileSystem/tests/RandomAccess/WriteGatherAsync.cs b/src/libraries/System.IO.FileSystem/tests/RandomAccess/WriteGatherAsync.cs
index f89cfd3b4fc623..bf995a318fd9a4 100644
--- a/src/libraries/System.IO.FileSystem/tests/RandomAccess/WriteGatherAsync.cs
+++ b/src/libraries/System.IO.FileSystem/tests/RandomAccess/WriteGatherAsync.cs
@@ -64,6 +64,22 @@ public async Task WriteUsingEmptyBufferReturnsAsync(FileOptions options)
}
}
+ [Theory]
+ [MemberData(nameof(GetSyncAsyncOptions))]
+ public async Task WriteBeyondEndOfFileExtendsTheFileAsync(FileOptions options)
+ {
+ string filePath = GetTestFilePath();
+
+ using (SafeFileHandle handle = File.OpenHandle(filePath, FileMode.CreateNew, FileAccess.Write, options: options))
+ {
+ Assert.Equal(0, RandomAccess.GetLength(handle));
+ await RandomAccess.WriteAsync(handle, new ReadOnlyMemory[] { new byte[1] { 1 } }, fileOffset: 1);
+ Assert.Equal(2, RandomAccess.GetLength(handle));
+ }
+
+ Assert.Equal(new byte[] { 0, 1 }, await File.ReadAllBytesAsync(filePath));
+ }
+
[Theory]
[MemberData(nameof(GetSyncAsyncOptions))]
public async Task WritesBytesFromGivenBufferToGivenFileAtGivenOffsetAsync(FileOptions options)
diff --git a/src/libraries/System.IO.Packaging/src/System.IO.Packaging.csproj b/src/libraries/System.IO.Packaging/src/System.IO.Packaging.csproj
index abb185806210a8..c9a5e30a03c67b 100644
--- a/src/libraries/System.IO.Packaging/src/System.IO.Packaging.csproj
+++ b/src/libraries/System.IO.Packaging/src/System.IO.Packaging.csproj
@@ -48,6 +48,7 @@
+
diff --git a/src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackageXmlStringTable.cs b/src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackageXmlStringTable.cs
index cf76091a95d16f..2b1ca4d24560b4 100644
--- a/src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackageXmlStringTable.cs
+++ b/src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackageXmlStringTable.cs
@@ -12,63 +12,63 @@ namespace System.IO.Packaging
internal static class PackageXmlStringTable
{
// Fields
- private static readonly NameTable s_nameTable = new NameTable();
+ private static readonly ThreadSafeNameTable s_nameTable = new ThreadSafeNameTable();
private static readonly XmlStringTableStruct[] s_xmlstringtable = new XmlStringTableStruct[0x1b];
// Methods
static PackageXmlStringTable()
{
- object nameString = s_nameTable.Add("http://www.w3.org/2001/XMLSchema-instance");
+ object nameString = s_nameTable.AddNoLock("http://www.w3.org/2001/XMLSchema-instance");
s_xmlstringtable[1] = new XmlStringTableStruct(nameString, PackageXmlEnum.NotDefined, null);
- nameString = s_nameTable.Add("xsi");
+ nameString = s_nameTable.AddNoLock("xsi");
s_xmlstringtable[2] = new XmlStringTableStruct(nameString, PackageXmlEnum.NotDefined, null);
- nameString = s_nameTable.Add("xmlns");
+ nameString = s_nameTable.AddNoLock("xmlns");
s_xmlstringtable[3] = new XmlStringTableStruct(nameString, PackageXmlEnum.NotDefined, null);
- nameString = s_nameTable.Add("http://schemas.openxmlformats.org/package/2006/metadata/core-properties");
+ nameString = s_nameTable.AddNoLock("http://schemas.openxmlformats.org/package/2006/metadata/core-properties");
s_xmlstringtable[4] = new XmlStringTableStruct(nameString, PackageXmlEnum.NotDefined, null);
- nameString = s_nameTable.Add("http://purl.org/dc/elements/1.1/");
+ nameString = s_nameTable.AddNoLock("http://purl.org/dc/elements/1.1/");
s_xmlstringtable[5] = new XmlStringTableStruct(nameString, PackageXmlEnum.NotDefined, null);
- nameString = s_nameTable.Add("http://purl.org/dc/terms/");
+ nameString = s_nameTable.AddNoLock("http://purl.org/dc/terms/");
s_xmlstringtable[6] = new XmlStringTableStruct(nameString, PackageXmlEnum.NotDefined, null);
- nameString = s_nameTable.Add("dc");
+ nameString = s_nameTable.AddNoLock("dc");
s_xmlstringtable[7] = new XmlStringTableStruct(nameString, PackageXmlEnum.NotDefined, null);
- nameString = s_nameTable.Add("dcterms");
+ nameString = s_nameTable.AddNoLock("dcterms");
s_xmlstringtable[8] = new XmlStringTableStruct(nameString, PackageXmlEnum.NotDefined, null);
- nameString = s_nameTable.Add("coreProperties");
+ nameString = s_nameTable.AddNoLock("coreProperties");
s_xmlstringtable[9] = new XmlStringTableStruct(nameString, PackageXmlEnum.PackageCorePropertiesNamespace, "NotSpecified");
- nameString = s_nameTable.Add("type");
+ nameString = s_nameTable.AddNoLock("type");
s_xmlstringtable[10] = new XmlStringTableStruct(nameString, PackageXmlEnum.NotDefined, "NotSpecified");
- nameString = s_nameTable.Add("creator");
+ nameString = s_nameTable.AddNoLock("creator");
s_xmlstringtable[11] = new XmlStringTableStruct(nameString, PackageXmlEnum.DublinCorePropertiesNamespace, "String");
- nameString = s_nameTable.Add("identifier");
+ nameString = s_nameTable.AddNoLock("identifier");
s_xmlstringtable[12] = new XmlStringTableStruct(nameString, PackageXmlEnum.DublinCorePropertiesNamespace, "String");
- nameString = s_nameTable.Add("title");
+ nameString = s_nameTable.AddNoLock("title");
s_xmlstringtable[13] = new XmlStringTableStruct(nameString, PackageXmlEnum.DublinCorePropertiesNamespace, "String");
- nameString = s_nameTable.Add("subject");
+ nameString = s_nameTable.AddNoLock("subject");
s_xmlstringtable[14] = new XmlStringTableStruct(nameString, PackageXmlEnum.DublinCorePropertiesNamespace, "String");
- nameString = s_nameTable.Add("description");
+ nameString = s_nameTable.AddNoLock("description");
s_xmlstringtable[15] = new XmlStringTableStruct(nameString, PackageXmlEnum.DublinCorePropertiesNamespace, "String");
- nameString = s_nameTable.Add("language");
+ nameString = s_nameTable.AddNoLock("language");
s_xmlstringtable[0x10] = new XmlStringTableStruct(nameString, PackageXmlEnum.DublinCorePropertiesNamespace, "String");
- nameString = s_nameTable.Add("created");
+ nameString = s_nameTable.AddNoLock("created");
s_xmlstringtable[0x11] = new XmlStringTableStruct(nameString, PackageXmlEnum.DublinCoreTermsNamespace, "DateTime");
- nameString = s_nameTable.Add("modified");
+ nameString = s_nameTable.AddNoLock("modified");
s_xmlstringtable[0x12] = new XmlStringTableStruct(nameString, PackageXmlEnum.DublinCoreTermsNamespace, "DateTime");
- nameString = s_nameTable.Add("contentType");
+ nameString = s_nameTable.AddNoLock("contentType");
s_xmlstringtable[0x13] = new XmlStringTableStruct(nameString, PackageXmlEnum.PackageCorePropertiesNamespace, "String");
- nameString = s_nameTable.Add("keywords");
+ nameString = s_nameTable.AddNoLock("keywords");
s_xmlstringtable[20] = new XmlStringTableStruct(nameString, PackageXmlEnum.PackageCorePropertiesNamespace, "String");
- nameString = s_nameTable.Add("category");
+ nameString = s_nameTable.AddNoLock("category");
s_xmlstringtable[0x15] = new XmlStringTableStruct(nameString, PackageXmlEnum.PackageCorePropertiesNamespace, "String");
- nameString = s_nameTable.Add("version");
+ nameString = s_nameTable.AddNoLock("version");
s_xmlstringtable[0x16] = new XmlStringTableStruct(nameString, PackageXmlEnum.PackageCorePropertiesNamespace, "String");
- nameString = s_nameTable.Add("lastModifiedBy");
+ nameString = s_nameTable.AddNoLock("lastModifiedBy");
s_xmlstringtable[0x17] = new XmlStringTableStruct(nameString, PackageXmlEnum.PackageCorePropertiesNamespace, "String");
- nameString = s_nameTable.Add("contentStatus");
+ nameString = s_nameTable.AddNoLock("contentStatus");
s_xmlstringtable[0x18] = new XmlStringTableStruct(nameString, PackageXmlEnum.PackageCorePropertiesNamespace, "String");
- nameString = s_nameTable.Add("revision");
+ nameString = s_nameTable.AddNoLock("revision");
s_xmlstringtable[0x19] = new XmlStringTableStruct(nameString, PackageXmlEnum.PackageCorePropertiesNamespace, "String");
- nameString = s_nameTable.Add("lastPrinted");
+ nameString = s_nameTable.AddNoLock("lastPrinted");
s_xmlstringtable[0x1a] = new XmlStringTableStruct(nameString, PackageXmlEnum.PackageCorePropertiesNamespace, "DateTime");
}
@@ -161,5 +161,43 @@ internal string? ValueType
}
}
}
+
+ private sealed class ThreadSafeNameTable : NameTable
+ {
+ public override string Add(char[] array, int offset, int length)
+ {
+ lock (this)
+ {
+ return base.Add(array, offset, length);
+ }
+ }
+
+ public override string Add(string array)
+ {
+ lock (this)
+ {
+ return base.Add(array);
+ }
+ }
+
+ // can be used only from static ctor (which is always executed by a single thread)
+ internal string AddNoLock(string array) => base.Add(array);
+
+ public override string? Get(char[] array, int offset, int length)
+ {
+ lock (this)
+ {
+ return base.Get(array, offset, length);
+ }
+ }
+
+ public override string? Get(string array)
+ {
+ lock (this)
+ {
+ return base.Get(array);
+ }
+ }
+ }
}
}
diff --git a/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/TranscodingReadStream.cs b/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/TranscodingReadStream.cs
index 894ea8c7860cd6..cc8ef875b9d71b 100644
--- a/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/TranscodingReadStream.cs
+++ b/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/TranscodingReadStream.cs
@@ -208,17 +208,20 @@ protected override void Dispose(bool disposing)
{
_disposed = true;
- Debug.Assert(_charBuffer.Array != null);
- ArrayPool.Shared.Return(_charBuffer.Array);
+ char[]? charBuffer = _charBuffer.Array;
+ Debug.Assert(charBuffer != null);
_charBuffer = default;
+ ArrayPool.Shared.Return(charBuffer);
- Debug.Assert(_byteBuffer.Array != null);
- ArrayPool.Shared.Return(_byteBuffer.Array);
+ byte[]? byteBuffer = _byteBuffer.Array;
+ Debug.Assert(byteBuffer != null);
_byteBuffer = default;
+ ArrayPool.Shared.Return(byteBuffer);
- Debug.Assert(_overflowBuffer.Array != null);
- ArrayPool.Shared.Return(_overflowBuffer.Array);
+ byte[]? overflowBuffer = _overflowBuffer.Array;
+ Debug.Assert(overflowBuffer != null);
_overflowBuffer = default;
+ ArrayPool.Shared.Return(overflowBuffer);
_stream.Dispose();
}
diff --git a/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/TranscodingWriteStream.cs b/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/TranscodingWriteStream.cs
index 51c73d00634c39..2217baefb6ea40 100644
--- a/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/TranscodingWriteStream.cs
+++ b/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/TranscodingWriteStream.cs
@@ -133,8 +133,9 @@ protected override void Dispose(bool disposing)
if (!_disposed)
{
_disposed = true;
- ArrayPool.Shared.Return(_charBuffer);
+ char[] toReturn = _charBuffer;
_charBuffer = null!;
+ ArrayPool.Shared.Return(toReturn);
}
}
diff --git a/src/libraries/System.Net.Http/src/ILLink/ILLink.Substitutions.mobile.xml b/src/libraries/System.Net.Http/src/ILLink/ILLink.Substitutions.mobile.xml
new file mode 100644
index 00000000000000..5b705abeb24bda
--- /dev/null
+++ b/src/libraries/System.Net.Http/src/ILLink/ILLink.Substitutions.mobile.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/src/libraries/System.Net.Http/src/ILLink/ILLink.Substitutions.xml b/src/libraries/System.Net.Http/src/ILLink/ILLink.Substitutions.xml
index 8af1dcbdfa8a6a..5e70f6fbb5d7d5 100644
--- a/src/libraries/System.Net.Http/src/ILLink/ILLink.Substitutions.xml
+++ b/src/libraries/System.Net.Http/src/ILLink/ILLink.Substitutions.xml
@@ -3,8 +3,5 @@
-
-
-
diff --git a/src/libraries/System.Net.Http/src/System.Net.Http.csproj b/src/libraries/System.Net.Http/src/System.Net.Http.csproj
index 330c6cf1614468..77ed5b9c436c64 100644
--- a/src/libraries/System.Net.Http/src/System.Net.Http.csproj
+++ b/src/libraries/System.Net.Http/src/System.Net.Http.csproj
@@ -1,4 +1,4 @@
-
+
win
true
@@ -18,6 +18,8 @@
+
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.cs
index 2e1434b0b49935..3b77aeafc0467b 100644
--- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.cs
+++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.cs
@@ -815,16 +815,6 @@ private void PrepareRequestMessage(HttpRequestMessage request)
return (pendingRequestsCts, DisposeTokenSource: false, pendingRequestsCts);
}
- private static bool IsNativeHandlerEnabled()
- {
- if (!AppContext.TryGetSwitch("System.Net.Http.UseNativeHttpHandler", out bool isEnabled))
- {
- return false;
- }
-
- return isEnabled;
- }
-
private Uri? CreateUri(string? uri) =>
string.IsNullOrEmpty(uri) ? null : new Uri(uri, UriKind.RelativeOrAbsolute);
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs
index 309e60f65a9156..cfe17837ce96c3 100644
--- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs
+++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs
@@ -9,6 +9,7 @@
using System.Globalization;
using System.Net.Security;
using System.Reflection;
+using System.Runtime.ExceptionServices;
using System.Runtime.Versioning;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
@@ -424,7 +425,15 @@ private object InvokeNativeHandlerMethod(string name, params object?[] parameter
s_cachedMethods[name] = method;
}
- return method!.Invoke(_nativeHandler, parameters)!;
+ try
+ {
+ return method!.Invoke(_nativeHandler, parameters)!;
+ }
+ catch (TargetInvocationException e)
+ {
+ ExceptionDispatchInfo.Capture(e.InnerException!).Throw();
+ throw;
+ }
}
private static bool IsNativeHandlerEnabled => RuntimeSettingParser.QueryRuntimeSettingSwitch(
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs
index d3e6a90c4305b5..6b2012d6df384c 100644
--- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs
+++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs
@@ -283,7 +283,7 @@ private void OnServerGoAway(long lastProcessedStreamId)
lock (SyncObj)
{
- if (lastProcessedStreamId > _lastProcessedStreamId)
+ if (_lastProcessedStreamId != -1 && lastProcessedStreamId > _lastProcessedStreamId)
{
// Server can send multiple GOAWAY frames.
// Spec says a server MUST NOT increase the stream ID in subsequent GOAWAYs,
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs
index 19d8eb20262039..45b74472b402cb 100644
--- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs
+++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs
@@ -141,7 +141,7 @@ public async Task SendAsync(CancellationToken cancellationT
// If we don't have content, or we are doing Expect 100 Continue, then we can't rely on
// this and must send our headers immediately.
- await _stream.WriteAsync(_sendBuffer.ActiveMemory, requestCancellationSource.Token).ConfigureAwait(false);
+ await _stream.WriteAsync(_sendBuffer.ActiveMemory, endStream: _expect100ContinueCompletionSource == null, requestCancellationSource.Token).ConfigureAwait(false);
_sendBuffer.Discard(_sendBuffer.ActiveLength);
if (_expect100ContinueCompletionSource != null)
@@ -150,10 +150,6 @@ public async Task SendAsync(CancellationToken cancellationT
// TODO: MsQuic may not need any flushing.
await _stream.FlushAsync(cancellationToken).ConfigureAwait(false);
}
- else
- {
- _stream.Shutdown();
- }
}
// If using duplex content, the content will continue sending after this method completes.
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Headers.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Headers.cs
index 9f03c1750e448f..c736eb6bb2a6bd 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Headers.cs
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Headers.cs
@@ -407,6 +407,7 @@ public async Task SendAsync_GetWithInvalidHostHeader_ThrowsException()
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/56292")]
[ActiveIssue("https://github.com/dotnet/runtime/issues/54160", TestPlatforms.Browser)]
public async Task SendAsync_WithZeroLengthHeaderName_Throws()
{
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http3.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http3.cs
index 22d0370ef10fc7..2f78323b56ec1f 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http3.cs
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http3.cs
@@ -458,6 +458,7 @@ public enum CancellationType
}
[ConditionalTheory(nameof(IsMsQuicSupported))]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/56194")]
[InlineData(CancellationType.Dispose)]
[InlineData(CancellationType.CancellationToken)]
public async Task ResponseCancellation_ServerReceivesCancellation(CancellationType type)
@@ -545,6 +546,7 @@ public async Task ResponseCancellation_ServerReceivesCancellation(CancellationTy
}
[Fact]
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/56265")]
public async Task ResponseCancellation_BothCancellationTokenAndDispose_Success()
{
if (UseQuicImplementationProvider != QuicImplementationProviders.MsQuic)
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/LoopbackSocksServer.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/LoopbackSocksServer.cs
index 9f22e671dea380..781b7be21f2388 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/LoopbackSocksServer.cs
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/LoopbackSocksServer.cs
@@ -1,13 +1,11 @@
// 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.IO;
using System.Net.Sockets;
-using System.Net.Test.Common;
using System.Runtime.ExceptionServices;
using System.Text;
-using System.Threading;
using System.Threading.Tasks;
namespace System.Net.Http.Functional.Tests
@@ -15,20 +13,17 @@ namespace System.Net.Http.Functional.Tests
///
/// Provides a test-only SOCKS4/5 proxy.
///
- internal class LoopbackSocksServer : IDisposable
+ internal class LoopbackSocksServer : IAsyncDisposable
{
private readonly Socket _listener;
- private readonly ManualResetEvent _serverStopped;
- private bool _disposed;
-
- private int _connections;
- public int Connections => _connections;
+ private readonly List _connectionTasks = new();
+ private readonly TaskCompletionSource _serverStopped = new(TaskCreationOptions.RunContinuationsAsynchronously);
public int Port { get; }
private string? _username, _password;
- private LoopbackSocksServer(string? username = null, string? password = null)
+ public LoopbackSocksServer(string? username = null, string? password = null)
{
if (password != null && username == null)
{
@@ -40,74 +35,37 @@ private LoopbackSocksServer(string? username = null, string? password = null)
_listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
- _listener.Listen(int.MaxValue);
+ _listener.Listen();
var ep = (IPEndPoint)_listener.LocalEndPoint;
Port = ep.Port;
- _serverStopped = new ManualResetEvent(false);
- }
-
- private void Start()
- {
Task.Run(async () =>
{
- var activeTasks = new ConcurrentDictionary();
-
- try
+ while (true)
{
- while (true)
+ try
{
Socket s = await _listener.AcceptAsync().ConfigureAwait(false);
- var connectionTask = Task.Run(async () =>
+ _connectionTasks.Add(Task.Run(async () =>
{
- try
- {
- await ProcessConnection(s).ConfigureAwait(false);
- }
- catch (Exception ex)
+ using (var ns = new NetworkStream(s, ownsSocket: true))
{
- EventSourceTestLogging.Log.TestAncillaryError(ex);
+ await ProcessRequest(s, ns).ConfigureAwait(false);
}
- });
-
- activeTasks.TryAdd(connectionTask, 0);
- _ = connectionTask.ContinueWith(t => activeTasks.TryRemove(connectionTask, out _), TaskContinuationOptions.ExecuteSynchronously);
+ }));
+ }
+ catch
+ {
+ break;
}
- }
- catch (SocketException ex) when (ex.SocketErrorCode == SocketError.OperationAborted)
- {
- // caused during Dispose() to cancel the loop. ignore.
- }
- catch (Exception ex)
- {
- EventSourceTestLogging.Log.TestAncillaryError(ex);
- }
-
- try
- {
- await Task.WhenAll(activeTasks.Keys).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- EventSourceTestLogging.Log.TestAncillaryError(ex);
}
- _serverStopped.Set();
+ _serverStopped.SetResult();
});
}
- private async Task ProcessConnection(Socket s)
- {
- Interlocked.Increment(ref _connections);
-
- using (var ns = new NetworkStream(s, ownsSocket: true))
- {
- await ProcessRequest(s, ns).ConfigureAwait(false);
- }
- }
-
private async Task ProcessRequest(Socket clientSocket, NetworkStream ns)
{
int version = await ns.ReadByteAsync().ConfigureAwait(false);
@@ -344,21 +302,27 @@ private async ValueTask ReadToFillAsync(Stream stream, Memory buffer)
}
}
- public static LoopbackSocksServer Create(string? username = null, string? password = null)
+ public async ValueTask DisposeAsync()
{
- var server = new LoopbackSocksServer(username, password);
- server.Start();
+ _listener.Dispose();
+ await _serverStopped.Task;
- return server;
- }
+ List exceptions = new();
+ foreach (Task task in _connectionTasks)
+ {
+ try
+ {
+ await task;
+ }
+ catch (Exception ex)
+ {
+ exceptions.Add(ex);
+ }
+ }
- public void Dispose()
- {
- if (!_disposed)
+ if (exceptions.Count > 0)
{
- _listener.Dispose();
- _serverStopped.WaitOne();
- _disposed = true;
+ throw new AggregateException(exceptions);
}
}
}
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/SocksProxyTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/SocksProxyTest.cs
index 821794e9f82d5e..cb60661313b211 100644
--- a/src/libraries/System.Net.Http/tests/FunctionalTests/SocksProxyTest.cs
+++ b/src/libraries/System.Net.Http/tests/FunctionalTests/SocksProxyTest.cs
@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
-using System.IO;
using System.Linq;
using System.Net.Test.Common;
using System.Threading.Tasks;
@@ -38,7 +37,7 @@ public async Task TestLoopbackAsync(string scheme, bool useSsl, bool useAuth, st
await LoopbackServerFactory.CreateClientAndServerAsync(
async uri =>
{
- using LoopbackSocksServer proxy = useAuth ? LoopbackSocksServer.Create("DOTNET", "424242") : LoopbackSocksServer.Create();
+ await using var proxy = useAuth ? new LoopbackSocksServer("DOTNET", "424242") : new LoopbackSocksServer();
using HttpClientHandler handler = CreateHttpClientHandler();
using HttpClient client = CreateHttpClient(handler);
@@ -93,7 +92,7 @@ public static IEnumerable