From 012504f75933d1d60313f42c548cbb49a16f6907 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Wed, 14 May 2025 02:05:50 +0000 Subject: [PATCH 01/11] Update dependencies from https://github.com/dotnet/dotnet build 268047 --- eng/Version.Details.xml | 142 ++++++++++++++++++++-------------------- eng/Versions.props | 64 +++++++++--------- eng/common/build.sh | 2 +- eng/common/darc-init.sh | 2 +- global.json | 8 +-- 5 files changed, 109 insertions(+), 109 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 24fbe6c2292204..4334646004f689 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,5 +1,5 @@ - + https://github.com/dotnet/icu @@ -41,91 +41,91 @@ https://github.com/dotnet/llvm-project da5dd054a531e6fea65643b7e754285b73eab433 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f https://github.com/dotnet/runtime-assets @@ -263,33 +263,33 @@ https://github.com/dotnet/llvm-project da5dd054a531e6fea65643b7e754285b73eab433 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f https://github.com/dotnet/xharness @@ -303,9 +303,9 @@ https://github.com/dotnet/xharness e85bb14e85357ab678c2bcb0b6f2bac634fdd49b - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f https://dev.azure.com/dnceng/internal/_git/dotnet-optimization @@ -331,29 +331,29 @@ https://github.com/dotnet/runtime-assets 1cfc6ba21d0377b51f17eac4fdc2557f7b1e8693 - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f - + https://github.com/dotnet/dotnet - 85778473549347b3e4bad3ea009e9438df7b11bb + 5d437e96e412b189af05abb84753996de9aa698f https://dev.azure.com/dnceng/internal/_git/dotnet-optimization diff --git a/eng/Versions.props b/eng/Versions.props index 6fe9ec30dcc4b7..863db3ea20431b 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -36,17 +36,17 @@ - 10.0.0-preview.25260.104 + 10.0.0-preview.25263.104 - 5.0.0-1.25260.104 + 5.0.0-1.25263.104 - 5.0.0-1.25260.104 - 5.0.0-1.25260.104 - 5.0.0-1.25260.104 + 5.0.0-1.25263.104 + 5.0.0-1.25263.104 + 5.0.0-1.25263.104 - 10.0.100-preview.5.25260.104 + 10.0.100-preview.5.25263.104 - 10.0.0-beta.25260.104 - 10.0.0-beta.25260.104 - 10.0.0-beta.25260.104 - 10.0.0-beta.25260.104 - 2.9.2-beta.25260.104 - 10.0.0-beta.25260.104 - 2.9.2-beta.25260.104 - 10.0.0-beta.25260.104 - 10.0.0-beta.25260.104 - 10.0.0-beta.25260.104 - 10.0.0-beta.25260.104 - 10.0.0-beta.25260.104 - 10.0.0-beta.25260.104 - 10.0.0-beta.25260.104 - 10.0.0-beta.25260.104 - 10.0.0-beta.25260.104 + 10.0.0-beta.25263.104 + 10.0.0-beta.25263.104 + 10.0.0-beta.25263.104 + 10.0.0-beta.25263.104 + 2.9.2-beta.25263.104 + 10.0.0-beta.25263.104 + 2.9.2-beta.25263.104 + 10.0.0-beta.25263.104 + 10.0.0-beta.25263.104 + 10.0.0-beta.25263.104 + 10.0.0-beta.25263.104 + 10.0.0-beta.25263.104 + 10.0.0-beta.25263.104 + 10.0.0-beta.25263.104 + 10.0.0-beta.25263.104 + 10.0.0-beta.25263.104 1.4.0 6.0.0-preview.1.102 - 10.0.0-preview.5.25260.104 + 10.0.0-preview.5.25263.104 6.0.0 - 10.0.0-preview.5.25260.104 - 10.0.0-preview.5.25260.104 + 10.0.0-preview.5.25263.104 + 10.0.0-preview.5.25263.104 6.0.0 4.6.1 @@ -128,16 +128,16 @@ 8.0.0 8.0.1 5.0.0 - 10.0.0-preview.5.25260.104 - 10.0.0-preview.5.25260.104 + 10.0.0-preview.5.25263.104 + 10.0.0-preview.5.25263.104 6.0.0 5.0.0 5.0.0 5.0.0 7.0.0 - 10.0.0-preview.5.25260.104 + 10.0.0-preview.5.25263.104 7.0.0 - 10.0.0-preview.5.25260.104 + 10.0.0-preview.5.25263.104 8.0.0 4.5.1 @@ -180,7 +180,7 @@ 2.0.0 17.10.0-beta1.24272.1 - 2.0.0-beta5.25260.104 + 2.0.0-beta5.25263.104 3.1.16 2.1.0 2.0.3 @@ -226,7 +226,7 @@ 9.0.0-preview-20241010.1 - 0.11.5-alpha.25260.104 + 0.11.5-alpha.25263.104 10.0.0-preview.5.25261.1 @@ -258,7 +258,7 @@ Note: when the name is updated, make sure to update dependency name in eng/pipelines/common/xplat-setup.yml like - DarcDependenciesChanged.Microsoft_NET_Workload_Emscripten_Current_Manifest-10_0_100_Transport --> - 10.0.100-preview.5.25260.104 + 10.0.100-preview.5.25263.104 $(MicrosoftNETWorkloadEmscriptenCurrentManifest100100TransportVersion) 1.1.87-gba258badda diff --git a/eng/common/build.sh b/eng/common/build.sh index 36fba82a37930d..27ae2c85601f07 100755 --- a/eng/common/build.sh +++ b/eng/common/build.sh @@ -136,7 +136,7 @@ while [[ $# > 0 ]]; do restore=true pack=true ;; - -productBuild|-pb) + -productbuild|-pb) build=true product_build=true restore=true diff --git a/eng/common/darc-init.sh b/eng/common/darc-init.sh index 36dbd45e1ce866..e889f439b8dc99 100755 --- a/eng/common/darc-init.sh +++ b/eng/common/darc-init.sh @@ -68,7 +68,7 @@ function InstallDarcCli { fi fi - local arcadeServicesSource="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json" + local arcadeServicesSource="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json" echo "Installing Darc CLI version $darcVersion..." echo "You may need to restart your command shell if this is the first dotnet tool you have installed." diff --git a/global.json b/global.json index 8616c8a6541983..61659e8b7de6f4 100644 --- a/global.json +++ b/global.json @@ -8,11 +8,11 @@ "dotnet": "10.0.100-preview.3.25201.16" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25260.104", - "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25260.104", - "Microsoft.DotNet.SharedFramework.Sdk": "10.0.0-beta.25260.104", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25263.104", + "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25263.104", + "Microsoft.DotNet.SharedFramework.Sdk": "10.0.0-beta.25263.104", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", - "Microsoft.NET.Sdk.IL": "10.0.0-preview.5.25260.104" + "Microsoft.NET.Sdk.IL": "10.0.0-preview.5.25263.104" } } From 4e15389665a9a0062a726aa7aa8aa5492665575a Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Thu, 15 May 2025 02:08:34 +0000 Subject: [PATCH 02/11] Update dependencies from https://github.com/dotnet/dotnet build 268099 Updated Dependencies: System.CommandLine (Version 2.0.0-beta5.25263.104 -> 2.0.0-beta5.25260.104) Microsoft.DotNet.Cecil (Version 0.11.5-alpha.25263.104 -> 0.11.5-alpha.25260.104) Microsoft.NET.Workload.Emscripten.Current.Manifest-10.0.100.Transport, Microsoft.DotNet.ApiCompat.Task (Version 10.0.100-preview.5.25263.104 -> 10.0.100-preview.5.25260.104) Microsoft.DotNet.Arcade.Sdk, Microsoft.DotNet.XliffTasks, Microsoft.DotNet.Helix.Sdk, Microsoft.DotNet.GenAPI, Microsoft.DotNet.GenFacades, Microsoft.DotNet.XUnitExtensions, Microsoft.DotNet.Build.Tasks.Archives, Microsoft.DotNet.Build.Tasks.Packaging, Microsoft.DotNet.Build.Tasks.Installers, Microsoft.DotNet.Build.Tasks.Templating, Microsoft.DotNet.Build.Tasks.Workloads, Microsoft.DotNet.CodeAnalysis, Microsoft.DotNet.Build.Tasks.TargetFramework, Microsoft.DotNet.RemoteExecutor, Microsoft.DotNet.Build.Tasks.Feed, Microsoft.DotNet.SharedFramework.Sdk, Microsoft.DotNet.PackageTesting (Version 10.0.0-beta.25263.104 -> 10.0.0-beta.25260.104) Microsoft.DotNet.XUnitAssert, Microsoft.DotNet.XUnitConsoleRunner (Version 2.9.2-beta.25263.104 -> 2.9.2-beta.25260.104) Microsoft.NETCore.App.Runtime.win-x64, runtime.native.System.IO.Ports, Microsoft.NETCore.ILAsm, Microsoft.NET.Sdk.IL, System.Text.Json, System.Reflection.Metadata, System.Reflection.MetadataLoadContext (Version 10.0.0-preview.5.25263.104 -> 10.0.0-preview.5.25260.104) Microsoft.Net.Compilers.Toolset, Microsoft.CodeAnalysis, Microsoft.CodeAnalysis.CSharp, Microsoft.CodeAnalysis.Analyzers (Version 5.0.0-1.25263.104 -> 5.0.0-1.25260.104) Microsoft.CodeAnalysis.NetAnalyzers (Version 10.0.0-preview.25263.104 -> 10.0.0-preview.25260.104) --- eng/Version.Details.xml | 142 +++++++++--------- eng/Versions.props | 64 ++++---- .../core-templates/steps/source-build.yml | 3 +- global.json | 8 +- 4 files changed, 108 insertions(+), 109 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 4334646004f689..9e1be69ce97f27 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,5 +1,5 @@ - + https://github.com/dotnet/icu @@ -41,91 +41,91 @@ https://github.com/dotnet/llvm-project da5dd054a531e6fea65643b7e754285b73eab433 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 https://github.com/dotnet/runtime-assets @@ -263,33 +263,33 @@ https://github.com/dotnet/llvm-project da5dd054a531e6fea65643b7e754285b73eab433 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 https://github.com/dotnet/xharness @@ -303,9 +303,9 @@ https://github.com/dotnet/xharness e85bb14e85357ab678c2bcb0b6f2bac634fdd49b - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization @@ -331,29 +331,29 @@ https://github.com/dotnet/runtime-assets 1cfc6ba21d0377b51f17eac4fdc2557f7b1e8693 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 - + https://github.com/dotnet/dotnet - 5d437e96e412b189af05abb84753996de9aa698f + 362a4227bd38985f75f6a6d7f6733c7d62414569 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization diff --git a/eng/Versions.props b/eng/Versions.props index 863db3ea20431b..6429bc61482ac7 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -36,17 +36,17 @@ - 10.0.0-preview.25263.104 + 10.0.0-preview.25263.108 - 5.0.0-1.25263.104 + 5.0.0-1.25263.108 - 5.0.0-1.25263.104 - 5.0.0-1.25263.104 - 5.0.0-1.25263.104 + 5.0.0-1.25263.108 + 5.0.0-1.25263.108 + 5.0.0-1.25263.108 - 10.0.100-preview.5.25263.104 + 10.0.100-preview.5.25263.108 - 10.0.0-beta.25263.104 - 10.0.0-beta.25263.104 - 10.0.0-beta.25263.104 - 10.0.0-beta.25263.104 - 2.9.2-beta.25263.104 - 10.0.0-beta.25263.104 - 2.9.2-beta.25263.104 - 10.0.0-beta.25263.104 - 10.0.0-beta.25263.104 - 10.0.0-beta.25263.104 - 10.0.0-beta.25263.104 - 10.0.0-beta.25263.104 - 10.0.0-beta.25263.104 - 10.0.0-beta.25263.104 - 10.0.0-beta.25263.104 - 10.0.0-beta.25263.104 + 10.0.0-beta.25263.108 + 10.0.0-beta.25263.108 + 10.0.0-beta.25263.108 + 10.0.0-beta.25263.108 + 2.9.2-beta.25263.108 + 10.0.0-beta.25263.108 + 2.9.2-beta.25263.108 + 10.0.0-beta.25263.108 + 10.0.0-beta.25263.108 + 10.0.0-beta.25263.108 + 10.0.0-beta.25263.108 + 10.0.0-beta.25263.108 + 10.0.0-beta.25263.108 + 10.0.0-beta.25263.108 + 10.0.0-beta.25263.108 + 10.0.0-beta.25263.108 1.4.0 6.0.0-preview.1.102 - 10.0.0-preview.5.25263.104 + 10.0.0-preview.5.25263.108 6.0.0 - 10.0.0-preview.5.25263.104 - 10.0.0-preview.5.25263.104 + 10.0.0-preview.5.25263.108 + 10.0.0-preview.5.25263.108 6.0.0 4.6.1 @@ -128,16 +128,16 @@ 8.0.0 8.0.1 5.0.0 - 10.0.0-preview.5.25263.104 - 10.0.0-preview.5.25263.104 + 10.0.0-preview.5.25263.108 + 10.0.0-preview.5.25263.108 6.0.0 5.0.0 5.0.0 5.0.0 7.0.0 - 10.0.0-preview.5.25263.104 + 10.0.0-preview.5.25263.108 7.0.0 - 10.0.0-preview.5.25263.104 + 10.0.0-preview.5.25263.108 8.0.0 4.5.1 @@ -180,7 +180,7 @@ 2.0.0 17.10.0-beta1.24272.1 - 2.0.0-beta5.25263.104 + 2.0.0-beta5.25263.108 3.1.16 2.1.0 2.0.3 @@ -226,7 +226,7 @@ 9.0.0-preview-20241010.1 - 0.11.5-alpha.25263.104 + 0.11.5-alpha.25263.108 10.0.0-preview.5.25261.1 @@ -258,7 +258,7 @@ Note: when the name is updated, make sure to update dependency name in eng/pipelines/common/xplat-setup.yml like - DarcDependenciesChanged.Microsoft_NET_Workload_Emscripten_Current_Manifest-10_0_100_Transport --> - 10.0.100-preview.5.25263.104 + 10.0.100-preview.5.25263.108 $(MicrosoftNETWorkloadEmscriptenCurrentManifest100100TransportVersion) 1.1.87-gba258badda diff --git a/eng/common/core-templates/steps/source-build.yml b/eng/common/core-templates/steps/source-build.yml index f2a0f347fdd67a..0dde553c3ebfbb 100644 --- a/eng/common/core-templates/steps/source-build.yml +++ b/eng/common/core-templates/steps/source-build.yml @@ -51,13 +51,12 @@ steps: ${{ coalesce(parameters.platform.buildScript, './build.sh') }} --ci \ --configuration $buildConfig \ --restore --build --pack -bl \ + --source-build \ ${{ parameters.platform.buildArguments }} \ $internalRuntimeDownloadArgs \ $targetRidArgs \ $baseRidArgs \ $portableBuildArgs \ - /p:DotNetBuildSourceOnly=true \ - /p:DotNetBuildRepo=true \ displayName: Build - template: /eng/common/core-templates/steps/publish-pipeline-artifacts.yml diff --git a/global.json b/global.json index 61659e8b7de6f4..c3a58690de0619 100644 --- a/global.json +++ b/global.json @@ -8,11 +8,11 @@ "dotnet": "10.0.100-preview.3.25201.16" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25263.104", - "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25263.104", - "Microsoft.DotNet.SharedFramework.Sdk": "10.0.0-beta.25263.104", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25263.108", + "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25263.108", + "Microsoft.DotNet.SharedFramework.Sdk": "10.0.0-beta.25263.108", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", - "Microsoft.NET.Sdk.IL": "10.0.0-preview.5.25263.104" + "Microsoft.NET.Sdk.IL": "10.0.0-preview.5.25263.108" } } From 9ad9b8c152b414636c2ee2020470f49731d2c076 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Thu, 15 May 2025 14:10:05 +0000 Subject: [PATCH 03/11] [VMR] Codeflow 362a422-ad85650 [[ commit created by automation ]] --- Directory.Build.props | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Directory.Build.props b/Directory.Build.props index 7e5c028ecfa209..084308a0dd1fc1 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -192,6 +192,8 @@ false false + + false Date: Thu, 15 May 2025 14:10:17 +0000 Subject: [PATCH 04/11] Update dependencies from https://github.com/dotnet/dotnet build 268384 Updated Dependencies: System.CommandLine (Version 2.0.0-beta5.25263.108 -> 2.0.0-beta5.25260.104) Microsoft.DotNet.Cecil (Version 0.11.5-alpha.25263.108 -> 0.11.5-alpha.25260.104) Microsoft.NET.Workload.Emscripten.Current.Manifest-10.0.100.Transport, Microsoft.DotNet.ApiCompat.Task (Version 10.0.100-preview.5.25263.108 -> 10.0.100-preview.5.25260.104) Microsoft.DotNet.Arcade.Sdk, Microsoft.DotNet.XliffTasks, Microsoft.DotNet.Helix.Sdk, Microsoft.DotNet.GenAPI, Microsoft.DotNet.GenFacades, Microsoft.DotNet.XUnitExtensions, Microsoft.DotNet.Build.Tasks.Archives, Microsoft.DotNet.Build.Tasks.Packaging, Microsoft.DotNet.Build.Tasks.Installers, Microsoft.DotNet.Build.Tasks.Templating, Microsoft.DotNet.Build.Tasks.Workloads, Microsoft.DotNet.CodeAnalysis, Microsoft.DotNet.Build.Tasks.TargetFramework, Microsoft.DotNet.RemoteExecutor, Microsoft.DotNet.Build.Tasks.Feed, Microsoft.DotNet.SharedFramework.Sdk, Microsoft.DotNet.PackageTesting (Version 10.0.0-beta.25263.108 -> 10.0.0-beta.25260.104) Microsoft.DotNet.XUnitAssert, Microsoft.DotNet.XUnitConsoleRunner (Version 2.9.2-beta.25263.108 -> 2.9.2-beta.25260.104) Microsoft.NETCore.App.Runtime.win-x64, runtime.native.System.IO.Ports, Microsoft.NETCore.ILAsm, Microsoft.NET.Sdk.IL, System.Text.Json, System.Reflection.Metadata, System.Reflection.MetadataLoadContext (Version 10.0.0-preview.5.25263.108 -> 10.0.0-preview.5.25260.104) Microsoft.Net.Compilers.Toolset, Microsoft.CodeAnalysis, Microsoft.CodeAnalysis.CSharp, Microsoft.CodeAnalysis.Analyzers (Version 5.0.0-1.25263.108 -> 5.0.0-1.25260.104) Microsoft.CodeAnalysis.NetAnalyzers (Version 10.0.0-preview.25263.108 -> 10.0.0-preview.25260.104) --- eng/Version.Details.xml | 142 ++++++++++++++++++++-------------------- eng/Versions.props | 64 +++++++++--------- eng/common/tools.ps1 | 4 +- eng/common/tools.sh | 2 +- global.json | 8 +-- 5 files changed, 109 insertions(+), 111 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 9e1be69ce97f27..d8fff638db1bd7 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,5 +1,5 @@ - + https://github.com/dotnet/icu @@ -41,91 +41,91 @@ https://github.com/dotnet/llvm-project da5dd054a531e6fea65643b7e754285b73eab433 - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee https://github.com/dotnet/runtime-assets @@ -263,33 +263,33 @@ https://github.com/dotnet/llvm-project da5dd054a531e6fea65643b7e754285b73eab433 - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee https://github.com/dotnet/xharness @@ -303,9 +303,9 @@ https://github.com/dotnet/xharness e85bb14e85357ab678c2bcb0b6f2bac634fdd49b - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee https://dev.azure.com/dnceng/internal/_git/dotnet-optimization @@ -331,29 +331,29 @@ https://github.com/dotnet/runtime-assets 1cfc6ba21d0377b51f17eac4fdc2557f7b1e8693 - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee - + https://github.com/dotnet/dotnet - 362a4227bd38985f75f6a6d7f6733c7d62414569 + ad8565092bbfdd5c8b4a94a718d10b2d394f7aee https://dev.azure.com/dnceng/internal/_git/dotnet-optimization diff --git a/eng/Versions.props b/eng/Versions.props index 6429bc61482ac7..ddf9a537dbe093 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -36,17 +36,17 @@ - 10.0.0-preview.25263.108 + 10.0.0-preview.25265.101 - 5.0.0-1.25263.108 + 5.0.0-1.25265.101 - 5.0.0-1.25263.108 - 5.0.0-1.25263.108 - 5.0.0-1.25263.108 + 5.0.0-1.25265.101 + 5.0.0-1.25265.101 + 5.0.0-1.25265.101 - 10.0.100-preview.5.25263.108 + 10.0.100-preview.5.25265.101 - 10.0.0-beta.25263.108 - 10.0.0-beta.25263.108 - 10.0.0-beta.25263.108 - 10.0.0-beta.25263.108 - 2.9.2-beta.25263.108 - 10.0.0-beta.25263.108 - 2.9.2-beta.25263.108 - 10.0.0-beta.25263.108 - 10.0.0-beta.25263.108 - 10.0.0-beta.25263.108 - 10.0.0-beta.25263.108 - 10.0.0-beta.25263.108 - 10.0.0-beta.25263.108 - 10.0.0-beta.25263.108 - 10.0.0-beta.25263.108 - 10.0.0-beta.25263.108 + 10.0.0-beta.25265.101 + 10.0.0-beta.25265.101 + 10.0.0-beta.25265.101 + 10.0.0-beta.25265.101 + 2.9.2-beta.25265.101 + 10.0.0-beta.25265.101 + 2.9.2-beta.25265.101 + 10.0.0-beta.25265.101 + 10.0.0-beta.25265.101 + 10.0.0-beta.25265.101 + 10.0.0-beta.25265.101 + 10.0.0-beta.25265.101 + 10.0.0-beta.25265.101 + 10.0.0-beta.25265.101 + 10.0.0-beta.25265.101 + 10.0.0-beta.25265.101 1.4.0 6.0.0-preview.1.102 - 10.0.0-preview.5.25263.108 + 10.0.0-preview.5.25265.101 6.0.0 - 10.0.0-preview.5.25263.108 - 10.0.0-preview.5.25263.108 + 10.0.0-preview.5.25265.101 + 10.0.0-preview.5.25265.101 6.0.0 4.6.1 @@ -128,16 +128,16 @@ 8.0.0 8.0.1 5.0.0 - 10.0.0-preview.5.25263.108 - 10.0.0-preview.5.25263.108 + 10.0.0-preview.5.25265.101 + 10.0.0-preview.5.25265.101 6.0.0 5.0.0 5.0.0 5.0.0 7.0.0 - 10.0.0-preview.5.25263.108 + 10.0.0-preview.5.25265.101 7.0.0 - 10.0.0-preview.5.25263.108 + 10.0.0-preview.5.25265.101 8.0.0 4.5.1 @@ -180,7 +180,7 @@ 2.0.0 17.10.0-beta1.24272.1 - 2.0.0-beta5.25263.108 + 2.0.0-beta5.25265.101 3.1.16 2.1.0 2.0.3 @@ -226,7 +226,7 @@ 9.0.0-preview-20241010.1 - 0.11.5-alpha.25263.108 + 0.11.5-alpha.25265.101 10.0.0-preview.5.25261.1 @@ -258,7 +258,7 @@ Note: when the name is updated, make sure to update dependency name in eng/pipelines/common/xplat-setup.yml like - DarcDependenciesChanged.Microsoft_NET_Workload_Emscripten_Current_Manifest-10_0_100_Transport --> - 10.0.100-preview.5.25263.108 + 10.0.100-preview.5.25265.101 $(MicrosoftNETWorkloadEmscriptenCurrentManifest100100TransportVersion) 1.1.87-gba258badda diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index 7373e5305465d7..5f40a3f8238a8b 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -68,8 +68,6 @@ $ErrorActionPreference = 'Stop' # True if the build is a product build [bool]$productBuild = if (Test-Path variable:productBuild) { $productBuild } else { $false } -[String[]]$properties = if (Test-Path variable:properties) { $properties } else { @() } - function Create-Directory ([string[]] $path) { New-Item -Path $path -Force -ItemType 'Directory' | Out-Null } @@ -853,7 +851,7 @@ function MSBuild-Core() { # When running on Azure Pipelines, override the returned exit code to avoid double logging. # Skip this when the build is a child of the VMR orchestrator build. - if ($ci -and $env:SYSTEM_TEAMPROJECT -ne $null -and !$productBuild -and -not($properties -like "*DotNetBuildRepo=true*")) { + if ($ci -and $env:SYSTEM_TEAMPROJECT -ne $null -and !$productBuild) { Write-PipelineSetResult -Result "Failed" -Message "msbuild execution failed." # Exiting with an exit code causes the azure pipelines task to log yet another "noise" error # The above Write-PipelineSetResult will cause the task to be marked as failure without adding yet another error diff --git a/eng/common/tools.sh b/eng/common/tools.sh index cc007b1f15ad05..25f5932eee982a 100755 --- a/eng/common/tools.sh +++ b/eng/common/tools.sh @@ -507,7 +507,7 @@ function MSBuild-Core { # When running on Azure Pipelines, override the returned exit code to avoid double logging. # Skip this when the build is a child of the VMR orchestrator build. - if [[ "$ci" == true && -n ${SYSTEM_TEAMPROJECT:-} && "$product_build" != true && "$properties" != *"DotNetBuildRepo=true"* ]]; then + if [[ "$ci" == true && -n ${SYSTEM_TEAMPROJECT:-} && "$product_build" != true ]]; then Write-PipelineSetResult -result "Failed" -message "msbuild execution failed." # Exiting with an exit code causes the azure pipelines task to log yet another "noise" error # The above Write-PipelineSetResult will cause the task to be marked as failure without adding yet another error diff --git a/global.json b/global.json index c3a58690de0619..64a0bb7b61745d 100644 --- a/global.json +++ b/global.json @@ -8,11 +8,11 @@ "dotnet": "10.0.100-preview.3.25201.16" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25263.108", - "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25263.108", - "Microsoft.DotNet.SharedFramework.Sdk": "10.0.0-beta.25263.108", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25265.101", + "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25265.101", + "Microsoft.DotNet.SharedFramework.Sdk": "10.0.0-beta.25265.101", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", - "Microsoft.NET.Sdk.IL": "10.0.0-preview.5.25263.108" + "Microsoft.NET.Sdk.IL": "10.0.0-preview.5.25265.101" } } From 9235b2ca940e86187bc6c231e1be74d57fc03cb7 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Fri, 16 May 2025 07:18:39 +0000 Subject: [PATCH 05/11] [VMR] Codeflow ad85650-b1ecb85 [[ commit created by automation ]] --- eng/Subsets.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/Subsets.props b/eng/Subsets.props index 96c5cf476590ee..4aa019b3c8499b 100644 --- a/eng/Subsets.props +++ b/eng/Subsets.props @@ -83,7 +83,7 @@ - + true From b787a07b506f6dbfcdf342c5751cabfe3a079d1b Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Fri, 16 May 2025 07:18:50 +0000 Subject: [PATCH 06/11] Update dependencies from https://github.com/dotnet/dotnet build 268494 Updated Dependencies: System.CommandLine (Version 2.0.0-beta5.25265.101 -> 2.0.0-beta5.25260.104) Microsoft.DotNet.Cecil (Version 0.11.5-alpha.25265.101 -> 0.11.5-alpha.25260.104) Microsoft.NET.Workload.Emscripten.Current.Manifest-10.0.100.Transport, Microsoft.DotNet.ApiCompat.Task (Version 10.0.100-preview.5.25265.101 -> 10.0.100-preview.5.25260.104) Microsoft.DotNet.Arcade.Sdk, Microsoft.DotNet.XliffTasks, Microsoft.DotNet.Helix.Sdk, Microsoft.DotNet.GenAPI, Microsoft.DotNet.GenFacades, Microsoft.DotNet.XUnitExtensions, Microsoft.DotNet.Build.Tasks.Archives, Microsoft.DotNet.Build.Tasks.Packaging, Microsoft.DotNet.Build.Tasks.Installers, Microsoft.DotNet.Build.Tasks.Templating, Microsoft.DotNet.Build.Tasks.Workloads, Microsoft.DotNet.CodeAnalysis, Microsoft.DotNet.Build.Tasks.TargetFramework, Microsoft.DotNet.RemoteExecutor, Microsoft.DotNet.Build.Tasks.Feed, Microsoft.DotNet.SharedFramework.Sdk, Microsoft.DotNet.PackageTesting (Version 10.0.0-beta.25265.101 -> 10.0.0-beta.25260.104) Microsoft.DotNet.XUnitAssert, Microsoft.DotNet.XUnitConsoleRunner (Version 2.9.2-beta.25265.101 -> 2.9.2-beta.25260.104) Microsoft.NETCore.App.Runtime.win-x64, runtime.native.System.IO.Ports, Microsoft.NETCore.ILAsm, Microsoft.NET.Sdk.IL, System.Text.Json, System.Reflection.Metadata, System.Reflection.MetadataLoadContext (Version 10.0.0-preview.5.25265.101 -> 10.0.0-preview.5.25260.104) Microsoft.Net.Compilers.Toolset, Microsoft.CodeAnalysis, Microsoft.CodeAnalysis.CSharp, Microsoft.CodeAnalysis.Analyzers (Version 5.0.0-1.25265.101 -> 5.0.0-1.25260.104) Microsoft.CodeAnalysis.NetAnalyzers (Version 10.0.0-preview.25265.101 -> 10.0.0-preview.25260.104) --- eng/Version.Details.xml | 142 ++++++++++++++++++++-------------------- eng/Versions.props | 64 +++++++++--------- eng/common/build.ps1 | 2 +- eng/common/build.sh | 6 +- global.json | 12 ++-- 5 files changed, 113 insertions(+), 113 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index d8fff638db1bd7..f10dc6857daf17 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,5 +1,5 @@ - + https://github.com/dotnet/icu @@ -41,91 +41,91 @@ https://github.com/dotnet/llvm-project da5dd054a531e6fea65643b7e754285b73eab433 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 https://github.com/dotnet/runtime-assets @@ -263,33 +263,33 @@ https://github.com/dotnet/llvm-project da5dd054a531e6fea65643b7e754285b73eab433 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 https://github.com/dotnet/xharness @@ -303,9 +303,9 @@ https://github.com/dotnet/xharness e85bb14e85357ab678c2bcb0b6f2bac634fdd49b - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization @@ -331,29 +331,29 @@ https://github.com/dotnet/runtime-assets 1cfc6ba21d0377b51f17eac4fdc2557f7b1e8693 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 - + https://github.com/dotnet/dotnet - ad8565092bbfdd5c8b4a94a718d10b2d394f7aee + b1ecb85a159b533cda852c2e90fb12c348982ee1 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization diff --git a/eng/Versions.props b/eng/Versions.props index ddf9a537dbe093..7dd2c34845987f 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -36,17 +36,17 @@ - 10.0.0-preview.25265.101 + 10.0.0-preview.25265.106 - 5.0.0-1.25265.101 + 5.0.0-1.25265.106 - 5.0.0-1.25265.101 - 5.0.0-1.25265.101 - 5.0.0-1.25265.101 + 5.0.0-1.25265.106 + 5.0.0-1.25265.106 + 5.0.0-1.25265.106 - 10.0.100-preview.5.25265.101 + 10.0.100-preview.5.25265.106 - 10.0.0-beta.25265.101 - 10.0.0-beta.25265.101 - 10.0.0-beta.25265.101 - 10.0.0-beta.25265.101 - 2.9.2-beta.25265.101 - 10.0.0-beta.25265.101 - 2.9.2-beta.25265.101 - 10.0.0-beta.25265.101 - 10.0.0-beta.25265.101 - 10.0.0-beta.25265.101 - 10.0.0-beta.25265.101 - 10.0.0-beta.25265.101 - 10.0.0-beta.25265.101 - 10.0.0-beta.25265.101 - 10.0.0-beta.25265.101 - 10.0.0-beta.25265.101 + 10.0.0-beta.25265.106 + 10.0.0-beta.25265.106 + 10.0.0-beta.25265.106 + 10.0.0-beta.25265.106 + 2.9.2-beta.25265.106 + 10.0.0-beta.25265.106 + 2.9.2-beta.25265.106 + 10.0.0-beta.25265.106 + 10.0.0-beta.25265.106 + 10.0.0-beta.25265.106 + 10.0.0-beta.25265.106 + 10.0.0-beta.25265.106 + 10.0.0-beta.25265.106 + 10.0.0-beta.25265.106 + 10.0.0-beta.25265.106 + 10.0.0-beta.25265.106 1.4.0 6.0.0-preview.1.102 - 10.0.0-preview.5.25265.101 + 10.0.0-preview.5.25265.106 6.0.0 - 10.0.0-preview.5.25265.101 - 10.0.0-preview.5.25265.101 + 10.0.0-preview.5.25265.106 + 10.0.0-preview.5.25265.106 6.0.0 4.6.1 @@ -128,16 +128,16 @@ 8.0.0 8.0.1 5.0.0 - 10.0.0-preview.5.25265.101 - 10.0.0-preview.5.25265.101 + 10.0.0-preview.5.25265.106 + 10.0.0-preview.5.25265.106 6.0.0 5.0.0 5.0.0 5.0.0 7.0.0 - 10.0.0-preview.5.25265.101 + 10.0.0-preview.5.25265.106 7.0.0 - 10.0.0-preview.5.25265.101 + 10.0.0-preview.5.25265.106 8.0.0 4.5.1 @@ -180,7 +180,7 @@ 2.0.0 17.10.0-beta1.24272.1 - 2.0.0-beta5.25265.101 + 2.0.0-beta5.25265.106 3.1.16 2.1.0 2.0.3 @@ -226,7 +226,7 @@ 9.0.0-preview-20241010.1 - 0.11.5-alpha.25265.101 + 0.11.5-alpha.25265.106 10.0.0-preview.5.25261.1 @@ -258,7 +258,7 @@ Note: when the name is updated, make sure to update dependency name in eng/pipelines/common/xplat-setup.yml like - DarcDependenciesChanged.Microsoft_NET_Workload_Emscripten_Current_Manifest-10_0_100_Transport --> - 10.0.100-preview.5.25265.101 + 10.0.100-preview.5.25265.106 $(MicrosoftNETWorkloadEmscriptenCurrentManifest100100TransportVersion) 1.1.87-gba258badda diff --git a/eng/common/build.ps1 b/eng/common/build.ps1 index 6b3be1916fcaf5..ae2309e312d789 100644 --- a/eng/common/build.ps1 +++ b/eng/common/build.ps1 @@ -127,7 +127,7 @@ function Build { /p:Deploy=$deploy ` /p:Test=$test ` /p:Pack=$pack ` - /p:DotNetBuildRepo=$productBuild ` + /p:DotNetBuild=$productBuild ` /p:IntegrationTest=$integrationTest ` /p:PerformanceTest=$performanceTest ` /p:Sign=$sign ` diff --git a/eng/common/build.sh b/eng/common/build.sh index 27ae2c85601f07..da906da202626d 100755 --- a/eng/common/build.sh +++ b/eng/common/build.sh @@ -129,14 +129,14 @@ while [[ $# > 0 ]]; do -pack) pack=true ;; - -sourcebuild|-sb) + -sourcebuild|-source-build|-sb) build=true source_build=true product_build=true restore=true pack=true ;; - -productbuild|-pb) + -productbuild|-product-build|-pb) build=true product_build=true restore=true @@ -241,7 +241,7 @@ function Build { /p:RepoRoot="$repo_root" \ /p:Restore=$restore \ /p:Build=$build \ - /p:DotNetBuildRepo=$product_build \ + /p:DotNetBuild=$product_build \ /p:DotNetBuildSourceOnly=$source_build \ /p:Rebuild=$rebuild \ /p:Test=$test \ diff --git a/global.json b/global.json index 64a0bb7b61745d..c24456f28a27cb 100644 --- a/global.json +++ b/global.json @@ -1,18 +1,18 @@ { "sdk": { - "version": "10.0.100-preview.3.25201.16", + "version": "10.0.100-preview.5.25230.108", "allowPrerelease": true, "rollForward": "major" }, "tools": { - "dotnet": "10.0.100-preview.3.25201.16" + "dotnet": "10.0.100-preview.5.25230.108" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25265.101", - "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25265.101", - "Microsoft.DotNet.SharedFramework.Sdk": "10.0.0-beta.25265.101", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25265.106", + "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25265.106", + "Microsoft.DotNet.SharedFramework.Sdk": "10.0.0-beta.25265.106", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", - "Microsoft.NET.Sdk.IL": "10.0.0-preview.5.25265.101" + "Microsoft.NET.Sdk.IL": "10.0.0-preview.5.25265.106" } } From 0b7c54ecc61efb763f153588ae84fb671b9934c8 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Sat, 17 May 2025 02:03:05 +0000 Subject: [PATCH 07/11] Update dependencies from https://github.com/dotnet/dotnet build 268651 Updated Dependencies: System.CommandLine (Version 2.0.0-beta5.25265.106 -> 2.0.0-beta5.25260.104) Microsoft.DotNet.Cecil (Version 0.11.5-alpha.25265.106 -> 0.11.5-alpha.25260.104) Microsoft.NET.Workload.Emscripten.Current.Manifest-10.0.100.Transport, Microsoft.DotNet.ApiCompat.Task (Version 10.0.100-preview.5.25265.106 -> 10.0.100-preview.5.25260.104) Microsoft.DotNet.Arcade.Sdk, Microsoft.DotNet.XliffTasks, Microsoft.DotNet.Helix.Sdk, Microsoft.DotNet.GenAPI, Microsoft.DotNet.GenFacades, Microsoft.DotNet.XUnitExtensions, Microsoft.DotNet.Build.Tasks.Archives, Microsoft.DotNet.Build.Tasks.Packaging, Microsoft.DotNet.Build.Tasks.Installers, Microsoft.DotNet.Build.Tasks.Templating, Microsoft.DotNet.Build.Tasks.Workloads, Microsoft.DotNet.CodeAnalysis, Microsoft.DotNet.Build.Tasks.TargetFramework, Microsoft.DotNet.RemoteExecutor, Microsoft.DotNet.Build.Tasks.Feed, Microsoft.DotNet.SharedFramework.Sdk, Microsoft.DotNet.PackageTesting (Version 10.0.0-beta.25265.106 -> 10.0.0-beta.25260.104) Microsoft.DotNet.XUnitAssert, Microsoft.DotNet.XUnitConsoleRunner (Version 2.9.2-beta.25265.106 -> 2.9.2-beta.25260.104) Microsoft.NETCore.App.Runtime.win-x64, runtime.native.System.IO.Ports, Microsoft.NETCore.ILAsm, Microsoft.NET.Sdk.IL, System.Text.Json, System.Reflection.Metadata, System.Reflection.MetadataLoadContext (Version 10.0.0-preview.5.25265.106 -> 10.0.0-preview.5.25260.104) Microsoft.Net.Compilers.Toolset, Microsoft.CodeAnalysis, Microsoft.CodeAnalysis.CSharp, Microsoft.CodeAnalysis.Analyzers (Version 5.0.0-1.25265.106 -> 5.0.0-1.25260.104) Microsoft.CodeAnalysis.NetAnalyzers (Version 10.0.0-preview.25265.106 -> 10.0.0-preview.25260.104) --- eng/Version.Details.xml | 142 ++++++++++++++++++++-------------------- eng/Versions.props | 64 +++++++++--------- global.json | 12 ++-- 3 files changed, 109 insertions(+), 109 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index f10dc6857daf17..acdfb70e9a3af8 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,5 +1,5 @@ - + https://github.com/dotnet/icu @@ -41,91 +41,91 @@ https://github.com/dotnet/llvm-project da5dd054a531e6fea65643b7e754285b73eab433 - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c https://github.com/dotnet/runtime-assets @@ -263,33 +263,33 @@ https://github.com/dotnet/llvm-project da5dd054a531e6fea65643b7e754285b73eab433 - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c https://github.com/dotnet/xharness @@ -303,9 +303,9 @@ https://github.com/dotnet/xharness e85bb14e85357ab678c2bcb0b6f2bac634fdd49b - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c https://dev.azure.com/dnceng/internal/_git/dotnet-optimization @@ -331,29 +331,29 @@ https://github.com/dotnet/runtime-assets 1cfc6ba21d0377b51f17eac4fdc2557f7b1e8693 - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c - + https://github.com/dotnet/dotnet - b1ecb85a159b533cda852c2e90fb12c348982ee1 + 604dfc7f29729283704bee27b1e844c1fa044b9c https://dev.azure.com/dnceng/internal/_git/dotnet-optimization diff --git a/eng/Versions.props b/eng/Versions.props index 7dd2c34845987f..660fc5ddd69210 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -36,17 +36,17 @@ - 10.0.0-preview.25265.106 + 10.0.0-preview.25266.103 - 5.0.0-1.25265.106 + 5.0.0-1.25266.103 - 5.0.0-1.25265.106 - 5.0.0-1.25265.106 - 5.0.0-1.25265.106 + 5.0.0-1.25266.103 + 5.0.0-1.25266.103 + 5.0.0-1.25266.103 - 10.0.100-preview.5.25265.106 + 10.0.100-preview.5.25266.103 - 10.0.0-beta.25265.106 - 10.0.0-beta.25265.106 - 10.0.0-beta.25265.106 - 10.0.0-beta.25265.106 - 2.9.2-beta.25265.106 - 10.0.0-beta.25265.106 - 2.9.2-beta.25265.106 - 10.0.0-beta.25265.106 - 10.0.0-beta.25265.106 - 10.0.0-beta.25265.106 - 10.0.0-beta.25265.106 - 10.0.0-beta.25265.106 - 10.0.0-beta.25265.106 - 10.0.0-beta.25265.106 - 10.0.0-beta.25265.106 - 10.0.0-beta.25265.106 + 10.0.0-beta.25266.103 + 10.0.0-beta.25266.103 + 10.0.0-beta.25266.103 + 10.0.0-beta.25266.103 + 2.9.2-beta.25266.103 + 10.0.0-beta.25266.103 + 2.9.2-beta.25266.103 + 10.0.0-beta.25266.103 + 10.0.0-beta.25266.103 + 10.0.0-beta.25266.103 + 10.0.0-beta.25266.103 + 10.0.0-beta.25266.103 + 10.0.0-beta.25266.103 + 10.0.0-beta.25266.103 + 10.0.0-beta.25266.103 + 10.0.0-beta.25266.103 1.4.0 6.0.0-preview.1.102 - 10.0.0-preview.5.25265.106 + 10.0.0-preview.5.25266.103 6.0.0 - 10.0.0-preview.5.25265.106 - 10.0.0-preview.5.25265.106 + 10.0.0-preview.5.25266.103 + 10.0.0-preview.5.25266.103 6.0.0 4.6.1 @@ -128,16 +128,16 @@ 8.0.0 8.0.1 5.0.0 - 10.0.0-preview.5.25265.106 - 10.0.0-preview.5.25265.106 + 10.0.0-preview.5.25266.103 + 10.0.0-preview.5.25266.103 6.0.0 5.0.0 5.0.0 5.0.0 7.0.0 - 10.0.0-preview.5.25265.106 + 10.0.0-preview.5.25266.103 7.0.0 - 10.0.0-preview.5.25265.106 + 10.0.0-preview.5.25266.103 8.0.0 4.5.1 @@ -180,7 +180,7 @@ 2.0.0 17.10.0-beta1.24272.1 - 2.0.0-beta5.25265.106 + 2.0.0-beta5.25266.103 3.1.16 2.1.0 2.0.3 @@ -226,7 +226,7 @@ 9.0.0-preview-20241010.1 - 0.11.5-alpha.25265.106 + 0.11.5-alpha.25266.103 10.0.0-preview.5.25261.1 @@ -258,7 +258,7 @@ Note: when the name is updated, make sure to update dependency name in eng/pipelines/common/xplat-setup.yml like - DarcDependenciesChanged.Microsoft_NET_Workload_Emscripten_Current_Manifest-10_0_100_Transport --> - 10.0.100-preview.5.25265.106 + 10.0.100-preview.5.25266.103 $(MicrosoftNETWorkloadEmscriptenCurrentManifest100100TransportVersion) 1.1.87-gba258badda diff --git a/global.json b/global.json index c24456f28a27cb..5c0d27836ba42f 100644 --- a/global.json +++ b/global.json @@ -1,18 +1,18 @@ { "sdk": { - "version": "10.0.100-preview.5.25230.108", + "version": "10.0.100-preview.5.25265.106", "allowPrerelease": true, "rollForward": "major" }, "tools": { - "dotnet": "10.0.100-preview.5.25230.108" + "dotnet": "10.0.100-preview.5.25265.106" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25265.106", - "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25265.106", - "Microsoft.DotNet.SharedFramework.Sdk": "10.0.0-beta.25265.106", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25266.103", + "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25266.103", + "Microsoft.DotNet.SharedFramework.Sdk": "10.0.0-beta.25266.103", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", - "Microsoft.NET.Sdk.IL": "10.0.0-preview.5.25265.106" + "Microsoft.NET.Sdk.IL": "10.0.0-preview.5.25266.103" } } From dc8ff8ffdca777375a9aad48d88086d918396fa4 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Sun, 18 May 2025 02:03:14 +0000 Subject: [PATCH 08/11] [VMR] Codeflow 1307a67-1307a67 [[ commit created by automation ]] From 87d79505f0aa006beb076853267967d448a1d71a Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Sun, 18 May 2025 02:03:25 +0000 Subject: [PATCH 09/11] Update dependencies from https://github.com/dotnet/dotnet build 268722 No dependency updates to commit --- eng/Version.Details.xml | 142 ++++++++++++++++++++-------------------- eng/Versions.props | 64 +++++++++--------- global.json | 8 +-- 3 files changed, 107 insertions(+), 107 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index acdfb70e9a3af8..e8a2ee453aaa30 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,5 +1,5 @@ - + https://github.com/dotnet/icu @@ -41,91 +41,91 @@ https://github.com/dotnet/llvm-project da5dd054a531e6fea65643b7e754285b73eab433 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 https://github.com/dotnet/runtime-assets @@ -263,33 +263,33 @@ https://github.com/dotnet/llvm-project da5dd054a531e6fea65643b7e754285b73eab433 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 https://github.com/dotnet/xharness @@ -303,9 +303,9 @@ https://github.com/dotnet/xharness e85bb14e85357ab678c2bcb0b6f2bac634fdd49b - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization @@ -331,29 +331,29 @@ https://github.com/dotnet/runtime-assets 1cfc6ba21d0377b51f17eac4fdc2557f7b1e8693 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 - + https://github.com/dotnet/dotnet - 604dfc7f29729283704bee27b1e844c1fa044b9c + 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization diff --git a/eng/Versions.props b/eng/Versions.props index 660fc5ddd69210..2ee5e9f7799fde 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -36,17 +36,17 @@ - 10.0.0-preview.25266.103 + 10.0.0-preview.25267.102 - 5.0.0-1.25266.103 + 5.0.0-1.25267.102 - 5.0.0-1.25266.103 - 5.0.0-1.25266.103 - 5.0.0-1.25266.103 + 5.0.0-1.25267.102 + 5.0.0-1.25267.102 + 5.0.0-1.25267.102 - 10.0.100-preview.5.25266.103 + 10.0.100-preview.5.25267.102 - 10.0.0-beta.25266.103 - 10.0.0-beta.25266.103 - 10.0.0-beta.25266.103 - 10.0.0-beta.25266.103 - 2.9.2-beta.25266.103 - 10.0.0-beta.25266.103 - 2.9.2-beta.25266.103 - 10.0.0-beta.25266.103 - 10.0.0-beta.25266.103 - 10.0.0-beta.25266.103 - 10.0.0-beta.25266.103 - 10.0.0-beta.25266.103 - 10.0.0-beta.25266.103 - 10.0.0-beta.25266.103 - 10.0.0-beta.25266.103 - 10.0.0-beta.25266.103 + 10.0.0-beta.25267.102 + 10.0.0-beta.25267.102 + 10.0.0-beta.25267.102 + 10.0.0-beta.25267.102 + 2.9.2-beta.25267.102 + 10.0.0-beta.25267.102 + 2.9.2-beta.25267.102 + 10.0.0-beta.25267.102 + 10.0.0-beta.25267.102 + 10.0.0-beta.25267.102 + 10.0.0-beta.25267.102 + 10.0.0-beta.25267.102 + 10.0.0-beta.25267.102 + 10.0.0-beta.25267.102 + 10.0.0-beta.25267.102 + 10.0.0-beta.25267.102 1.4.0 6.0.0-preview.1.102 - 10.0.0-preview.5.25266.103 + 10.0.0-preview.5.25267.102 6.0.0 - 10.0.0-preview.5.25266.103 - 10.0.0-preview.5.25266.103 + 10.0.0-preview.5.25267.102 + 10.0.0-preview.5.25267.102 6.0.0 4.6.1 @@ -128,16 +128,16 @@ 8.0.0 8.0.1 5.0.0 - 10.0.0-preview.5.25266.103 - 10.0.0-preview.5.25266.103 + 10.0.0-preview.5.25267.102 + 10.0.0-preview.5.25267.102 6.0.0 5.0.0 5.0.0 5.0.0 7.0.0 - 10.0.0-preview.5.25266.103 + 10.0.0-preview.5.25267.102 7.0.0 - 10.0.0-preview.5.25266.103 + 10.0.0-preview.5.25267.102 8.0.0 4.5.1 @@ -180,7 +180,7 @@ 2.0.0 17.10.0-beta1.24272.1 - 2.0.0-beta5.25266.103 + 2.0.0-beta5.25267.102 3.1.16 2.1.0 2.0.3 @@ -226,7 +226,7 @@ 9.0.0-preview-20241010.1 - 0.11.5-alpha.25266.103 + 0.11.5-alpha.25267.102 10.0.0-preview.5.25261.1 @@ -258,7 +258,7 @@ Note: when the name is updated, make sure to update dependency name in eng/pipelines/common/xplat-setup.yml like - DarcDependenciesChanged.Microsoft_NET_Workload_Emscripten_Current_Manifest-10_0_100_Transport --> - 10.0.100-preview.5.25266.103 + 10.0.100-preview.5.25267.102 $(MicrosoftNETWorkloadEmscriptenCurrentManifest100100TransportVersion) 1.1.87-gba258badda diff --git a/global.json b/global.json index 5c0d27836ba42f..714fecff2d503a 100644 --- a/global.json +++ b/global.json @@ -8,11 +8,11 @@ "dotnet": "10.0.100-preview.5.25265.106" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25266.103", - "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25266.103", - "Microsoft.DotNet.SharedFramework.Sdk": "10.0.0-beta.25266.103", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25267.102", + "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25267.102", + "Microsoft.DotNet.SharedFramework.Sdk": "10.0.0-beta.25267.102", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", - "Microsoft.NET.Sdk.IL": "10.0.0-preview.5.25266.103" + "Microsoft.NET.Sdk.IL": "10.0.0-preview.5.25267.102" } } From eb774c2f78cf10029e5729ecac86d098e2d1c377 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Wed, 21 May 2025 02:03:40 +0000 Subject: [PATCH 10/11] [VMR] Codeflow 29638e8-29638e8 [[ commit created by automation ]] --- NuGet.config | 2 + docs/design/coreclr/jit/GC-write-barriers.md | 101 ++ eng/testing/tests.browser.targets | 5 +- eng/testing/tests.wasm.targets | 1 + src/coreclr/clrdefinitions.cmake | 4 - src/coreclr/debug/daccess/enummem.cpp | 5 - src/coreclr/inc/executableallocator.h | 15 - src/coreclr/inc/loaderheap.h | 24 +- src/coreclr/interpreter/compiler.cpp | 8 + src/coreclr/interpreter/intops.def | 1 + src/coreclr/jit/async.cpp | 32 + src/coreclr/jit/compiler.h | 50 +- src/coreclr/jit/gentree.cpp | 20 +- src/coreclr/jit/hwintrinsiccodegenxarch.cpp | 51 - src/coreclr/jit/hwintrinsicxarch.cpp | 28 + src/coreclr/jit/importer.cpp | 5 +- src/coreclr/jit/inductionvariableopts.cpp | 274 +++-- src/coreclr/jit/jitconfigvalues.h | 3 + src/coreclr/jit/lowerxarch.cpp | 9 +- src/coreclr/jit/morph.cpp | 73 +- src/coreclr/jit/promotion.cpp | 31 + src/coreclr/jit/promotiondecomposition.cpp | 27 + src/coreclr/jit/promotionliveness.cpp | 84 +- src/coreclr/jit/rationalize.cpp | 51 + src/coreclr/jit/scev.cpp | 44 +- src/coreclr/minipal/Unix/doublemapping.cpp | 323 ----- src/coreclr/minipal/Windows/doublemapping.cpp | 20 - src/coreclr/minipal/minipal.h | 35 - .../nativeaot/Runtime/unix/PalRedhawkUnix.cpp | 2 +- src/coreclr/pal/inc/unixasmmacrosarm64.inc | 7 + src/coreclr/utilcode/executableallocator.cpp | 76 +- .../utilcode/interleavedloaderheap.cpp | 98 +- src/coreclr/vm/CMakeLists.txt | 3 +- src/coreclr/vm/amd64/thunktemplates.S | 146 --- src/coreclr/vm/arm64/asmhelpers.S | 77 -- src/coreclr/vm/arm64/asmhelpers.asm | 78 -- src/coreclr/vm/arm64/patchedcode.S | 379 +++++- src/coreclr/vm/arm64/patchedcode.asm | 456 ++++++-- src/coreclr/vm/arm64/patchedcodeconstants.h | 35 + src/coreclr/vm/arm64/stubs.cpp | 58 +- src/coreclr/vm/arm64/thunktemplates.S | 111 -- src/coreclr/vm/callcounting.cpp | 27 +- src/coreclr/vm/callcounting.h | 2 +- src/coreclr/vm/codeman.cpp | 30 +- src/coreclr/vm/codeman.h | 12 +- src/coreclr/vm/debuginfostore.cpp | 13 +- src/coreclr/vm/debuginfostore.h | 2 +- src/coreclr/vm/finalizerthread.cpp | 8 +- src/coreclr/vm/gc_unwind_x86.inl | 7 +- src/coreclr/vm/gcenv.ee.cpp | 25 +- src/coreclr/vm/interpexec.cpp | 13 + src/coreclr/vm/jitinterface.h | 64 - src/coreclr/vm/jitinterfacegen.cpp | 5 +- src/coreclr/vm/loaderallocator.cpp | 9 +- src/coreclr/vm/method.cpp | 19 +- src/coreclr/vm/precode.cpp | 53 +- src/coreclr/vm/precode.h | 9 +- src/coreclr/vm/profdetach.cpp | 3 - src/coreclr/vm/profilinghelper.cpp | 7 - ...rfaceamd64.cpp => writebarriermanager.cpp} | 1036 +++++++++-------- src/coreclr/vm/writebarriermanager.h | 98 ++ .../Security/Cryptography/CryptoPool.cs | 4 +- .../PrivateKeyAssociationTests.Shared.cs | 151 +++ .../X509Certificates/MLKemCertTests.cs | 2 +- .../X509CertificateKeyAccessors.cs | 133 ++- .../Microsoft.Bcl.Cryptography.Tests.csproj | 2 + .../PrivateKeyAssociationTests.cs | 9 + .../src/System/Collections/Generic/Stack.cs | 2 +- .../src/System.Net.Mail.csproj | 1 + .../src/System/Net/BufferBuilder.cs | 7 + .../src/System/Net/Mail/MailMessage.cs | 27 +- .../src/System/Net/Mail/MailPriority.cs | 99 +- .../src/System/Net/Mail/MailWriter.cs | 2 +- .../src/System/Net/Mail/ReadWriteAdapter.cs | 61 + .../src/System/Net/Mail/SmtpClient.cs | 5 +- .../src/System/Net/Mail/SmtpCommands.cs | 506 ++++---- .../src/System/Net/Mail/SmtpConnection.cs | 18 +- .../src/System/Net/Mail/SmtpReplyReader.cs | 64 +- .../System/Net/Mail/SmtpReplyReaderFactory.cs | 215 +--- .../src/System/Net/Mail/SmtpTransport.cs | 2 +- .../src/System/Net/Mime/BaseWriter.cs | 69 +- .../src/System/Net/Mime/MimeBasePart.cs | 46 +- .../src/System/Net/Mime/MimeMultiPart.cs | 182 +-- .../src/System/Net/Mime/MimePart.cs | 175 +-- .../src/System/Net/Mime/MimeWriter.cs | 28 +- .../tests/Functional/LoggingTest.cs | 2 +- .../Functional/LoopbackServerTestBase.cs | 6 +- .../tests/Functional/LoopbackSmtpServer.cs | 5 +- .../tests/Functional/MailMessageTest.cs | 15 +- .../Functional/SmtpClientConnectionTest.cs | 11 + .../tests/Functional/SmtpClientTest.cs | 14 +- .../Unit/System.Net.Mail.Unit.Tests.csproj | 2 + .../src/System/Collections/Generic/Queue.cs | 2 +- .../src/System/Double.cs | 2 +- .../src/System/Numerics/Vector2.cs | 4 +- .../src/System/Numerics/Vector3.cs | 4 +- .../Runtime/CompilerServices/AsyncHelpers.cs | 21 + .../CompilerServices/RuntimeFeature.cs | 10 +- .../System/Runtime/InteropServices/NFloat.cs | 4 +- .../System/Runtime/Intrinsics/Vector128.cs | 4 +- .../System/Runtime/Intrinsics/Vector256.cs | 4 +- .../System/Runtime/Intrinsics/Vector512.cs | 4 +- .../System/Runtime/Intrinsics/Vector64_1.cs | 2 +- .../src/System/Single.cs | 2 +- .../System.Runtime/ref/System.Runtime.cs | 10 + .../PrivateKeyAssociationTests.cs | 96 +- .../gen/RegexGenerator.Emitter.cs | 52 +- .../RegexGeneratorOutputTests.cs | 202 +++- src/mono/browser/build/BrowserWasmApp.targets | 1 - .../browser/runtime/jiterpreter-opcodes.ts | 21 + .../runtime/jiterpreter-trace-generator.ts | 6 +- src/mono/browser/runtime/loader/globals.ts | 3 +- src/mono/browser/runtime/startup.ts | 8 +- src/mono/browser/runtime/types/internal.ts | 2 + .../CMakeLists.txt | 5 +- .../CMakeLists.txt | 4 + src/native/libs/System.Native/CMakeLists.txt | 4 + .../CMakeLists.txt | 4 + .../Contracts/StackWalk/Context/Unwinder.cs | 15 +- src/tasks/AndroidAppBuilder/ApkBuilder.cs | 26 +- .../CoreclrTestWrapperLib.cs | 33 +- src/tests/Directory.Build.props | 5 + src/tests/async/Directory.Build.props | 4 + .../RuntimeAsyncMethodGenerationAttribute.cs | 10 + .../awaitingnotasync/awaitingnotasync.cs | 7 +- .../async/collectible-alc/collectible-alc.cs | 6 +- .../cse-array-index-byref.cs | 3 +- .../async/eh-microbench/eh-microbench.cs | 10 +- .../fibonacci-with-yields.cs | 5 +- .../fibonacci-with-yields_struct_return.cs | 5 +- .../fibonacci-without-yields-config-await.cs | 4 +- .../fibonacci-without-yields.cs | 5 +- .../async/gc-roots-scan/gc-roots-scan.cs | 4 +- src/tests/async/implement/implement.cs | 8 +- .../mincallcost-microbench.cs | 29 +- src/tests/async/object/object.cs | 3 +- .../objects-captured/objects-captured.cs | 4 +- src/tests/async/override/override.cs | 9 +- src/tests/async/pgo/pgo.cs | 12 +- src/tests/async/pinvoke/pinvoke.cs | 2 +- src/tests/async/returns/returns.cs | 10 +- .../async/shared-generic/shared-generic.cs | 17 +- src/tests/async/simple-eh/simple-eh.cs | 5 +- src/tests/async/simple-eh/simple-eh.csproj | 1 + src/tests/async/small/small.cs | 2 +- .../strength-reduction/strength-reduction.cs | 29 + .../strength-reduction.csproj | 8 + src/tests/async/struct/struct.cs | 8 +- .../taskbased-asyncfibonacci-with-yields.cs | 2 + ...taskbased-asyncfibonacci-without-yields.cs | 2 + src/tests/async/valuetask/valuetask.cs | 2 +- ...luetaskbased-asyncfibonacci-with-yields.cs | 2 + ...taskbased-asyncfibonacci-without-yields.cs | 2 + .../async/varying-yields/varying-yields.cs | 28 +- src/tests/async/void/void.cs | 3 +- src/tests/async/with-yields/with-yields.cs | 5 +- .../async/without-yields/without-yields.cs | 5 +- src/tests/build.proj | 7 +- 158 files changed, 3511 insertions(+), 3476 deletions(-) create mode 100644 docs/design/coreclr/jit/GC-write-barriers.md create mode 100644 src/coreclr/vm/arm64/patchedcodeconstants.h rename src/coreclr/vm/{amd64/jitinterfaceamd64.cpp => writebarriermanager.cpp} (87%) create mode 100644 src/coreclr/vm/writebarriermanager.h create mode 100644 src/libraries/System.Net.Mail/src/System/Net/Mail/ReadWriteAdapter.cs create mode 100644 src/tests/async/RuntimeAsyncMethodGenerationAttribute.cs create mode 100644 src/tests/async/strength-reduction/strength-reduction.cs create mode 100644 src/tests/async/strength-reduction/strength-reduction.csproj diff --git a/NuGet.config b/NuGet.config index b8539443065853..240b4807a1aa17 100644 --- a/NuGet.config +++ b/NuGet.config @@ -19,6 +19,8 @@ + + diff --git a/docs/design/coreclr/jit/GC-write-barriers.md b/docs/design/coreclr/jit/GC-write-barriers.md new file mode 100644 index 00000000000000..c0b58e572d5d4f --- /dev/null +++ b/docs/design/coreclr/jit/GC-write-barriers.md @@ -0,0 +1,101 @@ +# GC write barriers + +The GC write barrier function (JIT_WriteBarrier) is generally the hottest function in CoreCLR and is written in assembly. The full pseudo code for the function is as follows: + + +```` +JIT_WriteBarrier(Object **dst, Object *ref) + Set *dst = ref + + // Shadow Heap update + ifdef WRITE_BARRIER_CHECK: // Only set in DEBUG mode + if g_GCShadow != 0: + long *shadow_dst = g_GCShadow + (dst - g_lowest_address) + // Check shadow heap location is within shadow heap + if shadow_dst < g_GCShadowEnd: + *shadow_dst = ref + atomic: wait for stores to complete + if *dst != ref: + *shadow_dst = INVALIDGCVALUE + + // Update the write watch table, if it's in use + ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP: + if g_sw_ww_table != 0: + char *ww_table_dst = g_sw_ww_table + (dst>>11) + if *ww_table_dst != 0: + *ww_table_dst = 0xff + + // Return if the reference is not in ephemeral generations + if ref < g_ephemeral_low || ref >= g_ephemeral_high: + return + + // Region Checks + if g_region_to_generation_table != 0: + + // Calculate region generations + char reg_loc_dst = *((dst >> g_region_shr) + g_region_to_generation_table) + char reg_loc_ref = *((ref >> g_region_shr) + g_region_to_generation_table) + + // Return if the region we're storing into is Gen 0 + if reg_loc_dst == 0: + return + + // Return if the new reference is not from old to young + if reg_loc_ref >= reg_loc_dst: + return + + // Bitwise write barriers only + if g_region_use_bitwise_write_barrier: + + char *card_table_dst = (dst >> 11) + g_card_table + char dst_bit = 1 << (dst >> 8 && 7) + + // Check if we need to update the card table + if *card_table_dst & dst_bit == 0: + return + + // Atomically update the card table + lock: *card_table_dst |= dst_bit + + goto CardBundle + + // Check if we need to update the card table + char *card_table_dst = (dst >> 11) + g_card_table + if *card_table_dst == 0xff: + return + + // Update the card table + *card_table_dst = 0xff + +CardBundle: + + // Mark the card bundle table as dirty + Ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES: + char card_bundle_dst = (dst >> 21) + g_card_bundle_table + if *card_bundle_dst != 0xff: + *card_bundle_dst = 0xff + +```` + +The Checked Write Barrier has additional checks: + +```` +JIT_CheckedWriteBarrier(Object **dst, Object *ref) + + // Return if the destination is not on the heap + if ref < g_lowest_address || ref >= g_highest_address: + return + + return JIT_WriteBarrier(dst, ref) +```` + +## WriteBarrierManager + +On AMD64 and Arm64, there several different implementations of the write barrier function. Each version is a subset of the `JIT_WriteBarrier` above, assuming different state, meaning most `if` checks can be skipped. The actual write barrier that is called is a copy of one of these implementations. + +The WriteBarrierManager keeps track of which implementation is currently being used. As internal state changes, the WriteBarrierManager updates the copy to the correct implementation. In practice, most of the internal state is fixed on startup, with only changes to/from use of write watch barriers changing during runtime. + +`WRITE_BARRIER_CHECK` is only set in `DEBUG` mode. On Arm64 `WRITE_BARRIER_CHECK` checks exist at the top of each version of the function when `DEBUG` mode is enabled. On `Amd64` these checks do not exist. Instead, a special `JIT_WriteBarrier_Debug` version of the function exists, which contains most of the functionality of `JIT_WriteBarrier` pseudo code and is used exclusively when `DEBUG` mode is enabled. + +On Arm64, `g_region_use_bitwise_write_barrier` is only set if LSE atomics are present on the hardware, as only LSE provides a single instruction to atomically update a byte via a bitwise OR. + diff --git a/eng/testing/tests.browser.targets b/eng/testing/tests.browser.targets index d591b8a608bebe..4264bde6d01999 100644 --- a/eng/testing/tests.browser.targets +++ b/eng/testing/tests.browser.targets @@ -13,9 +13,10 @@ - false + true + false true <_WasmMainJSFileName Condition="'$(WasmMainJSPath)' != ''">$([System.IO.Path]::GetFileName('$(WasmMainJSPath)')) diff --git a/eng/testing/tests.wasm.targets b/eng/testing/tests.wasm.targets index 10148f9c8effc5..a5aed85a7fcd2a 100644 --- a/eng/testing/tests.wasm.targets +++ b/eng/testing/tests.wasm.targets @@ -133,6 +133,7 @@ <_WasmPropertyNames Include="WasmDedup" /> <_WasmPropertyNames Include="WasmLinkIcalls" /> <_WasmPropertyNames Include="WasmNativeStrip" /> + <_WasmPropertyNames Include="WasmNativeDebugSymbols" /> <_WasmPropertyNames Include="_WasmDevel" /> <_WasmPropertyNames Include="_WasmStrictVersionMatch" /> <_WasmPropertyNames Include="WasmEmitSymbolMap" /> diff --git a/src/coreclr/clrdefinitions.cmake b/src/coreclr/clrdefinitions.cmake index cb3b645ff0e58d..efb6ab0738a1a5 100644 --- a/src/coreclr/clrdefinitions.cmake +++ b/src/coreclr/clrdefinitions.cmake @@ -218,10 +218,6 @@ if (FEATURE_STUBPRECODE_DYNAMIC_HELPERS) add_definitions(-DFEATURE_STUBPRECODE_DYNAMIC_HELPERS) endif() -if (CLR_CMAKE_TARGET_APPLE) - add_definitions(-DFEATURE_MAP_THUNKS_FROM_IMAGE) -endif() - # Use this function to enable building with a specific target OS and architecture set of defines # This is known to work for the set of defines used by the JIT and gcinfo, it is not likely correct for # other components of the runtime diff --git a/src/coreclr/debug/daccess/enummem.cpp b/src/coreclr/debug/daccess/enummem.cpp index 95d401caa0daa9..0f5d418d648ba8 100644 --- a/src/coreclr/debug/daccess/enummem.cpp +++ b/src/coreclr/debug/daccess/enummem.cpp @@ -591,8 +591,6 @@ HRESULT ClrDataAccess::DumpManagedExcepObject(CLRDataEnumMemoryFlags flags, OBJE // Pulls in data to translate from token to MethodDesc FindLoadedMethodRefOrDef(pMD->GetMethodTable()->GetModule(), pMD->GetMemberDef()); - // Pulls in sequence points. - DebugInfoManager::EnumMemoryRegionsForMethodDebugInfo(flags, pMD); PCODE addr = pMD->GetNativeCode(); if (addr != (PCODE)NULL) { @@ -970,9 +968,6 @@ HRESULT ClrDataAccess::EnumMemWalkStackHelper(CLRDataEnumMemoryFlags flags, // back to source lines for functions on stacks is very useful and we don't // want to allow the function to fail for all targets. - // Pulls in sequence points and local variable info - DebugInfoManager::EnumMemoryRegionsForMethodDebugInfo(flags, pMethodDesc); - #if defined(FEATURE_EH_FUNCLETS) && defined(USE_GC_INFO_DECODER) if (addr != (PCODE)NULL) diff --git a/src/coreclr/inc/executableallocator.h b/src/coreclr/inc/executableallocator.h index 973b950ad369bc..11caf3a6857d2d 100644 --- a/src/coreclr/inc/executableallocator.h +++ b/src/coreclr/inc/executableallocator.h @@ -182,9 +182,6 @@ class ExecutableAllocator // Return true if double mapping is enabled. static bool IsDoubleMappingEnabled(); - // Release memory allocated via DoubleMapping for either templates or normal double mapped data - void ReleaseWorker(void* pRX, bool releaseTemplate); - // Initialize the allocator instance bool Initialize(); @@ -265,18 +262,6 @@ class ExecutableAllocator // Unmap the RW mapping at the specified address void UnmapRW(void* pRW); - - // Allocate thunks from a template. pTemplate is the return value from CreateTemplate - void* AllocateThunksFromTemplate(void *pTemplate, size_t templateSize); - - // Free a set of thunks allocated from templates. pThunks must have been returned from AllocateThunksFromTemplate - void FreeThunksFromTemplate(void *pThunks, size_t templateSize); - - // Create a template - // If templateInImage is not null, it will attempt to use it as the template, otherwise it will create an temporary in memory file to serve as the template - // Some OS/Architectures may/may not be able to work with this, so this api is permitted to return NULL, and callers should have an alternate approach using - // the codePageGenerator directly. - void* CreateTemplate(void* templateInImage, size_t templateSize, void (*codePageGenerator)(uint8_t* pageBase, uint8_t* pageBaseRX, size_t size)); }; #define ExecutableWriterHolder ExecutableWriterHolderNoLog diff --git a/src/coreclr/inc/loaderheap.h b/src/coreclr/inc/loaderheap.h index d3040e0b4aa448..782f93cedc6264 100644 --- a/src/coreclr/inc/loaderheap.h +++ b/src/coreclr/inc/loaderheap.h @@ -455,19 +455,10 @@ class UnlockedLoaderHeap : public UnlockedLoaderHeapBase static void WeGotAFaultNowWhat(UnlockedLoaderHeap *pHeap); }; -struct InterleavedLoaderHeapConfig -{ - uint32_t StubSize; - void* Template; - void (*CodePageGenerator)(uint8_t* pageBase, uint8_t* pageBaseRX, size_t size); -}; - -void InitializeLoaderHeapConfig(InterleavedLoaderHeapConfig *pConfig, size_t stubSize, void* templateInImage, void (*codePageGenerator)(uint8_t* pageBase, uint8_t* pageBaseRX, size_t size)); - //=============================================================================== // This is the base class for InterleavedLoaderHeap It's used as a simple // allocator for stubs in a scheme where each stub is a small fixed size, and is paired -// with memory which is GetStubCodePageSize() bytes away. In addition there is an +// with memory which is GetOSStubPageSize() bytes away. In addition there is an // ability to free is via a "backout" mechanism that is not considered to have good performance. // //=============================================================================== @@ -501,13 +492,16 @@ class UnlockedInterleavedLoaderHeap : public UnlockedLoaderHeapBase InterleavedStubFreeListNode *m_pFreeListHead; - const InterleavedLoaderHeapConfig *m_pConfig; +public: +public: + void (*m_codePageGenerator)(BYTE* pageBase, BYTE* pageBaseRX, SIZE_T size); #ifndef DACCESS_COMPILE protected: UnlockedInterleavedLoaderHeap( RangeList *pRangeList, - const InterleavedLoaderHeapConfig *pConfig); + void (*codePageGenerator)(BYTE* pageBase, BYTE* pageBaseRX, SIZE_T size), + DWORD dwGranularity); virtual ~UnlockedInterleavedLoaderHeap(); #endif @@ -1045,11 +1039,13 @@ class InterleavedLoaderHeap : public UnlockedInterleavedLoaderHeap public: InterleavedLoaderHeap(RangeList *pRangeList, BOOL fUnlocked, - const InterleavedLoaderHeapConfig *pConfig + void (*codePageGenerator)(BYTE* pageBase, BYTE* pageBaseRX, SIZE_T size), + DWORD dwGranularity ) : UnlockedInterleavedLoaderHeap( pRangeList, - pConfig), + codePageGenerator, + dwGranularity), m_CriticalSection(fUnlocked ? NULL : CreateLoaderHeapLock()) { WRAPPER_NO_CONTRACT; diff --git a/src/coreclr/interpreter/compiler.cpp b/src/coreclr/interpreter/compiler.cpp index cf584149c87dce..9073f7a4d02c54 100644 --- a/src/coreclr/interpreter/compiler.cpp +++ b/src/coreclr/interpreter/compiler.cpp @@ -1418,6 +1418,10 @@ void InterpCompiler::EmitBranch(InterpOpcode opcode, int32_t ilOffset) if (target < 0 || target >= m_ILCodeSize) assert(0); + // Backwards branch, emit safepoint + if (ilOffset < 0) + AddIns(INTOP_SAFEPOINT); + InterpBasicBlock *pTargetBB = m_ppOffsetToBB[target]; assert(pTargetBB != NULL); @@ -2123,6 +2127,10 @@ int InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo) codeEnd = m_ip + m_ILCodeSize; + // Safepoint at each method entry. This could be done as part of a call, rather than + // adding an opcode. + AddIns(INTOP_SAFEPOINT); + linkBBlocks = true; needsRetryEmit = false; retry_emit: diff --git a/src/coreclr/interpreter/intops.def b/src/coreclr/interpreter/intops.def index ab9caede9b0b14..ee27ab900242e3 100644 --- a/src/coreclr/interpreter/intops.def +++ b/src/coreclr/interpreter/intops.def @@ -35,6 +35,7 @@ OPDEF(INTOP_LDLOCA, "ldloca", 3, 1, 0, InterpOpInt) OPDEF(INTOP_SWITCH, "switch", 0, 0, 1, InterpOpSwitch) +OPDEF(INTOP_SAFEPOINT, "safepoint", 1, 0, 0, InterpOpNoArgs) OPDEF(INTOP_BR, "br", 2, 0, 0, InterpOpBranch) OPDEF(INTOP_BRFALSE_I4, "brfalse.i4", 3, 0, 1, InterpOpBranch) diff --git a/src/coreclr/jit/async.cpp b/src/coreclr/jit/async.cpp index d4818b87074411..33ec19ce75d51b 100644 --- a/src/coreclr/jit/async.cpp +++ b/src/coreclr/jit/async.cpp @@ -1,6 +1,38 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +// +// This file implements the transformation of C# async methods into state +// machines. The transformation takes place late in the JIT pipeline, when most +// optimizations have already been performed, right before lowering. +// +// The transformation performs the following key operations: +// +// 1. Each async call becomes a suspension point where execution can pause and +// return to the caller, accompanied by a resumption point where execution can +// continue when the awaited operation completes. +// +// 2. When suspending at a suspension point a continuation object is created that contains: +// - All live local variables +// - State number to identify which await is being resumed +// - Return value from the awaited operation (filled in by the callee later) +// - Exception information if an exception occurred +// - Resumption function pointer +// - Flags containing additional information +// +// 3. The method entry is modified to include dispatch logic that checks for an +// incoming continuation and jumps to the appropriate resumption point. +// +// 4. Special handling is included for: +// - Exception propagation across await boundaries +// - Return value management for different types (primitives, references, structs) +// - Tiered compilation and On-Stack Replacement (OSR) +// - Optimized state capture based on variable liveness analysis +// +// The transformation ensures that the semantics of the original async method are +// preserved while enabling efficient suspension and resumption of execution. +// + #include "jitpch.h" #include "jitstd/algorithm.h" #include "async.h" diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index de0f6afbdc8fc5..daf898ff37217f 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -72,22 +72,22 @@ inline var_types genActualType(T value); * Forward declarations */ -struct InfoHdr; // defined in GCInfo.h -struct escapeMapping_t; // defined in fgdiagnostic.cpp -class emitter; // defined in emit.h -struct ShadowParamVarInfo; // defined in GSChecks.cpp -struct InitVarDscInfo; // defined in registerargconvention.h -class FgStack; // defined in fgbasic.cpp -class Instrumentor; // defined in fgprofile.cpp -class SpanningTreeVisitor; // defined in fgprofile.cpp -class CSE_DataFlow; // defined in optcse.cpp -struct CSEdsc; // defined in optcse.h -class CSE_HeuristicCommon; // defined in optcse.h -class OptBoolsDsc; // defined in optimizer.cpp -struct JumpThreadInfo; // defined in redundantbranchopts.cpp -class ProfileSynthesis; // defined in profilesynthesis.h -class LoopLocalOccurrences; // defined in inductionvariableopts.cpp -class RangeCheck; // defined in rangecheck.h +struct InfoHdr; // defined in GCInfo.h +struct escapeMapping_t; // defined in fgdiagnostic.cpp +class emitter; // defined in emit.h +struct ShadowParamVarInfo; // defined in GSChecks.cpp +struct InitVarDscInfo; // defined in registerargconvention.h +class FgStack; // defined in fgbasic.cpp +class Instrumentor; // defined in fgprofile.cpp +class SpanningTreeVisitor; // defined in fgprofile.cpp +class CSE_DataFlow; // defined in optcse.cpp +struct CSEdsc; // defined in optcse.h +class CSE_HeuristicCommon; // defined in optcse.h +class OptBoolsDsc; // defined in optimizer.cpp +struct JumpThreadInfo; // defined in redundantbranchopts.cpp +class ProfileSynthesis; // defined in profilesynthesis.h +class PerLoopInfo; // defined in inductionvariableopts.cpp +class RangeCheck; // defined in rangecheck.h #ifdef DEBUG struct IndentStack; #endif @@ -7654,33 +7654,30 @@ class Compiler void optVisitBoundingExitingCondBlocks(FlowGraphNaturalLoop* loop, TFunctor func); bool optMakeLoopDownwardsCounted(ScalarEvolutionContext& scevContext, FlowGraphNaturalLoop* loop, - LoopLocalOccurrences* loopLocals); + PerLoopInfo* loopLocals); bool optMakeExitTestDownwardsCounted(ScalarEvolutionContext& scevContext, FlowGraphNaturalLoop* loop, BasicBlock* exiting, - LoopLocalOccurrences* loopLocals); + PerLoopInfo* loopLocals); bool optCanAndShouldChangeExitTest(GenTree* cond, bool dump); - bool optLocalHasNonLoopUses(unsigned lclNum, FlowGraphNaturalLoop* loop, LoopLocalOccurrences* loopLocals); + bool optLocalHasNonLoopUses(unsigned lclNum, FlowGraphNaturalLoop* loop, PerLoopInfo* loopLocals); bool optLocalIsLiveIntoBlock(unsigned lclNum, BasicBlock* block); - bool optWidenIVs(ScalarEvolutionContext& scevContext, FlowGraphNaturalLoop* loop, LoopLocalOccurrences* loopLocals); - bool optWidenPrimaryIV(FlowGraphNaturalLoop* loop, - unsigned lclNum, - ScevAddRec* addRec, - LoopLocalOccurrences* loopLocals); + bool optWidenIVs(ScalarEvolutionContext& scevContext, FlowGraphNaturalLoop* loop, PerLoopInfo* loopLocals); + bool optWidenPrimaryIV(FlowGraphNaturalLoop* loop, unsigned lclNum, ScevAddRec* addRec, PerLoopInfo* loopLocals); bool optCanSinkWidenedIV(unsigned lclNum, FlowGraphNaturalLoop* loop); bool optIsIVWideningProfitable(unsigned lclNum, BasicBlock* initBlock, bool initedToConstant, FlowGraphNaturalLoop* loop, - LoopLocalOccurrences* loopLocals); + PerLoopInfo* loopLocals); void optBestEffortReplaceNarrowIVUses( unsigned lclNum, unsigned ssaNum, unsigned newLclNum, BasicBlock* block, Statement* firstStmt); void optReplaceWidenedIV(unsigned lclNum, unsigned ssaNum, unsigned newLclNum, Statement* stmt); void optSinkWidenedIV(unsigned lclNum, unsigned newLclNum, FlowGraphNaturalLoop* loop); - bool optRemoveUnusedIVs(FlowGraphNaturalLoop* loop, LoopLocalOccurrences* loopLocals); + bool optRemoveUnusedIVs(FlowGraphNaturalLoop* loop, PerLoopInfo* loopLocals); bool optIsUpdateOfIVWithoutSideEffects(GenTree* tree, unsigned lclNum); // Redundant branch opts @@ -7708,6 +7705,7 @@ class Compiler BitVecTraits* apTraits; ASSERT_TP apFull; ASSERT_TP apLocal; + ASSERT_TP apLocalPostorder; ASSERT_TP apLocalIfTrue; enum optAssertionKind : uint8_t diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 4993bf556c1701..46d8517f5a9fa5 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -27867,8 +27867,14 @@ GenTree* Compiler::gtNewSimdWithElementNode( var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); assert(varTypeIsArithmetic(simdBaseType)); + assert(op2->IsCnsIntOrI()); assert(varTypeIsArithmetic(op3)); + ssize_t imm8 = op2->AsIntCon()->IconValue(); + ssize_t count = simdSize / genTypeSize(simdBaseType); + + assert((0 <= imm8) && (imm8 < count)); + #if defined(TARGET_XARCH) switch (simdBaseType) { @@ -27934,20 +27940,6 @@ GenTree* Compiler::gtNewSimdWithElementNode( #error Unsupported platform #endif // !TARGET_XARCH && !TARGET_ARM64 - int immUpperBound = getSIMDVectorLength(simdSize, simdBaseType) - 1; - bool rangeCheckNeeded = !op2->OperIsConst(); - - if (!rangeCheckNeeded) - { - ssize_t imm8 = op2->AsIntCon()->IconValue(); - rangeCheckNeeded = (imm8 < 0) || (imm8 > immUpperBound); - } - - if (rangeCheckNeeded) - { - op2 = addRangeCheckForHWIntrinsic(op2, 0, immUpperBound); - } - return gtNewSimdHWIntrinsicNode(type, op1, op2, op3, hwIntrinsicID, simdBaseJitType, simdSize); } diff --git a/src/coreclr/jit/hwintrinsiccodegenxarch.cpp b/src/coreclr/jit/hwintrinsiccodegenxarch.cpp index a4f22c16ec2c6f..ea114113412d81 100644 --- a/src/coreclr/jit/hwintrinsiccodegenxarch.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenxarch.cpp @@ -1832,7 +1832,6 @@ void CodeGen::genBaseIntrinsic(GenTreeHWIntrinsic* node, insOpts instOptions) GenTree* op1 = (node->GetOperandCount() >= 1) ? node->Op(1) : nullptr; GenTree* op2 = (node->GetOperandCount() >= 2) ? node->Op(2) : nullptr; - GenTree* op3 = (node->GetOperandCount() >= 3) ? node->Op(3) : nullptr; genConsumeMultiOpOperands(node); regNumber op1Reg = (op1 == nullptr) ? REG_NA : op1->GetRegNum(); @@ -1969,56 +1968,6 @@ void CodeGen::genBaseIntrinsic(GenTreeHWIntrinsic* node, insOpts instOptions) break; } - case NI_Vector128_WithElement: - case NI_Vector256_WithElement: - case NI_Vector512_WithElement: - { - // Optimize the case where op2 is not a constant. - assert(!op2->OperIsConst()); - - // We don't have an instruction to implement this intrinsic if the index is not a constant. - // So we will use the SIMD temp location to store the vector, set the value and then reload it. - // The range check will already have been performed, so at this point we know we have an index - // within the bounds of the vector. - - unsigned simdInitTempVarNum = compiler->lvaSIMDInitTempVarNum; - noway_assert(simdInitTempVarNum != BAD_VAR_NUM); - - bool isEBPbased; - unsigned offs = compiler->lvaFrameAddress(simdInitTempVarNum, &isEBPbased); - -#if !FEATURE_FIXED_OUT_ARGS - if (!isEBPbased) - { - // Adjust the offset by the amount currently pushed on the CPU stack - offs += genStackLevel; - } -#else - assert(genStackLevel == 0); -#endif // !FEATURE_FIXED_OUT_ARGS - - regNumber indexReg = op2->GetRegNum(); - regNumber valueReg = op3->GetRegNum(); // New element value to be stored - - // Store the vector to the temp location. - GetEmitter()->emitIns_S_R(ins_Store(simdType, compiler->isSIMDTypeLocalAligned(simdInitTempVarNum)), - emitTypeSize(simdType), op1Reg, simdInitTempVarNum, 0); - - // Set the desired element. - GetEmitter()->emitIns_ARX_R(ins_Move_Extend(op3->TypeGet(), false), // Store - emitTypeSize(baseType), // Of the vector baseType - valueReg, // From valueReg - (isEBPbased) ? REG_EBP : REG_ESP, // Stack-based - indexReg, // Indexed - genTypeSize(baseType), // by the size of the baseType - offs); // Offset - - // Write back the modified vector to the original location. - GetEmitter()->emitIns_R_S(ins_Load(simdType, compiler->isSIMDTypeLocalAligned(simdInitTempVarNum)), - emitTypeSize(simdType), targetReg, simdInitTempVarNum, 0); - break; - } - case NI_Vector128_GetElement: case NI_Vector256_GetElement: case NI_Vector512_GetElement: diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp index 29fe70b74b62a6..72328592e3ac1a 100644 --- a/src/coreclr/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/jit/hwintrinsicxarch.cpp @@ -4273,6 +4273,34 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, assert(sig->numArgs == 3); GenTree* indexOp = impStackTop(1).val; + if (!indexOp->OperIsConst()) + { + if (!opts.OptimizationEnabled()) + { + // Only enable late stage rewriting if optimizations are enabled + // as we won't otherwise encounter a constant at the later point + return nullptr; + } + + op3 = impPopStack().val; + op2 = impPopStack().val; + op1 = impSIMDPopStack(); + + retNode = gtNewSimdHWIntrinsicNode(retType, op1, op2, op3, intrinsic, simdBaseJitType, simdSize); + + retNode->AsHWIntrinsic()->SetMethodHandle(this, method R2RARG(*entryPoint)); + break; + } + + ssize_t imm8 = indexOp->AsIntCon()->IconValue(); + ssize_t count = simdSize / genTypeSize(simdBaseType); + + if ((imm8 >= count) || (imm8 < 0)) + { + // Using software fallback if index is out of range (throw exception) + return nullptr; + } + switch (simdBaseType) { // Using software fallback if simdBaseType is not supported by hardware diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 075e0e8d540f93..af6fa9769a4551 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -9936,9 +9936,10 @@ void Compiler::impImportBlockCode(BasicBlock* block) impPushOnStack(gtNewLclvNode(lclNum, TYP_REF), tiRetVal); #ifdef DEBUG - // Under SPMI, look up info we might ask for if we stack allocate this array + // Under SPMI, look up info we might ask for if we stack allocate this array, + // but only if we know the precise type // - if (JitConfig.EnableExtraSuperPmiQueries()) + if (JitConfig.EnableExtraSuperPmiQueries() && !eeIsSharedInst(resolvedToken.hClass)) { void* pEmbedClsHnd; info.compCompHnd->embedClassHandle(resolvedToken.hClass, &pEmbedClsHnd); diff --git a/src/coreclr/jit/inductionvariableopts.cpp b/src/coreclr/jit/inductionvariableopts.cpp index 77f15adfb07a12..56818096912e60 100644 --- a/src/coreclr/jit/inductionvariableopts.cpp +++ b/src/coreclr/jit/inductionvariableopts.cpp @@ -1,11 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +// // This file contains code to optimize induction variables in loops based on // scalar evolution analysis (see scev.h and scev.cpp for more information // about the scalar evolution analysis). // -// Currently the following optimizations are done: +// Currently the following optimizations are implemented: // // IV widening: // This widens primary induction variables from 32 bits into 64 bits. This is @@ -37,21 +38,26 @@ // single instruction, bypassing the need to do a separate comparison with a // bound. // -// Strength reduction (disabled): -// This changes the stride of primary IVs in a loop to avoid more expensive -// multiplications inside the loop. Commonly the primary IVs are only used -// for indexing memory at some element size, which can end up with these -// multiplications. +// Strength reduction: +// Strength reduction identifies cases where all uses of a primary IV compute +// a common derived value. Commonly this happens when indexing memory at some +// element size, resulting in multiplications. It introduces a new primary IV +// that directly computes this derived value, avoiding the need for the +// original primary IV and its associated calculations. The optimization +// handles GC pointers carefully, ensuring all accesses remain within managed +// objects. // -// Strength reduction frequently relies on reversing the loop to remove the -// last non-multiplied use of the primary IV. +// Unused IV removal: +// This removes induction variables that are only used for self-updates with +// no external uses. This commonly happens after other IV optimizations have +// replaced all meaningful uses of an IV with a different, more efficient IV. // #include "jitpch.h" #include "scev.h" -// Data structure that keeps track of local occurrences inside loops. -class LoopLocalOccurrences +// Data structure that keeps track of per-loop info, like occurrences and suspension-points inside loops. +class PerLoopInfo { struct Occurrence { @@ -63,19 +69,26 @@ class LoopLocalOccurrences typedef JitHashTable, Occurrence*> LocalToOccurrenceMap; + struct LoopInfo + { + LocalToOccurrenceMap* LocalToOccurrences = nullptr; + bool HasSuspensionPoint = false; + }; + FlowGraphNaturalLoops* m_loops; - // For every loop, we track all occurrences exclusive to that loop. - // Occurrences in descendant loops are not kept in their ancestor's maps. - LocalToOccurrenceMap** m_maps; + // For every loop, we track all occurrences exclusive to that loop, and + // whether or not the loop has a suspension point. + // Occurrences/suspensions in descendant loops are not kept in their ancestor's maps. + LoopInfo* m_info; // Blocks whose IR we have visited to find local occurrences in. BitVec m_visitedBlocks; - LocalToOccurrenceMap* GetOrCreateMap(FlowGraphNaturalLoop* loop); + LoopInfo* GetOrCreateInfo(FlowGraphNaturalLoop* loop); template - bool VisitLoopNestMaps(FlowGraphNaturalLoop* loop, TFunc& func); + bool VisitLoopNestInfo(FlowGraphNaturalLoop* loop, TFunc& func); public: - LoopLocalOccurrences(FlowGraphNaturalLoops* loops); + PerLoopInfo(FlowGraphNaturalLoops* loops); template bool VisitOccurrences(FlowGraphNaturalLoop* loop, unsigned lclNum, TFunc func); @@ -85,38 +98,40 @@ class LoopLocalOccurrences template bool VisitStatementsWithOccurrences(FlowGraphNaturalLoop* loop, unsigned lclNum, TFunc func); + bool HasSuspensionPoint(FlowGraphNaturalLoop* loop); + void Invalidate(FlowGraphNaturalLoop* loop); }; -LoopLocalOccurrences::LoopLocalOccurrences(FlowGraphNaturalLoops* loops) +PerLoopInfo::PerLoopInfo(FlowGraphNaturalLoops* loops) : m_loops(loops) { - Compiler* comp = loops->GetDfsTree()->GetCompiler(); - m_maps = loops->NumLoops() == 0 ? nullptr : new (comp, CMK_LoopOpt) LocalToOccurrenceMap* [loops->NumLoops()] {}; + Compiler* comp = loops->GetDfsTree()->GetCompiler(); + m_info = loops->NumLoops() == 0 ? nullptr : new (comp, CMK_LoopOpt) LoopInfo[loops->NumLoops()]; BitVecTraits poTraits = loops->GetDfsTree()->PostOrderTraits(); m_visitedBlocks = BitVecOps::MakeEmpty(&poTraits); } //------------------------------------------------------------------------------ -// LoopLocalOccurrences:GetOrCreateMap: -// Get or create the map of occurrences exclusive to a single loop. +// PerLoopInfo:GetOrCreateInfo: +// Get or create the info exclusive to a single loop. // // Parameters: // loop - The loop // // Returns: -// Map of occurrences. +// Loop information. // // Remarks: // As a precondition occurrences of all descendant loops must already have // been found. // -LoopLocalOccurrences::LocalToOccurrenceMap* LoopLocalOccurrences::GetOrCreateMap(FlowGraphNaturalLoop* loop) +PerLoopInfo::LoopInfo* PerLoopInfo::GetOrCreateInfo(FlowGraphNaturalLoop* loop) { - LocalToOccurrenceMap* map = m_maps[loop->GetIndex()]; - if (map != nullptr) + LoopInfo& info = m_info[loop->GetIndex()]; + if (info.LocalToOccurrences != nullptr) { - return map; + return &info; } BitVecTraits poTraits = m_loops->GetDfsTree()->PostOrderTraits(); @@ -132,11 +147,10 @@ LoopLocalOccurrences::LocalToOccurrenceMap* LoopLocalOccurrences::GetOrCreateMap } #endif - Compiler* comp = m_loops->GetDfsTree()->GetCompiler(); - map = new (comp, CMK_LoopOpt) LocalToOccurrenceMap(comp->getAllocator(CMK_LoopOpt)); - m_maps[loop->GetIndex()] = map; + Compiler* comp = m_loops->GetDfsTree()->GetCompiler(); + info.LocalToOccurrences = new (comp, CMK_LoopOpt) LocalToOccurrenceMap(comp->getAllocator(CMK_LoopOpt)); - loop->VisitLoopBlocksReversePostOrder([=, &poTraits](BasicBlock* block) { + loop->VisitLoopBlocksReversePostOrder([=, &poTraits, &info](BasicBlock* block) { if (!BitVecOps::TryAddElemD(&poTraits, m_visitedBlocks, block->bbPostorderNum)) { return BasicBlockVisit::Continue; @@ -146,13 +160,15 @@ LoopLocalOccurrences::LocalToOccurrenceMap* LoopLocalOccurrences::GetOrCreateMap { for (GenTree* node : stmt->TreeList()) { + info.HasSuspensionPoint |= node->IsCall() && node->AsCall()->IsAsync(); + if (!node->OperIsAnyLocal()) { continue; } - GenTreeLclVarCommon* lcl = node->AsLclVarCommon(); - Occurrence** occurrence = map->LookupPointerOrAdd(lcl->GetLclNum(), nullptr); + GenTreeLclVarCommon* lcl = node->AsLclVarCommon(); + Occurrence** occurrence = info.LocalToOccurrences->LookupPointerOrAdd(lcl->GetLclNum(), nullptr); Occurrence* newOccurrence = new (comp, CMK_LoopOpt) Occurrence; newOccurrence->Block = block; @@ -166,15 +182,15 @@ LoopLocalOccurrences::LocalToOccurrenceMap* LoopLocalOccurrences::GetOrCreateMap return BasicBlockVisit::Continue; }); - return map; + return &info; } //------------------------------------------------------------------------------ -// LoopLocalOccurrences:VisitLoopNestMaps: -// Visit all occurrence maps of the specified loop nest. +// PerLoopInfo:VisitLoopNestInfo: +// Visit all info of the specified loop nest. // // Type parameters: -// TFunc - bool(LocalToOccurrenceMap*) functor that returns true to continue +// TFunc - bool(LoopInfo*) functor that returns true to continue // the visit and false to abort. // // Parameters: @@ -185,21 +201,21 @@ LoopLocalOccurrences::LocalToOccurrenceMap* LoopLocalOccurrences::GetOrCreateMap // True if the visit completed; false if "func" returned false for any map. // template -bool LoopLocalOccurrences::VisitLoopNestMaps(FlowGraphNaturalLoop* loop, TFunc& func) +bool PerLoopInfo::VisitLoopNestInfo(FlowGraphNaturalLoop* loop, TFunc& func) { for (FlowGraphNaturalLoop* child = loop->GetChild(); child != nullptr; child = child->GetSibling()) { - if (!VisitLoopNestMaps(child, func)) + if (!VisitLoopNestInfo(child, func)) { return false; } } - return func(GetOrCreateMap(loop)); + return func(GetOrCreateInfo(loop)); } //------------------------------------------------------------------------------ -// LoopLocalOccurrences:VisitOccurrences: +// PerLoopInfo:VisitOccurrences: // Visit all occurrences of the specified local inside the loop. // // Type parameters: @@ -216,11 +232,11 @@ bool LoopLocalOccurrences::VisitLoopNestMaps(FlowGraphNaturalLoop* loop, TFunc& // returning false. // template -bool LoopLocalOccurrences::VisitOccurrences(FlowGraphNaturalLoop* loop, unsigned lclNum, TFunc func) +bool PerLoopInfo::VisitOccurrences(FlowGraphNaturalLoop* loop, unsigned lclNum, TFunc func) { - auto visitor = [=, &func](LocalToOccurrenceMap* map) { + auto visitor = [=, &func](LoopInfo* info) { Occurrence* occurrence; - if (!map->Lookup(lclNum, &occurrence)) + if (!info->LocalToOccurrences->Lookup(lclNum, &occurrence)) { return true; } @@ -240,11 +256,11 @@ bool LoopLocalOccurrences::VisitOccurrences(FlowGraphNaturalLoop* loop, unsigned return true; }; - return VisitLoopNestMaps(loop, visitor); + return VisitLoopNestInfo(loop, visitor); } //------------------------------------------------------------------------------ -// LoopLocalOccurrences:HasAnyOccurrences: +// PerLoopInfo:HasAnyOccurrences: // Check if this loop has any occurrences of the specified local. // // Parameters: @@ -257,7 +273,7 @@ bool LoopLocalOccurrences::VisitOccurrences(FlowGraphNaturalLoop* loop, unsigned // Remarks: // Does not take promotion into account. // -bool LoopLocalOccurrences::HasAnyOccurrences(FlowGraphNaturalLoop* loop, unsigned lclNum) +bool PerLoopInfo::HasAnyOccurrences(FlowGraphNaturalLoop* loop, unsigned lclNum) { if (!VisitOccurrences(loop, lclNum, [](BasicBlock* block, Statement* stmt, GenTreeLclVarCommon* tree) { return false; @@ -270,7 +286,7 @@ bool LoopLocalOccurrences::HasAnyOccurrences(FlowGraphNaturalLoop* loop, unsigne } //------------------------------------------------------------------------------ -// LoopLocalOccurrences:VisitStatementsWithOccurrences: +// PerLoopInfo:VisitStatementsWithOccurrences: // Visit all statements with occurrences of the specified local inside // the loop. // @@ -292,11 +308,11 @@ bool LoopLocalOccurrences::HasAnyOccurrences(FlowGraphNaturalLoop* loop, unsigne // once. // template -bool LoopLocalOccurrences::VisitStatementsWithOccurrences(FlowGraphNaturalLoop* loop, unsigned lclNum, TFunc func) +bool PerLoopInfo::VisitStatementsWithOccurrences(FlowGraphNaturalLoop* loop, unsigned lclNum, TFunc func) { - auto visitor = [=, &func](LocalToOccurrenceMap* map) { + auto visitor = [=, &func](LoopInfo* info) { Occurrence* occurrence; - if (!map->Lookup(lclNum, &occurrence)) + if (!info->LocalToOccurrences->Lookup(lclNum, &occurrence)) { return true; } @@ -330,7 +346,43 @@ bool LoopLocalOccurrences::VisitStatementsWithOccurrences(FlowGraphNaturalLoop* return true; }; - return VisitLoopNestMaps(loop, visitor); + return VisitLoopNestInfo(loop, visitor); +} + +//------------------------------------------------------------------------------ +// PerLoopInfo:HasSuspensionPoint: +// Check if a loop has a suspension point. +// +// Parameters: +// loop - The loop +// +// Returns: +// True if so. +// +bool PerLoopInfo::HasSuspensionPoint(FlowGraphNaturalLoop* loop) +{ + if (!loop->GetDfsTree()->GetCompiler()->compIsAsync()) + { + return false; + } + + auto visitor = [](LoopInfo* info) { + if (info->HasSuspensionPoint) + { + // Abort now that we've found a suspension point + return false; + } + + return true; + }; + + if (!VisitLoopNestInfo(loop, visitor)) + { + // Aborted, so has a suspension point + return true; + } + + return false; } //------------------------------------------------------------------------ @@ -340,16 +392,18 @@ bool LoopLocalOccurrences::VisitStatementsWithOccurrences(FlowGraphNaturalLoop* // Parameters: // loop - The loop // -void LoopLocalOccurrences::Invalidate(FlowGraphNaturalLoop* loop) +void PerLoopInfo::Invalidate(FlowGraphNaturalLoop* loop) { for (FlowGraphNaturalLoop* child = loop->GetChild(); child != nullptr; child = child->GetSibling()) { Invalidate(child); } - if (m_maps[loop->GetIndex()] != nullptr) + LoopInfo& info = m_info[loop->GetIndex()]; + if (info.LocalToOccurrences != nullptr) { - m_maps[loop->GetIndex()] = nullptr; + info.LocalToOccurrences = nullptr; + info.HasSuspensionPoint = false; BitVecTraits poTraits = m_loops->GetDfsTree()->PostOrderTraits(); loop->VisitLoopBlocks([=, &poTraits](BasicBlock* block) { @@ -446,7 +500,7 @@ bool Compiler::optCanSinkWidenedIV(unsigned lclNum, FlowGraphNaturalLoop* loop) // initBlock - The block in where the new IV would be initialized // initedToConstant - Whether or not the new IV will be initialized to a constant // loop - The loop -// loopLocals - Data structure tracking local uses inside the loop +// loopInfo - Data structure tracking loop info, like local occurrences // // // Returns: @@ -462,11 +516,8 @@ bool Compiler::optCanSinkWidenedIV(unsigned lclNum, FlowGraphNaturalLoop* loop) // 2. We need to store the wide IV back into the narrow one in each of // the exits where the narrow IV is live-in. // -bool Compiler::optIsIVWideningProfitable(unsigned lclNum, - BasicBlock* initBlock, - bool initedToConstant, - FlowGraphNaturalLoop* loop, - LoopLocalOccurrences* loopLocals) +bool Compiler::optIsIVWideningProfitable( + unsigned lclNum, BasicBlock* initBlock, bool initedToConstant, FlowGraphNaturalLoop* loop, PerLoopInfo* loopInfo) { for (FlowGraphNaturalLoop* otherLoop : m_loops->InReversePostOrder()) { @@ -522,7 +573,7 @@ bool Compiler::optIsIVWideningProfitable(unsigned lclNum, return true; }; - loopLocals->VisitOccurrences(loop, lclNum, measure); + loopInfo->VisitOccurrences(loop, lclNum, measure); if (!initedToConstant) { @@ -763,14 +814,12 @@ void Compiler::optBestEffortReplaceNarrowIVUses( // Parameters: // scevContext - Context for scalar evolution // loop - The loop -// loopLocals - Data structure for locals occurrences +// loopInfo - Data structure for tracking loop info, like locals occurrences // // Returns: // True if any primary IV was widened. // -bool Compiler::optWidenIVs(ScalarEvolutionContext& scevContext, - FlowGraphNaturalLoop* loop, - LoopLocalOccurrences* loopLocals) +bool Compiler::optWidenIVs(ScalarEvolutionContext& scevContext, FlowGraphNaturalLoop* loop, PerLoopInfo* loopInfo) { JITDUMP("Considering primary IVs of " FMT_LP " for widening\n", loop->GetIndex()); @@ -811,14 +860,14 @@ bool Compiler::optWidenIVs(ScalarEvolutionContext& scevContext, // For a struct field with occurrences of the parent local we won't // be able to do much. - if (lclDsc->lvIsStructField && loopLocals->HasAnyOccurrences(loop, lclDsc->lvParentLcl)) + if (lclDsc->lvIsStructField && loopInfo->HasAnyOccurrences(loop, lclDsc->lvParentLcl)) { JITDUMP(" V%02u is a struct field whose parent local V%02u has occurrences inside the loop\n", lclNum, lclDsc->lvParentLcl); continue; } - if (optWidenPrimaryIV(loop, lclNum, addRec, loopLocals)) + if (optWidenPrimaryIV(loop, lclNum, addRec, loopInfo)) { numWidened++; } @@ -835,12 +884,9 @@ bool Compiler::optWidenIVs(ScalarEvolutionContext& scevContext, // loop - The loop // lclNum - The primary IV // addRec - The add recurrence for the primary IV -// loopLocals - Data structure for locals occurrences +// loopInfo - Data structure for tracking loop info like locals occurrences // -bool Compiler::optWidenPrimaryIV(FlowGraphNaturalLoop* loop, - unsigned lclNum, - ScevAddRec* addRec, - LoopLocalOccurrences* loopLocals) +bool Compiler::optWidenPrimaryIV(FlowGraphNaturalLoop* loop, unsigned lclNum, ScevAddRec* addRec, PerLoopInfo* loopInfo) { LclVarDsc* lclDsc = lvaGetDesc(lclNum); if (lclDsc->TypeGet() != TYP_INT) @@ -882,7 +928,7 @@ bool Compiler::optWidenPrimaryIV(FlowGraphNaturalLoop* loop, initBlock = startSsaDsc->GetBlock(); } - if (!optIsIVWideningProfitable(lclNum, initBlock, initToConstant, loop, loopLocals)) + if (!optIsIVWideningProfitable(lclNum, initBlock, initToConstant, loop, loopInfo)) { return false; } @@ -977,10 +1023,10 @@ bool Compiler::optWidenPrimaryIV(FlowGraphNaturalLoop* loop, return true; }; - loopLocals->VisitStatementsWithOccurrences(loop, lclNum, replace); + loopInfo->VisitStatementsWithOccurrences(loop, lclNum, replace); optSinkWidenedIV(lclNum, newLclNum, loop); - loopLocals->Invalidate(loop); + loopInfo->Invalidate(loop); return true; } @@ -1031,21 +1077,21 @@ void Compiler::optVisitBoundingExitingCondBlocks(FlowGraphNaturalLoop* loop, TFu // Parameters: // scevContext - Context for scalar evolution // loop - Loop to transform -// loopLocals - Data structure that tracks occurrences of locals in the loop +// loopInfo - Data structure that tracks occurrences of locals in the loop // // Returns: // True if the loop was made downwards counted; otherwise false. // bool Compiler::optMakeLoopDownwardsCounted(ScalarEvolutionContext& scevContext, FlowGraphNaturalLoop* loop, - LoopLocalOccurrences* loopLocals) + PerLoopInfo* loopInfo) { JITDUMP("Checking if we should make " FMT_LP " downwards counted\n", loop->GetIndex()); bool changed = false; optVisitBoundingExitingCondBlocks(loop, [=, &scevContext, &changed](BasicBlock* exiting) { JITDUMP(" Considering exiting block " FMT_BB "\n", exiting->bbNum); - changed |= optMakeExitTestDownwardsCounted(scevContext, loop, exiting, loopLocals); + changed |= optMakeExitTestDownwardsCounted(scevContext, loop, exiting, loopInfo); }); return changed; @@ -1060,7 +1106,7 @@ bool Compiler::optMakeLoopDownwardsCounted(ScalarEvolutionContext& scevContext, // scevContext - SCEV context // loop - The specific loop // exiting - Exiting block -// loopLocals - Data structure tracking local uses +// loopInfo - Data structure tracking local uses // // Returns: // True if any modification was made. @@ -1068,7 +1114,7 @@ bool Compiler::optMakeLoopDownwardsCounted(ScalarEvolutionContext& scevContext, bool Compiler::optMakeExitTestDownwardsCounted(ScalarEvolutionContext& scevContext, FlowGraphNaturalLoop* loop, BasicBlock* exiting, - LoopLocalOccurrences* loopLocals) + PerLoopInfo* loopInfo) { // Note: keep the heuristics here in sync with // `StrengthReductionContext::IsUseExpectedToBeRemoved`. @@ -1099,7 +1145,7 @@ bool Compiler::optMakeExitTestDownwardsCounted(ScalarEvolutionContext& scevConte unsigned candidateLclNum = stmt->GetRootNode()->AsLclVarCommon()->GetLclNum(); - if (optLocalHasNonLoopUses(candidateLclNum, loop, loopLocals)) + if (optLocalHasNonLoopUses(candidateLclNum, loop, loopInfo)) { continue; } @@ -1122,7 +1168,7 @@ bool Compiler::optMakeExitTestDownwardsCounted(ScalarEvolutionContext& scevConte return false; }; - if (!loopLocals->VisitStatementsWithOccurrences(loop, candidateLclNum, checkRemovableUse)) + if (!loopInfo->VisitStatementsWithOccurrences(loop, candidateLclNum, checkRemovableUse)) { // Aborted means we found a non-removable use continue; @@ -1215,7 +1261,7 @@ bool Compiler::optMakeExitTestDownwardsCounted(ScalarEvolutionContext& scevConte DISPSTMT(jtrueStmt); JITDUMP("\n"); - loopLocals->Invalidate(loop); + loopInfo->Invalidate(loop); return true; } @@ -1270,16 +1316,16 @@ bool Compiler::optCanAndShouldChangeExitTest(GenTree* cond, bool dump) // Parameters: // lclNum - The local // loop - The loop -// loopLocals - Data structure tracking local uses +// loopInfo - Data structure tracking local uses // // Returns: // True if the local may have non-loop uses (or if it is a field with uses of // the parent struct). // -bool Compiler::optLocalHasNonLoopUses(unsigned lclNum, FlowGraphNaturalLoop* loop, LoopLocalOccurrences* loopLocals) +bool Compiler::optLocalHasNonLoopUses(unsigned lclNum, FlowGraphNaturalLoop* loop, PerLoopInfo* loopInfo) { LclVarDsc* varDsc = lvaGetDesc(lclNum); - if (varDsc->lvIsStructField && loopLocals->HasAnyOccurrences(loop, varDsc->lvParentLcl)) + if (varDsc->lvIsStructField && loopInfo->HasAnyOccurrences(loop, varDsc->lvParentLcl)) { return true; } @@ -1362,7 +1408,7 @@ class StrengthReductionContext Compiler* m_comp; ScalarEvolutionContext& m_scevContext; FlowGraphNaturalLoop* m_loop; - LoopLocalOccurrences& m_loopLocals; + PerLoopInfo& m_loopInfo; ArrayStack m_backEdgeBounds; SimplificationAssumptions m_simplAssumptions; @@ -1403,11 +1449,11 @@ class StrengthReductionContext StrengthReductionContext(Compiler* comp, ScalarEvolutionContext& scevContext, FlowGraphNaturalLoop* loop, - LoopLocalOccurrences& loopLocals) + PerLoopInfo& loopInfo) : m_comp(comp) , m_scevContext(scevContext) , m_loop(loop) - , m_loopLocals(loopLocals) + , m_loopInfo(loopInfo) , m_backEdgeBounds(comp->getAllocator(CMK_LoopIVOpts)) , m_cursors1(comp->getAllocator(CMK_LoopIVOpts)) , m_cursors2(comp->getAllocator(CMK_LoopIVOpts)) @@ -1484,7 +1530,7 @@ bool StrengthReductionContext::TryStrengthReduce() continue; } - if (m_comp->optLocalHasNonLoopUses(primaryIVLcl->GetLclNum(), m_loop, &m_loopLocals)) + if (m_comp->optLocalHasNonLoopUses(primaryIVLcl->GetLclNum(), m_loop, &m_loopInfo)) { // We won't be able to remove this primary IV JITDUMP(" Has non-loop uses\n"); @@ -1524,12 +1570,20 @@ bool StrengthReductionContext::TryStrengthReduce() assert(nextIV != nullptr); - if (varTypeIsGC(nextIV->Type) && !StaysWithinManagedObject(nextCursors, nextIV)) + if (varTypeIsGC(nextIV->Type)) { - JITDUMP( - " Next IV computes a GC pointer that we cannot prove to be inside a managed object. Bailing.\n", - varTypeName(nextIV->Type)); - break; + if (m_loopInfo.HasSuspensionPoint(m_loop)) + { + JITDUMP(" Next IV computes a GC pointer in a loop with a suspension point. Bailing.\n"); + break; + } + + if (!StaysWithinManagedObject(nextCursors, nextIV)) + { + JITDUMP( + " Next IV computes a GC pointer that we cannot prove to be inside a managed object. Bailing.\n"); + break; + } } ExpandStoredCursors(nextCursors, cursors); @@ -1573,7 +1627,7 @@ bool StrengthReductionContext::TryStrengthReduce() if (TryReplaceUsesWithNewPrimaryIV(cursors, currentIV)) { strengthReducedAny = true; - m_loopLocals.Invalidate(m_loop); + m_loopInfo.Invalidate(m_loop); } } @@ -1686,7 +1740,7 @@ bool StrengthReductionContext::InitializeCursors(GenTreeLclVarCommon* primaryIVL return true; }; - if (!m_loopLocals.VisitOccurrences(m_loop, primaryIVLcl->GetLclNum(), visitor) || (m_cursors1.Height() <= 0)) + if (!m_loopInfo.VisitOccurrences(m_loop, primaryIVLcl->GetLclNum(), visitor) || (m_cursors1.Height() <= 0)) { JITDUMP(" Could not create cursors for all loop uses of primary IV\n"); return false; @@ -1882,7 +1936,7 @@ void StrengthReductionContext::ExpandStoredCursors(ArrayStack* curso GenTreeLclVarCommon* storedLcl = parent->AsLclVarCommon(); if ((storedLcl->Data() == cur) && ((cur->gtFlags & GTF_SIDE_EFFECT) == 0) && storedLcl->HasSsaIdentity() && - !m_comp->optLocalHasNonLoopUses(storedLcl->GetLclNum(), m_loop, &m_loopLocals)) + !m_comp->optLocalHasNonLoopUses(storedLcl->GetLclNum(), m_loop, &m_loopInfo)) { int numCreated = 0; ScevAddRec* cursorIV = cursor->IV; @@ -1922,7 +1976,7 @@ void StrengthReductionContext::ExpandStoredCursors(ArrayStack* curso return true; }; - if (m_loopLocals.VisitOccurrences(m_loop, storedLcl->GetLclNum(), createExtraCursor)) + if (m_loopInfo.VisitOccurrences(m_loop, storedLcl->GetLclNum(), createExtraCursor)) { JITDUMP( " [%06u] was the data of store [%06u]; expanded to %d new cursors, and will replace with a store of 0\n", @@ -2678,12 +2732,12 @@ bool StrengthReductionContext::InsertionPointPostDominatesUses(BasicBlock* // // Parameters: // loop - The loop -// loopLocals - Locals of the loop +// loopInfo - Locals of the loop // // Returns: // True if any primary IV was removed. // -bool Compiler::optRemoveUnusedIVs(FlowGraphNaturalLoop* loop, LoopLocalOccurrences* loopLocals) +bool Compiler::optRemoveUnusedIVs(FlowGraphNaturalLoop* loop, PerLoopInfo* loopInfo) { JITDUMP(" Now looking for unnecessary primary IVs\n"); @@ -2697,7 +2751,7 @@ bool Compiler::optRemoveUnusedIVs(FlowGraphNaturalLoop* loop, LoopLocalOccurrenc unsigned lclNum = stmt->GetRootNode()->AsLclVarCommon()->GetLclNum(); JITDUMP(" V%02u", lclNum); - if (optLocalHasNonLoopUses(lclNum, loop, loopLocals)) + if (optLocalHasNonLoopUses(lclNum, loop, loopInfo)) { JITDUMP(" has non-loop uses, cannot remove\n"); continue; @@ -2707,7 +2761,7 @@ bool Compiler::optRemoveUnusedIVs(FlowGraphNaturalLoop* loop, LoopLocalOccurrenc return optIsUpdateOfIVWithoutSideEffects(stmt->GetRootNode(), lclNum); }; - if (!loopLocals->VisitStatementsWithOccurrences(loop, lclNum, visit)) + if (!loopInfo->VisitStatementsWithOccurrences(loop, lclNum, visit)) { JITDUMP(" has essential uses, cannot remove\n"); continue; @@ -2720,9 +2774,9 @@ bool Compiler::optRemoveUnusedIVs(FlowGraphNaturalLoop* loop, LoopLocalOccurrenc return true; }; - loopLocals->VisitStatementsWithOccurrences(loop, lclNum, remove); + loopInfo->VisitStatementsWithOccurrences(loop, lclNum, remove); numRemoved++; - loopLocals->Invalidate(loop); + loopInfo->Invalidate(loop); } Metrics.UnusedIVsRemoved += numRemoved; @@ -2810,7 +2864,7 @@ PhaseStatus Compiler::optInductionVariables() m_loops = FlowGraphNaturalLoops::Find(m_dfsTree); } - LoopLocalOccurrences loopLocals(m_loops); + PerLoopInfo loopInfo(m_loops); ScalarEvolutionContext scevContext(this); JITDUMP("Optimizing induction variables:\n"); @@ -2830,14 +2884,14 @@ PhaseStatus Compiler::optInductionVariables() continue; } - StrengthReductionContext strengthReductionContext(this, scevContext, loop, loopLocals); + StrengthReductionContext strengthReductionContext(this, scevContext, loop, loopInfo); if (strengthReductionContext.TryStrengthReduce()) { Metrics.LoopsStrengthReduced++; changed = true; } - if (optMakeLoopDownwardsCounted(scevContext, loop, &loopLocals)) + if (optMakeLoopDownwardsCounted(scevContext, loop, &loopInfo)) { Metrics.LoopsMadeDownwardsCounted++; changed = true; @@ -2847,14 +2901,14 @@ PhaseStatus Compiler::optInductionVariables() // addressing modes can include the zero/sign-extension of the index // for free. #if defined(TARGET_XARCH) && defined(TARGET_64BIT) - if (optWidenIVs(scevContext, loop, &loopLocals)) + if (optWidenIVs(scevContext, loop, &loopInfo)) { Metrics.LoopsIVWidened++; changed = true; } #endif - if (optRemoveUnusedIVs(loop, &loopLocals)) + if (optRemoveUnusedIVs(loop, &loopInfo)) { changed = true; } diff --git a/src/coreclr/jit/jitconfigvalues.h b/src/coreclr/jit/jitconfigvalues.h index 92a1cb5bf8f9ae..c42560d33bdcdd 100644 --- a/src/coreclr/jit/jitconfigvalues.h +++ b/src/coreclr/jit/jitconfigvalues.h @@ -808,6 +808,9 @@ RELEASE_CONFIG_INTEGER(JitEnablePhysicalPromotion, "JitEnablePhysicalPromotion", // Enable cross-block local assertion prop RELEASE_CONFIG_INTEGER(JitEnableCrossBlockLocalAssertionProp, "JitEnableCrossBlockLocalAssertionProp", 1) +// Enable postorder local assertion prop +RELEASE_CONFIG_INTEGER(JitEnablePostorderLocalAssertionProp, "JitEnablePostorderLocalAssertionProp", 1) + // Enable strength reduction RELEASE_CONFIG_INTEGER(JitEnableStrengthReduction, "JitEnableStrengthReduction", 1) diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index 17baca1ea00ea6..e81f0ea60142cd 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -5658,14 +5658,7 @@ GenTree* Lowering::LowerHWIntrinsicWithElement(GenTreeHWIntrinsic* node) GenTree* op2 = node->Op(2); GenTree* op3 = node->Op(3); - if (!op2->OperIsConst()) - { - comp->getSIMDInitTempVarNum(simdType); - - // We will specially handle WithElement in codegen when op2 isn't a constant - ContainCheckHWIntrinsic(node); - return node->gtNext; - } + assert(op2->OperIsConst()); ssize_t count = simdSize / genTypeSize(simdBaseType); ssize_t imm8 = op2->AsIntCon()->IconValue(); diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 3705bc6faa2c8b..99c18f19b584bf 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -7104,6 +7104,7 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA if (optLocalAssertionProp) { isQmarkColon = true; + BitVecOps::ClearD(apTraits, apLocalPostorder); } break; @@ -7744,6 +7745,40 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA qmarkOp2 = oldTree->AsOp()->gtOp2->AsOp()->gtOp2; } + // During global morph, give assertion prop another shot at this tree. + // + // We need to use the "postorder" assertion set here, because apLocal + // may reflect results from subtrees that have since been reordered. + // + // apLocalPostorder only includes live assertions from prior statements. + // + if (fgGlobalMorph && optLocalAssertionProp && (optAssertionCount > 0)) + { + GenTree* optimizedTree = tree; + bool again = JitConfig.JitEnablePostorderLocalAssertionProp() > 0; + bool didOptimize = false; + + if (!again) + { + JITDUMP("*** Postorder assertion prop disabled by config\n"); + } + + while (again) + { + tree = optimizedTree; + optimizedTree = optAssertionProp(apLocalPostorder, tree, nullptr, nullptr); + again = (optimizedTree != nullptr); + didOptimize |= again; + } + + assert(tree != nullptr); + + if (didOptimize) + { + gtUpdateNodeSideEffects(tree); + } + } + // Try to fold it, maybe we get lucky, tree = gtFoldExpr(tree); @@ -11716,13 +11751,12 @@ void Compiler::fgKillDependentAssertionsSingle(unsigned lclNum DEBUGARG(GenTree* { // Active dependent assertions are killed here // - ASSERT_TP killed = BitVecOps::MakeCopy(apTraits, GetAssertionDep(lclNum)); - BitVecOps::IntersectionD(apTraits, killed, apLocal); - - if (killed) - { + ASSERT_TP killed = GetAssertionDep(lclNum); #ifdef DEBUG + bool hasKills = !BitVecOps::IsEmptyIntersection(apTraits, apLocal, killed); + if (hasKills) + { AssertionIndex index = optAssertionCount; while (killed && (index > 0)) { @@ -11742,10 +11776,11 @@ void Compiler::fgKillDependentAssertionsSingle(unsigned lclNum DEBUGARG(GenTree* index--; } + } #endif - BitVecOps::DiffD(apTraits, apLocal, killed); - } + BitVecOps::DiffD(apTraits, apLocal, killed); + BitVecOps::DiffD(apTraits, apLocalPostorder, killed); } //------------------------------------------------------------------------ @@ -11762,7 +11797,7 @@ void Compiler::fgKillDependentAssertionsSingle(unsigned lclNum DEBUGARG(GenTree* // void Compiler::fgKillDependentAssertions(unsigned lclNum DEBUGARG(GenTree* tree)) { - if (BitVecOps::IsEmpty(apTraits, apLocal)) + if (BitVecOps::IsEmpty(apTraits, apLocal) && BitVecOps::IsEmpty(apTraits, apLocalPostorder)) { return; } @@ -12448,6 +12483,11 @@ void Compiler::fgMorphStmts(BasicBlock* block) compCurStmt = stmt; GenTree* oldTree = stmt->GetRootNode(); + if (optLocalAssertionProp) + { + BitVecOps::Assign(apTraits, apLocalPostorder, apLocal); + } + #ifdef DEBUG unsigned oldHash = verbose ? gtHashValue(oldTree) : DUMMY_INIT(~0); @@ -12668,7 +12708,8 @@ void Compiler::fgMorphBlock(BasicBlock* block, MorphUnreachableInfo* unreachable // Each block starts with an empty table, and no available assertions // optAssertionReset(0); - apLocal = BitVecOps::MakeEmpty(apTraits); + BitVecOps::ClearD(apTraits, apLocal); + BitVecOps::ClearD(apTraits, apLocalPostorder); } else { @@ -12806,6 +12847,8 @@ void Compiler::fgMorphBlock(BasicBlock* block, MorphUnreachableInfo* unreachable apLocal = BitVecOps::MakeEmpty(apTraits); } + BitVecOps::Assign(apTraits, apLocalPostorder, apLocal); + JITDUMPEXEC(optDumpAssertionIndices("Assertions in: ", apLocal)); } } @@ -12874,6 +12917,8 @@ PhaseStatus Compiler::fgMorphBlocks() // Local assertion prop is enabled if we are optimizing. // optAssertionInit(/* isLocalProp*/ true); + apLocal = BitVecOps::MakeEmpty(apTraits); + apLocalPostorder = BitVecOps::MakeEmpty(apTraits); } else { @@ -13009,10 +13054,12 @@ PhaseStatus Compiler::fgMorphBlocks() if (optLocalAssertionProp) { - Metrics.LocalAssertionCount = optAssertionCount; - Metrics.LocalAssertionOverflow = optAssertionOverflow; - Metrics.MorphTrackedLocals = lvaTrackedCount; - Metrics.MorphLocals = lvaCount; + Metrics.LocalAssertionCount = optAssertionCount; + Metrics.LocalAssertionOverflow = optAssertionOverflow; + Metrics.MorphTrackedLocals = lvaTrackedCount; + Metrics.MorphLocals = lvaCount; + optLocalAssertionProp = false; + optCrossBlockLocalAssertionProp = false; } // We may have converted a tailcall into a loop, in which case the first BB diff --git a/src/coreclr/jit/promotion.cpp b/src/coreclr/jit/promotion.cpp index b1e3af0f917896..b6f55fd0525021 100644 --- a/src/coreclr/jit/promotion.cpp +++ b/src/coreclr/jit/promotion.cpp @@ -1,6 +1,37 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +// +// Physical promotion is an optimization where struct fields accessed as +// LCL_FLD nodes are promoted to individual primitive-typed local variables +// accessed as LCL_VAR, allowing register allocation and removing unnecessary +// memory operations. +// +// Key components: +// +// 1. Candidate Identification: +// - Identifies struct locals that aren't already promoted and aren't address-exposed +// - Analyzes access patterns to determine which fields are good promotion candidates +// - Uses weighted cost models to balance performance and code size and to take PGO +// data into account +// +// 2. Field Promotion: +// - Creates primitive-typed replacement locals for selected fields +// - Records which parts of the struct remains unpromoted +// +// 3. Access Transformation: +// - Transforms local field accesses to use promoted field variables +// - Decomposes struct stores and copies to operate on the primitive fields +// - Handles call argument passing and returns with field lists where appropriate +// - Tracks when values in promoted fields vs. original struct are fresher +// - Inserts read-backs when the struct field is fresher than the promoted local +// - Inserts write-backs when the promoted local is fresher than the struct field +// - Ensures proper state across basic block boundaries and exception flow +// +// The transformation carefully handles OSR locals, parameters, and call arguments, +// while maintaining correct behavior for exception handling and control flow. +// + #include "jitpch.h" #include "promotion.h" #include "jitstd/algorithm.h" diff --git a/src/coreclr/jit/promotiondecomposition.cpp b/src/coreclr/jit/promotiondecomposition.cpp index a8c6a00ce50adc..7f2dbf0257fa2f 100644 --- a/src/coreclr/jit/promotiondecomposition.cpp +++ b/src/coreclr/jit/promotiondecomposition.cpp @@ -1,6 +1,33 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +// +// This file provides the machinery to decompose stores and initializations +// involving physically promoted structs into stores/initialization involving +// individual fields. +// +// Key components include: +// +// 1. DecompositionStatementList +// - Collects statement trees during decomposition +// - Converts them to a single comma tree at the end +// +// 2. DecompositionPlan +// - Plans the decomposition of block operations +// - Manages mappings between source and destination replacements +// - Supports both copies between structs and initializations +// - Creates specialized access plans for remainders (unpromoted parts) +// +// 3. Field-by-field copying and initialization +// - Determines optimal order and strategy for field operations +// - Handles cases where replacements partially overlap +// - Optimizes GC pointer handling to minimize write barriers +// - Special cases primitive fields when possible +// +// This works in coordination with the ReplaceVisitor from promotion.cpp to +// transform IR after physical promotion decisions have been made. +// + #include "jitpch.h" #include "promotion.h" #include "jitstd/algorithm.h" diff --git a/src/coreclr/jit/promotionliveness.cpp b/src/coreclr/jit/promotionliveness.cpp index 93ac0c1eaf6e7d..e137caab827500 100644 --- a/src/coreclr/jit/promotionliveness.cpp +++ b/src/coreclr/jit/promotionliveness.cpp @@ -4,6 +4,42 @@ #include "jitpch.h" #include "promotion.h" +// +// This file implements a specialized liveness analysis for physically promoted struct fields +// and remainders. Unlike standard JIT liveness analysis, it focuses on accurately tracking +// which fields are live at specific program points to optimize physically promoted struct operations. +// +// Key characteristics: +// +// 1. Separate Bit Vectors: +// - Maintains its own liveness bit vectors separate from the main compiler's bbLiveIn/bbLiveOut +// - Uses "dense" indices: bit vectors only contain entries for the remainder and replacement +// fields of physically promoted structs (allocating 1 + num_fields indices per local) +// - Does not update BasicBlock::bbLiveIn or other standard liveness storage, as this would +// require allocating regular tracked indices (lvVarIndex) for all new fields +// +// 2. Liveness Representation: +// - Writes liveness into IR using normal GTF_VAR_DEATH flags +// - Important: After liveness is computed but before replacement phase completes, +// GTF_VAR_DEATH semantics temporarily differ from the rest of the JIT +// (e.g., "LCL_FLD int V16 [+8] (last use)" indicates that specific field is dying, +// not the whole variable) +// - For struct uses that can indicate deaths of multiple fields or remainder parts, +// maintains side information accessed via GetDeathsForStructLocal() +// +// 3. Analysis Process: +// - Single-pass dataflow computation (no DCE iterations, unlike other liveness passes) +// - Handles QMark nodes specially for conditional execution +// - Accounts for implicit exception flow +// - Distinguishes between full definitions and partial definitions +// +// The liveness information is critical for: +// - Avoiding creation of dead stores (especially to remainders, which the SSA liveness +// pass handles very conservatively as partial definitions) +// - Marking replacement fields with proper liveness flags for subsequent compiler phases +// - Optimizing read-back operations by determining when they're unnecessary +// + struct BasicBlockLiveness { // Variables used before a full definition. @@ -22,54 +58,6 @@ struct BasicBlockLiveness // Run: // Compute liveness information pertaining the promoted structs. // -// Remarks: -// For each promoted aggregate we compute the liveness for its remainder and -// all of its fields. Unlike regular liveness we currently do not do any DCE -// here and so only do the dataflow computation once. -// -// The liveness information is written into the IR using the normal -// GTF_VAR_DEATH flag. Note that the semantics of GTF_VAR_DEATH differs from -// the rest of the JIT for a short while between the liveness is computed and -// the replacement phase has run: in particular, after this liveness pass you -// may see a node like: -// -// LCL_FLD int V16 tmp9 [+8] (last use) -// -// that indicates that this particular field (or the remainder if it wasn't -// promoted) is dying, not that V16 itself is dying. After replacement has -// run the semantics align with the rest of the JIT: in the promoted case V16 -// [+8] would be replaced by its promoted field local, and in the remainder -// case all non-remainder uses of V16 would also be. -// -// There is one catch which is struct uses of the local. These can indicate -// deaths of multiple fields and also the remainder, so this information is -// stored on the side. PromotionLiveness::GetDeathsForStructLocal is used to -// query this information. -// -// The liveness information is used by decomposition to avoid creating dead -// stores, and also to mark the replacement field uses/defs with proper -// up-to-date liveness information to be used by future phases (forward sub -// and morph, as of writing this). It is also used to avoid creating -// unnecessary read-backs; this is mostly just a TP optimization as future -// liveness passes would be expected to DCE these anyway. -// -// Avoiding the creation of dead stores to the remainder is especially -// important as these otherwise would often end up looking like partial -// definitions, and the other liveness passes handle partial definitions very -// conservatively and are not able to DCE them. -// -// Unlike the other liveness passes we keep the per-block liveness -// information on the side and we do not update BasicBlock::bbLiveIn et al. -// This relies on downstream phases not requiring/wanting to use per-basic -// block live-in/live-out/var-use/var-def sets. To be able to update these we -// would need to give the new locals "regular" tracked indices (i.e. allocate -// a lvVarIndex). -// -// The indices allocated and used internally within the liveness computation -// are "dense" in the sense that the bit vectors only have indices for -// remainders and the replacement fields introduced by this pass. In other -// words, we allocate 1 + num_fields indices for each promoted struct local). -// void PromotionLiveness::Run() { m_structLclToTrackedIndex = new (m_compiler, CMK_Promotion) unsigned[m_compiler->lvaCount]{}; diff --git a/src/coreclr/jit/rationalize.cpp b/src/coreclr/jit/rationalize.cpp index 1c7d31f9eb400d..be2e6f619447b0 100644 --- a/src/coreclr/jit/rationalize.cpp +++ b/src/coreclr/jit/rationalize.cpp @@ -385,6 +385,57 @@ void Rationalizer::RewriteHWIntrinsicAsUserCall(GenTree** use, ArrayStackOperIsConst()) + { + ssize_t imm8 = op2->AsIntCon()->IconValue(); + ssize_t count = simdSize / genTypeSize(simdBaseType); + + if ((imm8 >= count) || (imm8 < 0)) + { + // Using software fallback if index is out of range (throw exception) + break; + } + +#if defined(TARGET_XARCH) + if (varTypeIsIntegral(simdBaseType)) + { + if (varTypeIsLong(simdBaseType)) + { + if (!comp->compOpportunisticallyDependsOn(InstructionSet_SSE41_X64)) + { + break; + } + } + else if (!varTypeIsShort(simdBaseType)) + { + if (!comp->compOpportunisticallyDependsOn(InstructionSet_SSE41)) + { + break; + } + } + } +#endif // TARGET_XARCH + + result = comp->gtNewSimdWithElementNode(retType, op1, op2, op3, simdBaseJitType, simdSize); + break; + } + break; + } + default: { if (sigInfo.numArgs == 0) diff --git a/src/coreclr/jit/scev.cpp b/src/coreclr/jit/scev.cpp index e1140e48660cd5..5a11e81e85a542 100644 --- a/src/coreclr/jit/scev.cpp +++ b/src/coreclr/jit/scev.cpp @@ -1,12 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +// // This file contains code to analyze how the value of induction variables // evolve (scalar evolution analysis), and to turn them into the SCEV IR // defined in scev.h. The analysis is inspired by "Michael Wolfe. 1992. Beyond // induction variables." and also by LLVM's scalar evolution analysis. // -// The main idea of scalar evolution nalysis is to give a closed form +// The main idea of scalar evolution analysis is to give a closed form // describing the value of tree nodes inside loops even when taking into // account that they are changing on each loop iteration. This is useful for // optimizations that want to reason about values of IR nodes inside loops, @@ -28,34 +29,19 @@ // describes its value (possibly taking its evolution into account). Note that // SCEV nodes are immutable and the values they represent are _not_ // flow-dependent; that is, they don't exist at a specific location inside the -// loop, even though some particular tree node gave rise to that SCEV node. The -// analysis itself _is_ flow-dependent and guarantees that the Scev* returned -// describes the value that corresponds to what the tree node computes at its -// specific location. However, it would be perfectly legal for two trees at -// different locations in the loop to analyze to the same SCEV node (even -// potentially returning the same pointer). For example, in theory "i" and "j" -// in the following loop would both be represented by the same add recurrence -// , and the analysis could even return the same Scev* for both of -// them, even if it does not today: -// -// int i = 0; -// while (true) -// { -// i++; -// ... -// int j = i - 1; -// } -// -// Actually materializing the value of a SCEV node back into tree IR is not -// implemented yet, but generally would depend on the availability of tree -// nodes that compute the dependent values at the point where the IR is to be -// materialized. -// -// Besides the add recurrences the analysis itself is generally a -// straightforward translation from JIT IR into the SCEV IR. Creating the add -// recurrences requires paying attention to the structure of PHIs, and -// disambiguating the values coming from outside the loop and the values coming -// from the backedges. +// loop, even though some particular tree node gave rise to that SCEV node. +// +// The SCEV analysis is capable of: +// +// 1. Identifying both direct and indirect induction variables +// 2. Simplifying complex expressions involving induction variables +// 3. Determining when recurrences won't overflow during loop execution +// 4. Computing exact trip counts for countable loops +// 5. Converting SCEV expressions back to JIT IR and value numbers +// +// Understanding the relationship between values across iterations enables +// many loop optimizations, including strength reduction, loop reversal, +// and IV widening, which are implemented in inductionvariableopts.cpp. // #include "jitpch.h" diff --git a/src/coreclr/minipal/Unix/doublemapping.cpp b/src/coreclr/minipal/Unix/doublemapping.cpp index 4a2516bea58484..b866da9f93e6f1 100644 --- a/src/coreclr/minipal/Unix/doublemapping.cpp +++ b/src/coreclr/minipal/Unix/doublemapping.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -26,11 +25,6 @@ #include "minipal.h" #include "minipal/cpufeatures.h" -#ifndef TARGET_APPLE -#include -#include -#endif // TARGET_APPLE - #ifdef TARGET_APPLE #include @@ -259,320 +253,3 @@ bool VMToOSInterface::ReleaseRWMapping(void* pStart, size_t size) { return munmap(pStart, size) != -1; } - -#ifndef TARGET_APPLE -#define MAX_TEMPLATE_THUNK_TYPES 3 // Maximum number of times the CreateTemplate api can be called -struct TemplateThunkMappingData -{ - int fdImage; - off_t offsetInFileOfStartOfSection; - void* addrOfStartOfSection; // Always NULL if the template mapping data could not be initialized - void* addrOfEndOfSection; - bool imageTemplates; - int templatesCreated; - off_t nonImageTemplateCurrent; -}; - -struct InitializeTemplateThunkLocals -{ - void* pTemplate; - Dl_info info; - TemplateThunkMappingData data; -}; - -static TemplateThunkMappingData *s_pThunkData = NULL; - -#ifdef FEATURE_MAP_THUNKS_FROM_IMAGE - -static Elf32_Word Elf32_WordMin(Elf32_Word left, Elf32_Word right) -{ - return left < right ? left : right; -} - -static int InitializeTemplateThunkMappingDataPhdrCallback(struct dl_phdr_info *info, size_t size, void *dataPtr) -{ - InitializeTemplateThunkLocals *locals = (InitializeTemplateThunkLocals*)dataPtr; - - if ((void*)info->dlpi_addr == locals->info.dli_fbase) - { - for (size_t j = 0; j < info->dlpi_phnum; j++) - { - uint8_t* baseSectionAddr = (uint8_t*)locals->info.dli_fbase + info->dlpi_phdr[j].p_vaddr; - if (locals->pTemplate < baseSectionAddr) - { - // Address is before the virtual address of this section begins - continue; - } - - // Since this is all in support of mapping code from the file, we need to ensure that the region we find - // is actually present in the file. - Elf32_Word sizeOfSectionWhichCanBeMapped = Elf32_WordMin(info->dlpi_phdr[j].p_filesz, info->dlpi_phdr[j].p_memsz); - - uint8_t* endAddressAllowedForTemplate = baseSectionAddr + sizeOfSectionWhichCanBeMapped; - if (locals->pTemplate >= endAddressAllowedForTemplate) - { - // Template is after the virtual address of this section ends (or the mappable region of the file) - continue; - } - - // At this point, we have found the template section. Attempt to open the file, and record the various offsets for future use - - if (strlen(info->dlpi_name) == 0) - { - // This image cannot be directly referenced without capturing the argv[0] parameter - return -1; - } - - int fdImage = open(info->dlpi_name, O_RDONLY); - if (fdImage == -1) - { - return -1; // Opening the image didn't work - } - - locals->data.fdImage = fdImage; - locals->data.offsetInFileOfStartOfSection = info->dlpi_phdr[j].p_offset; - locals->data.addrOfStartOfSection = baseSectionAddr; - locals->data.addrOfEndOfSection = baseSectionAddr + sizeOfSectionWhichCanBeMapped; - locals->data.imageTemplates = true; - return 1; // We have found the result. Abort further processing. - } - } - - // This isn't the interesting .so - return 0; -} -#endif // FEATURE_MAP_THUNKS_FROM_IMAGE - -TemplateThunkMappingData *InitializeTemplateThunkMappingData(void* pTemplate) -{ - InitializeTemplateThunkLocals locals; - locals.pTemplate = pTemplate; - locals.data.fdImage = 0; - locals.data.offsetInFileOfStartOfSection = 0; - locals.data.addrOfStartOfSection = NULL; - locals.data.addrOfEndOfSection = NULL; - locals.data.imageTemplates = false; - locals.data.nonImageTemplateCurrent = 0; - locals.data.templatesCreated = 0; - -#ifdef FEATURE_MAP_THUNKS_FROM_IMAGE - if (dladdr(pTemplate, &locals.info) != 0) - { - dl_iterate_phdr(InitializeTemplateThunkMappingDataPhdrCallback, &locals); - } -#endif // FEATURE_MAP_THUNKS_FROM_IMAGE - - if (locals.data.addrOfStartOfSection == NULL) - { - // This is the detail of thunk data which indicates if we were able to compute the template mapping data from the image. - -#ifdef TARGET_FREEBSD - int fd = shm_open(SHM_ANON, O_RDWR | O_CREAT, S_IRWXU); -#elif defined(TARGET_LINUX) || defined(TARGET_ANDROID) - int fd = memfd_create("doublemapper-template", MFD_CLOEXEC); -#else - int fd = -1; - -#ifndef TARGET_ANDROID - // Bionic doesn't have shm_{open,unlink} - // POSIX fallback - if (fd == -1) - { - char name[24]; - sprintf(name, "/shm-dotnet-template-%d", getpid()); - name[sizeof(name) - 1] = '\0'; - shm_unlink(name); - fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600); - shm_unlink(name); - } -#endif // !TARGET_ANDROID -#endif - if (fd != -1) - { - off_t maxFileSize = MAX_TEMPLATE_THUNK_TYPES * 0x10000; // The largest page size we support currently is 64KB. - if (ftruncate(fd, maxFileSize) == -1) // Reserve a decent size chunk of logical memory for these things. - { - close(fd); - } - else - { - locals.data.fdImage = fd; - locals.data.offsetInFileOfStartOfSection = 0; - // We simulate the template thunk mapping data existing in mapped ram, by declaring that it exists at at - // an address which is not NULL, and which is naturally aligned on the largest page size supported by any - // architecture we support (0x10000). We do this, as the generalized logic here is designed around remapping - // already mapped memory, and by doing this we are able to share that logic. - locals.data.addrOfStartOfSection = (void*)0x10000; - locals.data.addrOfEndOfSection = ((uint8_t*)locals.data.addrOfStartOfSection) + maxFileSize; - locals.data.imageTemplates = false; - } - } - } - - - TemplateThunkMappingData *pAllocatedData = (TemplateThunkMappingData*)malloc(sizeof(TemplateThunkMappingData)); - *pAllocatedData = locals.data; - TemplateThunkMappingData *pExpectedNull = NULL; - if (__atomic_compare_exchange_n (&s_pThunkData, &pExpectedNull, pAllocatedData, false, __ATOMIC_RELEASE, __ATOMIC_RELAXED)) - { - return pAllocatedData; - } - else - { - free(pAllocatedData); - return __atomic_load_n(&s_pThunkData, __ATOMIC_ACQUIRE); - } -} -#endif - -bool VMToOSInterface::AllocateThunksFromTemplateRespectsStartAddress() -{ -#ifdef TARGET_APPLE - return false; -#else - return true; -#endif -} - -void* VMToOSInterface::CreateTemplate(void* pImageTemplate, size_t templateSize, void (*codePageGenerator)(uint8_t* pageBase, uint8_t* pageBaseRX, size_t size)) -{ -#ifdef TARGET_APPLE - return pImageTemplate; -#elif defined(TARGET_X86) - return NULL; // X86 doesn't support high performance relative addressing, which makes the template system not work -#else - if (pImageTemplate == NULL) - return NULL; - - TemplateThunkMappingData* pThunkData = __atomic_load_n(&s_pThunkData, __ATOMIC_ACQUIRE); - if (s_pThunkData == NULL) - { - pThunkData = InitializeTemplateThunkMappingData(pImageTemplate); - } - - // Unable to create template mapping region - if (pThunkData->addrOfStartOfSection == NULL) - { - return NULL; - } - - int templatesCreated = __atomic_add_fetch(&pThunkData->templatesCreated, 1, __ATOMIC_SEQ_CST); - assert(templatesCreated <= MAX_TEMPLATE_THUNK_TYPES); - - if (!pThunkData->imageTemplates) - { - // Need to allocate a memory mapped region to fill in the data - off_t locationInFileToStoreGeneratedCode = __atomic_fetch_add((off_t*)&pThunkData->nonImageTemplateCurrent, (off_t)templateSize, __ATOMIC_SEQ_CST); - void* mappedMemory = mmap(NULL, templateSize, PROT_READ | PROT_WRITE, MAP_SHARED, pThunkData->fdImage, locationInFileToStoreGeneratedCode); - if (mappedMemory != MAP_FAILED) - { - codePageGenerator((uint8_t*)mappedMemory, (uint8_t*)mappedMemory, templateSize); - munmap(mappedMemory, templateSize); - return ((uint8_t*)pThunkData->addrOfStartOfSection) + locationInFileToStoreGeneratedCode; - } - else - { - return NULL; - } - } - else - { - return pImageTemplate; - } -#endif -} - -void* VMToOSInterface::AllocateThunksFromTemplate(void* pTemplate, size_t templateSize, void* pStartSpecification) -{ -#ifdef TARGET_APPLE - vm_address_t addr, taddr; - vm_prot_t prot, max_prot; - kern_return_t ret; - - // Allocate two contiguous ranges of memory: the first range will contain the stubs - // and the second range will contain their data. - do - { - ret = vm_allocate(mach_task_self(), &addr, templateSize * 2, VM_FLAGS_ANYWHERE); - } while (ret == KERN_ABORTED); - - if (ret != KERN_SUCCESS) - { - return NULL; - } - - do - { - ret = vm_remap( - mach_task_self(), &addr, templateSize, 0, VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE, - mach_task_self(), (vm_address_t)pTemplate, FALSE, &prot, &max_prot, VM_INHERIT_SHARE); - } while (ret == KERN_ABORTED); - - if (ret != KERN_SUCCESS) - { - do - { - ret = vm_deallocate(mach_task_self(), addr, templateSize * 2); - } while (ret == KERN_ABORTED); - - return NULL; - } - return (void*)addr; -#else - TemplateThunkMappingData* pThunkData = __atomic_load_n(&s_pThunkData, __ATOMIC_ACQUIRE); - if (s_pThunkData == NULL) - { - pThunkData = InitializeTemplateThunkMappingData(pTemplate); - } - - if (pThunkData->addrOfStartOfSection == NULL) - { - // This is the detail of thunk data which indicates if we were able to compute the template mapping data - return NULL; - } - - if (pTemplate < pThunkData->addrOfStartOfSection) - { - return NULL; - } - - uint8_t* endOfTemplate = ((uint8_t*)pTemplate + templateSize); - if (endOfTemplate > pThunkData->addrOfEndOfSection) - return NULL; - - size_t sectionOffset = (uint8_t*)pTemplate - (uint8_t*)pThunkData->addrOfStartOfSection; - off_t fileOffset = pThunkData->offsetInFileOfStartOfSection + sectionOffset; - - void *pStart = mmap(pStartSpecification, templateSize * 2, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | (pStartSpecification != NULL ? MAP_FIXED : 0), -1, 0); - if (pStart == MAP_FAILED) - { - return NULL; - } - - void *pStartCode = mmap(pStart, templateSize, PROT_READ | PROT_EXEC, MAP_PRIVATE | MAP_FIXED, pThunkData->fdImage, fileOffset); - if (pStart != pStartCode) - { - munmap(pStart, templateSize * 2); - return NULL; - } - - return pStart; -#endif -} - -bool VMToOSInterface::FreeThunksFromTemplate(void* thunks, size_t templateSize) -{ -#ifdef TARGET_APPLE - kern_return_t ret; - - do - { - ret = vm_deallocate(mach_task_self(), (vm_address_t)thunks, templateSize * 2); - } while (ret == KERN_ABORTED); - - return ret == KERN_SUCCESS ? true : false; -#else - munmap(thunks, templateSize * 2); - return true; -#endif -} diff --git a/src/coreclr/minipal/Windows/doublemapping.cpp b/src/coreclr/minipal/Windows/doublemapping.cpp index f5f25f2bec92cc..9e8ddfed8e964d 100644 --- a/src/coreclr/minipal/Windows/doublemapping.cpp +++ b/src/coreclr/minipal/Windows/doublemapping.cpp @@ -210,23 +210,3 @@ bool VMToOSInterface::ReleaseRWMapping(void* pStart, size_t size) { return UnmapViewOfFile(pStart); } - -void* VMToOSInterface::CreateTemplate(void* pImageTemplate, size_t templateSize, void (*codePageGenerator)(uint8_t* pageBase, uint8_t* pageBaseRX, size_t size)) -{ - return NULL; -} - -bool VMToOSInterface::AllocateThunksFromTemplateRespectsStartAddress() -{ - return false; -} - -void* VMToOSInterface::AllocateThunksFromTemplate(void* pTemplate, size_t templateSize, void* pStart) -{ - return NULL; -} - -bool VMToOSInterface::FreeThunksFromTemplate(void* thunks, size_t templateSize) -{ - return false; -} diff --git a/src/coreclr/minipal/minipal.h b/src/coreclr/minipal/minipal.h index 01f497e60e6d7e..afecd9ce74dc72 100644 --- a/src/coreclr/minipal/minipal.h +++ b/src/coreclr/minipal/minipal.h @@ -75,41 +75,6 @@ class VMToOSInterface // Return: // true if it succeeded, false if it failed static bool ReleaseRWMapping(void* pStart, size_t size); - - // Create a template for use by AllocateThunksFromTemplate - // Parameters: - // pImageTemplate - Address of start of template in the image for coreclr. (All addresses passed to the api in a process must be from the same module, if any call uses a pImageTemplate, all calls MUST) - // templateSize - Size of the template - // codePageGenerator - If the system is unable to use pImageTemplate, use this parameter to generate the code page instead - // - // Return: - // NULL if creating the template fails - // Non-NULL, a pointer to the template - static void* CreateTemplate(void* pImageTemplate, size_t templateSize, void (*codePageGenerator)(uint8_t* pageBase, uint8_t* pageBaseRX, size_t size)); - - // Indicate if the AllocateThunksFromTemplate function respects the pStart address passed to AllocateThunksFromTemplate on this platform - // Return: - // true if the parameter is respected, false if not - static bool AllocateThunksFromTemplateRespectsStartAddress(); - - // Allocate thunks from template - // Parameters: - // pTemplate - Value returned from CreateTemplate - // templateSize - Size of the templates block in the image - // pStart - Where to allocate (Specify NULL if no particular address is required). If non-null, this must be an address returned by ReserveDoubleMappedMemory - // - // Return: - // NULL if the allocation fails - // Non-NULL, a pointer to the allocated region. - static void* AllocateThunksFromTemplate(void* pTemplate, size_t templateSize, void* pStart); - - // Free thunks allocated from template - // Parameters: - // pThunks - Address previously returned by AllocateThunksFromTemplate - // templateSize - Size of the templates block in the image - // Return: - // true if it succeeded, false if it failed - static bool FreeThunksFromTemplate(void* thunks, size_t templateSize); }; #if defined(HOST_64BIT) && defined(FEATURE_CACHED_INTERFACE_DISPATCH) diff --git a/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp b/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp index 94ad25ceab8bdb..a928e7018da25f 100644 --- a/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp +++ b/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp @@ -526,7 +526,7 @@ REDHAWK_PALEXPORT UInt32_BOOL REDHAWK_PALAPI PalAllocateThunksFromTemplate(HANDL vm_prot_t prot, max_prot; kern_return_t ret; - // Allocate two contiguous ranges of memory: the first range will contain the stubs + // Allocate two contiguous ranges of memory: the first range will contain the trampolines // and the second range will contain their data. do { diff --git a/src/coreclr/pal/inc/unixasmmacrosarm64.inc b/src/coreclr/pal/inc/unixasmmacrosarm64.inc index 640716f8058d5d..746e48321db352 100644 --- a/src/coreclr/pal/inc/unixasmmacrosarm64.inc +++ b/src/coreclr/pal/inc/unixasmmacrosarm64.inc @@ -37,6 +37,13 @@ C_FUNC(\Name): C_FUNC(\Name): .endm +// On MacOS, local labels cannot be used in arithmetic expressions. +#if defined(__APPLE__) +#define FIXUP_LABEL(name) name +#else +#define FIXUP_LABEL(name) .L##name +#endif + .macro LEAF_ENTRY Name, Section .global C_FUNC(\Name) #if defined(__APPLE__) diff --git a/src/coreclr/utilcode/executableallocator.cpp b/src/coreclr/utilcode/executableallocator.cpp index 0242377072238c..d145ab03987a08 100644 --- a/src/coreclr/utilcode/executableallocator.cpp +++ b/src/coreclr/utilcode/executableallocator.cpp @@ -503,11 +503,6 @@ void* ExecutableAllocator::Commit(void* pStart, size_t size, bool isExecutable) } void ExecutableAllocator::Release(void* pRX) -{ - ReleaseWorker(pRX, false /* this is the standard Release of normally allocated memory */); -} - -void ExecutableAllocator::ReleaseWorker(void* pRX, bool releaseTemplate) { LIMITED_METHOD_CONTRACT; @@ -553,19 +548,9 @@ void ExecutableAllocator::ReleaseWorker(void* pRX, bool releaseTemplate) cachedMappingThatOverlaps = FindOverlappingCachedMapping(pBlock); } - if (releaseTemplate) + if (!VMToOSInterface::ReleaseDoubleMappedMemory(m_doubleMemoryMapperHandle, pRX, pBlock->offset, pBlock->size)) { - if (!VMToOSInterface::FreeThunksFromTemplate(pRX, pBlock->size / 2)) - { - g_fatalErrorHandler(COR_E_EXECUTIONENGINE, W("Releasing the template mapped memory failed")); - } - } - else - { - if (!VMToOSInterface::ReleaseDoubleMappedMemory(m_doubleMemoryMapperHandle, pRX, pBlock->offset, pBlock->size)) - { - g_fatalErrorHandler(COR_E_EXECUTIONENGINE, W("Releasing the double mapped memory failed")); - } + g_fatalErrorHandler(COR_E_EXECUTIONENGINE, W("Releasing the double mapped memory failed")); } // Put the released block into the free block list pBlock->baseRX = NULL; @@ -977,60 +962,3 @@ void ExecutableAllocator::UnmapRW(void* pRW) g_fatalErrorHandler(COR_E_EXECUTIONENGINE, W("Releasing the RW mapping failed")); } } - -void* ExecutableAllocator::AllocateThunksFromTemplate(void *pTemplate, size_t templateSize) -{ - if (IsDoubleMappingEnabled() && VMToOSInterface::AllocateThunksFromTemplateRespectsStartAddress()) - { - CRITSEC_Holder csh(m_CriticalSection); - - bool isFreeBlock; - BlockRX* block = AllocateBlock(templateSize * 2, &isFreeBlock); - if (block == NULL) - { - return NULL; - } - - void* result = VMToOSInterface::ReserveDoubleMappedMemory(m_doubleMemoryMapperHandle, block->offset, templateSize * 2, 0, 0); - - if (result != NULL) - { - block->baseRX = result; - AddRXBlock(block); - } - else - { - BackoutBlock(block, isFreeBlock); - } - - void *pTemplateAddressAllocated = VMToOSInterface::AllocateThunksFromTemplate(pTemplate, templateSize, block->baseRX); - - if (pTemplateAddressAllocated == NULL) - { - ReleaseWorker(block->baseRX, false); - } - - return pTemplateAddressAllocated; - } - else - { - return VMToOSInterface::AllocateThunksFromTemplate(pTemplate, templateSize, NULL); - } -} - -void ExecutableAllocator::FreeThunksFromTemplate(void *pThunks, size_t templateSize) -{ - if (IsDoubleMappingEnabled() && VMToOSInterface::AllocateThunksFromTemplateRespectsStartAddress()) - { - ReleaseWorker(pThunks, true /* This is a release of template allocated memory */); - } - else - { - VMToOSInterface::FreeThunksFromTemplate(pThunks, templateSize); - } -} - -void* ExecutableAllocator::CreateTemplate(void* templateInImage, size_t templateSize, void (*codePageGenerator)(uint8_t* pageBase, uint8_t* pageBaseRX, size_t size)) -{ - return VMToOSInterface::CreateTemplate(templateInImage, templateSize, codePageGenerator); -} diff --git a/src/coreclr/utilcode/interleavedloaderheap.cpp b/src/coreclr/utilcode/interleavedloaderheap.cpp index 082e337caebda1..d908ea20c194db 100644 --- a/src/coreclr/utilcode/interleavedloaderheap.cpp +++ b/src/coreclr/utilcode/interleavedloaderheap.cpp @@ -33,13 +33,10 @@ namespace UnlockedInterleavedLoaderHeap::UnlockedInterleavedLoaderHeap( RangeList *pRangeList, - const InterleavedLoaderHeapConfig *pConfig) : + void (*codePageGenerator)(BYTE* pageBase, BYTE* pageBaseRX, SIZE_T size), + DWORD dwGranularity) : UnlockedLoaderHeapBase(LoaderHeapImplementationKind::Interleaved), - m_pEndReservedRegion(NULL), - m_dwGranularity(pConfig->StubSize), - m_pRangeList(pRangeList), - m_pFreeListHead(NULL), - m_pConfig(pConfig) + m_pFreeListHead(NULL) { CONTRACTL { @@ -49,7 +46,15 @@ UnlockedInterleavedLoaderHeap::UnlockedInterleavedLoaderHeap( } CONTRACTL_END; + m_pEndReservedRegion = NULL; + + m_pRangeList = pRangeList; + _ASSERTE((GetStubCodePageSize() % GetOsPageSize()) == 0); // Stub code page size MUST be in increments of the page size. (Really it must be a power of 2 as well, but this is good enough) + m_dwGranularity = dwGranularity; + + _ASSERTE(codePageGenerator != NULL); + m_codePageGenerator = codePageGenerator; } // ~LoaderHeap is not synchronised (obviously) @@ -75,14 +80,7 @@ UnlockedInterleavedLoaderHeap::~UnlockedInterleavedLoaderHeap() pVirtualAddress = pSearch->pVirtualAddress; pNext = pSearch->pNext; - if (m_pConfig->Template != NULL) - { - ExecutableAllocator::Instance()->FreeThunksFromTemplate(pVirtualAddress, GetStubCodePageSize()); - } - else - { - ExecutableAllocator::Instance()->Release(pVirtualAddress); - } + ExecutableAllocator::Instance()->Release(pVirtualAddress); delete pSearch; } @@ -103,7 +101,6 @@ size_t UnlockedInterleavedLoaderHeap::GetBytesAvailReservedRegion() BOOL UnlockedInterleavedLoaderHeap::CommitPages(void* pData, size_t dwSizeToCommitPart) { - _ASSERTE(m_pConfig->Template == NULL); // This path should only be used for LoaderHeaps which use the standard ExecutableAllocator functions // Commit first set of pages, since it will contain the LoaderHeapBlock { void *pTemp = ExecutableAllocator::Instance()->Commit(pData, dwSizeToCommitPart, IsExecutable()); @@ -124,7 +121,7 @@ BOOL UnlockedInterleavedLoaderHeap::CommitPages(void* pData, size_t dwSizeToComm } ExecutableWriterHolder codePageWriterHolder((BYTE*)pData, dwSizeToCommitPart, ExecutableAllocator::DoNotAddToCache); - m_pConfig->CodePageGenerator(codePageWriterHolder.GetRW(), (BYTE*)pData, dwSizeToCommitPart); + m_codePageGenerator(codePageWriterHolder.GetRW(), (BYTE*)pData, dwSizeToCommitPart); FlushInstructionCache(GetCurrentProcess(), pData, dwSizeToCommitPart); return TRUE; @@ -140,8 +137,6 @@ BOOL UnlockedInterleavedLoaderHeap::UnlockedReservePages(size_t dwSizeToCommit) } CONTRACTL_END; - _ASSERTE(m_pConfig->Template == NULL); // This path should only be used for LoaderHeaps which use the standard ExecutableAllocator functions - size_t dwSizeToReserve; // Round to page size again @@ -227,14 +222,6 @@ BOOL UnlockedInterleavedLoaderHeap::UnlockedReservePages(size_t dwSizeToCommit) return TRUE; } -void ReleaseAllocatedThunks(BYTE* thunks) -{ - ExecutableAllocator::Instance()->FreeThunksFromTemplate(thunks, GetStubCodePageSize()); -} - -using ThunkMemoryHolder = SpecializedWrapper; - - // Get some more committed pages - either commit some more in the current reserved region, or, if it // has run out, reserve another set of pages. // Returns: FALSE if we can't get any more memory @@ -250,57 +237,6 @@ BOOL UnlockedInterleavedLoaderHeap::GetMoreCommittedPages(size_t dwMinSize) } CONTRACTL_END; - if (m_pConfig->Template != NULL) - { - ThunkMemoryHolder newAllocatedThunks = (BYTE*)ExecutableAllocator::Instance()->AllocateThunksFromTemplate(m_pConfig->Template, GetStubCodePageSize()); - if (newAllocatedThunks == NULL) - { - return FALSE; - } - - NewHolder pNewBlock = new (nothrow) LoaderHeapBlock; - if (pNewBlock == NULL) - { - return FALSE; - } - - size_t dwSizeToReserve = GetStubCodePageSize() * 2; - - // Record reserved range in range list, if one is specified - // Do this AFTER the commit - otherwise we'll have bogus ranges included. - if (m_pRangeList != NULL) - { - if (!m_pRangeList->AddRange((const BYTE *) newAllocatedThunks, - ((const BYTE *) newAllocatedThunks) + dwSizeToReserve, - (void *) this)) - { - return FALSE; - } - } - - m_dwTotalAlloc += dwSizeToReserve; - - pNewBlock.SuppressRelease(); - newAllocatedThunks.SuppressRelease(); - - pNewBlock->dwVirtualSize = dwSizeToReserve; - pNewBlock->pVirtualAddress = newAllocatedThunks; - pNewBlock->pNext = m_pFirstBlock; - pNewBlock->m_fReleaseMemory = TRUE; - - // Add to the linked list - m_pFirstBlock = pNewBlock; - - m_pAllocPtr = (BYTE*)newAllocatedThunks; - m_pPtrToEndOfCommittedRegion = m_pAllocPtr + GetStubCodePageSize(); - m_pEndReservedRegion = m_pAllocPtr + dwSizeToReserve; // For consistency with the non-template path m_pEndReservedRegion is after the end of the data area - m_dwTotalAlloc += GetStubCodePageSize(); - - return TRUE; - } - - // From here, all work is only for the dynamically allocated InterleavedLoaderHeap path - // If we have memory we can use, what are you doing here! _ASSERTE(dwMinSize > (SIZE_T)(m_pPtrToEndOfCommittedRegion - m_pAllocPtr)); @@ -538,13 +474,5 @@ void *UnlockedInterleavedLoaderHeap::UnlockedAllocStub( return pResult; } - -void InitializeLoaderHeapConfig(InterleavedLoaderHeapConfig *pConfig, size_t stubSize, void* templateInImage, void (*codePageGenerator)(uint8_t* pageBase, uint8_t* pageBaseRX, size_t size)) -{ - pConfig->StubSize = (uint32_t)stubSize; - pConfig->Template = ExecutableAllocator::Instance()->CreateTemplate(templateInImage, GetStubCodePageSize(), codePageGenerator); - pConfig->CodePageGenerator = codePageGenerator; -} - #endif // #ifndef DACCESS_COMPILE diff --git a/src/coreclr/vm/CMakeLists.txt b/src/coreclr/vm/CMakeLists.txt index e910f0579fff38..32e932906abd4f 100644 --- a/src/coreclr/vm/CMakeLists.txt +++ b/src/coreclr/vm/CMakeLists.txt @@ -785,11 +785,11 @@ if(CLR_CMAKE_TARGET_ARCH_AMD64) ) set(VM_SOURCES_WKS_ARCH - ${ARCH_SOURCES_DIR}/jitinterfaceamd64.cpp ${ARCH_SOURCES_DIR}/profiler.cpp exceptionhandling.cpp gcinfodecoder.cpp jitinterfacegen.cpp + writebarriermanager.cpp ) set(VM_HEADERS_WKS_ARCH @@ -856,6 +856,7 @@ elseif(CLR_CMAKE_TARGET_ARCH_ARM64) set(VM_SOURCES_WKS_ARCH ${ARCH_SOURCES_DIR}/profiler.cpp gcinfodecoder.cpp + writebarriermanager.cpp ) if(CLR_CMAKE_HOST_UNIX) diff --git a/src/coreclr/vm/amd64/thunktemplates.S b/src/coreclr/vm/amd64/thunktemplates.S index 611556da202bb9..ebb0f6f67f193d 100644 --- a/src/coreclr/vm/amd64/thunktemplates.S +++ b/src/coreclr/vm/amd64/thunktemplates.S @@ -5,155 +5,9 @@ #include "unixasmmacros.inc" #include "asmconstants.h" -#ifdef FEATURE_MAP_THUNKS_FROM_IMAGE - -#define POINTER_SIZE 0x08 - -#define THUNKS_MAP_SIZE 0x4000 - -#define PAGE_SIZE 0x4000 -#define PAGE_SIZE_LOG2 14 - - -#define DATA_SLOT(stub, field, thunkSize, thunkTemplateName) C_FUNC(thunkTemplateName) + THUNKS_MAP_SIZE + stub##Data__##field + IN_PAGE_INDEX * thunkSize - -// ---------- -// StubPrecode -// ---------- - -#define STUB_PRECODE_CODESIZE 0x18 // 3 instructions, 13 bytes encoded + 11 bytes of padding -#define STUB_PRECODE_DATASIZE 0x18 // 2 qwords + a BYTE -.set STUB_PRECODE_NUM_THUNKS_PER_MAPPING,(THUNKS_MAP_SIZE / STUB_PRECODE_CODESIZE) - -.macro THUNKS_BLOCK_STUB_PRECODE - IN_PAGE_INDEX = 0 - .rept STUB_PRECODE_NUM_THUNKS_PER_MAPPING - - mov r10, [rip + DATA_SLOT(StubPrecode, SecretParam, STUB_PRECODE_CODESIZE, StubPrecodeCodeTemplate)] - jmp [rip + DATA_SLOT(StubPrecode, Target, STUB_PRECODE_CODESIZE, StubPrecodeCodeTemplate)] - // The above is 13 bytes - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 - IN_PAGE_INDEX = IN_PAGE_INDEX + 1 - .endr -.endm - - .text - .p2align PAGE_SIZE_LOG2 -LEAF_ENTRY StubPrecodeCodeTemplate - THUNKS_BLOCK_STUB_PRECODE -LEAF_END_MARKED StubPrecodeCodeTemplate, _TEXT - -// ---------- -// FixupPrecode -// ---------- - -#define FIXUP_PRECODE_CODESIZE 0x18 -#define FIXUP_PRECODE_DATASIZE 0x18 // 3 qwords -.set FIXUP_PRECODE_NUM_THUNKS_PER_MAPPING,(THUNKS_MAP_SIZE / FIXUP_PRECODE_CODESIZE) - -.macro THUNKS_BLOCK_FIXUP_PRECODE - IN_PAGE_INDEX = 0 - .rept FIXUP_PRECODE_NUM_THUNKS_PER_MAPPING - - jmp [rip + DATA_SLOT(FixupPrecode, Target, FIXUP_PRECODE_CODESIZE, FixupPrecodeCodeTemplate)] - mov r10, [rip + DATA_SLOT(FixupPrecode, MethodDesc, FIXUP_PRECODE_CODESIZE, FixupPrecodeCodeTemplate)] - jmp [rip + DATA_SLOT(FixupPrecode, PrecodeFixupThunk, FIXUP_PRECODE_CODESIZE, FixupPrecodeCodeTemplate)] - // The above is 19 bytes - int 3 - int 3 - int 3 - int 3 - int 3 - IN_PAGE_INDEX = IN_PAGE_INDEX + 1 - .endr -.endm - - .text - .p2align PAGE_SIZE_LOG2 -LEAF_ENTRY FixupPrecodeCodeTemplate - THUNKS_BLOCK_FIXUP_PRECODE - // We need 16 bytes of padding to pad this out - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 -LEAF_END_MARKED FixupPrecodeCodeTemplate, _TEXT - -// ---------- -// CallCountingStub -// ---------- - -#define CALLCOUNTING_CODESIZE 0x18 -#define CALLCOUNTING_DATASIZE 0x18 // 3 qwords -.set CALLCOUNTING_NUM_THUNKS_PER_MAPPING, (THUNKS_MAP_SIZE / CALLCOUNTING_CODESIZE) -.macro THUNKS_BLOCK_CALLCOUNTING - IN_PAGE_INDEX = 0 - .rept CALLCOUNTING_NUM_THUNKS_PER_MAPPING - - mov rax,QWORD PTR [rip + DATA_SLOT(CallCountingStub, RemainingCallCountCell, CALLCOUNTING_CODESIZE, CallCountingStubCodeTemplate)] - dec WORD PTR [rax] - je 0f - jmp QWORD PTR [rip + DATA_SLOT(CallCountingStub, TargetForMethod, CALLCOUNTING_CODESIZE, CallCountingStubCodeTemplate)] - 0: - jmp QWORD PTR [rip + DATA_SLOT(CallCountingStub, TargetForThresholdReached, CALLCOUNTING_CODESIZE, CallCountingStubCodeTemplate)] - IN_PAGE_INDEX = IN_PAGE_INDEX + 1 - .endr -.endm - - .text - .p2align PAGE_SIZE_LOG2 -LEAF_ENTRY CallCountingStubCodeTemplate - THUNKS_BLOCK_CALLCOUNTING - // We need 16 bytes of padding to pad this out - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 - int 3 -LEAF_END_MARKED CallCountingStubCodeTemplate, _TEXT - -#endif - // STUB_PAGE_SIZE must match the behavior of GetStubCodePageSize() on this architecture/os STUB_PAGE_SIZE = 16384 -#ifdef DATA_SLOT -#undef DATA_SLOT -#endif - #define DATA_SLOT(stub, field) C_FUNC(stub##Code) + STUB_PAGE_SIZE + stub##Data__##field LEAF_ENTRY StubPrecodeCode, _TEXT diff --git a/src/coreclr/vm/arm64/asmhelpers.S b/src/coreclr/vm/arm64/asmhelpers.S index 03e495606fac9f..bdb9d5d42809d8 100644 --- a/src/coreclr/vm/arm64/asmhelpers.S +++ b/src/coreclr/vm/arm64/asmhelpers.S @@ -180,83 +180,6 @@ PATCH_LABEL ThePreStubPatchLabel ret lr LEAF_END ThePreStubPatch, _TEXT -// void JIT_UpdateWriteBarrierState(bool skipEphemeralCheck, size_t writeableOffset) -// -// Update shadow copies of the various state info required for barrier -// -// State info is contained in a literal pool at the end of the function -// Placed in text section so that it is close enough to use ldr literal and still -// be relocatable. Eliminates need for PREPARE_EXTERNAL_VAR in hot code. -// -// Align and group state info together so it fits in a single cache line -// and each entry can be written atomically -// -LEAF_ENTRY JIT_UpdateWriteBarrierState, _TEXT - PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -16 - - // x0-x7, x10 will contain intended new state - // x8 will preserve skipEphemeralCheck - // x12 will be used for pointers - - mov x8, x0 - mov x9, x1 - - PREPARE_EXTERNAL_VAR g_card_table, x12 - ldr x0, [x12] - -#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES - PREPARE_EXTERNAL_VAR g_card_bundle_table, x12 - ldr x1, [x12] -#endif - -#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP - PREPARE_EXTERNAL_VAR g_write_watch_table, x12 - ldr x2, [x12] -#endif - - PREPARE_EXTERNAL_VAR g_ephemeral_low, x12 - ldr x3, [x12] - - PREPARE_EXTERNAL_VAR g_ephemeral_high, x12 - ldr x4, [x12] - - cbz x8, LOCAL_LABEL(EphemeralCheckEnabled) - movz x3, #0 - movn x4, #0 -LOCAL_LABEL(EphemeralCheckEnabled): - - PREPARE_EXTERNAL_VAR g_lowest_address, x12 - ldr x5, [x12] - - PREPARE_EXTERNAL_VAR g_highest_address, x12 - ldr x6, [x12] - -#ifdef WRITE_BARRIER_CHECK - PREPARE_EXTERNAL_VAR g_GCShadow, x12 - ldr x7, [x12] - - PREPARE_EXTERNAL_VAR g_GCShadowEnd, x12 - ldr x10, [x12] -#endif - - // Update wbs state - PREPARE_EXTERNAL_VAR JIT_WriteBarrier_Table_Loc, x12 - ldr x12, [x12] - add x12, x12, x9 - - stp x0, x1, [x12], 16 - stp x2, x3, [x12], 16 - stp x4, x5, [x12], 16 - str x6, [x12], 8 -#ifdef WRITE_BARRIER_CHECK - stp x7, x10, [x12], 16 -#endif - - - EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 16 - EPILOG_RETURN -LEAF_END JIT_UpdateWriteBarrierState - // ------------------------// ------------------------------------------------------------------ // __declspec(naked) void F_CALL_CONV JIT_WriteBarrier_Callable(Object **dst, Object* val) LEAF_ENTRY JIT_WriteBarrier_Callable, _TEXT diff --git a/src/coreclr/vm/arm64/asmhelpers.asm b/src/coreclr/vm/arm64/asmhelpers.asm index ce63e41a084db5..a5864d120da364 100644 --- a/src/coreclr/vm/arm64/asmhelpers.asm +++ b/src/coreclr/vm/arm64/asmhelpers.asm @@ -248,84 +248,6 @@ ThePreStubPatchLabel ret lr LEAF_END -;----------------------------------------------------------------------------- -; void JIT_UpdateWriteBarrierState(bool skipEphemeralCheck, size_t writeableOffset) -; -; Update shadow copies of the various state info required for barrier -; -; State info is contained in a literal pool at the end of the function -; Placed in text section so that it is close enough to use ldr literal and still -; be relocatable. Eliminates need for PREPARE_EXTERNAL_VAR in hot code. -; -; Align and group state info together so it fits in a single cache line -; and each entry can be written atomically -; - LEAF_ENTRY JIT_UpdateWriteBarrierState - PROLOG_SAVE_REG_PAIR fp, lr, #-16! - - ; x0-x7, x10 will contain intended new state - ; x8 will preserve skipEphemeralCheck - ; x12 will be used for pointers - - mov x8, x0 - mov x9, x1 - - adrp x12, g_card_table - ldr x0, [x12, g_card_table] - -#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES - adrp x12, g_card_bundle_table - ldr x1, [x12, g_card_bundle_table] -#endif - -#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP - adrp x12, g_write_watch_table - ldr x2, [x12, g_write_watch_table] -#endif - - adrp x12, g_ephemeral_low - ldr x3, [x12, g_ephemeral_low] - - adrp x12, g_ephemeral_high - ldr x4, [x12, g_ephemeral_high] - - ; Check skipEphemeralCheck - cbz x8, EphemeralCheckEnabled - movz x3, #0 - movn x4, #0 - -EphemeralCheckEnabled - adrp x12, g_lowest_address - ldr x5, [x12, g_lowest_address] - - adrp x12, g_highest_address - ldr x6, [x12, g_highest_address] - -#ifdef WRITE_BARRIER_CHECK - adrp x12, $g_GCShadow - ldr x7, [x12, $g_GCShadow] - - adrp x12, $g_GCShadowEnd - ldr x10, [x12, $g_GCShadowEnd] -#endif - - ; Update wbs state - adrp x12, JIT_WriteBarrier_Table_Loc - ldr x12, [x12, JIT_WriteBarrier_Table_Loc] - add x12, x12, x9 - stp x0, x1, [x12], 16 - stp x2, x3, [x12], 16 - stp x4, x5, [x12], 16 - str x6, [x12], 8 -#ifdef WRITE_BARRIER_CHECK - stp x7, x10, [x12], 16 -#endif - - EPILOG_RESTORE_REG_PAIR fp, lr, #16! - EPILOG_RETURN - - LEAF_END JIT_UpdateWriteBarrierState - #ifdef FEATURE_COMINTEROP ; ------------------------------------------------------------------ diff --git a/src/coreclr/vm/arm64/patchedcode.S b/src/coreclr/vm/arm64/patchedcode.S index 0e223cbc1d33ab..2bea90942e66a4 100644 --- a/src/coreclr/vm/arm64/patchedcode.S +++ b/src/coreclr/vm/arm64/patchedcode.S @@ -3,6 +3,7 @@ #include "asmconstants.h" #include "unixasmmacros.inc" +#include "patchedcodeconstants.h" //----------------------------------------------------------------------------- // The following Macros help in WRITE_BARRIER Implementations @@ -85,6 +86,10 @@ WRITE_BARRIER_END JIT_CheckedWriteBarrier //----------------------------------------------------------------------------- // void JIT_WriteBarrier(Object** dst, Object* src) +// +// Empty function which at runtime is patched with one of the JIT_WriteBarrier_ +// functions below. +// // On entry: // x14 : the destination address (LHS of the assignment) // x15 : the object reference (RHS of the assignment) @@ -99,25 +104,82 @@ WRITE_BARRIER_END JIT_CheckedWriteBarrier // if you add more trashed registers. // WRITE_BARRIER_ENTRY JIT_WriteBarrier - stlr x15, [x14] + // This must be greater than the largest JIT_WriteBarrier_ function. + .space JIT_WriteBarrier_Size, 0 +WRITE_BARRIER_END JIT_WriteBarrier +//----------------------------------------------------------------------------- +// JIT_WriteBarrier_Table +// +// Patchable literal pool +// + .balign 64 // Align to power of two at least as big as patchable literal pool so that it fits optimally in cache line +WRITE_BARRIER_ENTRY JIT_WriteBarrier_Table +PATCH_LABEL JIT_WriteBarrier_Patch_Label_CardTable + .quad 0 +PATCH_LABEL JIT_WriteBarrier_Patch_Label_CardBundleTable + .quad 0 +PATCH_LABEL JIT_WriteBarrier_Patch_Label_WriteWatchTable + .quad 0 +PATCH_LABEL JIT_WriteBarrier_Patch_Label_Lower + .quad 0 +PATCH_LABEL JIT_WriteBarrier_Patch_Label_Upper + .quad 0 +LOCAL_LABEL(wbs_lowest_address): +PATCH_LABEL JIT_WriteBarrier_Patch_Label_LowestAddress + .quad 0 +LOCAL_LABEL(wbs_highest_address): +PATCH_LABEL JIT_WriteBarrier_Patch_Label_HighestAddress + .quad 0 +PATCH_LABEL JIT_WriteBarrier_Patch_Label_RegionToGeneration + .quad 0 +PATCH_LABEL JIT_WriteBarrier_Patch_Label_RegionShr + .quad 0 #ifdef WRITE_BARRIER_CHECK +PATCH_LABEL JIT_WriteBarrier_Patch_Label_GCShadow + .quad 0 +PATCH_LABEL JIT_WriteBarrier_Patch_Label_GCShadowEnd + .quad 0 +#endif +WRITE_BARRIER_END JIT_WriteBarrier_Table + +// ------------------------------------------------------------------ +// End of the writeable code region +LEAF_ENTRY JIT_PatchedCodeLast, _TEXT + ret lr +LEAF_END JIT_PatchedCodeLast, _TEXT + + + +//----------------------------------------------------------------------------- +// The following Macros are used by the different JIT_WriteBarrier_ functions. +// +// + +.macro WRITE_BARRIER_ENTRY_STUB start +FIXUP_LABEL(\start): + stlr x15, [x14] +.endm + + +.macro WRITE_BARRIER_SHADOW_UPDATE_STUB start + #ifdef WRITE_BARRIER_CHECK // Update GC Shadow Heap // Do not perform the work if g_GCShadow is 0 - ldr x12, LOCAL_LABEL(wbs_GCShadow) - cbz x12, LOCAL_LABEL(ShadowUpdateEnd) + ldr x12, JIT_WriteBarrier_Offset_GCShadow + FIXUP_LABEL(\start) + cbz x12, LOCAL_LABEL(ShadowUpdateEnd\@) // Compute address of shadow heap location: // pShadow = g_GCShadow + (x14 - g_lowest_address) - ldr x17, LOCAL_LABEL(wbs_lowest_address) + ldr x17, JIT_WriteBarrier_Offset_LowestAddress + FIXUP_LABEL(\start) sub x17, x14, x17 add x12, x17, x12 // if (pShadow >= g_GCShadowEnd) goto end - ldr x17, LOCAL_LABEL(wbs_GCShadowEnd) + ldr x17, JIT_WriteBarrier_Offset_GCShadowEnd + FIXUP_LABEL(\start) cmp x12, x17 - bhs LOCAL_LABEL(ShadowUpdateEnd) + bhs LOCAL_LABEL(ShadowUpdateEnd\@) // *pShadow = x15 str x15, [x12] @@ -129,96 +191,305 @@ WRITE_BARRIER_ENTRY JIT_WriteBarrier // if ([x14] == x15) goto end ldr x17, [x14] cmp x17, x15 - beq LOCAL_LABEL(ShadowUpdateEnd) + beq LOCAL_LABEL(ShadowUpdateEnd\@) // *pShadow = INVALIDGCVALUE (0xcccccccd) movz x17, #0xcccd movk x17, #0xcccc, LSL #16 str x17, [x12] - -LOCAL_LABEL(ShadowUpdateEnd): #endif +LOCAL_LABEL(ShadowUpdateEnd\@): +.endm + +.macro WRITE_BARRIER_WRITE_WATCH_FOR_GC_HEAP_STUB start, exit #ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP // Update the write watch table if necessary - ldr x12, LOCAL_LABEL(wbs_sw_ww_table) - cbz x12, LOCAL_LABEL(CheckCardTable) + ldr x12, JIT_WriteBarrier_Offset_WriteWatchTable + FIXUP_LABEL(\start) add x12, x12, x14, lsr #0xc // SoftwareWriteWatch::AddressToTableByteIndexShift ldrb w17, [x12] - cbnz x17, LOCAL_LABEL(CheckCardTable) + cbnz x17, LOCAL_LABEL(WriteWatchForGCHeapEnd\@) mov w17, #0xFF strb w17, [x12] +LOCAL_LABEL(WriteWatchForGCHeapEnd\@): #endif +.endm -LOCAL_LABEL(CheckCardTable): - // Branch to Exit if the reference is not in the Gen0 heap - ldr x12, LOCAL_LABEL(wbs_ephemeral_low) - ldr x17, LOCAL_LABEL(wbs_ephemeral_high) + +.macro WRITE_BARRIER_CHECK_EPHEMERAL_LOW_STUB start, exit + // Branch to Exit if the reference is not in the ephemeral generations. + ldr x12, JIT_WriteBarrier_Offset_Lower + FIXUP_LABEL(\start) + cmp x15, x12 + blo LOCAL_LABEL(\exit) +.endm + + +.macro WRITE_BARRIER_CHECK_EPHEMERAL_LOW_AND_HIGH_STUB start, exit + // Branch to Exit if the reference is not in the ephemeral generations. + ldr x12, JIT_WriteBarrier_Offset_Lower + FIXUP_LABEL(\start) + ldr x17, JIT_WriteBarrier_Offset_Upper + FIXUP_LABEL(\start) cmp x15, x12 ccmp x15, x17, #0x2, hs - bhs LOCAL_LABEL(Exit) + bhs LOCAL_LABEL(\exit) +.endm + + +.macro WRITE_BARRIER_REGION_CHECK_STUB start, exit + // Calculate region generations + ldr x17, JIT_WriteBarrier_Offset_RegionToGeneration + FIXUP_LABEL(\start) + ldr w12, JIT_WriteBarrier_Offset_RegionShr + FIXUP_LABEL(\start) + lsr x15, x15, x12 + add x15, x15, x17 // x15 = (RHS >> wbs_region_shr) + wbs_region_to_generation_table + lsr x12, x14, x12 + add x12, x12, x17 // x12 = (LHS >> wbs_region_shr) + wbs_region_to_generation_table + // Check whether the region we are storing into is gen 0 - nothing to do in this case + ldrb w12, [x12] + cbz w12, LOCAL_LABEL(\exit) + + // Return if the new reference is not from old to young + ldrb w15, [x15] + cmp w15, w12 + bhs LOCAL_LABEL(\exit) +.endm + + +.macro WRITE_BARRIER_CHECK_BIT_REGIONS_CARD_TABLE_STUB start, exit // Check if we need to update the card table - ldr x12, LOCAL_LABEL(wbs_card_table) + lsr w17, w14, 8 + and w17, w17, 7 + movz w15, 1 + lsl w17, w15, w17 // w17 = 1 << (LHS >> 8 && 7) + ldr x12, JIT_WriteBarrier_Offset_CardTable + FIXUP_LABEL(\start) add x15, x12, x14, lsr #11 - ldrb w12, [x15] + ldrb w12, [x15] // w12 = [(LHS >> 11) + g_card_table] + tst w12, w17 + bne LOCAL_LABEL(\exit) + + // Atomically update the card table + // Requires LSE, but the code is only compiled for 8.0 + .word 0x383131FF // stsetb w17, [x15] +.endm + + +.macro WRITE_BARRIER_CHECK_CARD_TABLE_STUB start, exit + // Check if we need to update the card table + ldr x12, JIT_WriteBarrier_Offset_CardTable + FIXUP_LABEL(\start) + add x15, x12, x14, lsr #11 + ldrb w12, [x15] // w12 = [(RHS >> 11) + g_card_table] cmp x12, 0xFF - beq LOCAL_LABEL(Exit) + beq LOCAL_LABEL(\exit) // Update the card table mov x12, 0xFF strb w12, [x15] +.endm + +.macro WRITE_BARRIER_CHECK_CARD_BUNDLE_TABLE_STUB start, exit #ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES // Check if we need to update the card bundle table - ldr x12, LOCAL_LABEL(wbs_card_bundle_table) + ldr x12, JIT_WriteBarrier_Offset_CardBundleTable + FIXUP_LABEL(\start) add x15, x12, x14, lsr #21 ldrb w12, [x15] cmp x12, 0xFF - beq LOCAL_LABEL(Exit) + beq LOCAL_LABEL(\exit) // Update the card bundle mov x12, 0xFF strb w12, [x15] #endif +.endm + -LOCAL_LABEL(Exit): +.macro WRITE_BARRIER_RETURN_STUB exit +LOCAL_LABEL(\exit): // Increment by 8 to implement JIT_ByRefWriteBarrier contract. // TODO: Consider duplicating the logic to get rid of this redundant 'add' // for JIT_WriteBarrier/JIT_CheckedWriteBarrier add x14, x14, 8 ret lr -WRITE_BARRIER_END JIT_WriteBarrier +.endm - // Begin patchable literal pool - .balign 64 // Align to power of two at least as big as patchable literal pool so that it fits optimally in cache line -WRITE_BARRIER_ENTRY JIT_WriteBarrier_Table -LOCAL_LABEL(wbs_begin): -LOCAL_LABEL(wbs_card_table): - .quad 0 -LOCAL_LABEL(wbs_card_bundle_table): - .quad 0 -LOCAL_LABEL(wbs_sw_ww_table): - .quad 0 -LOCAL_LABEL(wbs_ephemeral_low): - .quad 0 -LOCAL_LABEL(wbs_ephemeral_high): - .quad 0 -LOCAL_LABEL(wbs_lowest_address): - .quad 0 -LOCAL_LABEL(wbs_highest_address): - .quad 0 -#ifdef WRITE_BARRIER_CHECK -LOCAL_LABEL(wbs_GCShadow): - .quad 0 -LOCAL_LABEL(wbs_GCShadowEnd): - .quad 0 -#endif -WRITE_BARRIER_END JIT_WriteBarrier_Table +//----------------------------------------------------------------------------- +// void JIT_WriteBarrier_PreGrow64(Object** dst, Object* src) +// +// Skipped functionality: +// Does not update the write watch table +// Does not check wbs_ephemeral_high +// No region checks +// +LEAF_ENTRY JIT_WriteBarrier_PreGrow64, _TEXT + WRITE_BARRIER_ENTRY_STUB Start_PreGrow64 + WRITE_BARRIER_SHADOW_UPDATE_STUB Start_PreGrow64 + WRITE_BARRIER_CHECK_EPHEMERAL_LOW_STUB Start_PreGrow64, Exit_PreGrow64 + WRITE_BARRIER_CHECK_CARD_TABLE_STUB Start_PreGrow64, Exit_PreGrow64 + WRITE_BARRIER_CHECK_CARD_BUNDLE_TABLE_STUB Start_PreGrow64, Exit_PreGrow64 + WRITE_BARRIER_RETURN_STUB Exit_PreGrow64 +LEAF_END_MARKED JIT_WriteBarrier_PreGrow64, _TEXT + + +//----------------------------------------------------------------------------- +// void JIT_WriteBarrier_PostGrow64(Object** dst, Object* src) +// +// Skipped functionality: +// Does not update the write watch table +// No region checks +// +LEAF_ENTRY JIT_WriteBarrier_PostGrow64, _TEXT + WRITE_BARRIER_ENTRY_STUB Start_PostGrow64 + WRITE_BARRIER_SHADOW_UPDATE_STUB Start_PostGrow64 + WRITE_BARRIER_CHECK_EPHEMERAL_LOW_AND_HIGH_STUB Start_PostGrow64, Exit_PostGrow64 + WRITE_BARRIER_CHECK_CARD_TABLE_STUB Start_PostGrow64, Exit_PostGrow64 + WRITE_BARRIER_CHECK_CARD_BUNDLE_TABLE_STUB Start_PostGrow64, Exit_PostGrow64 + WRITE_BARRIER_RETURN_STUB Exit_PostGrow64 +LEAF_END_MARKED JIT_WriteBarrier_PostGrow64, _TEXT + + +//----------------------------------------------------------------------------- +// void JIT_WriteBarrier_SVR64(Object** dst, Object* src) +// +// SVR GC has multiple heaps, so it cannot provide one single ephemeral region to bounds check +// against, so we just skip the bounds checking all together and do our card table update unconditionally. +// +// Skipped functionality: +// Does not update the write watch table +// Does not check wbs_ephemeral_high or wbs_ephemeral_low +// No region checks +// +LEAF_ENTRY JIT_WriteBarrier_SVR64, _TEXT + WRITE_BARRIER_ENTRY_STUB Start_SVR64 + WRITE_BARRIER_SHADOW_UPDATE_STUB Start_SVR64 + WRITE_BARRIER_CHECK_CARD_TABLE_STUB Start_SVR64, Exit_SVR64 + WRITE_BARRIER_CHECK_CARD_BUNDLE_TABLE_STUB Start_SVR64, Exit_SVR64 + WRITE_BARRIER_RETURN_STUB Exit_SVR64 +LEAF_END_MARKED JIT_WriteBarrier_SVR64, _TEXT + + +//----------------------------------------------------------------------------- +// void JIT_WriteBarrier_Byte_Region64(Object** dst, Object* src) +// +// Skipped functionality: +// Does not update the write watch table +// Bitwise updates for region checks +// +LEAF_ENTRY JIT_WriteBarrier_Byte_Region64, _TEXT + WRITE_BARRIER_ENTRY_STUB Start_Byte_Region64 + WRITE_BARRIER_SHADOW_UPDATE_STUB Start_Byte_Region64 + WRITE_BARRIER_CHECK_EPHEMERAL_LOW_AND_HIGH_STUB Start_Byte_Region64, Exit_Byte_Region64 + WRITE_BARRIER_REGION_CHECK_STUB Start_Byte_Region64, Exit_Byte_Region64 + WRITE_BARRIER_CHECK_CARD_TABLE_STUB Start_Byte_Region64, Exit_Byte_Region64 + WRITE_BARRIER_CHECK_CARD_BUNDLE_TABLE_STUB Start_Byte_Region64, Exit_Byte_Region64 + WRITE_BARRIER_RETURN_STUB Exit_Byte_Region64 +LEAF_END_MARKED JIT_WriteBarrier_Byte_Region64, _TEXT + + +//----------------------------------------------------------------------------- +// void JIT_WriteBarrier_Bit_Region64(Object** dst, Object* src) +// +// Skipped functionality: +// Does not update the write watch table +// Does not call check card table stub +// +LEAF_ENTRY JIT_WriteBarrier_Bit_Region64, _TEXT + WRITE_BARRIER_ENTRY_STUB Start_Bit_Region64 + WRITE_BARRIER_SHADOW_UPDATE_STUB Start_Bit_Region64 + WRITE_BARRIER_CHECK_EPHEMERAL_LOW_AND_HIGH_STUB Start_Bit_Region64, Exit_Bit_Region64 + WRITE_BARRIER_REGION_CHECK_STUB Start_Bit_Region64, Exit_Bit_Region64 + WRITE_BARRIER_CHECK_BIT_REGIONS_CARD_TABLE_STUB Start_Bit_Region64, Exit_Bit_Region64 + WRITE_BARRIER_CHECK_CARD_BUNDLE_TABLE_STUB Start_Bit_Region64, Exit_Bit_Region64 + WRITE_BARRIER_RETURN_STUB Exit_Bit_Region64 +LEAF_END_MARKED JIT_WriteBarrier_Bit_Region64, _TEXT + + +//----------------------------------------------------------------------------- +// void JIT_WriteBarrier_WriteWatch_PreGrow64(Object** dst, Object* src) +// +// Skipped functionality: +// Does not check wbs_ephemeral_high +// No region checks +// +LEAF_ENTRY JIT_WriteBarrier_WriteWatch_PreGrow64, _TEXT + WRITE_BARRIER_ENTRY_STUB Start_WriteWatch_PreGrow64 + WRITE_BARRIER_SHADOW_UPDATE_STUB Start_WriteWatch_PreGrow64 + WRITE_BARRIER_WRITE_WATCH_FOR_GC_HEAP_STUB Start_WriteWatch_PreGrow64, Exit_WriteWatch_PreGrow64 + WRITE_BARRIER_CHECK_EPHEMERAL_LOW_STUB Start_WriteWatch_PreGrow64, Exit_WriteWatch_PreGrow64 + WRITE_BARRIER_CHECK_CARD_TABLE_STUB Start_WriteWatch_PreGrow64, Exit_WriteWatch_PreGrow64 + WRITE_BARRIER_CHECK_CARD_BUNDLE_TABLE_STUB Start_WriteWatch_PreGrow64, Exit_WriteWatch_PreGrow64 + WRITE_BARRIER_RETURN_STUB Exit_WriteWatch_PreGrow64 +LEAF_END_MARKED JIT_WriteBarrier_WriteWatch_PreGrow64, _TEXT + + +//----------------------------------------------------------------------------- +// void JIT_WriteBarrier_WriteWatch_PostGrow64(Object** dst, Object* src) +// +// Skipped functionality: +// No region checks +// +LEAF_ENTRY JIT_WriteBarrier_WriteWatch_PostGrow64, _TEXT + WRITE_BARRIER_ENTRY_STUB Start_WriteWatch_PostGrow64 + WRITE_BARRIER_SHADOW_UPDATE_STUB Start_WriteWatch_PostGrow64 + WRITE_BARRIER_WRITE_WATCH_FOR_GC_HEAP_STUB Start_WriteWatch_PostGrow64, Exit_WriteWatch_PostGrow64 + WRITE_BARRIER_CHECK_EPHEMERAL_LOW_AND_HIGH_STUB Start_WriteWatch_PostGrow64, Exit_WriteWatch_PostGrow64 + WRITE_BARRIER_CHECK_CARD_TABLE_STUB Start_WriteWatch_PostGrow64, Exit_WriteWatch_PostGrow64 + WRITE_BARRIER_CHECK_CARD_BUNDLE_TABLE_STUB Start_WriteWatch_PostGrow64, Exit_WriteWatch_PostGrow64 + WRITE_BARRIER_RETURN_STUB Exit_WriteWatch_PostGrow64 +LEAF_END_MARKED JIT_WriteBarrier_WriteWatch_PostGrow64, _TEXT + + +//----------------------------------------------------------------------------- +// void JIT_WriteBarrier_WriteWatch_SVR64(Object** dst, Object* src) +// +// SVR GC has multiple heaps, so it cannot provide one single ephemeral region to bounds check +// against, so we just skip the bounds checking all together and do our card table update unconditionally. +// +// Skipped functionality: +// Does not check wbs_ephemeral_high or wbs_ephemeral_low +// No region checks +// +LEAF_ENTRY JIT_WriteBarrier_WriteWatch_SVR64, _TEXT + WRITE_BARRIER_ENTRY_STUB Start_WriteWatch_SVR64 + WRITE_BARRIER_SHADOW_UPDATE_STUB Start_WriteWatch_SVR64 + WRITE_BARRIER_WRITE_WATCH_FOR_GC_HEAP_STUB Start_WriteWatch_SVR64, Exit_WriteWatch_SVR64 + WRITE_BARRIER_CHECK_CARD_TABLE_STUB Start_WriteWatch_SVR64, Exit_WriteWatch_SVR64 + WRITE_BARRIER_CHECK_CARD_BUNDLE_TABLE_STUB Start_WriteWatch_SVR64, Exit_WriteWatch_SVR64 + WRITE_BARRIER_RETURN_STUB Exit_WriteWatch_SVR64 +LEAF_END_MARKED JIT_WriteBarrier_WriteWatch_SVR64, _TEXT + + +//----------------------------------------------------------------------------- +// void JIT_WriteBarrier_WriteWatch_Byte_Region64(Object** dst, Object* src) +// +// Skipped functionality: +// Bitwise updates for region checks +// +LEAF_ENTRY JIT_WriteBarrier_WriteWatch_Byte_Region64, _TEXT + WRITE_BARRIER_ENTRY_STUB Start_WriteWatch_Byte_Region64 + WRITE_BARRIER_SHADOW_UPDATE_STUB Start_WriteWatch_Byte_Region64 + WRITE_BARRIER_WRITE_WATCH_FOR_GC_HEAP_STUB Start_WriteWatch_Byte_Region64, Exit_WriteWatch_Byte_Region64 + WRITE_BARRIER_CHECK_EPHEMERAL_LOW_AND_HIGH_STUB Start_WriteWatch_Byte_Region64, Exit_WriteWatch_Byte_Region64 + WRITE_BARRIER_REGION_CHECK_STUB Start_WriteWatch_Byte_Region64, Exit_WriteWatch_Byte_Region64 + WRITE_BARRIER_CHECK_CARD_TABLE_STUB Start_WriteWatch_Byte_Region64, Exit_WriteWatch_Byte_Region64 + WRITE_BARRIER_CHECK_CARD_BUNDLE_TABLE_STUB Start_WriteWatch_Byte_Region64, Exit_WriteWatch_Byte_Region64 + WRITE_BARRIER_RETURN_STUB Exit_WriteWatch_Byte_Region64 +LEAF_END_MARKED JIT_WriteBarrier_WriteWatch_Byte_Region64, _TEXT + + +//----------------------------------------------------------------------------- +// void JIT_WriteBarrier_WriteWatch_Bit_Region64(Object** dst, Object* src) +// +// Skipped functionality: +// Does not call check card table stub +// +LEAF_ENTRY JIT_WriteBarrier_WriteWatch_Bit_Region64, _TEXT + WRITE_BARRIER_ENTRY_STUB Start_WriteWatch_Bit_Region64 + WRITE_BARRIER_SHADOW_UPDATE_STUB Start_WriteWatch_Bit_Region64 + WRITE_BARRIER_WRITE_WATCH_FOR_GC_HEAP_STUB Start_WriteWatch_Bit_Region64, Exit_WriteWatch_Bit_Region64 + WRITE_BARRIER_CHECK_EPHEMERAL_LOW_AND_HIGH_STUB Start_WriteWatch_Bit_Region64, Exit_WriteWatch_Bit_Region64 + WRITE_BARRIER_REGION_CHECK_STUB Start_WriteWatch_Bit_Region64, Exit_WriteWatch_Bit_Region64 + WRITE_BARRIER_CHECK_BIT_REGIONS_CARD_TABLE_STUB Start_WriteWatch_Bit_Region64, Exit_WriteWatch_Bit_Region64 + WRITE_BARRIER_CHECK_CARD_BUNDLE_TABLE_STUB Start_WriteWatch_Bit_Region64, Exit_WriteWatch_Bit_Region64 + WRITE_BARRIER_RETURN_STUB Exit_WriteWatch_Bit_Region64 +LEAF_END_MARKED JIT_WriteBarrier_WriteWatch_Bit_Region64, _TEXT -// ------------------------------------------------------------------ -// End of the writeable code region -LEAF_ENTRY JIT_PatchedCodeLast, _TEXT - ret lr -LEAF_END JIT_PatchedCodeLast, _TEXT diff --git a/src/coreclr/vm/arm64/patchedcode.asm b/src/coreclr/vm/arm64/patchedcode.asm index 454b8cac0c4abe..500f1044d488d7 100644 --- a/src/coreclr/vm/arm64/patchedcode.asm +++ b/src/coreclr/vm/arm64/patchedcode.asm @@ -4,6 +4,7 @@ #include "ksarm64.h" #include "asmconstants.h" #include "asmmacros.h" +#include "patchedcodeconstants.h" ;;like TEXTAREA, but with 64 byte alignment so that we can align the patchable pool below to 64 without warning AREA |.text|,ALIGN=6,CODE,READONLY @@ -38,32 +39,6 @@ ret lr LEAF_END - ; Begin patchable literal pool - ALIGN 64 ; Align to power of two at least as big as patchable literal pool so that it fits optimally in cache line - WRITE_BARRIER_ENTRY JIT_WriteBarrier_Table -wbs_begin -wbs_card_table - DCQ 0 -wbs_card_bundle_table - DCQ 0 -wbs_sw_ww_table - DCQ 0 -wbs_ephemeral_low - DCQ 0 -wbs_ephemeral_high - DCQ 0 -wbs_lowest_address - DCQ 0 -wbs_highest_address - DCQ 0 -#ifdef WRITE_BARRIER_CHECK -wbs_GCShadow - DCQ 0 -wbs_GCShadowEnd - DCQ 0 -#endif - WRITE_BARRIER_END JIT_WriteBarrier_Table - ;----------------------------------------------------------------------------- ; void JIT_ByRefWriteBarrier ; On entry: @@ -117,6 +92,9 @@ NotInHeap ;----------------------------------------------------------------------------- ; void JIT_WriteBarrier(Object** dst, Object* src) +; +; Empty function which at runtime is patched with one of the JIT_WriteBarrier_ +; functions below. ; On entry: ; x14 : the destination address (LHS of the assignment) ; x15 : the object reference (RHS of the assignment) @@ -131,107 +109,395 @@ NotInHeap ; if you add more trashed registers. ; WRITE_BARRIER_ENTRY JIT_WriteBarrier - stlr x15, [x14] +; This must be greater than the largest JIT_WriteBarrier_ function. + space (232*4), 0 + WRITE_BARRIER_END JIT_WriteBarrier + ; Begin patchable literal pool + ALIGN 64 ; Align to power of two at least as big as patchable literal pool so that it fits optimally in cache line + WRITE_BARRIER_ENTRY JIT_WriteBarrier_Table + PATCH_LABEL JIT_WriteBarrier_Patch_Label_CardTable + DCQ 0 + PATCH_LABEL JIT_WriteBarrier_Patch_Label_CardBundleTable + DCQ 0 + PATCH_LABEL JIT_WriteBarrier_Patch_Label_WriteWatchTable + DCQ 0 + PATCH_LABEL JIT_WriteBarrier_Patch_Label_Lower + DCQ 0 + PATCH_LABEL JIT_WriteBarrier_Patch_Label_Upper + DCQ 0 +wbs_lowest_address + PATCH_LABEL JIT_WriteBarrier_Patch_Label_LowestAddress + DCQ 0 +wbs_highest_address + PATCH_LABEL JIT_WriteBarrier_Patch_Label_HighestAddress + DCQ 0 + PATCH_LABEL JIT_WriteBarrier_Patch_Label_RegionToGeneration + DCQ 0 + PATCH_LABEL JIT_WriteBarrier_Patch_Label_RegionShr + DCQ 0 #ifdef WRITE_BARRIER_CHECK + PATCH_LABEL JIT_WriteBarrier_Patch_Label_GCShadow + DCQ 0 + PATCH_LABEL JIT_WriteBarrier_Patch_Label_GCShadowEnd + DCQ 0 +#endif + WRITE_BARRIER_END JIT_WriteBarrier_Table + +; ------------------------------------------------------------------ +; End of the writeable code region + LEAF_ENTRY JIT_PatchedCodeLast + ret lr + LEAF_END + + + +;----------------------------------------------------------------------------- +; The following Macros are used by the different JIT_WriteBarrier_ functions. +; +; + + MACRO + WRITE_BARRIER_ENTRY_STUB $name +start$name + stlr x15, [x14] + MEND + + + MACRO + WRITE_BARRIER_SHADOW_UPDATE_STUB $name + #ifdef WRITE_BARRIER_CHECK ; Update GC Shadow Heap ; Do not perform the work if g_GCShadow is 0 - ldr x12, wbs_GCShadow - cbz x12, ShadowUpdateEnd + ldr x12, JIT_WriteBarrier_Offset_GCShadow + start$name + cbz x12, ShadowUpdateEnd$name ; Compute address of shadow heap location: - ; pShadow = $g_GCShadow + (x14 - g_lowest_address) - ldr x17, wbs_lowest_address - sub x17, x14, x17 - add x12, x17, x12 + ; pShadow = g_GCShadow + (x14 - g_lowest_address) + ldr x17, JIT_WriteBarrier_Offset_LowestAddress + start$name + sub x17, x14, x17 + add x12, x17, x12 - ; if (pShadow >= $g_GCShadowEnd) goto end - ldr x17, wbs_GCShadowEnd - cmp x12, x17 - bhs ShadowUpdateEnd + ; if (pShadow >= g_GCShadowEnd) goto end + ldr x17, JIT_WriteBarrier_Offset_GCShadowEnd + start$name + cmp x12, x17 + bhs ShadowUpdateEnd$name ; *pShadow = x15 - str x15, [x12] + str x15, [x12] ; Ensure that the write to the shadow heap occurs before the read from the GC heap so that race ; conditions are caught by INVALIDGCVALUE. - dmb ish + dmb ish ; if ([x14] == x15) goto end - ldr x17, [x14] - cmp x17, x15 - beq ShadowUpdateEnd + ldr x17, [x14] + cmp x17, x15 + beq ShadowUpdateEnd$name ; *pShadow = INVALIDGCVALUE (0xcccccccd) - movz x17, #0xcccd - movk x17, #0xcccc, LSL #16 - str x17, [x12] - -ShadowUpdateEnd -#endif + movz x17, #0xcccd + movk x17, #0xcccc, LSL #16 + str x17, [x12] + #endif +ShadowUpdateEnd$name + MEND -#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP + MACRO + WRITE_BARRIER_WRITE_WATCH_FOR_GC_HEAP_STUB $name + #ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP ; Update the write watch table if necessary - ldr x12, wbs_sw_ww_table - cbz x12, CheckCardTable - add x12, x12, x14, LSR #0xC // SoftwareWriteWatch::AddressToTableByteIndexShift - ldrb w17, [x12] - cbnz x17, CheckCardTable - mov w17, 0xFF - strb w17, [x12] -#endif + ldr x12, JIT_WriteBarrier_Offset_WriteWatchTable + start$name + ; SoftwareWriteWatch::AddressToTableByteIndexShift + add x12, x12, x14, lsr #0xc + ldrb w17, [x12] + cbnz x17, WriteWatchForGCHeapEnd$name + mov w17, #0xFF + strb w17, [x12] +WriteWatchForGCHeapEnd$name + #endif + MEND -CheckCardTable - ; Branch to Exit if the reference is not in the Gen0 heap - ldr x12, wbs_ephemeral_low - ldr x17, wbs_ephemeral_high - cmp x15, x12 - ccmp x15, x17, #0x2, hs - bhs Exit + MACRO + WRITE_BARRIER_CHECK_EPHEMERAL_LOW_STUB $name + ; Branch to Exit if the reference is not in the ephemeral generations. + ldr x12, JIT_WriteBarrier_Offset_Lower + start$name + cmp x15, x12 + blo exit$name + MEND - ; Check if we need to update the card table - ldr x12, wbs_card_table + MACRO + WRITE_BARRIER_CHECK_EPHEMERAL_LOW_AND_HIGH_STUB $name + ; Branch to Exit if the reference is not in the ephemeral generations. + ldr x12, JIT_WriteBarrier_Offset_Lower + start$name + ldr x17, JIT_WriteBarrier_Offset_Upper + start$name + cmp x15, x12 + ccmp x15, x17, #0x2, hs + bhs exit$name + MEND + + MACRO + WRITE_BARRIER_REGION_CHECK_STUB $name + ; Calculate region generations + ldr x17, JIT_WriteBarrier_Offset_RegionToGeneration + start$name + ldr w12, JIT_WriteBarrier_Offset_RegionShr + start$name + lsr x15, x15, x12 + add x15, x15, x17 ; x15 = (RHS >> wbs_region_shr) + wbs_region_to_generation_table + lsr x12, x14, x12 + add x12, x12, x17 ; x12 = (LHS >> wbs_region_shr) + wbs_region_to_generation_table + + ; Check whether the region we are storing into is gen 0 - nothing to do in this case + ldrb w12, [x12] + cbz w12, exit$name + + ; Return if the new reference is not from old to young + ldrb w15, [x15] + cmp w15, w12 + bhs exit$name + MEND - ; x15 := pointer into card table - add x15, x12, x14, lsr #11 + MACRO + WRITE_BARRIER_CHECK_BIT_REGIONS_CARD_TABLE_STUB $name + ; Check if we need to update the card table + lsr w17, w14, 8 + and w17, w17, 7 + movz w15, 1 + lsl w17, w15, w17 ; w17 = 1 << (LHS >> 8 && 7) + ldr x12, JIT_WriteBarrier_Offset_CardTable + start$name + add x15, x12, x14, lsr #11 + ldrb w12, [x15] ; w12 = [(LHS >> 11) + g_card_table] + tst w12, w17 + bne exit$name + + ; Atomically update the card table + ; Requires LSE, but the code is only compiled for 8.0 + ; stsetb w17, [x15] + DCD 0x383131FF + MEND - ldrb w12, [x15] - cmp x12, 0xFF - beq Exit + MACRO + WRITE_BARRIER_CHECK_CARD_TABLE_STUB $name + ; Check if we need to update the card table + ldr x12, JIT_WriteBarrier_Offset_CardTable + start$name + add x15, x12, x14, lsr #11 + ; w12 = [(RHS >> 11) + g_card_table] + ldrb w12, [x15] + cmp x12, 0xFF + beq exit$name ; Update the card table - mov x12, 0xFF - strb w12, [x15] + mov x12, 0xFF + strb w12, [x15] + MEND -#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES + MACRO + WRITE_BARRIER_CHECK_CARD_BUNDLE_TABLE_STUB $name + #ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES ; Check if we need to update the card bundle table - ldr x12, wbs_card_bundle_table - - ; x15 := pointer into card bundle table - add x15, x12, x14, lsr #21 - - ldrb w12, [x15] - cmp x12, 0xFF - beq Exit - - mov x12, 0xFF - strb w12, [x15] -#endif + ldr x12, JIT_WriteBarrier_Offset_CardBundleTable + start$name + add x15, x12, x14, lsr #21 + ldrb w12, [x15] + cmp x12, 0xFF + beq exit$name + + ; Update the card bundle + mov x12, 0xFF + strb w12, [x15] + #endif + MEND -Exit + MACRO + WRITE_BARRIER_RETURN_STUB $name +exit$name ; Increment by 8 to implement JIT_ByRefWriteBarrier contract. ; TODO: Consider duplicating the logic to get rid of this redundant 'add' ; for JIT_WriteBarrier/JIT_CheckedWriteBarrier - add x14, x14, 8 - ret lr - WRITE_BARRIER_END JIT_WriteBarrier + add x14, x14, 8 + ret lr + MEND + + ;----------------------------------------------------------------------------- + ; void JIT_WriteBarrier_PreGrow64(Object** dst, Object* src) + ; + ; Skipped functionality: + ; Does not update the write watch table + ; Does not check wbs_ephemeral_high + ; No region checks + ; + WRITE_BARRIER_ENTRY JIT_WriteBarrier_PreGrow64 + WRITE_BARRIER_ENTRY_STUB PreGrow64 + WRITE_BARRIER_SHADOW_UPDATE_STUB PreGrow64 + WRITE_BARRIER_CHECK_EPHEMERAL_LOW_STUB PreGrow64 + WRITE_BARRIER_CHECK_CARD_TABLE_STUB PreGrow64 + WRITE_BARRIER_CHECK_CARD_BUNDLE_TABLE_STUB PreGrow64 + WRITE_BARRIER_RETURN_STUB PreGrow64 + WRITE_BARRIER_END JIT_WriteBarrier_PreGrow64 + + + ;----------------------------------------------------------------------------- + ; void JIT_WriteBarrier_PostGrow64(Object** dst, Object* src) + ; + ; Skipped functionality: + ; Does not update the write watch table + ; No region checks + ; + WRITE_BARRIER_ENTRY JIT_WriteBarrier_PostGrow64 + WRITE_BARRIER_ENTRY_STUB PostGrow64 + WRITE_BARRIER_SHADOW_UPDATE_STUB PostGrow64 + WRITE_BARRIER_CHECK_EPHEMERAL_LOW_AND_HIGH_STUB PostGrow64 + WRITE_BARRIER_CHECK_CARD_TABLE_STUB PostGrow64 + WRITE_BARRIER_CHECK_CARD_BUNDLE_TABLE_STUB PostGrow64 + WRITE_BARRIER_RETURN_STUB PostGrow64 + WRITE_BARRIER_END JIT_WriteBarrier_PostGrow64 + + + ;----------------------------------------------------------------------------- + ; void JIT_WriteBarrier_SVR64(Object** dst, Object* src) + ; + ; SVR GC has multiple heaps, so it cannot provide one single ephemeral region to bounds check + ; against, so we just skip the bounds checking all together and do our card table update unconditionally. + ; + ; Skipped functionality: + ; Does not update the write watch table + ; Does not check wbs_ephemeral_high or wbs_ephemeral_low + ; No region checks + ; + WRITE_BARRIER_ENTRY JIT_WriteBarrier_SVR64 + WRITE_BARRIER_ENTRY_STUB SVR64 + WRITE_BARRIER_SHADOW_UPDATE_STUB SVR64 + WRITE_BARRIER_CHECK_CARD_TABLE_STUB SVR64 + WRITE_BARRIER_CHECK_CARD_BUNDLE_TABLE_STUB SVR64 + WRITE_BARRIER_RETURN_STUB SVR64 + WRITE_BARRIER_END JIT_WriteBarrier_SVR64 + + + ;----------------------------------------------------------------------------- + ; void JIT_WriteBarrier_Byte_Region64(Object** dst, Object* src) + ; + ; Skipped functionality: + ; Does not update the write watch table + ; Bitwise updates for region checks + ; + WRITE_BARRIER_ENTRY JIT_WriteBarrier_Byte_Region64 + WRITE_BARRIER_ENTRY_STUB Byte_Region64 + WRITE_BARRIER_SHADOW_UPDATE_STUB Byte_Region64 + WRITE_BARRIER_CHECK_EPHEMERAL_LOW_AND_HIGH_STUB Byte_Region64 + WRITE_BARRIER_REGION_CHECK_STUB Byte_Region64 + WRITE_BARRIER_CHECK_CARD_TABLE_STUB Byte_Region64 + WRITE_BARRIER_CHECK_CARD_BUNDLE_TABLE_STUB Byte_Region64 + WRITE_BARRIER_RETURN_STUB Byte_Region64 + WRITE_BARRIER_END JIT_WriteBarrier_Byte_Region64 + + + ;----------------------------------------------------------------------------- + ; void JIT_WriteBarrier_Bit_Region64(Object** dst, Object* src) + ; + ; Skipped functionality: + ; Does not update the write watch table + ; Does not call check card table stub + ; + WRITE_BARRIER_ENTRY JIT_WriteBarrier_Bit_Region64 + WRITE_BARRIER_ENTRY_STUB Bit_Region64 + WRITE_BARRIER_SHADOW_UPDATE_STUB Bit_Region64 + WRITE_BARRIER_CHECK_EPHEMERAL_LOW_AND_HIGH_STUB Bit_Region64 + WRITE_BARRIER_REGION_CHECK_STUB Bit_Region64 + WRITE_BARRIER_CHECK_BIT_REGIONS_CARD_TABLE_STUB Bit_Region64 + WRITE_BARRIER_CHECK_CARD_BUNDLE_TABLE_STUB Bit_Region64 + WRITE_BARRIER_RETURN_STUB Bit_Region64 + WRITE_BARRIER_END JIT_WriteBarrier_Bit_Region64 + + + ;----------------------------------------------------------------------------- + ; void JIT_WriteBarrier_WriteWatch_PreGrow64(Object** dst, Object* src) + ; + ; Skipped functionality: + ; Does not check wbs_ephemeral_high + ; No region checks + ; + WRITE_BARRIER_ENTRY JIT_WriteBarrier_WriteWatch_PreGrow64 + WRITE_BARRIER_ENTRY_STUB WriteWatch_PreGrow64 + WRITE_BARRIER_SHADOW_UPDATE_STUB WriteWatch_PreGrow64 + WRITE_BARRIER_WRITE_WATCH_FOR_GC_HEAP_STUB WriteWatch_PreGrow64 + WRITE_BARRIER_CHECK_EPHEMERAL_LOW_STUB WriteWatch_PreGrow64 + WRITE_BARRIER_CHECK_CARD_TABLE_STUB WriteWatch_PreGrow64 + WRITE_BARRIER_CHECK_CARD_BUNDLE_TABLE_STUB WriteWatch_PreGrow64 + WRITE_BARRIER_RETURN_STUB WriteWatch_PreGrow64 + WRITE_BARRIER_END JIT_WriteBarrier_WriteWatch_PreGrow64 + + + ;----------------------------------------------------------------------------- + ; void JIT_WriteBarrier_WriteWatch_PostGrow64(Object** dst, Object* src) + ; + ; Skipped functionality: + ; No region checks + ; + WRITE_BARRIER_ENTRY JIT_WriteBarrier_WriteWatch_PostGrow64 + WRITE_BARRIER_ENTRY_STUB WriteWatch_PostGrow64 + WRITE_BARRIER_SHADOW_UPDATE_STUB WriteWatch_PostGrow64 + WRITE_BARRIER_WRITE_WATCH_FOR_GC_HEAP_STUB WriteWatch_PostGrow64 + WRITE_BARRIER_CHECK_EPHEMERAL_LOW_AND_HIGH_STUB WriteWatch_PostGrow64 + WRITE_BARRIER_CHECK_CARD_TABLE_STUB WriteWatch_PostGrow64 + WRITE_BARRIER_CHECK_CARD_BUNDLE_TABLE_STUB WriteWatch_PostGrow64 + WRITE_BARRIER_RETURN_STUB WriteWatch_PostGrow64 + WRITE_BARRIER_END JIT_WriteBarrier_WriteWatch_PostGrow64 + + + ;----------------------------------------------------------------------------- + ; void JIT_WriteBarrier_WriteWatch_SVR64(Object** dst, Object* src) + ; + ; SVR GC has multiple heaps, so it cannot provide one single ephemeral region to bounds check + ; against, so we just skip the bounds checking all together and do our card table update unconditionally. + ; + ; Skipped functionality: + ; Does not check wbs_ephemeral_high or wbs_ephemeral_low + ; No region checks + ; + WRITE_BARRIER_ENTRY JIT_WriteBarrier_WriteWatch_SVR64 + WRITE_BARRIER_ENTRY_STUB WriteWatch_SVR64 + WRITE_BARRIER_SHADOW_UPDATE_STUB WriteWatch_SVR64 + WRITE_BARRIER_WRITE_WATCH_FOR_GC_HEAP_STUB WriteWatch_SVR64 + WRITE_BARRIER_CHECK_CARD_TABLE_STUB WriteWatch_SVR64 + WRITE_BARRIER_CHECK_CARD_BUNDLE_TABLE_STUB WriteWatch_SVR64 + WRITE_BARRIER_RETURN_STUB WriteWatch_SVR64 + WRITE_BARRIER_END JIT_WriteBarrier_WriteWatch_SVR64 + + + ;----------------------------------------------------------------------------- + ; void JIT_WriteBarrier_WriteWatch_Byte_Region64(Object** dst, Object* src) + ; + ; Skipped functionality: + ; Bitwise updates for region checks + ; + WRITE_BARRIER_ENTRY JIT_WriteBarrier_WriteWatch_Byte_Region64 + WRITE_BARRIER_ENTRY_STUB WriteWatch_Byte_Region64 + WRITE_BARRIER_SHADOW_UPDATE_STUB WriteWatch_Byte_Region64 + WRITE_BARRIER_WRITE_WATCH_FOR_GC_HEAP_STUB WriteWatch_Byte_Region64 + WRITE_BARRIER_CHECK_EPHEMERAL_LOW_AND_HIGH_STUB WriteWatch_Byte_Region64 + WRITE_BARRIER_REGION_CHECK_STUB WriteWatch_Byte_Region64 + WRITE_BARRIER_CHECK_CARD_TABLE_STUB WriteWatch_Byte_Region64 + WRITE_BARRIER_CHECK_CARD_BUNDLE_TABLE_STUB WriteWatch_Byte_Region64 + WRITE_BARRIER_RETURN_STUB WriteWatch_Byte_Region64 + WRITE_BARRIER_END JIT_WriteBarrier_WriteWatch_Byte_Region64 + + + ;----------------------------------------------------------------------------- + ; void JIT_WriteBarrier_WriteWatch_Bit_Region64(Object** dst, Object* src) + ; + ; Skipped functionality: + ; Does not call check card table stub + ; + WRITE_BARRIER_ENTRY JIT_WriteBarrier_WriteWatch_Bit_Region64 + WRITE_BARRIER_ENTRY_STUB WriteWatch_Bit_Region64 + WRITE_BARRIER_SHADOW_UPDATE_STUB WriteWatch_Bit_Region64 + WRITE_BARRIER_WRITE_WATCH_FOR_GC_HEAP_STUB WriteWatch_Bit_Region64 + WRITE_BARRIER_CHECK_EPHEMERAL_LOW_AND_HIGH_STUB WriteWatch_Bit_Region64 + WRITE_BARRIER_REGION_CHECK_STUB WriteWatch_Bit_Region64 + WRITE_BARRIER_CHECK_BIT_REGIONS_CARD_TABLE_STUB WriteWatch_Bit_Region64 + WRITE_BARRIER_CHECK_CARD_BUNDLE_TABLE_STUB WriteWatch_Bit_Region64 + WRITE_BARRIER_RETURN_STUB WriteWatch_Bit_Region64 + WRITE_BARRIER_END JIT_WriteBarrier_WriteWatch_Bit_Region64 -; ------------------------------------------------------------------ -; End of the writeable code region - LEAF_ENTRY JIT_PatchedCodeLast - ret lr - LEAF_END ; Must be at very end of file END diff --git a/src/coreclr/vm/arm64/patchedcodeconstants.h b/src/coreclr/vm/arm64/patchedcodeconstants.h new file mode 100644 index 00000000000000..1b4a32d210bd19 --- /dev/null +++ b/src/coreclr/vm/arm64/patchedcodeconstants.h @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// =========================================================================== +// File: patchedcodeconstants.h +// =========================================================================== + +#ifndef PATCHEDCODECONSTANTS_H +#define PATCHEDCODECONSTANTS_H + +// These are fixed constants becuase MacOS doesn't allow label arithmetic in +// LDR instructions. Asserts in writebarriermanager CALC_TABLE_LOCATION ensure +// the values are correct. + +#define JIT_WriteBarrier_Size 0x3a0 + +#ifdef TARGET_WINDOWS +#define JIT_WriteBarrier_Table_Offset (0x30 + JIT_WriteBarrier_Size) +#else +#define JIT_WriteBarrier_Table_Offset (0x2c + JIT_WriteBarrier_Size) +#endif + +#define JIT_WriteBarrier_Offset_CardTable (0x0 + JIT_WriteBarrier_Table_Offset) +#define JIT_WriteBarrier_Offset_CardBundleTable (0x8 + JIT_WriteBarrier_Table_Offset) +#define JIT_WriteBarrier_Offset_WriteWatchTable (0x10 + JIT_WriteBarrier_Table_Offset) +#define JIT_WriteBarrier_Offset_Lower (0x18 + JIT_WriteBarrier_Table_Offset) +#define JIT_WriteBarrier_Offset_Upper (0x20 + JIT_WriteBarrier_Table_Offset) +#define JIT_WriteBarrier_Offset_LowestAddress (0x28 + JIT_WriteBarrier_Table_Offset) +#define JIT_WriteBarrier_Offset_HighestAddress (0x30 + JIT_WriteBarrier_Table_Offset) +#define JIT_WriteBarrier_Offset_RegionToGeneration (0x38 + JIT_WriteBarrier_Table_Offset) +#define JIT_WriteBarrier_Offset_RegionShr (0x40 + JIT_WriteBarrier_Table_Offset) +#define JIT_WriteBarrier_Offset_GCShadow (0x48 + JIT_WriteBarrier_Table_Offset) +#define JIT_WriteBarrier_Offset_GCShadowEnd (0x50 + JIT_WriteBarrier_Table_Offset) + +#endif // PATCHEDCODECONSTANTS_H \ No newline at end of file diff --git a/src/coreclr/vm/arm64/stubs.cpp b/src/coreclr/vm/arm64/stubs.cpp index bc2ae8a0607ea9..43986504527d82 100644 --- a/src/coreclr/vm/arm64/stubs.cpp +++ b/src/coreclr/vm/arm64/stubs.cpp @@ -13,6 +13,7 @@ #include "virtualcallstub.h" #include "jitinterface.h" #include "ecall.h" +#include "writebarriermanager.h" #ifdef FEATURE_PERFMAP #include "perfmap.h" @@ -840,25 +841,6 @@ void emitCOMStubCall (ComCallMethodDesc *pCOMMethodRX, ComCallMethodDesc *pCOMMe #endif // FEATURE_COMINTEROP #if !defined(DACCESS_COMPILE) -EXTERN_C void JIT_UpdateWriteBarrierState(bool skipEphemeralCheck, size_t writeableOffset); - -extern "C" void STDCALL JIT_PatchedCodeStart(); -extern "C" void STDCALL JIT_PatchedCodeLast(); - -static void UpdateWriteBarrierState(bool skipEphemeralCheck) -{ - if (IsWriteBarrierCopyEnabled()) - { - BYTE *writeBarrierCodeStart = GetWriteBarrierCodeLocation((void*)JIT_PatchedCodeStart); - BYTE *writeBarrierCodeStartRW = writeBarrierCodeStart; - ExecutableWriterHolderNoLog writeBarrierWriterHolder; - { - writeBarrierWriterHolder.AssignExecutableWriterHolder(writeBarrierCodeStart, (BYTE*)JIT_PatchedCodeLast - (BYTE*)JIT_PatchedCodeStart); - writeBarrierCodeStartRW = writeBarrierWriterHolder.GetRW(); - } - JIT_UpdateWriteBarrierState(GCHeapUtilities::IsServerHeap(), writeBarrierCodeStartRW - writeBarrierCodeStart); - } -} void InitJITHelpers1() { @@ -866,6 +848,8 @@ void InitJITHelpers1() _ASSERTE(g_SystemInfo.dwNumberOfProcessors != 0); + g_WriteBarrierManager.Initialize(); + // Allocation helpers, faster but non-logging if (!((TrackAllocationsEnabled()) || (LoggingOn(LF_GCALLOC, LL_INFO10)) @@ -884,13 +868,8 @@ void InitJITHelpers1() ECall::DynamicallyAssignFCallImpl(GetEEFuncEntryPoint(AllocateString_MP_FastPortable), ECall::FastAllocateString); } } - - UpdateWriteBarrierState(GCHeapUtilities::IsServerHeap()); } - -#else -void UpdateWriteBarrierState(bool) {} #endif // !defined(DACCESS_COMPILE) #ifdef TARGET_WINDOWS @@ -1011,37 +990,6 @@ LONG CLRNoCatchHandler(EXCEPTION_POINTERS* pExceptionInfo, PVOID pv) return EXCEPTION_CONTINUE_SEARCH; } -void FlushWriteBarrierInstructionCache() -{ - // this wouldn't be called in arm64, just to comply with gchelpers.h -} - -int StompWriteBarrierEphemeral(bool isRuntimeSuspended) -{ - UpdateWriteBarrierState(GCHeapUtilities::IsServerHeap()); - return SWB_PASS; -} - -int StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck) -{ - UpdateWriteBarrierState(GCHeapUtilities::IsServerHeap()); - return SWB_PASS; -} - -#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP -int SwitchToWriteWatchBarrier(bool isRuntimeSuspended) -{ - UpdateWriteBarrierState(GCHeapUtilities::IsServerHeap()); - return SWB_PASS; -} - -int SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended) -{ - UpdateWriteBarrierState(GCHeapUtilities::IsServerHeap()); - return SWB_PASS; -} -#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP - #ifdef DACCESS_COMPILE BOOL GetAnyThunkTarget (T_CONTEXT *pctx, TADDR *pTarget, TADDR *pTargetMethodDesc) { diff --git a/src/coreclr/vm/arm64/thunktemplates.S b/src/coreclr/vm/arm64/thunktemplates.S index bbbc490854721e..df2abf7c29e0f7 100644 --- a/src/coreclr/vm/arm64/thunktemplates.S +++ b/src/coreclr/vm/arm64/thunktemplates.S @@ -4,117 +4,6 @@ #include "unixasmmacros.inc" #include "asmconstants.h" -#ifdef FEATURE_MAP_THUNKS_FROM_IMAGE -#define POINTER_SIZE 0x08 -// Since Arm64 supports 4KB, 16KB and 64KB page sizes, as the templates is only defined for 16KB page size, this cannot be used -// in a general purpose Linux environment. However it CAN be used on Apple platforms, which specify that 16KB is the system standard -// page size. - -#define THUNKS_MAP_SIZE 0x4000 - -#define PAGE_SIZE 0x4000 -#define PAGE_SIZE_LOG2 14 - - -#define DATA_SLOT(stub, field, thunkSize, thunkTemplateName) C_FUNC(thunkTemplateName) + THUNKS_MAP_SIZE + stub##Data__##field + IN_PAGE_INDEX * thunkSize - -// ---------- -// StubPrecode -// ---------- - -#define STUB_PRECODE_CODESIZE 0x18 // 3 instructions, 4 bytes each (and we also have 12 bytes of padding) -#define STUB_PRECODE_DATASIZE 0x18 // 2 qwords + 1 byte -.set STUB_PRECODE_NUM_THUNKS_PER_MAPPING, (THUNKS_MAP_SIZE / STUB_PRECODE_CODESIZE) - -.macro THUNKS_BLOCK_STUB_PRECODE - IN_PAGE_INDEX = 0 - .rept STUB_PRECODE_NUM_THUNKS_PER_MAPPING - - ldr x10, DATA_SLOT(StubPrecode, Target, STUB_PRECODE_CODESIZE, StubPrecodeCodeTemplate) - ldr x12, DATA_SLOT(StubPrecode, SecretParam, STUB_PRECODE_CODESIZE, StubPrecodeCodeTemplate) - br x10 - - brk 0xf000 // Stubs need to be 24-byte in size to allow for the data to be 2 pointers + 1 byte - brk 0xf000 // Stubs need to be 24-byte in size to allow for the data to be 2 pointers + 1 byte - brk 0xf000 // Stubs need to be 24-byte in size to allow for the data to be 2 pointers + 1 byte - - IN_PAGE_INDEX = IN_PAGE_INDEX + 1 - .endr -.endm - - .text - .p2align PAGE_SIZE_LOG2 -LEAF_ENTRY StubPrecodeCodeTemplate - THUNKS_BLOCK_STUB_PRECODE -LEAF_END_MARKED StubPrecodeCodeTemplate, _TEXT - -// ---------- -// FixupPrecode -// ---------- - -#define FIXUP_PRECODE_CODESIZE 0x18 // 5 instructions, 4 bytes each (and we also have 4 bytes of padding) -#define FIXUP_PRECODE_DATASIZE 0x18 // 3 qwords -.set FIXUP_PRECODE_NUM_THUNKS_PER_MAPPING,(THUNKS_MAP_SIZE / FIXUP_PRECODE_CODESIZE) - -.macro THUNKS_BLOCK_FIXUP_PRECODE - IN_PAGE_INDEX = 0 - .rept FIXUP_PRECODE_NUM_THUNKS_PER_MAPPING - - ldr x11, DATA_SLOT(FixupPrecode, Target, FIXUP_PRECODE_CODESIZE, FixupPrecodeCodeTemplate) - br x11 - ldr x12, DATA_SLOT(FixupPrecode, MethodDesc, FIXUP_PRECODE_CODESIZE, FixupPrecodeCodeTemplate) - ldr x11, DATA_SLOT(FixupPrecode, PrecodeFixupThunk, FIXUP_PRECODE_CODESIZE, FixupPrecodeCodeTemplate) - br x11 - brk 0xf000 // Stubs need to be 24-byte in size to allow for the data to be 3 pointers - - IN_PAGE_INDEX = IN_PAGE_INDEX + 1 - .endr -.endm - - .text - .p2align PAGE_SIZE_LOG2 -LEAF_ENTRY FixupPrecodeCodeTemplate - THUNKS_BLOCK_FIXUP_PRECODE -LEAF_END_MARKED FixupPrecodeCodeTemplate, _TEXT - -// ---------- -// CallCountingStub -// ---------- - -#define CALLCOUNTING_CODESIZE 0x28 // 5 instructions, 4 bytes each (and we also have 4 bytes of padding) -#define CALLCOUNTING_DATASIZE 0x18 // 3 qwords -.set CALLCOUNTING_NUM_THUNKS_PER_MAPPING, (THUNKS_MAP_SIZE / CALLCOUNTING_CODESIZE) - -.macro THUNKS_BLOCK_CALLCOUNTING - IN_PAGE_INDEX = 0 - .rept CALLCOUNTING_NUM_THUNKS_PER_MAPPING - - ldr x9, DATA_SLOT(CallCountingStub, RemainingCallCountCell, CALLCOUNTING_CODESIZE, CallCountingStubCodeTemplate) - ldrh w10, [x9] - subs w10, w10, #1 - strh w10, [x9] - beq 0f - ldr x9, DATA_SLOT(CallCountingStub, TargetForMethod, CALLCOUNTING_CODESIZE, CallCountingStubCodeTemplate) - br x9 -0: - ldr x10, DATA_SLOT(CallCountingStub, TargetForThresholdReached, CALLCOUNTING_CODESIZE, CallCountingStubCodeTemplate) - br x10 - brk 0xf000 // Stubs need to be 40-byte in size to allow for the data to be pointer aligned - - IN_PAGE_INDEX = IN_PAGE_INDEX + 1 - .endr -.endm - - .text - .p2align PAGE_SIZE_LOG2 -LEAF_ENTRY CallCountingStubCodeTemplate - THUNKS_BLOCK_CALLCOUNTING -LEAF_END_MARKED CallCountingStubCodeTemplate, _TEXT -#endif - -#ifdef DATA_SLOT -#undef DATA_SLOT -#endif #define DATA_SLOT(stub, field) . - (. - C_FUNC(stub##Code\STUB_PAGE_SIZE)) + \STUB_PAGE_SIZE + stub##Data__##field .irp STUB_PAGE_SIZE, 16384, 32768, 65536 diff --git a/src/coreclr/vm/callcounting.cpp b/src/coreclr/vm/callcounting.cpp index f5168fc0f799b1..0f26b7d4090096 100644 --- a/src/coreclr/vm/callcounting.cpp +++ b/src/coreclr/vm/callcounting.cpp @@ -293,14 +293,6 @@ void (*CallCountingStub::CallCountingStubCode)(); #ifndef DACCESS_COMPILE -static InterleavedLoaderHeapConfig s_callCountingHeapConfig; - -#ifdef FEATURE_MAP_THUNKS_FROM_IMAGE -extern "C" void CallCountingStubCodeTemplate(); -#else -#define CallCountingStubCodeTemplate NULL -#endif - void CallCountingStub::StaticInitialize() { #if defined(TARGET_ARM64) && defined(TARGET_UNIX) @@ -318,22 +310,14 @@ void CallCountingStub::StaticInitialize() EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Unsupported OS page size")); } #undef ENUM_PAGE_SIZE - - if (CallCountingStubCodeTemplate != NULL && pageSize != 0x4000) - { - // This should fail if the template is used on a platform which doesn't support the supported page size for templates - ThrowHR(COR_E_EXECUTIONENGINE); - } #else _ASSERTE((SIZE_T)((BYTE*)CallCountingStubCode_End - (BYTE*)CallCountingStubCode) <= CallCountingStub::CodeSize); #endif - - InitializeLoaderHeapConfig(&s_callCountingHeapConfig, CallCountingStub::CodeSize, (void*)CallCountingStubCodeTemplate, CallCountingStub::GenerateCodePage); } #endif // DACCESS_COMPILE -void CallCountingStub::GenerateCodePage(uint8_t* pageBase, uint8_t* pageBaseRX, size_t pageSize) +void CallCountingStub::GenerateCodePage(BYTE* pageBase, BYTE* pageBaseRX, SIZE_T pageSize) { #ifdef TARGET_X86 int totalCodeSize = (pageSize / CallCountingStub::CodeSize) * CallCountingStub::CodeSize; @@ -344,13 +328,13 @@ void CallCountingStub::GenerateCodePage(uint8_t* pageBase, uint8_t* pageBaseRX, // Set absolute addresses of the slots in the stub BYTE* pCounterSlot = pageBaseRX + i + pageSize + offsetof(CallCountingStubData, RemainingCallCountCell); - *(uint8_t**)(pageBase + i + SYMBOL_VALUE(CallCountingStubCode_RemainingCallCountCell_Offset)) = pCounterSlot; + *(BYTE**)(pageBase + i + SYMBOL_VALUE(CallCountingStubCode_RemainingCallCountCell_Offset)) = pCounterSlot; BYTE* pTargetSlot = pageBaseRX + i + pageSize + offsetof(CallCountingStubData, TargetForMethod); - *(uint8_t**)(pageBase + i + SYMBOL_VALUE(CallCountingStubCode_TargetForMethod_Offset)) = pTargetSlot; + *(BYTE**)(pageBase + i + SYMBOL_VALUE(CallCountingStubCode_TargetForMethod_Offset)) = pTargetSlot; BYTE* pCountReachedZeroSlot = pageBaseRX + i + pageSize + offsetof(CallCountingStubData, TargetForThresholdReached); - *(uint8_t**)(pageBase + i + SYMBOL_VALUE(CallCountingStubCode_TargetForThresholdReached_Offset)) = pCountReachedZeroSlot; + *(BYTE**)(pageBase + i + SYMBOL_VALUE(CallCountingStubCode_TargetForThresholdReached_Offset)) = pCountReachedZeroSlot; } #else // TARGET_X86 FillStubCodePage(pageBase, (const void*)PCODEToPINSTR((PCODE)CallCountingStubCode), CallCountingStub::CodeSize, pageSize); @@ -370,7 +354,7 @@ NOINLINE InterleavedLoaderHeap *CallCountingManager::CallCountingStubAllocator:: _ASSERTE(m_heap == nullptr); - InterleavedLoaderHeap *heap = new InterleavedLoaderHeap(&m_heapRangeList, true /* fUnlocked */, &s_callCountingHeapConfig); + InterleavedLoaderHeap *heap = new InterleavedLoaderHeap(&m_heapRangeList, true /* fUnlocked */, CallCountingStub::GenerateCodePage, CallCountingStub::CodeSize); m_heap = heap; return heap; } @@ -491,7 +475,6 @@ CallCountingManager::~CallCountingManager() } #ifndef DACCESS_COMPILE - void CallCountingManager::StaticInitialize() { WRAPPER_NO_CONTRACT; diff --git a/src/coreclr/vm/callcounting.h b/src/coreclr/vm/callcounting.h index 59071aa51f140b..75a907f4d6ea3c 100644 --- a/src/coreclr/vm/callcounting.h +++ b/src/coreclr/vm/callcounting.h @@ -150,7 +150,7 @@ class CallCountingStub static void StaticInitialize(); #endif // !DACCESS_COMPILE - static void GenerateCodePage(uint8_t* pageBase, uint8_t* pageBaseRX, size_t size); + static void GenerateCodePage(BYTE* pageBase, BYTE* pageBaseRX, SIZE_T size); PTR_CallCount GetRemainingCallCountCell() const; PCODE GetTargetForMethod() const; diff --git a/src/coreclr/vm/codeman.cpp b/src/coreclr/vm/codeman.cpp index 35d3f0165ab84c..06ab31bc0e4ffc 100644 --- a/src/coreclr/vm/codeman.cpp +++ b/src/coreclr/vm/codeman.cpp @@ -4148,6 +4148,14 @@ void CodeHeader::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJ this->pRealCodeHeader.EnumMem(); +#ifdef FEATURE_EH_FUNCLETS + // UnwindInfos are stored in an array immediately following the RealCodeHeader structure in memory. + if (this->pRealCodeHeader->nUnwindInfos) + { + DacEnumMemoryRegion(PTR_TO_MEMBER_TADDR(RealCodeHeader, pRealCodeHeader, unwindInfos), this->pRealCodeHeader->nUnwindInfos * sizeof(T_RUNTIME_FUNCTION)); + } +#endif // FEATURE_EH_FUNCLETS + #ifdef FEATURE_ON_STACK_REPLACEMENT BOOL hasFlagByte = TRUE; #else @@ -4164,7 +4172,7 @@ void CodeHeader::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJitManager* pJ // Enumerate for minidumps. //----------------------------------------------------------------------------- template -void EECodeGenManager::EnumMemoryRegionsForMethodDebugInfoWorker(CLRDataEnumMemoryFlags flags, MethodDesc * pMD) +void EECodeGenManager::EnumMemoryRegionsForMethodDebugInfoWorker(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo) { CONTRACTL { @@ -4175,15 +4183,14 @@ void EECodeGenManager::EnumMemoryRegionsForMethodDebugInfoWorker(CLRDataEnumMemo CONTRACTL_END; DebugInfoRequest request; - PCODE addrCode = pMD->GetNativeCode(); - request.InitFromStartingAddr(pMD, addrCode); + request.InitFromStartingAddr(pCodeInfo->GetMethodDesc(), pCodeInfo->GetStartAddress()); TCodeHeader * pHeader = GetCodeHeaderFromDebugInfoRequest(request); pHeader->EnumMemoryRegions(flags, NULL); } -void EEJitManager::EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD) +void EEJitManager::EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo) { CONTRACTL { @@ -4193,7 +4200,7 @@ void EEJitManager::EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags fl } CONTRACTL_END; - EnumMemoryRegionsForMethodDebugInfoWorker(flags, pMD); + EnumMemoryRegionsForMethodDebugInfoWorker(flags, pCodeInfo); } #ifdef FEATURE_INTERPRETER @@ -4217,7 +4224,7 @@ void InterpreterCodeHeader::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, IJit } } -void InterpreterJitManager::EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD) +void InterpreterJitManager::EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo) { CONTRACTL { @@ -4227,7 +4234,7 @@ void InterpreterJitManager::EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemor } CONTRACTL_END; - EnumMemoryRegionsForMethodDebugInfoWorker(flags, pMD); + EnumMemoryRegionsForMethodDebugInfoWorker(flags, pCodeInfo); } #endif // FEATURE_INTERPRETER @@ -6314,16 +6321,15 @@ BOOL ReadyToRunJitManager::GetRichDebugInfo( // // Need to write out debug info // -void ReadyToRunJitManager::EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD) +void ReadyToRunJitManager::EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo) { SUPPORTS_DAC; - EECodeInfo codeInfo(pMD->GetNativeCode()); - if (!codeInfo.IsValid()) + if (!pCodeInfo->IsValid()) return; - ReadyToRunInfo * pReadyToRunInfo = JitTokenToReadyToRunInfo(codeInfo.GetMethodToken()); - PTR_RUNTIME_FUNCTION pRuntimeFunction = JitTokenToRuntimeFunction(codeInfo.GetMethodToken()); + ReadyToRunInfo * pReadyToRunInfo = JitTokenToReadyToRunInfo(pCodeInfo->GetMethodToken()); + PTR_RUNTIME_FUNCTION pRuntimeFunction = JitTokenToRuntimeFunction(pCodeInfo->GetMethodToken()); PTR_BYTE pDebugInfo = pReadyToRunInfo->GetDebugInfo(pRuntimeFunction); if (pDebugInfo == NULL) diff --git a/src/coreclr/vm/codeman.h b/src/coreclr/vm/codeman.h index 9e2eabdeecc09a..edad07c4341f8b 100644 --- a/src/coreclr/vm/codeman.h +++ b/src/coreclr/vm/codeman.h @@ -1781,7 +1781,7 @@ class IJitManager // DAC builds is compatible with the non-DAC one so that DAC virtual dispatch will work correctly. #if defined(DACCESS_COMPILE) virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); - virtual void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD) = 0; + virtual void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo) = 0; #if defined(FEATURE_EH_FUNCLETS) // Enumerate the memory necessary to retrieve the unwind info for a specific method virtual void EnumMemoryRegionsForMethodUnwindInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo) = 0; @@ -1924,7 +1924,7 @@ class EECodeGenManager : public IJitManager virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); protected: template - void EnumMemoryRegionsForMethodDebugInfoWorker(CLRDataEnumMemoryFlags flags, MethodDesc * pMD); + void EnumMemoryRegionsForMethodDebugInfoWorker(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo); #endif // !DACCESS_COMPILE private: @@ -2085,7 +2085,7 @@ class EEJitManager final : public EECodeGenManager GCInfoToken GetGCInfoToken(const METHODTOKEN& MethodToken); #ifdef DACCESS_COMPILE - virtual void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD); + virtual void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo); #endif // DACCESS_COMPILE #if !defined DACCESS_COMPILE @@ -2671,7 +2671,7 @@ class ReadyToRunJitManager final: public IJitManager #if defined(DACCESS_COMPILE) virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); - virtual void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD); + virtual void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo); #if defined(FEATURE_EH_FUNCLETS) // Enumerate the memory necessary to retrieve the unwind info for a specific method virtual void EnumMemoryRegionsForMethodUnwindInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo); @@ -2791,7 +2791,7 @@ class InterpreterJitManager final : public EECodeGenManager #if defined(DACCESS_COMPILE) - virtual void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD); + virtual void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo); #if defined(FEATURE_EH_FUNCLETS) virtual void EnumMemoryRegionsForMethodUnwindInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo) @@ -2941,7 +2941,7 @@ class EECodeInfo { return DecodeGCHdrInfoHelper(infoPtr); } - + *infoPtr = &m_hdrInfoBody; return m_hdrInfoTable; } diff --git a/src/coreclr/vm/debuginfostore.cpp b/src/coreclr/vm/debuginfostore.cpp index 789693f33b68ab..e3ef94a196066b 100644 --- a/src/coreclr/vm/debuginfostore.cpp +++ b/src/coreclr/vm/debuginfostore.cpp @@ -1025,7 +1025,7 @@ BOOL DebugInfoManager::GetRichDebugInfo( } #ifdef DACCESS_COMPILE -void DebugInfoManager::EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD) +void DebugInfoManager::EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo) { CONTRACTL { @@ -1035,18 +1035,23 @@ void DebugInfoManager::EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlag } CONTRACTL_END; - PCODE addrCode = pMD->GetNativeCode(); + if (!pCodeInfo->IsValid()) + { + return; + } + + PCODE addrCode = pCodeInfo->GetStartAddress(); if (addrCode == (PCODE)NULL) { return; } - IJitManager* pJitMan = ExecutionManager::FindJitMan(addrCode); + IJitManager* pJitMan = pCodeInfo->GetJitManager(); if (pJitMan == NULL) { return; // no info available. } - pJitMan->EnumMemoryRegionsForMethodDebugInfo(flags, pMD); + pJitMan->EnumMemoryRegionsForMethodDebugInfo(flags, pCodeInfo); } #endif diff --git a/src/coreclr/vm/debuginfostore.h b/src/coreclr/vm/debuginfostore.h index 1df939432ce6d7..699940486e2130 100644 --- a/src/coreclr/vm/debuginfostore.h +++ b/src/coreclr/vm/debuginfostore.h @@ -154,7 +154,7 @@ class DebugInfoManager OUT ULONG32* pNumRichMappings); #ifdef DACCESS_COMPILE - static void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, MethodDesc * pMD); + static void EnumMemoryRegionsForMethodDebugInfo(CLRDataEnumMemoryFlags flags, EECodeInfo * pCodeInfo); #endif }; diff --git a/src/coreclr/vm/finalizerthread.cpp b/src/coreclr/vm/finalizerthread.cpp index db45c4c0d8d9a1..21bd8e58416ba8 100644 --- a/src/coreclr/vm/finalizerthread.cpp +++ b/src/coreclr/vm/finalizerthread.cpp @@ -125,13 +125,8 @@ void FinalizerThread::FinalizeAllObjects() void FinalizerThread::WaitForFinalizerEvent (CLREvent *event) { - // Non-host environment - // We don't want kLowMemoryNotification to starve out kFinalizer - // (as the latter may help correct the former), and we don't want either - // to starve out kProfilingAPIAttach, as we want decent responsiveness - // to a user trying to attach a profiler. So check in this order: - // kProfilingAPIAttach alone (0 wait) + // (as the latter may help correct the former). So check in this order: // kFinalizer alone (2s wait) // all events together (infinite wait) @@ -162,7 +157,6 @@ void FinalizerThread::WaitForFinalizerEvent (CLREvent *event) // // * kLowMemoryNotification (if it's non-NULL && g_fEEStarted) // * kFinalizer (always) - // * kProfilingAPIAttach (if it's non-NULL) // // The enum code:MHandleType values become important here, as // WaitForMultipleObjects needs to wait on a contiguous set of non-NULL diff --git a/src/coreclr/vm/gc_unwind_x86.inl b/src/coreclr/vm/gc_unwind_x86.inl index c5d45a6c43074c..eb08dff6cf1079 100644 --- a/src/coreclr/vm/gc_unwind_x86.inl +++ b/src/coreclr/vm/gc_unwind_x86.inl @@ -2443,7 +2443,7 @@ void UnwindEspFrameEpilog( // We have already popped off the frame (excluding the callee-saved registers) - if (epilogBase[0] == X86_INSTR_POP_ECX) + if (epilogBase[offset] == X86_INSTR_POP_ECX) { // We may use "POP ecx" for doing "ADD ESP, 4", // or we may not (in the case of JMP epilogs) @@ -2560,8 +2560,11 @@ void UnwindEbpDoubleAlignFrameEpilog( { // do nothing before popping the callee-saved registers } - else if (info->rawStkSize == sizeof(void*)) + else if (info->rawStkSize == sizeof(void*) && epilogBase[offset] == X86_INSTR_POP_ECX) { + // We may use "POP ecx" for doing "ADD ESP, 4", + // or we may not (in the case of JMP epilogs) + // "pop ecx" will make ESP point to the callee-saved registers if (!InstructionAlreadyExecuted(offset, info->epilogOffs)) ESP += sizeof(void*); diff --git a/src/coreclr/vm/gcenv.ee.cpp b/src/coreclr/vm/gcenv.ee.cpp index b62915d6c766fa..9c4dccec648d17 100644 --- a/src/coreclr/vm/gcenv.ee.cpp +++ b/src/coreclr/vm/gcenv.ee.cpp @@ -1055,6 +1055,7 @@ void GCToEEInterface::StompWriteBarrier(WriteBarrierParameters* args) ThreadSuspend::RestartEE(FALSE, TRUE); } return; // unlike other branches we have already done cleanup so bailing out here + case WriteBarrierOp::StompEphemeral: assert(args->is_runtime_suspended && "the runtime must be suspended here!"); // StompEphemeral requires a new ephemeral low and a new ephemeral high @@ -1065,8 +1066,16 @@ void GCToEEInterface::StompWriteBarrier(WriteBarrierParameters* args) g_region_to_generation_table = args->region_to_generation_table; g_region_shr = args->region_shr; g_region_use_bitwise_write_barrier = args->region_use_bitwise_write_barrier; +#if defined(HOST_ARM64) + // Only allow bitwise write barriers if LSE atomics are present + if (!g_arm64_atomics_present) + { + g_region_use_bitwise_write_barrier = false; + } +#endif stompWBCompleteActions |= ::StompWriteBarrierEphemeral(args->is_runtime_suspended); break; + case WriteBarrierOp::Initialize: assert(args->is_runtime_suspended && "the runtime must be suspended here!"); // This operation should only be invoked once, upon initialization. @@ -1092,16 +1101,24 @@ void GCToEEInterface::StompWriteBarrier(WriteBarrierParameters* args) g_region_to_generation_table = args->region_to_generation_table; g_region_shr = args->region_shr; g_region_use_bitwise_write_barrier = args->region_use_bitwise_write_barrier; + g_ephemeral_low = args->ephemeral_low; + g_ephemeral_high = args->ephemeral_high; +#if defined(HOST_ARM64) + // Only allow bitwise write barriers if LSE atomics are present + if (!g_arm64_atomics_present) + { + g_region_use_bitwise_write_barrier = false; + } +#endif stompWBCompleteActions |= ::StompWriteBarrierResize(true, false); // StompWriteBarrierResize does not necessarily bash g_ephemeral_low - // usages, so we must do so here. This is particularly true on x86, + // usages, so we must do so here. This is particularly true on x86/Arm64, // where StompWriteBarrierResize will not bash g_ephemeral_low when // called with the parameters (true, false), as it is above. - g_ephemeral_low = args->ephemeral_low; - g_ephemeral_high = args->ephemeral_high; stompWBCompleteActions |= ::StompWriteBarrierEphemeral(true); break; + case WriteBarrierOp::SwitchToWriteWatch: #ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP assert(args->is_runtime_suspended && "the runtime must be suspended here!"); @@ -1113,6 +1130,7 @@ void GCToEEInterface::StompWriteBarrier(WriteBarrierParameters* args) assert(!"should never be called without FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP"); #endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP break; + case WriteBarrierOp::SwitchToNonWriteWatch: #ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP assert(args->is_runtime_suspended && "the runtime must be suspended here!"); @@ -1123,6 +1141,7 @@ void GCToEEInterface::StompWriteBarrier(WriteBarrierParameters* args) assert(!"should never be called without FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP"); #endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP break; + default: assert(!"unknown WriteBarrierOp enum"); } diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp index c90aaf377d4c4b..d907176a227207 100644 --- a/src/coreclr/vm/interpexec.cpp +++ b/src/coreclr/vm/interpexec.cpp @@ -36,6 +36,13 @@ static void InterpBreakpoint() void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFrame *pFrame, InterpThreadContext *pThreadContext) { + CONTRACTL + { + GC_TRIGGERS; + MODE_COOPERATIVE; + } + CONTRACTL_END; + #if defined(HOST_AMD64) && defined(HOST_WINDOWS) pInterpreterFrame->SetInterpExecMethodSSP((TADDR)_rdsspq()); #endif // HOST_AMD64 && HOST_WINDOWS @@ -293,6 +300,12 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr break; } + case INTOP_SAFEPOINT: + if (g_TrapReturningThreads) + JIT_PollGC(); + ip++; + break; + case INTOP_BR: ip += ip[1]; break; diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index 6639751c92b032..293f5241bf36a1 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -197,70 +197,6 @@ extern "C" FCDECL2(VOID, JIT_WriteBarrier_Callable, Object **dst, Object *ref); #define WriteBarrier_Helper JIT_WriteBarrier_Callable -#ifdef TARGET_AMD64 - - -class WriteBarrierManager -{ -public: - enum WriteBarrierType - { - WRITE_BARRIER_UNINITIALIZED, - WRITE_BARRIER_PREGROW64, - WRITE_BARRIER_POSTGROW64, -#ifdef FEATURE_SVR_GC - WRITE_BARRIER_SVR64, -#endif // FEATURE_SVR_GC - WRITE_BARRIER_BYTE_REGIONS64, - WRITE_BARRIER_BIT_REGIONS64, -#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP - WRITE_BARRIER_WRITE_WATCH_PREGROW64, - WRITE_BARRIER_WRITE_WATCH_POSTGROW64, -#ifdef FEATURE_SVR_GC - WRITE_BARRIER_WRITE_WATCH_SVR64, -#endif // FEATURE_SVR_GC - WRITE_BARRIER_WRITE_WATCH_BYTE_REGIONS64, - WRITE_BARRIER_WRITE_WATCH_BIT_REGIONS64, -#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP - WRITE_BARRIER_BUFFER - }; - - WriteBarrierManager(); - void Initialize(); - - int UpdateEphemeralBounds(bool isRuntimeSuspended); - int UpdateWriteWatchAndCardTableLocations(bool isRuntimeSuspended, bool bReqUpperBoundsCheck); - -#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP - int SwitchToWriteWatchBarrier(bool isRuntimeSuspended); - int SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended); -#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP - size_t GetCurrentWriteBarrierSize(); - -protected: - size_t GetSpecificWriteBarrierSize(WriteBarrierType writeBarrier); - PBYTE CalculatePatchLocation(LPVOID base, LPVOID label, int offset); - PCODE GetCurrentWriteBarrierCode(); - int ChangeWriteBarrierTo(WriteBarrierType newWriteBarrier, bool isRuntimeSuspended); - bool NeedDifferentWriteBarrier(bool bReqUpperBoundsCheck, bool bUseBitwiseWriteBarrier, WriteBarrierType* pNewWriteBarrierType); - -private: - void Validate(); - - WriteBarrierType m_currentWriteBarrier; - - PBYTE m_pWriteWatchTableImmediate; // PREGROW | POSTGROW | SVR | WRITE_WATCH | REGION - PBYTE m_pLowerBoundImmediate; // PREGROW | POSTGROW | | WRITE_WATCH | REGION - PBYTE m_pCardTableImmediate; // PREGROW | POSTGROW | SVR | WRITE_WATCH | REGION - PBYTE m_pCardBundleTableImmediate; // PREGROW | POSTGROW | SVR | WRITE_WATCH | REGION - PBYTE m_pUpperBoundImmediate; // | POSTGROW | | WRITE_WATCH | REGION - PBYTE m_pRegionToGenTableImmediate; // | | | WRITE_WATCH | REGION - PBYTE m_pRegionShrDest; // | | | WRITE_WATCH | REGION - PBYTE m_pRegionShrSrc; // | | | WRITE_WATCH | RETION -}; - -#endif // TARGET_AMD64 - EXTERN_C FCDECL2_VV(INT64, JIT_LMul, INT64 val1, INT64 val2); #ifndef HOST_64BIT diff --git a/src/coreclr/vm/jitinterfacegen.cpp b/src/coreclr/vm/jitinterfacegen.cpp index 2190f295b2a17a..cae7b5b9f6668f 100644 --- a/src/coreclr/vm/jitinterfacegen.cpp +++ b/src/coreclr/vm/jitinterfacegen.cpp @@ -17,6 +17,7 @@ #include "comdelegate.h" #include "field.h" #include "ecall.h" +#include "writebarriermanager.h" #ifdef HOST_64BIT @@ -27,10 +28,6 @@ EXTERN_C Object* AllocateStringFastUP (CLR_I4 cch); EXTERN_C Object* JIT_NewArr1OBJ_UP (CORINFO_CLASS_HANDLE arrayMT, INT_PTR size); EXTERN_C Object* JIT_NewArr1VC_UP (CORINFO_CLASS_HANDLE arrayMT, INT_PTR size); -#ifdef TARGET_AMD64 -extern WriteBarrierManager g_WriteBarrierManager; -#endif // TARGET_AMD64 - #endif // HOST_64BIT /*********************************************************************/ diff --git a/src/coreclr/vm/loaderallocator.cpp b/src/coreclr/vm/loaderallocator.cpp index f31d2d068bbfb8..5fe3bb2faf2831 100644 --- a/src/coreclr/vm/loaderallocator.cpp +++ b/src/coreclr/vm/loaderallocator.cpp @@ -1208,7 +1208,8 @@ void LoaderAllocator::Init(BYTE *pExecutableHeapMemory) m_pNewStubPrecodeHeap = new (&m_NewStubPrecodeHeapInstance) InterleavedLoaderHeap( &m_stubPrecodeRangeList, false /* fUnlocked */, - &s_stubPrecodeHeapConfig); + StubPrecode::GenerateCodePage, + StubPrecode::CodeSize); #if defined(FEATURE_STUBPRECODE_DYNAMIC_HELPERS) && defined(FEATURE_READYTORUN) if (IsCollectible()) @@ -1218,12 +1219,14 @@ void LoaderAllocator::Init(BYTE *pExecutableHeapMemory) m_pDynamicHelpersStubHeap = new (&m_DynamicHelpersHeapInstance) InterleavedLoaderHeap( &m_dynamicHelpersRangeList, false /* fUnlocked */, - &s_stubPrecodeHeapConfig); + StubPrecode::GenerateCodePage, + StubPrecode::CodeSize); #endif // defined(FEATURE_STUBPRECODE_DYNAMIC_HELPERS) && defined(FEATURE_READYTORUN) m_pFixupPrecodeHeap = new (&m_FixupPrecodeHeapInstance) InterleavedLoaderHeap(&m_fixupPrecodeRangeList, false /* fUnlocked */, - &s_fixupStubPrecodeHeapConfig); + FixupPrecode::GenerateCodePage, + FixupPrecode::CodeSize); // Initialize the EE marshaling data to NULL. m_pMarshalingData = NULL; diff --git a/src/coreclr/vm/method.cpp b/src/coreclr/vm/method.cpp index 6384d8aa2e9dc2..3b4314dce1df4e 100644 --- a/src/coreclr/vm/method.cpp +++ b/src/coreclr/vm/method.cpp @@ -3673,7 +3673,24 @@ MethodDesc::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) } // Need to save the Debug-Info for this method so that we can see it in a debugger later. - DebugInfoManager::EnumMemoryRegionsForMethodDebugInfo(flags, this); +#ifdef FEATURE_CODE_VERSIONING + { + CodeVersionManager::LockHolder codeVersioningLockHolder; + + CodeVersionManager* pCodeVersionManager = GetCodeVersionManager(); + NativeCodeVersionCollection nativeCodeVersions = pCodeVersionManager->GetNativeCodeVersions(dac_cast(this)); + for (NativeCodeVersionIterator iter = nativeCodeVersions.Begin(); iter != nativeCodeVersions.End(); iter++) + { + PCODE addrCode = iter->GetNativeCode(); + EECodeInfo codeInfo(addrCode); + DebugInfoManager::EnumMemoryRegionsForMethodDebugInfo(flags, &codeInfo); + } + } +#else + PCODE entryPoint = GetNativeCode(); + EECodeInfo codeInfo(entryPoint); + DebugInfoManager::EnumMemoryRegionsForMethodDebugInfo(flags, &codeInfo); +#endif // FEATURE_CODE_VERSIONING if (!IsNoMetadata() ||IsILStub()) { diff --git a/src/coreclr/vm/precode.cpp b/src/coreclr/vm/precode.cpp index 798e9849de3a6a..e3e3983e8716e1 100644 --- a/src/coreclr/vm/precode.cpp +++ b/src/coreclr/vm/precode.cpp @@ -15,11 +15,6 @@ #include "perfmap.h" #endif -InterleavedLoaderHeapConfig s_stubPrecodeHeapConfig; -#ifdef HAS_FIXUP_PRECODE -InterleavedLoaderHeapConfig s_fixupStubPrecodeHeapConfig; -#endif - //========================================================================================== // class Precode //========================================================================================== @@ -500,12 +495,6 @@ void (*StubPrecode::StubPrecodeCode)(); void (*StubPrecode::StubPrecodeCode_End)(); #endif -#ifdef FEATURE_MAP_THUNKS_FROM_IMAGE -extern "C" void StubPrecodeCodeTemplate(); -#else -#define StubPrecodeCodeTemplate NULL -#endif - void StubPrecode::StaticInitialize() { #if defined(TARGET_ARM64) && defined(TARGET_UNIX) @@ -523,13 +512,6 @@ void StubPrecode::StaticInitialize() default: EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Unsupported OS page size")); } - - if (StubPrecodeCodeTemplate != NULL && pageSize != 0x4000) - { - // This should fail if the template is used on a platform which doesn't support the supported page size for templates - ThrowHR(COR_E_EXECUTIONENGINE); - } - #undef ENUM_PAGE_SIZE #else _ASSERTE((SIZE_T)((BYTE*)StubPrecodeCode_End - (BYTE*)StubPrecodeCode) <= StubPrecode::CodeSize); @@ -542,22 +524,21 @@ void StubPrecode::StaticInitialize() _ASSERTE((*((BYTE*)PCODEToPINSTR((PCODE)StubPrecodeCode) + OFFSETOF_PRECODE_TYPE)) == StubPrecode::Type); #endif - InitializeLoaderHeapConfig(&s_stubPrecodeHeapConfig, StubPrecode::CodeSize, (void*)StubPrecodeCodeTemplate, StubPrecode::GenerateCodePage); } -void StubPrecode::GenerateCodePage(uint8_t* pageBase, uint8_t* pageBaseRX, size_t pageSize) +void StubPrecode::GenerateCodePage(BYTE* pageBase, BYTE* pageBaseRX, SIZE_T pageSize) { #ifdef TARGET_X86 int totalCodeSize = (pageSize / StubPrecode::CodeSize) * StubPrecode::CodeSize; for (int i = 0; i < totalCodeSize; i += StubPrecode::CodeSize) { - memcpy(pageBase + i, (const void*)StubPrecodeCode, (uint8_t*)StubPrecodeCode_End - (uint8_t*)StubPrecodeCode); + memcpy(pageBase + i, (const void*)StubPrecodeCode, (BYTE*)StubPrecodeCode_End - (BYTE*)StubPrecodeCode); - uint8_t* pTargetSlot = pageBaseRX + i + pageSize + offsetof(StubPrecodeData, Target); - *(uint8_t**)(pageBase + i + SYMBOL_VALUE(StubPrecodeCode_Target_Offset)) = pTargetSlot; + BYTE* pTargetSlot = pageBaseRX + i + pageSize + offsetof(StubPrecodeData, Target); + *(BYTE**)(pageBase + i + SYMBOL_VALUE(StubPrecodeCode_Target_Offset)) = pTargetSlot; BYTE* pMethodDescSlot = pageBaseRX + i + pageSize + offsetof(StubPrecodeData, SecretParam); - *(uint8_t**)(pageBase + i + SYMBOL_VALUE(StubPrecodeCode_MethodDesc_Offset)) = pMethodDescSlot; + *(BYTE**)(pageBase + i + SYMBOL_VALUE(StubPrecodeCode_MethodDesc_Offset)) = pMethodDescSlot; } #else // TARGET_X86 FillStubCodePage(pageBase, (const void*)PCODEToPINSTR((PCODE)StubPrecodeCode), StubPrecode::CodeSize, pageSize); @@ -645,12 +626,6 @@ void (*FixupPrecode::FixupPrecodeCode)(); void (*FixupPrecode::FixupPrecodeCode_End)(); #endif -#ifdef FEATURE_MAP_THUNKS_FROM_IMAGE -extern "C" void FixupPrecodeCodeTemplate(); -#else -#define FixupPrecodeCodeTemplate NULL -#endif - void FixupPrecode::StaticInitialize() { #if defined(TARGET_ARM64) && defined(TARGET_UNIX) @@ -670,12 +645,6 @@ void FixupPrecode::StaticInitialize() EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Unsupported OS page size")); } #undef ENUM_PAGE_SIZE - - if (FixupPrecodeCodeTemplate != NULL && pageSize != 0x4000) - { - // This should fail if the template is used on a platform which doesn't support the supported page size for templates - ThrowHR(COR_E_EXECUTIONENGINE); - } #else _ASSERTE((SIZE_T)((BYTE*)FixupPrecodeCode_End - (BYTE*)FixupPrecodeCode) <= FixupPrecode::CodeSize); #endif @@ -686,11 +655,9 @@ void FixupPrecode::StaticInitialize() #else _ASSERTE(*((BYTE*)PCODEToPINSTR((PCODE)FixupPrecodeCode) + OFFSETOF_PRECODE_TYPE) == FixupPrecode::Type); #endif - - InitializeLoaderHeapConfig(&s_fixupStubPrecodeHeapConfig, FixupPrecode::CodeSize, (void*)FixupPrecodeCodeTemplate, FixupPrecode::GenerateCodePage); } -void FixupPrecode::GenerateCodePage(uint8_t* pageBase, uint8_t* pageBaseRX, size_t pageSize) +void FixupPrecode::GenerateCodePage(BYTE* pageBase, BYTE* pageBaseRX, SIZE_T pageSize) { #ifdef TARGET_X86 int totalCodeSize = (pageSize / FixupPrecode::CodeSize) * FixupPrecode::CodeSize; @@ -698,14 +665,14 @@ void FixupPrecode::GenerateCodePage(uint8_t* pageBase, uint8_t* pageBaseRX, size for (int i = 0; i < totalCodeSize; i += FixupPrecode::CodeSize) { memcpy(pageBase + i, (const void*)FixupPrecodeCode, FixupPrecode::CodeSize); - uint8_t* pTargetSlot = pageBaseRX + i + pageSize + offsetof(FixupPrecodeData, Target); - *(uint8_t**)(pageBase + i + SYMBOL_VALUE(FixupPrecodeCode_Target_Offset)) = pTargetSlot; + BYTE* pTargetSlot = pageBaseRX + i + pageSize + offsetof(FixupPrecodeData, Target); + *(BYTE**)(pageBase + i + SYMBOL_VALUE(FixupPrecodeCode_Target_Offset)) = pTargetSlot; BYTE* pMethodDescSlot = pageBaseRX + i + pageSize + offsetof(FixupPrecodeData, MethodDesc); - *(uint8_t**)(pageBase + i + SYMBOL_VALUE(FixupPrecodeCode_MethodDesc_Offset)) = pMethodDescSlot; + *(BYTE**)(pageBase + i + SYMBOL_VALUE(FixupPrecodeCode_MethodDesc_Offset)) = pMethodDescSlot; BYTE* pPrecodeFixupThunkSlot = pageBaseRX + i + pageSize + offsetof(FixupPrecodeData, PrecodeFixupThunk); - *(uint8_t**)(pageBase + i + SYMBOL_VALUE(FixupPrecodeCode_PrecodeFixupThunk_Offset)) = pPrecodeFixupThunkSlot; + *(BYTE**)(pageBase + i + SYMBOL_VALUE(FixupPrecodeCode_PrecodeFixupThunk_Offset)) = pPrecodeFixupThunkSlot; } #else // TARGET_X86 FillStubCodePage(pageBase, (const void*)PCODEToPINSTR((PCODE)FixupPrecodeCode), FixupPrecode::CodeSize, pageSize); diff --git a/src/coreclr/vm/precode.h b/src/coreclr/vm/precode.h index 64394d259e91a4..87570f217292a0 100644 --- a/src/coreclr/vm/precode.h +++ b/src/coreclr/vm/precode.h @@ -225,7 +225,7 @@ struct StubPrecode pData->Target = (PCODE)target; } - static void GenerateCodePage(uint8_t* pageBase, uint8_t* pageBaseRX, size_t size); + static void GenerateCodePage(BYTE* pageBase, BYTE* pageBaseRX, SIZE_T size); #endif // !DACCESS_COMPILE }; @@ -428,7 +428,7 @@ struct FixupPrecode static void StaticInitialize(); - static void GenerateCodePage(uint8_t* pageBase, uint8_t* pageBaseRX, size_t size); + static void GenerateCodePage(BYTE* pageBase, BYTE* pageBaseRX, SIZE_T size); PTR_FixupPrecodeData GetData() const { @@ -861,9 +861,4 @@ struct PrecodeMachineDescriptor }; #endif //DACCESS_COMPILE -extern InterleavedLoaderHeapConfig s_stubPrecodeHeapConfig; -#ifdef HAS_FIXUP_PRECODE -extern InterleavedLoaderHeapConfig s_fixupStubPrecodeHeapConfig; -#endif - #endif // __PRECODE_H__ diff --git a/src/coreclr/vm/profdetach.cpp b/src/coreclr/vm/profdetach.cpp index 7bfcba8ed2cc6b..28b8442454cf0c 100644 --- a/src/coreclr/vm/profdetach.cpp +++ b/src/coreclr/vm/profdetach.cpp @@ -55,9 +55,6 @@ void ProfilerDetachInfo::Init() } -// ---------------------------------------------------------------------------- -// Implementation of ProfilingAPIAttachDetach statics - // ---------------------------------------------------------------------------- // ProfilingAPIDetach::Initialize diff --git a/src/coreclr/vm/profilinghelper.cpp b/src/coreclr/vm/profilinghelper.cpp index d94dce9d89c9c1..99eb7eb0921ec0 100644 --- a/src/coreclr/vm/profilinghelper.cpp +++ b/src/coreclr/vm/profilinghelper.cpp @@ -411,13 +411,6 @@ EXTERN_C void STDMETHODCALLTYPE ProfileTailcallNaked(UINT_PTR clientData); // Notes: // This function (or one of its callees) will log an error to the event log // if there is a failure -// -// Assumptions: -// InitializeProfiling is called during startup, AFTER the host has initialized its -// settings and the config variables have been read, but BEFORE the finalizer thread -// has entered its first wait state. ASSERTs are placed in -// code:ProfilingAPIAttachDetach::Initialize (which is called by this function, and -// which depends on these assumptions) to verify. // static HRESULT ProfilingAPIUtility::InitializeProfiling() diff --git a/src/coreclr/vm/amd64/jitinterfaceamd64.cpp b/src/coreclr/vm/writebarriermanager.cpp similarity index 87% rename from src/coreclr/vm/amd64/jitinterfaceamd64.cpp rename to src/coreclr/vm/writebarriermanager.cpp index 3df45e888b5dec..c9aac96ada37d5 100644 --- a/src/coreclr/vm/amd64/jitinterfaceamd64.cpp +++ b/src/coreclr/vm/writebarriermanager.cpp @@ -2,19 +2,21 @@ // The .NET Foundation licenses this file to you under the MIT license. // =========================================================================== -// File: JITinterfaceCpu.CPP +// File: writebariermanager.cpp // =========================================================================== -// This contains JITinterface routines that are specific to the -// AMD64 platform. They are modeled after the X86 specific routines -// found in JITinterfaceX86.cpp or JIThelp.asm - +// This contains JITinterface routines for managing which write barrier function +// is currently in use, and patching all related constants. #include "common.h" #include "jitinterface.h" #include "eeconfig.h" #include "excep.h" #include "threadsuspend.h" +#include "writebarriermanager.h" +#if !defined(WRITE_BARRIER_VARS_INLINE) +#include "patchedcodeconstants.h" +#endif extern uint8_t* g_ephemeral_low; extern uint8_t* g_ephemeral_high; @@ -22,35 +24,58 @@ extern uint32_t* g_card_table; extern uint32_t* g_card_bundle_table; // Patch Labels for the various write barriers -EXTERN_C void JIT_WriteBarrier_End(); +EXTERN_C void JIT_WriteBarrier_End(); EXTERN_C void JIT_WriteBarrier_PreGrow64(Object **dst, Object *ref); +EXTERN_C void JIT_WriteBarrier_PreGrow64_End(); +EXTERN_C void JIT_WriteBarrier_PostGrow64(Object **dst, Object *ref); +EXTERN_C void JIT_WriteBarrier_PostGrow64_End(); +#ifdef FEATURE_SVR_GC +EXTERN_C void JIT_WriteBarrier_SVR64(Object **dst, Object *ref); +EXTERN_C void JIT_WriteBarrier_SVR64_End(); +#endif // FEATURE_SVR_GC +EXTERN_C void JIT_WriteBarrier_Byte_Region64(Object **dst, Object *ref); +EXTERN_C void JIT_WriteBarrier_Byte_Region64_End(); +EXTERN_C void JIT_WriteBarrier_Bit_Region64(Object **dst, Object *ref); +EXTERN_C void JIT_WriteBarrier_Bit_Region64_End(); +#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP +EXTERN_C void JIT_WriteBarrier_WriteWatch_PreGrow64(Object **dst, Object *ref); +EXTERN_C void JIT_WriteBarrier_WriteWatch_PreGrow64_End(); +EXTERN_C void JIT_WriteBarrier_WriteWatch_PostGrow64(Object **dst, Object *ref); +EXTERN_C void JIT_WriteBarrier_WriteWatch_PostGrow64_End(); +#ifdef FEATURE_SVR_GC +EXTERN_C void JIT_WriteBarrier_WriteWatch_SVR64(Object **dst, Object *ref); +EXTERN_C void JIT_WriteBarrier_WriteWatch_SVR64_End(); +#endif // FEATURE_SVR_GC +EXTERN_C void JIT_WriteBarrier_WriteWatch_Byte_Region64(Object **dst, Object *ref); +EXTERN_C void JIT_WriteBarrier_WriteWatch_Byte_Region64_End(); +EXTERN_C void JIT_WriteBarrier_WriteWatch_Bit_Region64(Object **dst, Object *ref); +EXTERN_C void JIT_WriteBarrier_WriteWatch_Bit_Region64_End(); +#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP + + +#if defined(WRITE_BARRIER_VARS_INLINE) + EXTERN_C void JIT_WriteBarrier_PreGrow64_Patch_Label_Lower(); EXTERN_C void JIT_WriteBarrier_PreGrow64_Patch_Label_CardTable(); #ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES EXTERN_C void JIT_WriteBarrier_PreGrow64_Patch_Label_CardBundleTable(); #endif -EXTERN_C void JIT_WriteBarrier_PreGrow64_End(); -EXTERN_C void JIT_WriteBarrier_PostGrow64(Object **dst, Object *ref); EXTERN_C void JIT_WriteBarrier_PostGrow64_Patch_Label_Lower(); EXTERN_C void JIT_WriteBarrier_PostGrow64_Patch_Label_Upper(); EXTERN_C void JIT_WriteBarrier_PostGrow64_Patch_Label_CardTable(); #ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES EXTERN_C void JIT_WriteBarrier_PostGrow64_Patch_Label_CardBundleTable(); #endif -EXTERN_C void JIT_WriteBarrier_PostGrow64_End(); #ifdef FEATURE_SVR_GC -EXTERN_C void JIT_WriteBarrier_SVR64(Object **dst, Object *ref); EXTERN_C void JIT_WriteBarrier_SVR64_PatchLabel_CardTable(); #ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES EXTERN_C void JIT_WriteBarrier_SVR64_PatchLabel_CardBundleTable(); #endif -EXTERN_C void JIT_WriteBarrier_SVR64_End(); #endif // FEATURE_SVR_GC -EXTERN_C void JIT_WriteBarrier_Byte_Region64(Object **dst, Object *ref); EXTERN_C void JIT_WriteBarrier_Byte_Region64_Patch_Label_RegionToGeneration(); EXTERN_C void JIT_WriteBarrier_Byte_Region64_Patch_Label_RegionShrDest(); EXTERN_C void JIT_WriteBarrier_Byte_Region64_Patch_Label_Lower(); @@ -60,9 +85,7 @@ EXTERN_C void JIT_WriteBarrier_Byte_Region64_Patch_Label_CardTable(); #ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES EXTERN_C void JIT_WriteBarrier_Byte_Region64_Patch_Label_CardBundleTable(); #endif -EXTERN_C void JIT_WriteBarrier_Byte_Region64_End(); -EXTERN_C void JIT_WriteBarrier_Bit_Region64(Object **dst, Object *ref); EXTERN_C void JIT_WriteBarrier_Bit_Region64_Patch_Label_RegionToGeneration(); EXTERN_C void JIT_WriteBarrier_Bit_Region64_Patch_Label_RegionShrDest(); EXTERN_C void JIT_WriteBarrier_Bit_Region64_Patch_Label_Lower(); @@ -72,20 +95,15 @@ EXTERN_C void JIT_WriteBarrier_Bit_Region64_Patch_Label_CardTable(); #ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES EXTERN_C void JIT_WriteBarrier_Bit_Region64_Patch_Label_CardBundleTable(); #endif -EXTERN_C void JIT_WriteBarrier_Bit_Region64_End(); - #ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP -EXTERN_C void JIT_WriteBarrier_WriteWatch_PreGrow64(Object **dst, Object *ref); EXTERN_C void JIT_WriteBarrier_WriteWatch_PreGrow64_Patch_Label_WriteWatchTable(); EXTERN_C void JIT_WriteBarrier_WriteWatch_PreGrow64_Patch_Label_Lower(); EXTERN_C void JIT_WriteBarrier_WriteWatch_PreGrow64_Patch_Label_CardTable(); #ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES EXTERN_C void JIT_WriteBarrier_WriteWatch_PreGrow64_Patch_Label_CardBundleTable(); #endif -EXTERN_C void JIT_WriteBarrier_WriteWatch_PreGrow64_End(); -EXTERN_C void JIT_WriteBarrier_WriteWatch_PostGrow64(Object **dst, Object *ref); EXTERN_C void JIT_WriteBarrier_WriteWatch_PostGrow64_Patch_Label_WriteWatchTable(); EXTERN_C void JIT_WriteBarrier_WriteWatch_PostGrow64_Patch_Label_Lower(); EXTERN_C void JIT_WriteBarrier_WriteWatch_PostGrow64_Patch_Label_Upper(); @@ -93,19 +111,15 @@ EXTERN_C void JIT_WriteBarrier_WriteWatch_PostGrow64_Patch_Label_CardTable(); #ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES EXTERN_C void JIT_WriteBarrier_WriteWatch_PostGrow64_Patch_Label_CardBundleTable(); #endif -EXTERN_C void JIT_WriteBarrier_WriteWatch_PostGrow64_End(); #ifdef FEATURE_SVR_GC -EXTERN_C void JIT_WriteBarrier_WriteWatch_SVR64(Object **dst, Object *ref); EXTERN_C void JIT_WriteBarrier_WriteWatch_SVR64_PatchLabel_WriteWatchTable(); EXTERN_C void JIT_WriteBarrier_WriteWatch_SVR64_PatchLabel_CardTable(); #ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES EXTERN_C void JIT_WriteBarrier_WriteWatch_SVR64_PatchLabel_CardBundleTable(); #endif -EXTERN_C void JIT_WriteBarrier_WriteWatch_SVR64_End(); #endif // FEATURE_SVR_GC -EXTERN_C void JIT_WriteBarrier_WriteWatch_Byte_Region64(Object **dst, Object *ref); EXTERN_C void JIT_WriteBarrier_WriteWatch_Byte_Region64_Patch_Label_WriteWatchTable(); EXTERN_C void JIT_WriteBarrier_WriteWatch_Byte_Region64_Patch_Label_RegionToGeneration(); EXTERN_C void JIT_WriteBarrier_WriteWatch_Byte_Region64_Patch_Label_RegionShrDest(); @@ -116,9 +130,7 @@ EXTERN_C void JIT_WriteBarrier_WriteWatch_Byte_Region64_Patch_Label_CardTable(); #ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES EXTERN_C void JIT_WriteBarrier_WriteWatch_Byte_Region64_Patch_Label_CardBundleTable(); #endif -EXTERN_C void JIT_WriteBarrier_WriteWatch_Byte_Region64_End(); -EXTERN_C void JIT_WriteBarrier_WriteWatch_Bit_Region64(Object **dst, Object *ref); EXTERN_C void JIT_WriteBarrier_WriteWatch_Bit_Region64_Patch_Label_WriteWatchTable(); EXTERN_C void JIT_WriteBarrier_WriteWatch_Bit_Region64_Patch_Label_RegionToGeneration(); EXTERN_C void JIT_WriteBarrier_WriteWatch_Bit_Region64_Patch_Label_RegionShrDest(); @@ -129,16 +141,33 @@ EXTERN_C void JIT_WriteBarrier_WriteWatch_Bit_Region64_Patch_Label_CardTable(); #ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES EXTERN_C void JIT_WriteBarrier_WriteWatch_Bit_Region64_Patch_Label_CardBundleTable(); #endif -EXTERN_C void JIT_WriteBarrier_WriteWatch_Bit_Region64_End(); #endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP -WriteBarrierManager g_WriteBarrierManager; +#else // WRITE_BARRIER_VARS_INLINE -// Use this somewhat hokey macro to concatenate the function start with the patch -// label. This allows the code below to look relatively nice, but relies on the -// naming convention which we have established for these helpers. -#define CALC_PATCH_LOCATION(func,label,offset) CalculatePatchLocation((PVOID)func, (PVOID)func##_##label, offset) +EXTERN_C void JIT_WriteBarrier_Table(); +EXTERN_C void JIT_WriteBarrier_Table_End(); +EXTERN_C void JIT_WriteBarrier_Patch_Label_WriteWatchTable(); +EXTERN_C void JIT_WriteBarrier_Patch_Label_RegionToGeneration(); +EXTERN_C void JIT_WriteBarrier_Patch_Label_RegionShr(); +EXTERN_C void JIT_WriteBarrier_Patch_Label_Lower(); +EXTERN_C void JIT_WriteBarrier_Patch_Label_Upper(); +EXTERN_C void JIT_WriteBarrier_Patch_Label_CardTable(); +#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES +EXTERN_C void JIT_WriteBarrier_Patch_Label_CardBundleTable(); +#endif +#if defined(TARGET_ARM64) +EXTERN_C void JIT_WriteBarrier_Patch_Label_LowestAddress(); +EXTERN_C void JIT_WriteBarrier_Patch_Label_HighestAddress(); +#if defined(WRITE_BARRIER_CHECK) +EXTERN_C void JIT_WriteBarrier_Patch_Label_GCShadow(); +EXTERN_C void JIT_WriteBarrier_Patch_Label_GCShadowEnd(); +#endif // WRITE_BARRIER_CHECK +#endif // TARGET_ARM64 +#endif // WRITE_BARRIER_VARS_INLINE + +WriteBarrierManager g_WriteBarrierManager; WriteBarrierManager::WriteBarrierManager() : m_currentWriteBarrier(WRITE_BARRIER_UNINITIALIZED) @@ -146,173 +175,6 @@ WriteBarrierManager::WriteBarrierManager() : LIMITED_METHOD_CONTRACT; } -#ifndef CODECOVERAGE // Deactivate alignment validation for code coverage builds - // because the instrumentation tool will not preserve alignment - // constraints and we will fail. - -void WriteBarrierManager::Validate() -{ - CONTRACTL - { - MODE_ANY; - GC_NOTRIGGER; - NOTHROW; - } - CONTRACTL_END; - - // we have an invariant that the addresses of all the values that we update in our write barrier - // helpers must be naturally aligned, this is so that the update can happen atomically since there - // are places where these values are updated while the EE is running - // NOTE: we can't call this from the ctor since our infrastructure isn't ready for assert dialogs - - PBYTE pLowerBoundImmediate, pUpperBoundImmediate, pCardTableImmediate; - -#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES - PBYTE pCardBundleTableImmediate; -#endif - - pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PreGrow64, Patch_Label_Lower, 2); - pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PreGrow64, Patch_Label_CardTable, 2); - - _ASSERTE_ALL_BUILDS((reinterpret_cast(pLowerBoundImmediate) & 0x7) == 0); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardTableImmediate) & 0x7) == 0); - -#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES - pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PreGrow64, Patch_Label_CardBundleTable, 2); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardBundleTableImmediate) & 0x7) == 0); -#endif - - pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PostGrow64, Patch_Label_Lower, 2); - pUpperBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PostGrow64, Patch_Label_Upper, 2); - pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PostGrow64, Patch_Label_CardTable, 2); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pLowerBoundImmediate) & 0x7) == 0); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pUpperBoundImmediate) & 0x7) == 0); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardTableImmediate) & 0x7) == 0); - -#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES - pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PostGrow64, Patch_Label_CardBundleTable, 2); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardBundleTableImmediate) & 0x7) == 0); -#endif - -#ifdef FEATURE_SVR_GC - pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_SVR64, PatchLabel_CardTable, 2); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardTableImmediate) & 0x7) == 0); - -#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES - pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_SVR64, PatchLabel_CardBundleTable, 2); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardBundleTableImmediate) & 0x7) == 0); -#endif // FEATURE_MANUALLY_MANAGED_CARD_BUNDLES -#endif // FEATURE_SVR_GC - - PBYTE pRegionToGenTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Byte_Region64, Patch_Label_RegionToGeneration, 2); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pRegionToGenTableImmediate) & 0x7) == 0); - - pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Byte_Region64, Patch_Label_Lower, 2); - pUpperBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Byte_Region64, Patch_Label_Upper, 2); - pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Byte_Region64, Patch_Label_CardTable, 2); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pLowerBoundImmediate) & 0x7) == 0); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pUpperBoundImmediate) & 0x7) == 0); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardTableImmediate) & 0x7) == 0); - -#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES - pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Byte_Region64, Patch_Label_CardBundleTable, 2); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardBundleTableImmediate) & 0x7) == 0); -#endif - - pRegionToGenTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Bit_Region64, Patch_Label_RegionToGeneration, 2); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pRegionToGenTableImmediate) & 0x7) == 0); - - pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Bit_Region64, Patch_Label_Lower, 2); - pUpperBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Bit_Region64, Patch_Label_Upper, 2); - pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Bit_Region64, Patch_Label_CardTable, 2); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pLowerBoundImmediate) & 0x7) == 0); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pUpperBoundImmediate) & 0x7) == 0); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardTableImmediate) & 0x7) == 0); - -#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES - pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Bit_Region64, Patch_Label_CardBundleTable, 2); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardBundleTableImmediate) & 0x7) == 0); -#endif - -#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP - PBYTE pWriteWatchTableImmediate; - - pWriteWatchTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PreGrow64, Patch_Label_WriteWatchTable, 2); - pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PreGrow64, Patch_Label_Lower, 2); - pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PreGrow64, Patch_Label_CardTable, 2); - - _ASSERTE_ALL_BUILDS((reinterpret_cast(pWriteWatchTableImmediate) & 0x7) == 0); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pLowerBoundImmediate) & 0x7) == 0); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardTableImmediate) & 0x7) == 0); - -#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES - pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PreGrow64, Patch_Label_CardBundleTable, 2); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardBundleTableImmediate) & 0x7) == 0); -#endif - - pWriteWatchTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PostGrow64, Patch_Label_WriteWatchTable, 2); - pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PostGrow64, Patch_Label_Lower, 2); - pUpperBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PostGrow64, Patch_Label_Upper, 2); - pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PostGrow64, Patch_Label_CardTable, 2); - - _ASSERTE_ALL_BUILDS((reinterpret_cast(pWriteWatchTableImmediate) & 0x7) == 0); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pLowerBoundImmediate) & 0x7) == 0); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pUpperBoundImmediate) & 0x7) == 0); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardTableImmediate) & 0x7) == 0); - -#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES - pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PostGrow64, Patch_Label_CardBundleTable, 2); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardBundleTableImmediate) & 0x7) == 0); -#endif - -#ifdef FEATURE_SVR_GC - pWriteWatchTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_SVR64, PatchLabel_WriteWatchTable, 2); - pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_SVR64, PatchLabel_CardTable, 2); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pWriteWatchTableImmediate) & 0x7) == 0); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardTableImmediate) & 0x7) == 0); - -#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES - pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_SVR64, PatchLabel_CardBundleTable, 2); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardBundleTableImmediate) & 0x7) == 0); -#endif // FEATURE_MANUALLY_MANAGED_CARD_BUNDLES -#endif // FEATURE_SVR_GC - - pRegionToGenTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Byte_Region64, Patch_Label_RegionToGeneration, 2); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pRegionToGenTableImmediate) & 0x7) == 0); - - pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Byte_Region64, Patch_Label_Lower, 2); - pUpperBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Byte_Region64, Patch_Label_Upper, 2); - pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Byte_Region64, Patch_Label_CardTable, 2); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pLowerBoundImmediate) & 0x7) == 0); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pUpperBoundImmediate) & 0x7) == 0); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardTableImmediate) & 0x7) == 0); - -#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES - pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Byte_Region64, Patch_Label_CardBundleTable, 2); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardBundleTableImmediate) & 0x7) == 0); -#endif - - pRegionToGenTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Bit_Region64, Patch_Label_RegionToGeneration, 2); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pRegionToGenTableImmediate) & 0x7) == 0); - - pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Bit_Region64, Patch_Label_Lower, 2); - pUpperBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Bit_Region64, Patch_Label_Upper, 2); - pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Bit_Region64, Patch_Label_CardTable, 2); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pLowerBoundImmediate) & 0x7) == 0); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pUpperBoundImmediate) & 0x7) == 0); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardTableImmediate) & 0x7) == 0); - -#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES - pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Bit_Region64, Patch_Label_CardBundleTable, 2); - _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardBundleTableImmediate) & 0x7) == 0); -#endif - -#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP -} - -#endif // CODECOVERAGE - - PCODE WriteBarrierManager::GetCurrentWriteBarrierCode() { LIMITED_METHOD_CONTRACT; @@ -386,7 +248,11 @@ size_t WriteBarrierManager::GetSpecificWriteBarrierSize(WriteBarrierType writeBa return MARKED_FUNCTION_SIZE(JIT_WriteBarrier_WriteWatch_Bit_Region64); #endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP case WRITE_BARRIER_BUFFER: +#if defined(WRITE_BARRIER_VARS_INLINE) return MARKED_FUNCTION_SIZE(JIT_WriteBarrier); +#else + return (size_t)((LPBYTE)GetEEFuncEntryPoint(JIT_WriteBarrier_Table_End) - (LPBYTE)GetEEFuncEntryPoint(JIT_WriteBarrier)); +#endif default: UNREACHABLE_MSG("unexpected m_currentWriteBarrier!"); }; @@ -398,14 +264,6 @@ size_t WriteBarrierManager::GetCurrentWriteBarrierSize() return GetSpecificWriteBarrierSize(m_currentWriteBarrier); } -PBYTE WriteBarrierManager::CalculatePatchLocation(LPVOID base, LPVOID label, int offset) -{ - // the label should always come after the entrypoint for this funtion - _ASSERTE_ALL_BUILDS((LPBYTE)label > (LPBYTE)base); - - return (GetWriteBarrierCodeLocation((void*)JIT_WriteBarrier) + ((LPBYTE)GetEEFuncEntryPoint(label) - (LPBYTE)GetEEFuncEntryPoint(base) + offset)); -} - int WriteBarrierManager::ChangeWriteBarrierTo(WriteBarrierType newWriteBarrier, bool isRuntimeSuspended) { @@ -428,222 +286,16 @@ int WriteBarrierManager::ChangeWriteBarrierTo(WriteBarrierType newWriteBarrier, stompWBCompleteActions |= SWB_ICACHE_FLUSH; } - switch (newWriteBarrier) - { - case WRITE_BARRIER_PREGROW64: - { - m_pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PreGrow64, Patch_Label_Lower, 2); - m_pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PreGrow64, Patch_Label_CardTable, 2); - - // Make sure that we will be bashing the right places (immediates should be hardcoded to 0x0f0f0f0f0f0f0f0f0). - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pLowerBoundImmediate); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardTableImmediate); - -#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES - m_pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PreGrow64, Patch_Label_CardBundleTable, 2); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardBundleTableImmediate); +#if defined(WRITE_BARRIER_VARS_INLINE) + UpdatePatchLocations(newWriteBarrier); #endif - break; - } - case WRITE_BARRIER_POSTGROW64: - { - m_pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PostGrow64, Patch_Label_Lower, 2); - m_pUpperBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PostGrow64, Patch_Label_Upper, 2); - m_pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PostGrow64, Patch_Label_CardTable, 2); - - // Make sure that we will be bashing the right places (immediates should be hardcoded to 0x0f0f0f0f0f0f0f0f0). - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pLowerBoundImmediate); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardTableImmediate); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pUpperBoundImmediate); - -#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES - m_pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PostGrow64, Patch_Label_CardBundleTable, 2); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardBundleTableImmediate); -#endif - break; - } - -#ifdef FEATURE_SVR_GC - case WRITE_BARRIER_SVR64: - { - m_pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_SVR64, PatchLabel_CardTable, 2); - - // Make sure that we will be bashing the right places (immediates should be hardcoded to 0x0f0f0f0f0f0f0f0f0). - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardTableImmediate); - -#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES - m_pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_SVR64, PatchLabel_CardBundleTable, 2); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardBundleTableImmediate); -#endif - break; - } -#endif // FEATURE_SVR_GC - - case WRITE_BARRIER_BYTE_REGIONS64: - m_pRegionToGenTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Byte_Region64, Patch_Label_RegionToGeneration, 2); - m_pRegionShrDest = CALC_PATCH_LOCATION(JIT_WriteBarrier_Byte_Region64, Patch_Label_RegionShrDest, 3); - m_pRegionShrSrc = CALC_PATCH_LOCATION(JIT_WriteBarrier_Byte_Region64, Patch_Label_RegionShrSrc, 3); - m_pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Byte_Region64, Patch_Label_Lower, 2); - m_pUpperBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Byte_Region64, Patch_Label_Upper, 2); - m_pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Byte_Region64, Patch_Label_CardTable, 2); - - // Make sure that we will be bashing the right places (immediates should be hardcoded to 0x0f0f0f0f0f0f0f0f0). - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pRegionToGenTableImmediate); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pLowerBoundImmediate); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pUpperBoundImmediate); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardTableImmediate); - _ASSERTE_ALL_BUILDS( 0x16 == *(UINT8 *)m_pRegionShrDest); - _ASSERTE_ALL_BUILDS( 0x16 == *(UINT8 *)m_pRegionShrSrc); - -#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES - m_pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Byte_Region64, Patch_Label_CardBundleTable, 2); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardBundleTableImmediate); -#endif - break; - - case WRITE_BARRIER_BIT_REGIONS64: - m_pRegionToGenTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Bit_Region64, Patch_Label_RegionToGeneration, 2); - m_pRegionShrDest = CALC_PATCH_LOCATION(JIT_WriteBarrier_Bit_Region64, Patch_Label_RegionShrDest, 3); - m_pRegionShrSrc = CALC_PATCH_LOCATION(JIT_WriteBarrier_Bit_Region64, Patch_Label_RegionShrSrc, 3); - m_pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Bit_Region64, Patch_Label_Lower, 2); - m_pUpperBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Bit_Region64, Patch_Label_Upper, 2); - m_pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Bit_Region64, Patch_Label_CardTable, 2); - - // Make sure that we will be bashing the right places (immediates should be hardcoded to 0x0f0f0f0f0f0f0f0f0). - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pRegionToGenTableImmediate); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pLowerBoundImmediate); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pUpperBoundImmediate); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardTableImmediate); - _ASSERTE_ALL_BUILDS( 0x16 == *(UINT8 *)m_pRegionShrDest); - _ASSERTE_ALL_BUILDS( 0x16 == *(UINT8 *)m_pRegionShrSrc); - -#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES - m_pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Bit_Region64, Patch_Label_CardBundleTable, 2); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardBundleTableImmediate); -#endif - break; - -#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP - case WRITE_BARRIER_WRITE_WATCH_PREGROW64: - { - m_pWriteWatchTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PreGrow64, Patch_Label_WriteWatchTable, 2); - m_pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PreGrow64, Patch_Label_Lower, 2); - m_pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PreGrow64, Patch_Label_CardTable, 2); - - // Make sure that we will be bashing the right places (immediates should be hardcoded to 0x0f0f0f0f0f0f0f0f0). - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pWriteWatchTableImmediate); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pLowerBoundImmediate); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardTableImmediate); - -#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES - m_pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PreGrow64, Patch_Label_CardBundleTable, 2); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardBundleTableImmediate); -#endif - break; - } - - case WRITE_BARRIER_WRITE_WATCH_POSTGROW64: - { - m_pWriteWatchTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PostGrow64, Patch_Label_WriteWatchTable, 2); - m_pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PostGrow64, Patch_Label_Lower, 2); - m_pUpperBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PostGrow64, Patch_Label_Upper, 2); - m_pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PostGrow64, Patch_Label_CardTable, 2); - - // Make sure that we will be bashing the right places (immediates should be hardcoded to 0x0f0f0f0f0f0f0f0f0). - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pWriteWatchTableImmediate); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pLowerBoundImmediate); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardTableImmediate); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pUpperBoundImmediate); - -#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES - m_pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PostGrow64, Patch_Label_CardBundleTable, 2); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardBundleTableImmediate); -#endif - break; - } - -#ifdef FEATURE_SVR_GC - case WRITE_BARRIER_WRITE_WATCH_SVR64: - { - m_pWriteWatchTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_SVR64, PatchLabel_WriteWatchTable, 2); - m_pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_SVR64, PatchLabel_CardTable, 2); - - // Make sure that we will be bashing the right places (immediates should be hardcoded to 0x0f0f0f0f0f0f0f0f0). - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pWriteWatchTableImmediate); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardTableImmediate); - -#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES - m_pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_SVR64, PatchLabel_CardBundleTable, 2); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardBundleTableImmediate); -#endif - break; - } -#endif // FEATURE_SVR_GC - - case WRITE_BARRIER_WRITE_WATCH_BYTE_REGIONS64: - m_pWriteWatchTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Byte_Region64, Patch_Label_WriteWatchTable, 2); - m_pRegionToGenTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Byte_Region64, Patch_Label_RegionToGeneration, 2); - m_pRegionShrDest = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Byte_Region64, Patch_Label_RegionShrDest, 3); - m_pRegionShrSrc = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Byte_Region64, Patch_Label_RegionShrSrc, 3); - m_pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Byte_Region64, Patch_Label_Lower, 2); - m_pUpperBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Byte_Region64, Patch_Label_Upper, 2); - m_pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Byte_Region64, Patch_Label_CardTable, 2); - - // Make sure that we will be bashing the right places (immediates should be hardcoded to 0x0f0f0f0f0f0f0f0f0). - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pWriteWatchTableImmediate); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pRegionToGenTableImmediate); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pLowerBoundImmediate); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pUpperBoundImmediate); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardTableImmediate); - _ASSERTE_ALL_BUILDS( 0x16 == *(UINT8 *)m_pRegionShrDest); - _ASSERTE_ALL_BUILDS( 0x16 == *(UINT8 *)m_pRegionShrSrc); - -#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES - m_pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Byte_Region64, Patch_Label_CardBundleTable, 2); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardBundleTableImmediate); -#endif - break; - - case WRITE_BARRIER_WRITE_WATCH_BIT_REGIONS64: - m_pWriteWatchTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Bit_Region64, Patch_Label_WriteWatchTable, 2); - m_pRegionToGenTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Bit_Region64, Patch_Label_RegionToGeneration, 2); - m_pRegionShrDest = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Bit_Region64, Patch_Label_RegionShrDest, 3); - m_pRegionShrSrc = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Bit_Region64, Patch_Label_RegionShrSrc, 3); - m_pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Bit_Region64, Patch_Label_Lower, 2); - m_pUpperBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Bit_Region64, Patch_Label_Upper, 2); - m_pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Bit_Region64, Patch_Label_CardTable, 2); - - // Make sure that we will be bashing the right places (immediates should be hardcoded to 0x0f0f0f0f0f0f0f0f0). - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pWriteWatchTableImmediate); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pRegionToGenTableImmediate); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pLowerBoundImmediate); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pUpperBoundImmediate); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardTableImmediate); - _ASSERTE_ALL_BUILDS( 0x16 == *(UINT8 *)m_pRegionShrDest); - _ASSERTE_ALL_BUILDS( 0x16 == *(UINT8 *)m_pRegionShrSrc); - -#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES - m_pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Bit_Region64, Patch_Label_CardBundleTable, 2); - _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardBundleTableImmediate); -#endif - break; - - -#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP - - default: - UNREACHABLE_MSG("unexpected write barrier type!"); - } - - stompWBCompleteActions |= UpdateEphemeralBounds(true); - stompWBCompleteActions |= UpdateWriteWatchAndCardTableLocations(true, false); + stompWBCompleteActions |= UpdateEphemeralBounds(true); + stompWBCompleteActions |= UpdateWriteWatchAndCardTableLocations(true, false); return stompWBCompleteActions; } -#undef CALC_PATCH_LOCATION - void WriteBarrierManager::Initialize() { CONTRACTL @@ -654,7 +306,6 @@ void WriteBarrierManager::Initialize() } CONTRACTL_END; - // Ensure that the generic JIT_WriteBarrier function buffer is large enough to hold any of the more specific // write barrier implementations. size_t cbWriteBarrierBuffer = GetSpecificWriteBarrierSize(WRITE_BARRIER_BUFFER); @@ -676,11 +327,50 @@ void WriteBarrierManager::Initialize() _ASSERTE_ALL_BUILDS(cbWriteBarrierBuffer >= GetSpecificWriteBarrierSize(WRITE_BARRIER_WRITE_WATCH_BIT_REGIONS64)); #endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP -#if !defined(CODECOVERAGE) + +#if !defined(WRITE_BARRIER_VARS_INLINE) + + #define CALC_TABLE_LOCATION(var, offset) \ + assert(JIT_WriteBarrier_Offset_##offset == (PBYTE)JIT_WriteBarrier_Patch_Label_##offset - (PBYTE)JIT_WriteBarrier); \ + var = ((PBYTE)GetWriteBarrierCodeLocation((void*)JIT_WriteBarrier) + JIT_WriteBarrier_Offset_##offset); + + CALC_TABLE_LOCATION(m_pWriteWatchTableImmediate, WriteWatchTable); + CALC_TABLE_LOCATION(m_pRegionToGenTableImmediate, RegionToGeneration); + CALC_TABLE_LOCATION(m_pRegionShrDest, RegionShr); + CALC_TABLE_LOCATION(m_pLowerBoundImmediate, Lower); + CALC_TABLE_LOCATION(m_pUpperBoundImmediate, Upper); + CALC_TABLE_LOCATION(m_pCardTableImmediate, CardTable); +#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES + CALC_TABLE_LOCATION(m_pCardBundleTableImmediate, CardBundleTable); +#endif + +#if defined(TARGET_ARM64) + CALC_TABLE_LOCATION(m_lowestAddress, LowestAddress); + CALC_TABLE_LOCATION(m_highestAddress, HighestAddress); +#if defined(WRITE_BARRIER_CHECK) + CALC_TABLE_LOCATION(m_pGCShadow, GCShadow); + CALC_TABLE_LOCATION(m_pGCShadowEnd, GCShadowEnd); +#endif // WRITE_BARRIER_CHECK +#endif // TARGET_AMD64 + +#endif // !WRITE_BARRIER_VARS_INLINE + +#if !defined(CODECOVERAGE) && defined(WRITE_BARRIER_VARS_INLINE) Validate(); #endif } +template int updateVariable(PBYTE loc, T value) +{ + if (*(T*)loc != value) + { + ExecutableWriterHolder varWriterHolder((T*)loc, sizeof(T)); + *varWriterHolder.GetRW() = value; + return SWB_ICACHE_FLUSH; + } + return SWB_PASS; +} + bool WriteBarrierManager::NeedDifferentWriteBarrier(bool bReqUpperBoundsCheck, bool bUseBitwiseWriteBarrier, WriteBarrierType* pNewWriteBarrierType) { // Init code for the JIT_WriteBarrier assembly routine. Since it will be bashed everytime the GC Heap @@ -782,6 +472,8 @@ int WriteBarrierManager::UpdateEphemeralBounds(bool isRuntimeSuspended) return stompWBCompleteActions; #endif +#if defined(WRITE_BARRIER_VARS_INLINE) + switch (m_currentWriteBarrier) { case WRITE_BARRIER_POSTGROW64: @@ -792,45 +484,44 @@ int WriteBarrierManager::UpdateEphemeralBounds(bool isRuntimeSuspended) case WRITE_BARRIER_WRITE_WATCH_BYTE_REGIONS64: case WRITE_BARRIER_WRITE_WATCH_BIT_REGIONS64: #endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP - { - // Change immediate if different from new g_ephermeral_high. - if (*(UINT64*)m_pUpperBoundImmediate != (size_t)g_ephemeral_high) - { - ExecutableWriterHolder upperBoundWriterHolder((UINT64*)m_pUpperBoundImmediate, sizeof(UINT64)); - *upperBoundWriterHolder.GetRW() = (size_t)g_ephemeral_high; - stompWBCompleteActions |= SWB_ICACHE_FLUSH; - } - } + stompWBCompleteActions |= updateVariable(m_pUpperBoundImmediate, (size_t)g_ephemeral_high); FALLTHROUGH; + case WRITE_BARRIER_PREGROW64: #ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP case WRITE_BARRIER_WRITE_WATCH_PREGROW64: #endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP - { - // Change immediate if different from new g_ephermeral_low. - if (*(UINT64*)m_pLowerBoundImmediate != (size_t)g_ephemeral_low) - { - ExecutableWriterHolder lowerBoundImmediateWriterHolder((UINT64*)m_pLowerBoundImmediate, sizeof(UINT64)); - *lowerBoundImmediateWriterHolder.GetRW() = (size_t)g_ephemeral_low; - stompWBCompleteActions |= SWB_ICACHE_FLUSH; - } + stompWBCompleteActions |= updateVariable(m_pLowerBoundImmediate, (size_t)g_ephemeral_low); break; - } #ifdef FEATURE_SVR_GC case WRITE_BARRIER_SVR64: #ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP case WRITE_BARRIER_WRITE_WATCH_SVR64: #endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP - { break; - } #endif // FEATURE_SVR_GC default: UNREACHABLE_MSG("unexpected m_currentWriteBarrier in UpdateEphemeralBounds"); } +#else + + stompWBCompleteActions |= updateVariable(m_pUpperBoundImmediate, (size_t)g_ephemeral_high); + stompWBCompleteActions |= updateVariable(m_pLowerBoundImmediate, (size_t)g_ephemeral_low); +#endif //WRITE_BARRIER_VARS_INLINE + + +#if defined(TARGET_ARM64) + stompWBCompleteActions |= updateVariable(m_lowestAddress, (size_t)g_lowest_address); + stompWBCompleteActions |= updateVariable(m_highestAddress, (size_t)g_highest_address); +#if defined(WRITE_BARRIER_CHECK) + stompWBCompleteActions |= updateVariable(m_pGCShadow, (size_t)g_GCShadow); + stompWBCompleteActions |= updateVariable(m_pGCShadowEnd, (size_t)g_GCShadowEnd); +#endif // WRITE_BARRIER_CHECK +#endif // TARGET_AMD64 + return stompWBCompleteActions; } @@ -854,6 +545,7 @@ int WriteBarrierManager::UpdateWriteWatchAndCardTableLocations(bool isRuntimeSus #endif #ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP +#if defined(WRITE_BARRIER_VARS_INLINE) switch (m_currentWriteBarrier) { case WRITE_BARRIER_WRITE_WATCH_PREGROW64: @@ -863,65 +555,52 @@ int WriteBarrierManager::UpdateWriteWatchAndCardTableLocations(bool isRuntimeSus #endif // FEATURE_SVR_GC case WRITE_BARRIER_WRITE_WATCH_BYTE_REGIONS64: case WRITE_BARRIER_WRITE_WATCH_BIT_REGIONS64: - if (*(UINT64*)m_pWriteWatchTableImmediate != (size_t)g_write_watch_table) - { - ExecutableWriterHolder writeWatchTableImmediateWriterHolder((UINT64*)m_pWriteWatchTableImmediate, sizeof(UINT64)); - *writeWatchTableImmediateWriterHolder.GetRW() = (size_t)g_write_watch_table; - stompWBCompleteActions |= SWB_ICACHE_FLUSH; - } + stompWBCompleteActions |= updateVariable(m_pWriteWatchTableImmediate, (size_t)g_write_watch_table); break; default: - break; // clang seems to require all enum values to be covered for some reason + break; } +#else + stompWBCompleteActions |= updateVariable(m_pWriteWatchTableImmediate, (size_t)g_write_watch_table); +#endif #endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP + +#if defined(WRITE_BARRIER_VARS_INLINE) switch (m_currentWriteBarrier) { case WRITE_BARRIER_BYTE_REGIONS64: case WRITE_BARRIER_BIT_REGIONS64: case WRITE_BARRIER_WRITE_WATCH_BYTE_REGIONS64: case WRITE_BARRIER_WRITE_WATCH_BIT_REGIONS64: - if (*(UINT64*)m_pRegionToGenTableImmediate != (size_t)g_region_to_generation_table) - { - ExecutableWriterHolder writeWatchTableImmediateWriterHolder((UINT64*)m_pRegionToGenTableImmediate, sizeof(UINT64)); - *writeWatchTableImmediateWriterHolder.GetRW() = (size_t)g_region_to_generation_table; - stompWBCompleteActions |= SWB_ICACHE_FLUSH; - } - if (*m_pRegionShrDest != g_region_shr) - { - ExecutableWriterHolder writeWatchTableImmediateWriterHolder(m_pRegionShrDest, sizeof(UINT8)); - *writeWatchTableImmediateWriterHolder.GetRW() = g_region_shr; - stompWBCompleteActions |= SWB_ICACHE_FLUSH; - } - if (*m_pRegionShrSrc != g_region_shr) - { - ExecutableWriterHolder writeWatchTableImmediateWriterHolder(m_pRegionShrSrc, sizeof(UINT8)); - *writeWatchTableImmediateWriterHolder.GetRW() = g_region_shr; - stompWBCompleteActions |= SWB_ICACHE_FLUSH; - } + stompWBCompleteActions |= updateVariable(m_pRegionToGenTableImmediate, (size_t)g_region_to_generation_table); + stompWBCompleteActions |= updateVariable(m_pRegionShrDest, (size_t)g_region_shr); + stompWBCompleteActions |= updateVariable(m_pRegionShrSrc, (size_t)g_region_shr); break; default: - break; // clang seems to require all enum values to be covered for some reason - } - - if (*(UINT64*)m_pCardTableImmediate != (size_t)g_card_table) - { - ExecutableWriterHolder cardTableImmediateWriterHolder((UINT64*)m_pCardTableImmediate, sizeof(UINT64)); - *cardTableImmediateWriterHolder.GetRW() = (size_t)g_card_table; - stompWBCompleteActions |= SWB_ICACHE_FLUSH; + break; } +#else + stompWBCompleteActions |= updateVariable(m_pRegionToGenTableImmediate, (size_t)g_region_to_generation_table); + stompWBCompleteActions |= updateVariable(m_pRegionShrDest, g_region_shr); +#endif //WRITE_BARRIER_VARS_INLINE + stompWBCompleteActions |= updateVariable(m_pCardTableImmediate, (size_t)g_card_table); #ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES - if (*(UINT64*)m_pCardBundleTableImmediate != (size_t)g_card_bundle_table) - { - ExecutableWriterHolder cardBundleTableImmediateWriterHolder((UINT64*)m_pCardBundleTableImmediate, sizeof(UINT64)); - *cardBundleTableImmediateWriterHolder.GetRW() = (size_t)g_card_bundle_table; - stompWBCompleteActions |= SWB_ICACHE_FLUSH; - } + stompWBCompleteActions |= updateVariable(m_pCardBundleTableImmediate, (size_t)g_card_bundle_table); #endif +#if defined(TARGET_ARM64) + stompWBCompleteActions |= updateVariable(m_lowestAddress, (size_t)g_lowest_address); + stompWBCompleteActions |= updateVariable(m_highestAddress, (size_t)g_highest_address); +#if defined(WRITE_BARRIER_CHECK) + stompWBCompleteActions |= updateVariable(m_pGCShadow, (size_t)g_GCShadow); + stompWBCompleteActions |= updateVariable(m_pGCShadowEnd, (size_t)g_GCShadowEnd); +#endif // WRITE_BARRIER_CHECK +#endif // TARGET_AMD64 + return stompWBCompleteActions; } @@ -1003,7 +682,406 @@ int WriteBarrierManager::SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended) } #endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP -// This function bashes the super fast amd64 version of the JIT_WriteBarrier + +#if defined(WRITE_BARRIER_VARS_INLINE) + + +// Use this somewhat hokey macro to concatenate the function start with the patch +// label. This allows the code below to look relatively nice, but relies on the +// naming convention which we have established for these helpers. +#define CALC_PATCH_LOCATION(func,label,offset) CalculatePatchLocation((PVOID)func, (PVOID)func##_##label, offset) + +PBYTE WriteBarrierManager::CalculatePatchLocation(LPVOID base, LPVOID label, int inlineOffset) +{ + // the label should always come after or at the entrypoint for this funtion + _ASSERTE_ALL_BUILDS((LPBYTE)label >= (LPBYTE)base); + + BYTE* patchBase = GetWriteBarrierCodeLocation((void*)JIT_WriteBarrier); + return (patchBase + ((LPBYTE)GetEEFuncEntryPoint(label) - (LPBYTE)GetEEFuncEntryPoint(base))) + inlineOffset; +} + +// Deactivate alignment validation for code coverage builds +// because the instrumentation tool will not preserve alignment +// constraints and we will fail. +#if !defined(CODECOVERAGE) + +void WriteBarrierManager::Validate() +{ + CONTRACTL + { + MODE_ANY; + GC_NOTRIGGER; + NOTHROW; + } + CONTRACTL_END; + + // we have an invariant that the addresses of all the values that we update in our write barrier + // helpers must be naturally aligned, this is so that the update can happen atomically since there + // are places where these values are updated while the EE is running + // NOTE: we can't call this from the ctor since our infrastructure isn't ready for assert dialogs + + PBYTE pLowerBoundImmediate, pUpperBoundImmediate, pCardTableImmediate; + +#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES + PBYTE pCardBundleTableImmediate; +#endif + + pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PreGrow64, Patch_Label_Lower, 2); + pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PreGrow64, Patch_Label_CardTable, 2); + + _ASSERTE_ALL_BUILDS((reinterpret_cast(pLowerBoundImmediate) & 0x7) == 0); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardTableImmediate) & 0x7) == 0); + +#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES + pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PreGrow64, Patch_Label_CardBundleTable, 2); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardBundleTableImmediate) & 0x7) == 0); +#endif + + pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PostGrow64, Patch_Label_Lower, 2); + pUpperBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PostGrow64, Patch_Label_Upper, 2); + pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PostGrow64, Patch_Label_CardTable, 2); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pLowerBoundImmediate) & 0x7) == 0); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pUpperBoundImmediate) & 0x7) == 0); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardTableImmediate) & 0x7) == 0); + +#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES + pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PostGrow64, Patch_Label_CardBundleTable, 2); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardBundleTableImmediate) & 0x7) == 0); +#endif + +#ifdef FEATURE_SVR_GC + pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_SVR64, PatchLabel_CardTable, 2); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardTableImmediate) & 0x7) == 0); + +#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES + pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_SVR64, PatchLabel_CardBundleTable, 2); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardBundleTableImmediate) & 0x7) == 0); +#endif // FEATURE_MANUALLY_MANAGED_CARD_BUNDLES +#endif // FEATURE_SVR_GC + + PBYTE pRegionToGenTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Byte_Region64, Patch_Label_RegionToGeneration, 2); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pRegionToGenTableImmediate) & 0x7) == 0); + + pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Byte_Region64, Patch_Label_Lower, 2); + pUpperBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Byte_Region64, Patch_Label_Upper, 2); + pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Byte_Region64, Patch_Label_CardTable, 2); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pLowerBoundImmediate) & 0x7) == 0); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pUpperBoundImmediate) & 0x7) == 0); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardTableImmediate) & 0x7) == 0); + +#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES + pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Byte_Region64, Patch_Label_CardBundleTable, 2); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardBundleTableImmediate) & 0x7) == 0); +#endif + + pRegionToGenTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Bit_Region64, Patch_Label_RegionToGeneration, 2); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pRegionToGenTableImmediate) & 0x7) == 0); + + pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Bit_Region64, Patch_Label_Lower, 2); + pUpperBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Bit_Region64, Patch_Label_Upper, 2); + pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Bit_Region64, Patch_Label_CardTable, 2); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pLowerBoundImmediate) & 0x7) == 0); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pUpperBoundImmediate) & 0x7) == 0); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardTableImmediate) & 0x7) == 0); + +#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES + pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Bit_Region64, Patch_Label_CardBundleTable, 2); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardBundleTableImmediate) & 0x7) == 0); +#endif + +#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP + PBYTE pWriteWatchTableImmediate; + + pWriteWatchTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PreGrow64, Patch_Label_WriteWatchTable, 2); + pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PreGrow64, Patch_Label_Lower, 2); + pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PreGrow64, Patch_Label_CardTable, 2); + + _ASSERTE_ALL_BUILDS((reinterpret_cast(pWriteWatchTableImmediate) & 0x7) == 0); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pLowerBoundImmediate) & 0x7) == 0); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardTableImmediate) & 0x7) == 0); + +#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES + pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PreGrow64, Patch_Label_CardBundleTable, 2); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardBundleTableImmediate) & 0x7) == 0); +#endif + + pWriteWatchTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PostGrow64, Patch_Label_WriteWatchTable, 2); + pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PostGrow64, Patch_Label_Lower, 2); + pUpperBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PostGrow64, Patch_Label_Upper, 2); + pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PostGrow64, Patch_Label_CardTable, 2); + + _ASSERTE_ALL_BUILDS((reinterpret_cast(pWriteWatchTableImmediate) & 0x7) == 0); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pLowerBoundImmediate) & 0x7) == 0); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pUpperBoundImmediate) & 0x7) == 0); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardTableImmediate) & 0x7) == 0); + +#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES + pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PostGrow64, Patch_Label_CardBundleTable, 2); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardBundleTableImmediate) & 0x7) == 0); +#endif + +#ifdef FEATURE_SVR_GC + pWriteWatchTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_SVR64, PatchLabel_WriteWatchTable, 2); + pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_SVR64, PatchLabel_CardTable, 2); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pWriteWatchTableImmediate) & 0x7) == 0); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardTableImmediate) & 0x7) == 0); + +#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES + pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_SVR64, PatchLabel_CardBundleTable, 2); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardBundleTableImmediate) & 0x7) == 0); +#endif // FEATURE_MANUALLY_MANAGED_CARD_BUNDLES +#endif // FEATURE_SVR_GC + + pRegionToGenTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Byte_Region64, Patch_Label_RegionToGeneration, 2); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pRegionToGenTableImmediate) & 0x7) == 0); + + pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Byte_Region64, Patch_Label_Lower, 2); + pUpperBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Byte_Region64, Patch_Label_Upper, 2); + pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Byte_Region64, Patch_Label_CardTable, 2); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pLowerBoundImmediate) & 0x7) == 0); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pUpperBoundImmediate) & 0x7) == 0); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardTableImmediate) & 0x7) == 0); + +#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES + pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Byte_Region64, Patch_Label_CardBundleTable, 2); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardBundleTableImmediate) & 0x7) == 0); +#endif + + pRegionToGenTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Bit_Region64, Patch_Label_RegionToGeneration, 2); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pRegionToGenTableImmediate) & 0x7) == 0); + + pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Bit_Region64, Patch_Label_Lower, 2); + pUpperBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Bit_Region64, Patch_Label_Upper, 2); + pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Bit_Region64, Patch_Label_CardTable, 2); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pLowerBoundImmediate) & 0x7) == 0); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pUpperBoundImmediate) & 0x7) == 0); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardTableImmediate) & 0x7) == 0); + +#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES + pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Bit_Region64, Patch_Label_CardBundleTable, 2); + _ASSERTE_ALL_BUILDS((reinterpret_cast(pCardBundleTableImmediate) & 0x7) == 0); +#endif + +#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP +} + +#endif // CODECOVERAGE + +void WriteBarrierManager::UpdatePatchLocations(WriteBarrierType newWriteBarrier) +{ + switch (newWriteBarrier) + { + case WRITE_BARRIER_PREGROW64: + { + m_pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PreGrow64, Patch_Label_Lower, 2); + m_pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PreGrow64, Patch_Label_CardTable, 2); + + // Make sure that we will be bashing the right places (immediates should be hardcoded to 0x0f0f0f0f0f0f0f0f0). + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pLowerBoundImmediate); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardTableImmediate); + +#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES + m_pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PreGrow64, Patch_Label_CardBundleTable, 2); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardBundleTableImmediate); +#endif + break; + } + + case WRITE_BARRIER_POSTGROW64: + { + m_pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PostGrow64, Patch_Label_Lower, 2); + m_pUpperBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PostGrow64, Patch_Label_Upper, 2); + m_pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PostGrow64, Patch_Label_CardTable, 2); + + // Make sure that we will be bashing the right places (immediates should be hardcoded to 0x0f0f0f0f0f0f0f0f0). + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pLowerBoundImmediate); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardTableImmediate); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pUpperBoundImmediate); + +#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES + m_pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_PostGrow64, Patch_Label_CardBundleTable, 2); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardBundleTableImmediate); +#endif + break; + } + +#ifdef FEATURE_SVR_GC + case WRITE_BARRIER_SVR64: + { + m_pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_SVR64, PatchLabel_CardTable, 2); + + // Make sure that we will be bashing the right places (immediates should be hardcoded to 0x0f0f0f0f0f0f0f0f0). + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardTableImmediate); + +#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES + m_pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_SVR64, PatchLabel_CardBundleTable, 2); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardBundleTableImmediate); +#endif + break; + } +#endif // FEATURE_SVR_GC + + case WRITE_BARRIER_BYTE_REGIONS64: + m_pRegionToGenTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Byte_Region64, Patch_Label_RegionToGeneration, 2); + m_pRegionShrDest = CALC_PATCH_LOCATION(JIT_WriteBarrier_Byte_Region64, Patch_Label_RegionShrDest, 3); + m_pRegionShrSrc = CALC_PATCH_LOCATION(JIT_WriteBarrier_Byte_Region64, Patch_Label_RegionShrSrc, 3); + m_pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Byte_Region64, Patch_Label_Lower, 2); + m_pUpperBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Byte_Region64, Patch_Label_Upper, 2); + m_pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Byte_Region64, Patch_Label_CardTable, 2); + + // Make sure that we will be bashing the right places (immediates should be hardcoded to 0x0f0f0f0f0f0f0f0f0). + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pRegionToGenTableImmediate); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pLowerBoundImmediate); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pUpperBoundImmediate); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardTableImmediate); + _ASSERTE_ALL_BUILDS( 0x16 == *(UINT8 *)m_pRegionShrDest); + _ASSERTE_ALL_BUILDS( 0x16 == *(UINT8 *)m_pRegionShrSrc); + +#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES + m_pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Byte_Region64, Patch_Label_CardBundleTable, 2); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardBundleTableImmediate); +#endif + break; + + case WRITE_BARRIER_BIT_REGIONS64: + m_pRegionToGenTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Bit_Region64, Patch_Label_RegionToGeneration, 2); + m_pRegionShrDest = CALC_PATCH_LOCATION(JIT_WriteBarrier_Bit_Region64, Patch_Label_RegionShrDest, 3); + m_pRegionShrSrc = CALC_PATCH_LOCATION(JIT_WriteBarrier_Bit_Region64, Patch_Label_RegionShrSrc, 3); + m_pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Bit_Region64, Patch_Label_Lower, 2); + m_pUpperBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Bit_Region64, Patch_Label_Upper, 2); + m_pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Bit_Region64, Patch_Label_CardTable, 2); + + // Make sure that we will be bashing the right places (immediates should be hardcoded to 0x0f0f0f0f0f0f0f0f0). + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pRegionToGenTableImmediate); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pLowerBoundImmediate); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pUpperBoundImmediate); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardTableImmediate); + _ASSERTE_ALL_BUILDS( 0x16 == *(UINT8 *)m_pRegionShrDest); + _ASSERTE_ALL_BUILDS( 0x16 == *(UINT8 *)m_pRegionShrSrc); + +#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES + m_pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_Bit_Region64, Patch_Label_CardBundleTable, 2); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardBundleTableImmediate); +#endif + break; + +#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP + case WRITE_BARRIER_WRITE_WATCH_PREGROW64: + { + m_pWriteWatchTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PreGrow64, Patch_Label_WriteWatchTable, 2); + m_pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PreGrow64, Patch_Label_Lower, 2); + m_pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PreGrow64, Patch_Label_CardTable, 2); + + // Make sure that we will be bashing the right places (immediates should be hardcoded to 0x0f0f0f0f0f0f0f0f0). + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pWriteWatchTableImmediate); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pLowerBoundImmediate); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardTableImmediate); + +#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES + m_pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PreGrow64, Patch_Label_CardBundleTable, 2); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardBundleTableImmediate); +#endif + break; + } + + case WRITE_BARRIER_WRITE_WATCH_POSTGROW64: + { + m_pWriteWatchTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PostGrow64, Patch_Label_WriteWatchTable, 2); + m_pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PostGrow64, Patch_Label_Lower, 2); + m_pUpperBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PostGrow64, Patch_Label_Upper, 2); + m_pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PostGrow64, Patch_Label_CardTable, 2); + + // Make sure that we will be bashing the right places (immediates should be hardcoded to 0x0f0f0f0f0f0f0f0f0). + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pWriteWatchTableImmediate); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pLowerBoundImmediate); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardTableImmediate); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pUpperBoundImmediate); + +#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES + m_pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_PostGrow64, Patch_Label_CardBundleTable, 2); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardBundleTableImmediate); +#endif + break; + } + +#ifdef FEATURE_SVR_GC + case WRITE_BARRIER_WRITE_WATCH_SVR64: + { + m_pWriteWatchTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_SVR64, PatchLabel_WriteWatchTable, 2); + m_pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_SVR64, PatchLabel_CardTable, 2); + + // Make sure that we will be bashing the right places (immediates should be hardcoded to 0x0f0f0f0f0f0f0f0f0). + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pWriteWatchTableImmediate); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardTableImmediate); + +#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES + m_pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_SVR64, PatchLabel_CardBundleTable, 2); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardBundleTableImmediate); +#endif + break; + } +#endif // FEATURE_SVR_GC + + case WRITE_BARRIER_WRITE_WATCH_BYTE_REGIONS64: + m_pWriteWatchTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Byte_Region64, Patch_Label_WriteWatchTable, 2); + m_pRegionToGenTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Byte_Region64, Patch_Label_RegionToGeneration, 2); + m_pRegionShrDest = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Byte_Region64, Patch_Label_RegionShrDest, 3); + m_pRegionShrSrc = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Byte_Region64, Patch_Label_RegionShrSrc, 3); + m_pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Byte_Region64, Patch_Label_Lower, 2); + m_pUpperBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Byte_Region64, Patch_Label_Upper, 2); + m_pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Byte_Region64, Patch_Label_CardTable, 2); + + // Make sure that we will be bashing the right places (immediates should be hardcoded to 0x0f0f0f0f0f0f0f0f0). + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pWriteWatchTableImmediate); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pRegionToGenTableImmediate); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pLowerBoundImmediate); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pUpperBoundImmediate); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardTableImmediate); + _ASSERTE_ALL_BUILDS( 0x16 == *(UINT8 *)m_pRegionShrDest); + _ASSERTE_ALL_BUILDS( 0x16 == *(UINT8 *)m_pRegionShrSrc); + +#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES + m_pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Byte_Region64, Patch_Label_CardBundleTable, 2); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardBundleTableImmediate); +#endif + break; + + case WRITE_BARRIER_WRITE_WATCH_BIT_REGIONS64: + m_pWriteWatchTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Bit_Region64, Patch_Label_WriteWatchTable, 2); + m_pRegionToGenTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Bit_Region64, Patch_Label_RegionToGeneration, 2); + m_pRegionShrDest = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Bit_Region64, Patch_Label_RegionShrDest, 3); + m_pRegionShrSrc = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Bit_Region64, Patch_Label_RegionShrSrc, 3); + m_pLowerBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Bit_Region64, Patch_Label_Lower, 2); + m_pUpperBoundImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Bit_Region64, Patch_Label_Upper, 2); + m_pCardTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Bit_Region64, Patch_Label_CardTable, 2); + + // Make sure that we will be bashing the right places (immediates should be hardcoded to 0x0f0f0f0f0f0f0f0f0). + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pWriteWatchTableImmediate); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pRegionToGenTableImmediate); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pLowerBoundImmediate); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pUpperBoundImmediate); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardTableImmediate); + _ASSERTE_ALL_BUILDS( 0x16 == *(UINT8 *)m_pRegionShrDest); + _ASSERTE_ALL_BUILDS( 0x16 == *(UINT8 *)m_pRegionShrSrc); + +#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES + m_pCardBundleTableImmediate = CALC_PATCH_LOCATION(JIT_WriteBarrier_WriteWatch_Bit_Region64, Patch_Label_CardBundleTable, 2); + _ASSERTE_ALL_BUILDS(0xf0f0f0f0f0f0f0f0 == *(UINT64*)m_pCardBundleTableImmediate); +#endif + break; + + +#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP + + default: + UNREACHABLE_MSG("unexpected write barrier type!"); + } +} + +#endif // WRITE_BARRIER_VARS_INLINE + + +// This function bashes the super fast version of the JIT_WriteBarrier // helper. It should be called by the GC whenever the ephermeral region // bounds get changed, but still remain on the top of the GC Heap. int StompWriteBarrierEphemeral(bool isRuntimeSuspended) @@ -1016,7 +1094,7 @@ int StompWriteBarrierEphemeral(bool isRuntimeSuspended) return SWB_PASS; } -// This function bashes the super fast amd64 versions of the JIT_WriteBarrier +// This function bashes the super fast versions of the JIT_WriteBarrier // helpers. It should be called by the GC whenever the ephermeral region gets moved // from being at the top of the GC Heap, and/or when the cards table gets moved. int StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck) diff --git a/src/coreclr/vm/writebarriermanager.h b/src/coreclr/vm/writebarriermanager.h new file mode 100644 index 00000000000000..c8b8bc697b3f1e --- /dev/null +++ b/src/coreclr/vm/writebarriermanager.h @@ -0,0 +1,98 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// =========================================================================== +// File: writebarriermanager.h +// =========================================================================== + + +#ifndef WRITEBARRIERMANAGER_H +#define WRITEBARRIERMANAGER_H + +#if defined(TARGET_AMD64) || defined(TARGET_ARM64) + + +#if defined(TARGET_AMD64) +// Write barrier variables are inlined into the assembly code +#define WRITE_BARRIER_VARS_INLINE +// Else: Write barrier variables are in a table separate to the asm code +#endif + +class WriteBarrierManager +{ +public: + enum WriteBarrierType + { + WRITE_BARRIER_UNINITIALIZED, + WRITE_BARRIER_PREGROW64, + WRITE_BARRIER_POSTGROW64, +#ifdef FEATURE_SVR_GC + WRITE_BARRIER_SVR64, +#endif // FEATURE_SVR_GC + WRITE_BARRIER_BYTE_REGIONS64, + WRITE_BARRIER_BIT_REGIONS64, +#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP + WRITE_BARRIER_WRITE_WATCH_PREGROW64, + WRITE_BARRIER_WRITE_WATCH_POSTGROW64, +#ifdef FEATURE_SVR_GC + WRITE_BARRIER_WRITE_WATCH_SVR64, +#endif // FEATURE_SVR_GC + WRITE_BARRIER_WRITE_WATCH_BYTE_REGIONS64, + WRITE_BARRIER_WRITE_WATCH_BIT_REGIONS64, +#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP + WRITE_BARRIER_BUFFER + }; + + WriteBarrierManager(); + void Initialize(); + + int UpdateEphemeralBounds(bool isRuntimeSuspended); + int UpdateWriteWatchAndCardTableLocations(bool isRuntimeSuspended, bool bReqUpperBoundsCheck); + +#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP + int SwitchToWriteWatchBarrier(bool isRuntimeSuspended); + int SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended); +#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP + size_t GetCurrentWriteBarrierSize(); + +private: + size_t GetSpecificWriteBarrierSize(WriteBarrierType writeBarrier); + PCODE GetCurrentWriteBarrierCode(); + int ChangeWriteBarrierTo(WriteBarrierType newWriteBarrier, bool isRuntimeSuspended); + bool NeedDifferentWriteBarrier(bool bReqUpperBoundsCheck, bool bUseBitwiseWriteBarrier, WriteBarrierType* pNewWriteBarrierType); + + +#if defined(WRITE_BARRIER_VARS_INLINE) + PBYTE CalculatePatchLocation(LPVOID base, LPVOID label, int offset); + void Validate(); + void UpdatePatchLocations(WriteBarrierType newWriteBarrier); +#endif // WRITE_BARRIER_VARS_INLINE + + + WriteBarrierType m_currentWriteBarrier; + + PBYTE m_pWriteWatchTableImmediate; // PREGROW | POSTGROW | SVR | WRITE_WATCH | REGION + PBYTE m_pLowerBoundImmediate; // PREGROW | POSTGROW | | WRITE_WATCH | REGION + PBYTE m_pCardTableImmediate; // PREGROW | POSTGROW | SVR | WRITE_WATCH | REGION + PBYTE m_pCardBundleTableImmediate; // PREGROW | POSTGROW | SVR | WRITE_WATCH | REGION + PBYTE m_pUpperBoundImmediate; // | POSTGROW | | WRITE_WATCH | REGION + PBYTE m_pRegionToGenTableImmediate; // | | | WRITE_WATCH | REGION + PBYTE m_pRegionShrDest; // | | | WRITE_WATCH | REGION + PBYTE m_pRegionShrSrc; // | | | WRITE_WATCH | RETION + +#if defined(TARGET_ARM64) + PBYTE m_lowestAddress; + PBYTE m_highestAddress; +#if defined(WRITE_BARRIER_CHECK) + PBYTE m_pGCShadow; + PBYTE m_pGCShadowEnd; +#endif // WRITE_BARRIER_CHECK +#endif // TARGET_AMD64 + +}; + +extern WriteBarrierManager g_WriteBarrierManager; + +#endif // TARGET_AMD64 || TARGET_ARM64 + +#endif // WRITEBARRIERMANAGER_H diff --git a/src/libraries/Common/src/System/Security/Cryptography/CryptoPool.cs b/src/libraries/Common/src/System/Security/Cryptography/CryptoPool.cs index e4b71ded239f2d..7db07c0a176966 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/CryptoPool.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/CryptoPool.cs @@ -12,12 +12,12 @@ internal static class CryptoPool internal static byte[] Rent(int minimumLength) => ArrayPool.Shared.Rent(minimumLength); - internal static void Return(ArraySegment arraySegment) + internal static void Return(ArraySegment arraySegment, int clearSize = ClearAll) { Debug.Assert(arraySegment.Array != null); Debug.Assert(arraySegment.Offset == 0); - Return(arraySegment.Array, arraySegment.Count); + Return(arraySegment.Array, clearSize == ClearAll ? arraySegment.Count : clearSize); } internal static void Return(byte[] array, int clearSize = ClearAll) diff --git a/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/CertificateCreation/PrivateKeyAssociationTests.Shared.cs b/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/CertificateCreation/PrivateKeyAssociationTests.Shared.cs index 1f49d6af945884..5e3131573b5dd0 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/CertificateCreation/PrivateKeyAssociationTests.Shared.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/CertificateCreation/PrivateKeyAssociationTests.Shared.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Security.Cryptography.Tests; using System.Security.Cryptography.SLHDsa.Tests; using Xunit; using Xunit.Sdk; @@ -10,6 +11,9 @@ namespace System.Security.Cryptography.X509Certificates.Tests.CertificateCreatio { public static partial class PrivateKeyAssociationTests { + private static partial Func CopyWithPrivateKey_MLKem { get; } + private static partial Func GetMLKemPublicKey { get; } + private static partial Func GetMLKemPrivateKey { get; } private static partial Func CopyWithPrivateKey_SlhDsa { get; } private static partial Func GetSlhDsaPublicKey { get; } private static partial Func GetSlhDsaPrivateKey { get; } @@ -143,6 +147,153 @@ public static void CheckCopyWithPrivateKey_SlhDsa_OtherSlhDsa() } } + [ConditionalFact(typeof(MLKem), nameof(MLKem.IsSupported))] + public static void GetMLKemPublicKey_WithoutPrivateKey() + { + using (X509Certificate2 cert = MLKemCertTests.LoadCertificateFromPem(MLKemTestData.IetfMlKem512CertificatePem)) + using (MLKem certKey = GetMLKemPublicKey(cert)) + { + Assert.NotNull(certKey); + AssertExtensions.SequenceEqual(MLKemTestData.IetfMlKem512Spki, certKey.ExportSubjectPublicKeyInfo()); + + certKey.Encapsulate(out byte[] ciphertext, out _); + Assert.ThrowsAny(() => certKey.Decapsulate(ciphertext)); + } + } + + [ConditionalFact(typeof(MLKem), nameof(MLKem.IsSupported))] + public static void GetMLKemPublicKey_WithPrivateKey() + { + using (X509Certificate2 cert = X509CertificateLoader.LoadPkcs12( + MLKemTestData.IetfMlKem512PrivateKeySeedPfx, + MLKemTestData.EncryptedPrivateKeyPassword)) + using (MLKem certKey = GetMLKemPublicKey(cert)) + { + AssertExtensions.TrueExpression(cert.HasPrivateKey); + Assert.NotNull(certKey); + AssertExtensions.SequenceEqual(MLKemTestData.IetfMlKem512Spki, certKey.ExportSubjectPublicKeyInfo()); + + certKey.Encapsulate(out byte[] ciphertext, out _); + Assert.ThrowsAny(() => certKey.Decapsulate(ciphertext)); + } + } + + [ConditionalFact(typeof(MLKem), nameof(MLKem.IsSupported))] + public static void GetMLKemPrivateKey_NoPrivateKey() + { + using (X509Certificate2 cert = MLKemCertTests.LoadCertificateFromPem(MLKemTestData.IetfMlKem512CertificatePem)) + using (MLKem certKey = GetMLKemPrivateKey(cert)) + { + Assert.Null(certKey); + } + } + + [ConditionalFact(typeof(MLKem), nameof(MLKem.IsSupported))] + public static void GetMLKemPrivateKey_WithPrivateKey() + { + using (X509Certificate2 cert = X509CertificateLoader.LoadPkcs12( + MLKemTestData.IetfMlKem512PrivateKeySeedPfx, + MLKemTestData.EncryptedPrivateKeyPassword)) + using (MLKem certKey = GetMLKemPrivateKey(cert)) + { + AssertExtensions.TrueExpression(cert.HasPrivateKey); + AssertExtensions.SequenceEqual(MLKemTestData.IncrementalSeed, certKey.ExportPrivateSeed()); + } + } + + [ConditionalFact(typeof(MLKem), nameof(MLKem.IsSupported))] + public static void CheckCopyWithPrivateKey_MLKem() + { + using (X509Certificate2 pubOnly = MLKemCertTests.LoadCertificateFromPem(MLKemTestData.IetfMlKem512CertificatePem)) + using (MLKem privKey = MLKem.ImportPkcs8PrivateKey(MLKemTestData.IetfMlKem512PrivateKeySeed)) + using (X509Certificate2 wrongAlg = X509CertificateLoader.LoadCertificate(TestData.CertWithEnhancedKeyUsage)) + { + CheckCopyWithPrivateKey( + pubOnly, + wrongAlg, + privKey, + [ + () => MLKem.GenerateKey(MLKemAlgorithm.MLKem512), + () => MLKem.GenerateKey(MLKemAlgorithm.MLKem768), + () => MLKem.GenerateKey(MLKemAlgorithm.MLKem1024), + ], + CopyWithPrivateKey_MLKem, + GetMLKemPublicKey, + GetMLKemPrivateKey, + (priv, pub) => + { + pub.Encapsulate(out byte[] ciphertext, out byte[] pubSharedSecret); + byte[] privSharedSecret = priv.Decapsulate(ciphertext); + AssertExtensions.SequenceEqual(pubSharedSecret, privSharedSecret); + }); + } + } + + [ConditionalFact(typeof(MLKem), nameof(MLKem.IsSupported))] + public static void CheckCopyWithPrivateKey_MLKem_OtherMLKem_Seed() + { + using (X509Certificate2 pubOnly = MLKemCertTests.LoadCertificateFromPem(MLKemTestData.IetfMlKem512CertificatePem)) + using (MLKemContract contract = new(MLKemAlgorithm.MLKem512)) + { + contract.OnExportPrivateSeedCore = (Span destination) => + { + MLKemTestData.IncrementalSeed.CopyTo(destination); + }; + + contract.OnExportEncapsulationKeyCore = (Span destination) => + { + using MLKem publicKem = MLKem.ImportSubjectPublicKeyInfo(MLKemTestData.IetfMlKem512Spki); + publicKem.ExportEncapsulationKey(destination); + }; + + using (X509Certificate2 cert = CopyWithPrivateKey_MLKem(pubOnly, contract)) + { + AssertExtensions.TrueExpression(cert.HasPrivateKey); + + using (MLKem kem = GetMLKemPrivateKey(cert)) + { + AssertExtensions.SequenceEqual(MLKemTestData.IncrementalSeed, kem.ExportPrivateSeed()); + } + } + } + } + + [ConditionalFact(typeof(MLKem), nameof(MLKem.IsSupported))] + public static void CheckCopyWithPrivateKey_MLKem_OtherMLKem_DecapsulationKey() + { + using (X509Certificate2 pubOnly = MLKemCertTests.LoadCertificateFromPem(MLKemTestData.IetfMlKem512CertificatePem)) + using (MLKemContract contract = new(MLKemAlgorithm.MLKem512)) + { + contract.OnExportPrivateSeedCore = (Span destination) => + { + throw new CryptographicException("Should signal to try decaps key"); + }; + + contract.OnExportDecapsulationKeyCore = (Span destination) => + { + MLKemTestData.IetfMlKem512PrivateKeyDecapsulationKey.AsSpan().CopyTo(destination); + }; + + contract.OnExportEncapsulationKeyCore = (Span destination) => + { + using MLKem publicKem = MLKem.ImportSubjectPublicKeyInfo(MLKemTestData.IetfMlKem512Spki); + publicKem.ExportEncapsulationKey(destination); + }; + + using (X509Certificate2 cert = CopyWithPrivateKey_MLKem(pubOnly, contract)) + { + AssertExtensions.TrueExpression(cert.HasPrivateKey); + + using (MLKem kem = GetMLKemPrivateKey(cert)) + { + AssertExtensions.SequenceEqual( + MLKemTestData.IetfMlKem512PrivateKeyDecapsulationKey, + kem.ExportDecapsulationKey()); + } + } + } + } + private static partial void CheckCopyWithPrivateKey( X509Certificate2 cert, X509Certificate2 wrongAlgorithmCert, diff --git a/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/MLKemCertTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/MLKemCertTests.cs index eb3c0f056fb948..42e94421a67cae 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/MLKemCertTests.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/MLKemCertTests.cs @@ -126,7 +126,7 @@ public static IEnumerable MLKemCertificatePublicKeys } } - private static X509Certificate2 LoadCertificateFromPem(string pem) + internal static X509Certificate2 LoadCertificateFromPem(string pem) { #if NET return X509Certificate2.CreateFromPem(pem); diff --git a/src/libraries/Microsoft.Bcl.Cryptography/src/System/Security/Cryptography/X509Certificates/X509CertificateKeyAccessors.cs b/src/libraries/Microsoft.Bcl.Cryptography/src/System/Security/Cryptography/X509Certificates/X509CertificateKeyAccessors.cs index 07bfeddc3861da..cdf40e81ee45a8 100644 --- a/src/libraries/Microsoft.Bcl.Cryptography/src/System/Security/Cryptography/X509Certificates/X509CertificateKeyAccessors.cs +++ b/src/libraries/Microsoft.Bcl.Cryptography/src/System/Security/Cryptography/X509Certificates/X509CertificateKeyAccessors.cs @@ -1,12 +1,14 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using System.Formats.Asn1; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; -using System.Text; + +#if !NET10_0_OR_GREATER +using System.Security.Cryptography.Asn1; +#endif namespace System.Security.Cryptography.X509Certificates { @@ -15,6 +17,100 @@ namespace System.Security.Cryptography.X509Certificates /// public static class X509CertificateKeyAccessors { + /// + /// Gets the public key from this certificate. + /// + /// + /// The X.509 certificate that contains the public key. + /// + /// + /// The public key, or if this certificate does not have an ML-KEM public key. + /// + /// + /// is . + /// + /// + /// The certificate has an ML-KEM public key, but the platform does not support ML-KEM. + /// + /// + /// The public key was invalid, or otherwise could not be imported. + /// + [ExperimentalAttribute(Experimentals.PostQuantumCryptographyDiagId, UrlFormat = Experimentals.SharedUrlFormat)] + public static MLKem? GetMLKemPublicKey(this X509Certificate2 certificate) + { +#if NET10_0_OR_GREATER + return certificate.GetMLKemPublicKey(); +#else + if (MLKemAlgorithm.FromOid(certificate.GetKeyAlgorithm()) is null) + { + return null; + } + + ArraySegment encoded = GetCertificateSubjectPublicKeyInfo(certificate); + + try + { + return MLKem.ImportSubjectPublicKeyInfo(encoded); + } + finally + { + // SubjectPublicKeyInfo does not need to clear since it's public + CryptoPool.Return(encoded, clearSize: 0); + } +#endif + } + + /// + /// Gets the private key from this certificate. + /// + /// + /// The X.509 certificate that contains the private key. + /// + /// + /// The private key, or if this certificate does not have an ML-KEM private key. + /// + /// + /// An error occurred accessing the private key. + /// + [ExperimentalAttribute(Experimentals.PostQuantumCryptographyDiagId, UrlFormat = Experimentals.SharedUrlFormat)] + public static MLKem? GetMLKemPrivateKey(this X509Certificate2 certificate) => +#if NET10_0_OR_GREATER + certificate.GetMLKemPrivateKey(); +#else + throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_AlgorithmNotSupported, nameof(MLKem))); +#endif + + /// + /// Combines a private key with a certificate containing the associated public key into a + /// new instance that can access the private key. + /// + /// + /// The X.509 certificate that contains the public key. + /// + /// + /// The ML-KEM private key that corresponds to the ML-KEM public key in this certificate. + /// + /// + /// A new certificate with the property set to . + /// The current certificate isn't modified. + /// + /// + /// or is . + /// + /// + /// The specified private key doesn't match the public key for this certificate. + /// + /// + /// The certificate already has an associated private key. + /// + [ExperimentalAttribute(Experimentals.PostQuantumCryptographyDiagId, UrlFormat = Experimentals.SharedUrlFormat)] + public static X509Certificate2 CopyWithPrivateKey(this X509Certificate2 certificate, MLKem privateKey) => +#if NET10_0_OR_GREATER + certificate.CopyWithPrivateKey(privateKey); +#else + throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_AlgorithmNotSupported, nameof(MLKem))); +#endif + /// /// Gets the public key from this certificate. /// @@ -94,5 +190,36 @@ public static X509Certificate2 CopyWithPrivateKey(this X509Certificate2 certific #else throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_AlgorithmNotSupported, nameof(SlhDsa))); #endif + +#if !NET10_0_OR_GREATER + private static ArraySegment GetCertificateSubjectPublicKeyInfo(X509Certificate2 certificate) + { + // We construct the SubjectPublicKeyInfo from the certificate as-is, parameters and all. Consumers + // decide if the parameters are good or not. + SubjectPublicKeyInfoAsn spki = new SubjectPublicKeyInfoAsn + { + Algorithm = new AlgorithmIdentifierAsn + { + Algorithm = certificate.GetKeyAlgorithm(), + + // .NET Framework uses "empty" to indicate no value, not null, so normalize empty to null since + // the Asn types expect the parameters to be an ASN.1 ANY. + Parameters = certificate.GetKeyAlgorithmParameters() switch + { + null or { Length: 0 } => default(ReadOnlyMemory?), + byte[] array => array, + }, + }, + SubjectPublicKey = certificate.GetPublicKey(), + }; + + AsnWriter writer = new(AsnEncodingRules.DER); + spki.Encode(writer); + + byte[] rented = CryptoPool.Rent(writer.GetEncodedLength()); + int written = writer.Encode(rented); + return new ArraySegment(rented, offset: 0, count: written); + } +#endif } } diff --git a/src/libraries/Microsoft.Bcl.Cryptography/tests/Microsoft.Bcl.Cryptography.Tests.csproj b/src/libraries/Microsoft.Bcl.Cryptography/tests/Microsoft.Bcl.Cryptography.Tests.csproj index 94c7dc3e0ac90d..171882094f5b1e 100644 --- a/src/libraries/Microsoft.Bcl.Cryptography/tests/Microsoft.Bcl.Cryptography.Tests.csproj +++ b/src/libraries/Microsoft.Bcl.Cryptography/tests/Microsoft.Bcl.Cryptography.Tests.csproj @@ -148,6 +148,8 @@ Link="CommonTest\System\Security\Cryptography\AlgorithmImplementations\SlhDsa\SlhDsaTestHelpers.cs" /> + CopyWithPrivateKey_MLKem => + X509CertificateKeyAccessors.CopyWithPrivateKey; + + private static partial Func GetMLKemPublicKey => + X509CertificateKeyAccessors.GetMLKemPublicKey; + + private static partial Func GetMLKemPrivateKey => + X509CertificateKeyAccessors.GetMLKemPrivateKey; + private static partial Func CopyWithPrivateKey_SlhDsa => X509CertificateKeyAccessors.CopyWithPrivateKey; diff --git a/src/libraries/System.Collections/src/System/Collections/Generic/Stack.cs b/src/libraries/System.Collections/src/System/Collections/Generic/Stack.cs index 1317ed240c06a3..28c0996bd2e532 100644 --- a/src/libraries/System.Collections/src/System/Collections/Generic/Stack.cs +++ b/src/libraries/System.Collections/src/System/Collections/Generic/Stack.cs @@ -62,7 +62,7 @@ public Stack(IEnumerable collection) /// public int Capacity => _array.Length; - /// + /// bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; diff --git a/src/libraries/System.Net.Mail/src/System.Net.Mail.csproj b/src/libraries/System.Net.Mail/src/System.Net.Mail.csproj index 004fbbadd9ac77..189adf6b6c18e3 100644 --- a/src/libraries/System.Net.Mail/src/System.Net.Mail.csproj +++ b/src/libraries/System.Net.Mail/src/System.Net.Mail.csproj @@ -47,6 +47,7 @@ + diff --git a/src/libraries/System.Net.Mail/src/System/Net/BufferBuilder.cs b/src/libraries/System.Net.Mail/src/System/Net/BufferBuilder.cs index 2ca6684a405eaf..bbb1afb25fbb28 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/BufferBuilder.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/BufferBuilder.cs @@ -34,6 +34,13 @@ internal void Append(byte value) _buffer[_offset++] = value; } + internal void Append(ReadOnlyMemory value) + { + EnsureBuffer(value.Length); + value.Span.CopyTo(_buffer.AsSpan(_offset)); + _offset += value.Length; + } + internal void Append(ReadOnlySpan value) { EnsureBuffer(value.Length); diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mail/MailMessage.cs b/src/libraries/System.Net.Mail/src/System/Net/Mail/MailMessage.cs index c414b047f11235..6caf97c5d02504 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mail/MailMessage.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mail/MailMessage.cs @@ -3,10 +3,13 @@ using System; using System.Collections.Specialized; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Net.Mime; using System.Text; +using System.Threading; +using System.Threading.Tasks; namespace System.Net.Mail { @@ -429,22 +432,28 @@ private void SetContent(bool allowUnicode) } } - internal void Send(BaseWriter writer, bool sendEnvelope, bool allowUnicode) + internal void Send(BaseWriter writer, bool sendEnvelope, bool allowUnicode, CancellationToken cancellationToken = default) { - SetContent(allowUnicode); - _message.Send(writer, sendEnvelope, allowUnicode); + Task task = SendAsync(writer, sendEnvelope, allowUnicode, cancellationToken); + Debug.Assert(task.IsCompleted, "SendAsync should be completed synchronously."); + task.GetAwaiter().GetResult(); } - internal IAsyncResult BeginSend(BaseWriter writer, bool allowUnicode, - AsyncCallback? callback, object? state) + internal IAsyncResult BeginSend(BaseWriter writer, bool sendEnvelope, bool allowUnicode, AsyncCallback callback, object? state) { - SetContent(allowUnicode); - return _message.BeginSend(writer, allowUnicode, callback, state); + return TaskToAsyncResult.Begin(SendAsync(writer, sendEnvelope, allowUnicode), callback, state); + } + + internal static void EndSend(IAsyncResult asyncResult) + { + TaskToAsyncResult.End(asyncResult); } - internal void EndSend(IAsyncResult asyncResult) + internal async Task SendAsync(BaseWriter writer, bool sendEnvelope, bool allowUnicode, CancellationToken cancellationToken = default) + where TIOAdapter : IReadWriteAdapter { - _message.EndSend(asyncResult); + SetContent(allowUnicode); + await _message.SendAsync(writer, sendEnvelope, allowUnicode, cancellationToken).ConfigureAwait(false); } internal string BuildDeliveryStatusNotificationString() diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mail/MailPriority.cs b/src/libraries/System.Net.Mail/src/System/Net/Mail/MailPriority.cs index db52511ec6ebb6..f45299e71152ed 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mail/MailPriority.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mail/MailPriority.cs @@ -5,6 +5,8 @@ using System.Net.Mime; using System.Runtime.ExceptionServices; using System.Text; +using System.Threading; +using System.Threading.Tasks; namespace System.Net.Mail { @@ -139,7 +141,9 @@ internal string? Subject // extract the encoding from =?encoding?BorQ?blablalba?= inputEncoding = MimeBasePart.DecodeEncoding(value); } - catch (ArgumentException) { }; + catch (ArgumentException) + { + } if (inputEncoding != null && value != null) { @@ -240,94 +244,8 @@ internal MimeBasePart? Content #region Sending - internal void EmptySendCallback(IAsyncResult result) - { - Exception? e = null; - - if (result.CompletedSynchronously) - { - return; - } - - EmptySendContext context = (EmptySendContext)result.AsyncState!; - try - { - BaseWriter.EndGetContentStream(result).Close(); - } - catch (Exception ex) - { - e = ex; - } - context._result.InvokeCallback(e); - } - - internal sealed class EmptySendContext - { - internal EmptySendContext(BaseWriter writer, LazyAsyncResult result) - { - _writer = writer; - _result = result; - } - - internal LazyAsyncResult _result; - internal BaseWriter _writer; - } - - internal IAsyncResult BeginSend(BaseWriter writer, bool allowUnicode, - AsyncCallback? callback, object? state) - { - PrepareHeaders(allowUnicode); - writer.WriteHeaders(Headers, allowUnicode); - - if (Content != null) - { - return Content.BeginSend(writer, callback, allowUnicode, state); - } - else - { - LazyAsyncResult result = new LazyAsyncResult(this, state, callback); - IAsyncResult newResult = writer.BeginGetContentStream(EmptySendCallback, new EmptySendContext(writer, result)); - if (newResult.CompletedSynchronously) - { - BaseWriter.EndGetContentStream(newResult).Close(); - result.InvokeCallback(); - } - return result; - } - } - - internal void EndSend(IAsyncResult asyncResult) - { - ArgumentNullException.ThrowIfNull(asyncResult); - - if (Content != null) - { - Content.EndSend(asyncResult); - } - else - { - LazyAsyncResult? castedAsyncResult = asyncResult as LazyAsyncResult; - - if (castedAsyncResult == null || castedAsyncResult.AsyncObject != this) - { - throw new ArgumentException(SR.net_io_invalidasyncresult); - } - - if (castedAsyncResult.EndCalled) - { - throw new InvalidOperationException(SR.Format(SR.net_io_invalidendcall, nameof(EndSend))); - } - - castedAsyncResult.InternalWaitForCompletion(); - castedAsyncResult.EndCalled = true; - if (castedAsyncResult.Result is Exception e) - { - ExceptionDispatchInfo.Throw(e); - } - } - } - - internal void Send(BaseWriter writer, bool sendEnvelope, bool allowUnicode) + internal async Task SendAsync(BaseWriter writer, bool sendEnvelope, bool allowUnicode, CancellationToken cancellationToken = default) + where TIOAdapter : IReadWriteAdapter { if (sendEnvelope) { @@ -340,10 +258,11 @@ internal void Send(BaseWriter writer, bool sendEnvelope, bool allowUnicode) if (Content != null) { - Content.Send(writer, allowUnicode); + await Content.SendAsync(writer, allowUnicode, cancellationToken).ConfigureAwait(false); } else { + // No content to write, just close the stream writer.GetContentStream().Close(); } } diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mail/MailWriter.cs b/src/libraries/System.Net.Mail/src/System/Net/Mail/MailWriter.cs index c643885d53a5ee..9b8ea2ead14788 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mail/MailWriter.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mail/MailWriter.cs @@ -40,7 +40,7 @@ internal override void WriteHeaders(NameValueCollection headers, bool allowUnico internal override void Close() { _bufferBuilder.Append("\r\n"u8); - Flush(null); + Flush(); _stream.Close(); } diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mail/ReadWriteAdapter.cs b/src/libraries/System.Net.Mail/src/System/Net/Mail/ReadWriteAdapter.cs new file mode 100644 index 00000000000000..a5fbdb6469d0f2 --- /dev/null +++ b/src/libraries/System.Net.Mail/src/System/Net/Mail/ReadWriteAdapter.cs @@ -0,0 +1,61 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace System.Net.Mail +{ + internal interface IReadWriteAdapter + { + static abstract ValueTask ReadAsync(Stream stream, Memory buffer, CancellationToken cancellationToken); + static abstract ValueTask ReadAtLeastAsync(Stream stream, Memory buffer, int minimumBytes, bool throwOnEndOfStream, CancellationToken cancellationToken); + static abstract ValueTask WriteAsync(Stream stream, ReadOnlyMemory buffer, CancellationToken cancellationToken); + static abstract Task FlushAsync(Stream stream, CancellationToken cancellationToken); + static abstract Task WaitAsync(TaskCompletionSource waiter); + } + + internal readonly struct AsyncReadWriteAdapter : IReadWriteAdapter + { + public static ValueTask ReadAsync(Stream stream, Memory buffer, CancellationToken cancellationToken) => + stream.ReadAsync(buffer, cancellationToken); + + public static ValueTask ReadAtLeastAsync(Stream stream, Memory buffer, int minimumBytes, bool throwOnEndOfStream, CancellationToken cancellationToken) => + stream.ReadAtLeastAsync(buffer, minimumBytes, throwOnEndOfStream, cancellationToken); + + public static ValueTask WriteAsync(Stream stream, ReadOnlyMemory buffer, CancellationToken cancellationToken) => + stream.WriteAsync(buffer, cancellationToken); + + public static Task FlushAsync(Stream stream, CancellationToken cancellationToken) => stream.FlushAsync(cancellationToken); + + public static Task WaitAsync(TaskCompletionSource waiter) => waiter.Task; + } + + internal readonly struct SyncReadWriteAdapter : IReadWriteAdapter + { + public static ValueTask ReadAsync(Stream stream, Memory buffer, CancellationToken cancellationToken) => + new ValueTask(stream.Read(buffer.Span)); + + public static ValueTask ReadAtLeastAsync(Stream stream, Memory buffer, int minimumBytes, bool throwOnEndOfStream, CancellationToken cancellationToken) => + new ValueTask(stream.ReadAtLeast(buffer.Span, minimumBytes, throwOnEndOfStream)); + + public static ValueTask WriteAsync(Stream stream, ReadOnlyMemory buffer, CancellationToken cancellationToken) + { + stream.Write(buffer.Span); + return default; + } + + public static Task FlushAsync(Stream stream, CancellationToken cancellationToken) + { + stream.Flush(); + return Task.CompletedTask; + } + + public static Task WaitAsync(TaskCompletionSource waiter) + { + waiter.Task.GetAwaiter().GetResult(); + return Task.CompletedTask; + } + } +} diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpClient.cs b/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpClient.cs index 884d3b18a38669..5daccb14d32079 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpClient.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpClient.cs @@ -892,7 +892,7 @@ private void SendMessageCallback(IAsyncResult result) { try { - _message!.EndSend(result); + MailMessage.EndSend(result); // If some recipients failed but not others, throw AFTER sending the message. Complete(_failedRecipientException, result.AsyncState!); } @@ -929,8 +929,7 @@ private void SendMailCallback(IAsyncResult result) } else { - _message!.BeginSend(_writer, - IsUnicodeSupported(), new AsyncCallback(SendMessageCallback), result.AsyncState!); + _message!.BeginSend(_writer, DeliveryMethod != SmtpDeliveryMethod.Network, IsUnicodeSupported(), new AsyncCallback(SendMessageCallback), result.AsyncState!); } } catch (Exception e) diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpCommands.cs b/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpCommands.cs index 60bab14537f706..5c116f579607ec 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpCommands.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpCommands.cs @@ -2,204 +2,107 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Diagnostics; using System.Collections; using System.Globalization; using System.IO; using System.Net.Mime; using System.Runtime.ExceptionServices; using System.Text; +using System.Threading; +using System.Threading.Tasks; namespace System.Net.Mail { internal static class CheckCommand { - private static readonly AsyncCallback s_onReadLine = new AsyncCallback(OnReadLine); - private static readonly AsyncCallback s_onWrite = new AsyncCallback(OnWrite); - - internal static IAsyncResult BeginSend(SmtpConnection conn, AsyncCallback? callback, object? state) + internal static LineInfo Send(SmtpConnection conn) { - MultiAsyncResult multiResult = new MultiAsyncResult(conn, callback, state); - multiResult.Enter(); - IAsyncResult writeResult = conn.BeginFlush(s_onWrite, multiResult); - if (writeResult.CompletedSynchronously) - { - conn.EndFlush(writeResult); - multiResult.Leave(); - } - SmtpReplyReader reader = conn.Reader!.GetNextReplyReader(); - multiResult.Enter(); - - //this actually does a read on the stream. - IAsyncResult result = reader.BeginReadLine(s_onReadLine, multiResult); - if (result.CompletedSynchronously) - { - LineInfo info = SmtpReplyReader.EndReadLine(result); - if (!(multiResult.Result is Exception)) - multiResult.Result = info; - multiResult.Leave(); - } - multiResult.CompleteSequence(); - return multiResult; + Task task = SendAsync(conn); + Debug.Assert(task.IsCompleted, "CheckCommand.SendAsync should be completed synchronously."); + return task.GetAwaiter().GetResult(); } - - internal static object EndSend(IAsyncResult result, out string response) + internal static async Task SendAsync(SmtpConnection conn, CancellationToken cancellationToken = default) + where TIOAdapter : IReadWriteAdapter { - object commandResult = MultiAsyncResult.End(result)!; - if (commandResult is Exception e) - { - ExceptionDispatchInfo.Throw(e); - } + await conn.FlushAsync(cancellationToken).ConfigureAwait(false); + return await conn.Reader!.GetNextReplyReader().ReadLineAsync(cancellationToken).ConfigureAwait(false); + } + } - LineInfo info = (LineInfo)commandResult; - response = info.Line; - return info.StatusCode; + internal static class ReadLinesCommand + { + internal static LineInfo[] Send(SmtpConnection conn) + { + Task task = SendAsync(conn); + Debug.Assert(task.IsCompleted, "ReadLinesCommand.SendAsync should be completed synchronously."); + return task.GetAwaiter().GetResult(); } - private static void OnReadLine(IAsyncResult result) + internal static IAsyncResult BeginSend(SmtpConnection conn, AsyncCallback callback, object? state) { - if (!result.CompletedSynchronously) - { - MultiAsyncResult multiResult = (MultiAsyncResult)result.AsyncState!; - try - { - SmtpConnection conn = (SmtpConnection)multiResult.Context; - LineInfo info = SmtpReplyReader.EndReadLine(result); - if (!(multiResult.Result is Exception)) - multiResult.Result = info; - multiResult.Leave(); - } - catch (Exception e) - { - multiResult.Leave(e); - } - } + return TaskToAsyncResult.Begin(SendAsync(conn), callback, state); } - private static void OnWrite(IAsyncResult result) + internal static LineInfo[] EndSend(IAsyncResult asyncResult) { - if (!result.CompletedSynchronously) - { - MultiAsyncResult multiResult = (MultiAsyncResult)result.AsyncState!; - try - { - SmtpConnection conn = (SmtpConnection)multiResult.Context; - conn.EndFlush(result); - multiResult.Leave(); - } - catch (Exception e) - { - multiResult.Leave(e); - } - } + return TaskToAsyncResult.End(asyncResult); } - internal static SmtpStatusCode Send(SmtpConnection conn, out string response) + internal static async Task SendAsync(SmtpConnection conn, CancellationToken cancellationToken = default) + where TIOAdapter : IReadWriteAdapter { - conn.Flush(); - SmtpReplyReader reader = conn.Reader!.GetNextReplyReader(); - LineInfo info = reader.ReadLine(); - response = info.Line; - reader.Close(); - return info.StatusCode; + await conn.FlushAsync(cancellationToken).ConfigureAwait(false); + return await conn.Reader!.GetNextReplyReader().ReadLinesAsync(cancellationToken).ConfigureAwait(false); } } - internal static class ReadLinesCommand + internal static class AuthCommand { - private static readonly AsyncCallback s_onReadLines = new AsyncCallback(OnReadLines); - private static readonly AsyncCallback s_onWrite = new AsyncCallback(OnWrite); - - internal static IAsyncResult BeginSend(SmtpConnection conn, AsyncCallback? callback, object? state) + internal static LineInfo Send(SmtpConnection conn, string type, string message) { - MultiAsyncResult multiResult = new MultiAsyncResult(conn, callback, state); - multiResult.Enter(); - IAsyncResult writeResult = conn.BeginFlush(s_onWrite, multiResult); - if (writeResult.CompletedSynchronously) - { - conn.EndFlush(writeResult); - multiResult.Leave(); - } - SmtpReplyReader reader = conn.Reader!.GetNextReplyReader(); - multiResult.Enter(); - IAsyncResult readLinesResult = reader.BeginReadLines(s_onReadLines, multiResult); - if (readLinesResult.CompletedSynchronously) - { - LineInfo[] lines = SmtpReplyReader.EndReadLines(readLinesResult); - if (!(multiResult.Result is Exception)) - multiResult.Result = lines; - multiResult.Leave(); - } - multiResult.CompleteSequence(); - return multiResult; + Task task = SendAsync(conn, type, message); + Debug.Assert(task.IsCompleted, "AuthCommand.SendAsync should be completed synchronously."); + return task.GetAwaiter().GetResult(); } - internal static LineInfo[] EndSend(IAsyncResult result) + internal static LineInfo Send(SmtpConnection conn, string? message) { - object commandResult = MultiAsyncResult.End(result)!; - if (commandResult is Exception e) - { - ExceptionDispatchInfo.Throw(e); - } - return (LineInfo[])commandResult; + Task task = SendAsync(conn, message); + Debug.Assert(task.IsCompleted, "AuthCommand.SendAsync should be completed synchronously."); + return task.GetAwaiter().GetResult(); } - private static void OnReadLines(IAsyncResult result) + internal static IAsyncResult BeginSend(SmtpConnection conn, string type, string message, AsyncCallback callback, object? state) { - if (!result.CompletedSynchronously) - { - MultiAsyncResult multiResult = (MultiAsyncResult)result.AsyncState!; - try - { - SmtpConnection conn = (SmtpConnection)multiResult.Context; - LineInfo[] lines = SmtpReplyReader.EndReadLines(result); - if (!(multiResult.Result is Exception)) - multiResult.Result = lines; - multiResult.Leave(); - } - catch (Exception e) - { - multiResult.Leave(e); - } - } + return TaskToAsyncResult.Begin(SendAsync(conn, type, message), callback, state); } - private static void OnWrite(IAsyncResult result) + internal static IAsyncResult BeginSend(SmtpConnection conn, string? message, AsyncCallback callback, object? state) { - if (!result.CompletedSynchronously) - { - MultiAsyncResult multiResult = (MultiAsyncResult)result.AsyncState!; - try - { - SmtpConnection conn = (SmtpConnection)multiResult.Context; - conn.EndFlush(result); - multiResult.Leave(); - } - catch (Exception e) - { - multiResult.Leave(e); - } - } + return TaskToAsyncResult.Begin(SendAsync(conn, message), callback, state); } - internal static LineInfo[] Send(SmtpConnection conn) + + internal static LineInfo EndSend(IAsyncResult asyncResult) { - conn.Flush(); - return conn.Reader!.GetNextReplyReader().ReadLines(); + return TaskToAsyncResult.End(asyncResult); } - } - internal static class AuthCommand - { - internal static IAsyncResult BeginSend(SmtpConnection conn, string type, string message, AsyncCallback? callback, object? state) + internal static async Task SendAsync(SmtpConnection conn, string type, string message, CancellationToken cancellationToken = default) + where TIOAdapter : IReadWriteAdapter { PrepareCommand(conn, type, message); - return ReadLinesCommand.BeginSend(conn, callback, state); + LineInfo[] lines = await ReadLinesCommand.SendAsync(conn, cancellationToken).ConfigureAwait(false); + return CheckResponse(lines); } - internal static IAsyncResult BeginSend(SmtpConnection conn, string? message, AsyncCallback? callback, object? state) + internal static async Task SendAsync(SmtpConnection conn, string? message, CancellationToken cancellationToken = default) + where TIOAdapter : IReadWriteAdapter { PrepareCommand(conn, message); - return ReadLinesCommand.BeginSend(conn, callback, state); + LineInfo[] lines = await ReadLinesCommand.SendAsync(conn, cancellationToken).ConfigureAwait(false); + return CheckResponse(lines); } private static LineInfo CheckResponse(LineInfo[] lines) @@ -212,10 +115,6 @@ private static LineInfo CheckResponse(LineInfo[] lines) return lines[0]; } - internal static LineInfo EndSend(IAsyncResult result) - { - return CheckResponse(ReadLinesCommand.EndSend(result)); - } private static void PrepareCommand(SmtpConnection conn, string type, string message) { conn.BufferBuilder.Append(SmtpCommands.Auth); @@ -230,26 +129,33 @@ private static void PrepareCommand(SmtpConnection conn, string? message) conn.BufferBuilder.Append(message); conn.BufferBuilder.Append(SmtpCommands.CRLF); } + } - internal static LineInfo Send(SmtpConnection conn, string type, string message) + internal static class DataCommand + { + internal static void Send(SmtpConnection conn) { - PrepareCommand(conn, type, message); - return CheckResponse(ReadLinesCommand.Send(conn)); + Task task = SendAsync(conn); + Debug.Assert(task.IsCompleted, "DataCommand.SendAsync should be completed synchronously."); + task.GetAwaiter().GetResult(); } - internal static LineInfo Send(SmtpConnection conn, string? message) + internal static IAsyncResult BeginSend(SmtpConnection conn, AsyncCallback callback, object? state) { - PrepareCommand(conn, message); - return CheckResponse(ReadLinesCommand.Send(conn)); + return TaskToAsyncResult.Begin(SendAsync(conn), callback, state); } - } - internal static class DataCommand - { - internal static IAsyncResult BeginSend(SmtpConnection conn, AsyncCallback? callback, object? state) + internal static void EndSend(IAsyncResult asyncResult) + { + TaskToAsyncResult.End(asyncResult); + } + + internal static async Task SendAsync(SmtpConnection conn, CancellationToken cancellationToken = default) + where TIOAdapter : IReadWriteAdapter { PrepareCommand(conn); - return CheckCommand.BeginSend(conn, callback, state); + LineInfo info = await CheckCommand.SendAsync(conn, cancellationToken).ConfigureAwait(false); + CheckResponse(info.StatusCode, info.Line); } private static void CheckResponse(SmtpStatusCode statusCode, string serverResponse) @@ -274,13 +180,6 @@ private static void CheckResponse(SmtpStatusCode statusCode, string serverRespon } } - internal static void EndSend(IAsyncResult result) - { - string response; - SmtpStatusCode statusCode = (SmtpStatusCode)CheckCommand.EndSend(result, out response); - CheckResponse(statusCode, response); - } - private static void PrepareCommand(SmtpConnection conn) { if (conn.IsStreamOpen) @@ -290,18 +189,35 @@ private static void PrepareCommand(SmtpConnection conn) conn.BufferBuilder.Append(SmtpCommands.Data); } + } + internal static class DataStopCommand + { internal static void Send(SmtpConnection conn) + { + Task task = SendAsync(conn); + Debug.Assert(task.IsCompleted, "DataStopCommand.SendAsync should be completed synchronously."); + task.GetAwaiter().GetResult(); + } + + internal static IAsyncResult BeginSend(SmtpConnection conn, AsyncCallback callback, object? state) + { + return TaskToAsyncResult.Begin(SendAsync(conn), callback, state); + } + + internal static void EndSend(IAsyncResult asyncResult) + { + TaskToAsyncResult.End(asyncResult); + } + + internal static async Task SendAsync(SmtpConnection conn, CancellationToken cancellationToken = default) + where TIOAdapter : IReadWriteAdapter { PrepareCommand(conn); - string response; - SmtpStatusCode statusCode = CheckCommand.Send(conn, out response); - CheckResponse(statusCode, response); + LineInfo info = await CheckCommand.SendAsync(conn, cancellationToken).ConfigureAwait(false); + CheckResponse(info.StatusCode, info.Line); } - } - internal static class DataStopCommand - { private static void CheckResponse(SmtpStatusCode statusCode, string serverResponse) { switch (statusCode) @@ -335,21 +251,33 @@ private static void PrepareCommand(SmtpConnection conn) conn.BufferBuilder.Append(SmtpCommands.DataStop); } - internal static void Send(SmtpConnection conn) - { - PrepareCommand(conn); - string response; - SmtpStatusCode statusCode = CheckCommand.Send(conn, out response); - CheckResponse(statusCode, response); - } } internal static class EHelloCommand { - internal static IAsyncResult BeginSend(SmtpConnection conn, string domain, AsyncCallback? callback, object? state) + internal static string[] Send(SmtpConnection conn, string domain) + { + Task task = SendAsync(conn, domain); + Debug.Assert(task.IsCompleted, "EHelloCommand.SendAsync should be completed synchronously."); + return task.GetAwaiter().GetResult(); + } + + internal static IAsyncResult BeginSend(SmtpConnection conn, string domain, AsyncCallback callback, object? state) + { + return TaskToAsyncResult.Begin(SendAsync(conn, domain), callback, state); + } + + internal static string[] EndSend(IAsyncResult asyncResult) + { + return TaskToAsyncResult.End(asyncResult); + } + + internal static async Task SendAsync(SmtpConnection conn, string domain, CancellationToken cancellationToken = default) + where TIOAdapter : IReadWriteAdapter { PrepareCommand(conn, domain); - return ReadLinesCommand.BeginSend(conn, callback, state); + LineInfo[] lines = await ReadLinesCommand.SendAsync(conn, cancellationToken).ConfigureAwait(false); + return CheckResponse(lines); } private static string[] CheckResponse(LineInfo[] lines) @@ -375,10 +303,6 @@ private static string[] CheckResponse(LineInfo[] lines) return extensions; } - internal static string[] EndSend(IAsyncResult result) - { - return CheckResponse(ReadLinesCommand.EndSend(result)); - } private static void PrepareCommand(SmtpConnection conn, string domain) { if (conn.IsStreamOpen) @@ -390,20 +314,33 @@ private static void PrepareCommand(SmtpConnection conn, string domain) conn.BufferBuilder.Append(domain); conn.BufferBuilder.Append(SmtpCommands.CRLF); } - - internal static string[] Send(SmtpConnection conn, string domain) - { - PrepareCommand(conn, domain); - return CheckResponse(ReadLinesCommand.Send(conn)); - } } internal static class HelloCommand { - internal static IAsyncResult BeginSend(SmtpConnection conn, string domain, AsyncCallback? callback, object? state) + internal static void Send(SmtpConnection conn, string domain) + { + Task task = SendAsync(conn, domain); + Debug.Assert(task.IsCompleted, "HelloCommand.SendAsync should be completed synchronously."); + task.GetAwaiter().GetResult(); + } + + internal static IAsyncResult BeginSend(SmtpConnection conn, string domain, AsyncCallback callback, object? state) + { + return TaskToAsyncResult.Begin(SendAsync(conn, domain), callback, state); + } + + internal static void EndSend(IAsyncResult asyncResult) + { + TaskToAsyncResult.End(asyncResult); + } + + internal static async Task SendAsync(SmtpConnection conn, string domain, CancellationToken cancellationToken = default) + where TIOAdapter : IReadWriteAdapter { PrepareCommand(conn, domain); - return CheckCommand.BeginSend(conn, callback, state); + LineInfo info = await CheckCommand.SendAsync(conn, cancellationToken).ConfigureAwait(false); + CheckResponse(info.StatusCode, info.Line); } private static void CheckResponse(SmtpStatusCode statusCode, string serverResponse) @@ -426,13 +363,6 @@ private static void CheckResponse(SmtpStatusCode statusCode, string serverRespon } } - internal static void EndSend(IAsyncResult result) - { - string response; - SmtpStatusCode statusCode = (SmtpStatusCode)CheckCommand.EndSend(result, out response); - CheckResponse(statusCode, response); - } - private static void PrepareCommand(SmtpConnection conn, string domain) { if (conn.IsStreamOpen) @@ -444,22 +374,33 @@ private static void PrepareCommand(SmtpConnection conn, string domain) conn.BufferBuilder.Append(domain); conn.BufferBuilder.Append(SmtpCommands.CRLF); } - - internal static void Send(SmtpConnection conn, string domain) - { - PrepareCommand(conn, domain); - string response; - SmtpStatusCode statusCode = CheckCommand.Send(conn, out response); - CheckResponse(statusCode, response); - } } internal static class StartTlsCommand { - internal static IAsyncResult BeginSend(SmtpConnection conn, AsyncCallback? callback, object? state) + internal static void Send(SmtpConnection conn) + { + Task task = SendAsync(conn); + Debug.Assert(task.IsCompleted, "StartTlsCommand.SendAsync should be completed synchronously."); + task.GetAwaiter().GetResult(); + } + + internal static IAsyncResult BeginSend(SmtpConnection conn, AsyncCallback callback, object? state) + { + return TaskToAsyncResult.Begin(SendAsync(conn), callback, state); + } + + internal static void EndSend(IAsyncResult asyncResult) + { + TaskToAsyncResult.End(asyncResult); + } + + internal static async Task SendAsync(SmtpConnection conn, CancellationToken cancellationToken = default) + where TIOAdapter : IReadWriteAdapter { PrepareCommand(conn); - return CheckCommand.BeginSend(conn, callback, state); + LineInfo info = await CheckCommand.SendAsync(conn, cancellationToken).ConfigureAwait(false); + CheckResponse(info.StatusCode, info.Line); } private static void CheckResponse(SmtpStatusCode statusCode, string response) @@ -484,13 +425,6 @@ private static void CheckResponse(SmtpStatusCode statusCode, string response) } } - internal static void EndSend(IAsyncResult result) - { - string response; - SmtpStatusCode statusCode = (SmtpStatusCode)CheckCommand.EndSend(result, out response); - CheckResponse(statusCode, response); - } - private static void PrepareCommand(SmtpConnection conn) { if (conn.IsStreamOpen) @@ -501,23 +435,39 @@ private static void PrepareCommand(SmtpConnection conn) conn.BufferBuilder.Append(SmtpCommands.StartTls); conn.BufferBuilder.Append(SmtpCommands.CRLF); } - - internal static void Send(SmtpConnection conn) - { - PrepareCommand(conn); - string response; - SmtpStatusCode statusCode = CheckCommand.Send(conn, out response); - CheckResponse(statusCode, response); - } } internal static class MailCommand { - internal static IAsyncResult BeginSend(SmtpConnection conn, ReadOnlySpan command, MailAddress from, - bool allowUnicode, AsyncCallback? callback, object? state) + internal static void Send(SmtpConnection conn, ReadOnlySpan command, MailAddress from, bool allowUnicode) + { + Task task = SendAsync(conn, command, from, allowUnicode); + Debug.Assert(task.IsCompleted, "MailCommand.SendAsync should be completed synchronously."); + task.GetAwaiter().GetResult(); + } + + internal static IAsyncResult BeginSend(SmtpConnection conn, ReadOnlySpan command, MailAddress from, bool allowUnicode, AsyncCallback callback, object? state) + { + return TaskToAsyncResult.Begin(SendAsync(conn, command, from, allowUnicode), callback, state); + } + + internal static void EndSend(IAsyncResult asyncResult) + { + TaskToAsyncResult.End(asyncResult); + } + + internal static Task SendAsync(SmtpConnection conn, ReadOnlySpan command, MailAddress from, bool allowUnicode, CancellationToken cancellationToken = default) + where TIOAdapter : IReadWriteAdapter { PrepareCommand(conn, command, from, allowUnicode); - return CheckCommand.BeginSend(conn, callback, state); + return SendAndCheck(conn, cancellationToken); + + static async Task SendAndCheck(SmtpConnection conn, CancellationToken cancellationToken) + { + LineInfo info = await CheckCommand.SendAsync(conn, cancellationToken).ConfigureAwait(false); + CheckResponse(info.StatusCode, info.Line); + return info; + } } private static void CheckResponse(SmtpStatusCode statusCode, string response) @@ -543,13 +493,6 @@ private static void CheckResponse(SmtpStatusCode statusCode, string response) } } - internal static void EndSend(IAsyncResult result) - { - string response; - SmtpStatusCode statusCode = (SmtpStatusCode)CheckCommand.EndSend(result, out response); - CheckResponse(statusCode, response); - } - private static void PrepareCommand(SmtpConnection conn, ReadOnlySpan command, MailAddress from, bool allowUnicode) { if (conn.IsStreamOpen) @@ -565,22 +508,37 @@ private static void PrepareCommand(SmtpConnection conn, ReadOnlySpan comma } conn.BufferBuilder.Append(SmtpCommands.CRLF); } - - internal static void Send(SmtpConnection conn, ReadOnlySpan command, MailAddress from, bool allowUnicode) - { - PrepareCommand(conn, command, from, allowUnicode); - string response; - SmtpStatusCode statusCode = CheckCommand.Send(conn, out response); - CheckResponse(statusCode, response); - } } internal static class RecipientCommand { - internal static IAsyncResult BeginSend(SmtpConnection conn, string to, AsyncCallback? callback, object? state) + internal static bool Send(SmtpConnection conn, string to, out string response) + { + Task<(bool success, string response)> task = SendAsync(conn, to); + Debug.Assert(task.IsCompleted, "RecipientCommand.SendAsync should be completed synchronously."); + (bool success, string r) = task.GetAwaiter().GetResult(); + response = r; + return success; + } + + internal static IAsyncResult BeginSend(SmtpConnection conn, string to, AsyncCallback callback, object? state) + { + return TaskToAsyncResult.Begin(SendAsync(conn, to), callback, state); + } + + internal static bool EndSend(IAsyncResult asyncResult, out string response) + { + (bool success, string r) = TaskToAsyncResult.End<(bool success, string response)>(asyncResult); + response = r; + return success; + } + + internal static async Task<(bool success, string response)> SendAsync(SmtpConnection conn, string to, CancellationToken cancellationToken = default) + where TIOAdapter : IReadWriteAdapter { PrepareCommand(conn, to); - return CheckCommand.BeginSend(conn, callback, state); + LineInfo info = await CheckCommand.SendAsync(conn, cancellationToken).ConfigureAwait(false); + return (CheckResponse(info.StatusCode, info.Line), info.Line); } private static bool CheckResponse(SmtpStatusCode statusCode, string response) @@ -613,12 +571,6 @@ private static bool CheckResponse(SmtpStatusCode statusCode, string response) } } - internal static bool EndSend(IAsyncResult result, out string response) - { - SmtpStatusCode statusCode = (SmtpStatusCode)CheckCommand.EndSend(result, out response); - return CheckResponse(statusCode, response); - } - private static void PrepareCommand(SmtpConnection conn, string to) { if (conn.IsStreamOpen) @@ -630,18 +582,35 @@ private static void PrepareCommand(SmtpConnection conn, string to) conn.BufferBuilder.Append(to, true); // Unicode validation was done prior conn.BufferBuilder.Append(SmtpCommands.CRLF); } + } + internal static class QuitCommand + { + internal static void Send(SmtpConnection conn) + { + Task task = SendAsync(conn); + Debug.Assert(task.IsCompleted, "QuitCommand.SendAsync should be completed synchronously."); + task.GetAwaiter().GetResult(); + } - internal static bool Send(SmtpConnection conn, string to, out string response) + internal static IAsyncResult BeginSend(SmtpConnection conn, AsyncCallback callback, object? state) { - PrepareCommand(conn, to); - SmtpStatusCode statusCode = CheckCommand.Send(conn, out response); - return CheckResponse(statusCode, response); + return TaskToAsyncResult.Begin(SendAsync(conn), callback, state); + } + + internal static void EndSend(IAsyncResult asyncResult) + { + TaskToAsyncResult.End(asyncResult); + } + + internal static async Task SendAsync(SmtpConnection conn, CancellationToken cancellationToken = default) + where TIOAdapter : IReadWriteAdapter + { + PrepareCommand(conn); + await conn.FlushAsync(cancellationToken).ConfigureAwait(false); + // We don't read any response to match the synchronous behavior } - } - internal static class QuitCommand - { private static void PrepareCommand(SmtpConnection conn) { if (conn.IsStreamOpen) @@ -651,17 +620,6 @@ private static void PrepareCommand(SmtpConnection conn) conn.BufferBuilder.Append(SmtpCommands.Quit); } - - internal static void Send(SmtpConnection conn) - { - PrepareCommand(conn); - - // We simply flush and don't read the response - // to avoid blocking call that will impact users - // that are using async api, since this code - // will run on Dispose() - conn.Flush(); - } } internal static class SmtpCommands diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpConnection.cs b/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpConnection.cs index 3dfc0d9214df77..e33e3da411a501 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpConnection.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpConnection.cs @@ -14,6 +14,7 @@ using System.Security.Cryptography.X509Certificates; using System.Security.Principal; using System.Threading; +using System.Threading.Tasks; namespace System.Net.Mail { @@ -105,19 +106,26 @@ internal IAsyncResult BeginGetConnection(ContextAwareResult outerResult, AsyncCa internal IAsyncResult BeginFlush(AsyncCallback? callback, object? state) { - return _stream!.BeginWrite(_bufferBuilder.GetBuffer(), 0, _bufferBuilder.Length, callback, state); + return TaskToAsyncResult.Begin(FlushAsync(CancellationToken.None), callback, state); } - internal void EndFlush(IAsyncResult result) + internal static void EndFlush(IAsyncResult result) { - _stream!.EndWrite(result); + TaskToAsyncResult.End(result); + } + + internal async Task FlushAsync(CancellationToken cancellationToken = default) where TIOAdapter : IReadWriteAdapter + { + await TIOAdapter.WriteAsync(_stream!, _bufferBuilder.GetBuffer().AsMemory(0, _bufferBuilder.Length), cancellationToken).ConfigureAwait(false); _bufferBuilder.Reset(); } + internal void Flush() { - _stream!.Write(_bufferBuilder.GetBuffer(), 0, _bufferBuilder.Length); - _bufferBuilder.Reset(); + Task task = FlushAsync(CancellationToken.None); + Debug.Assert(task.IsCompleted, "FlushAsync should be completed synchronously."); + task.GetAwaiter().GetResult(); } private void ShutdownConnection(bool isAbort) diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpReplyReader.cs b/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpReplyReader.cs index 7887ac3c6d7f8a..a2de4cd060e0f4 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpReplyReader.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpReplyReader.cs @@ -2,13 +2,21 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Diagnostics; using System.IO; +using System.Threading; +using System.Threading.Tasks; namespace System.Net.Mail { //streams are read only; return of 0 means end of server's reply - internal sealed class SmtpReplyReader + internal sealed class SmtpReplyReader : IDisposable { + public void Dispose() + { + Close(); + } + private readonly SmtpReplyReaderFactory _reader; internal SmtpReplyReader(SmtpReplyReaderFactory reader) @@ -16,39 +24,65 @@ internal SmtpReplyReader(SmtpReplyReaderFactory reader) _reader = reader; } - internal IAsyncResult BeginReadLines(AsyncCallback? callback, object? state) + public void Close() { - return _reader.BeginReadLines(this, callback, state); + _reader.Close(this); } - internal IAsyncResult BeginReadLine(AsyncCallback? callback, object? state) + internal LineInfo[] ReadLines() { - return _reader.BeginReadLine(this, callback, state); + Task task = ReadLinesAsync(); + + Debug.Assert(task.IsCompleted, "ReadLinesAsync should be completed synchronously."); + return task.GetAwaiter().GetResult(); } - public void Close() + internal IAsyncResult BeginReadLines(AsyncCallback callback, object? state) { - _reader.Close(this); + return TaskToAsyncResult.Begin(ReadLinesAsync(), callback, state); } - internal static LineInfo[] EndReadLines(IAsyncResult result) + internal static LineInfo[] EndReadLines(IAsyncResult asyncResult) { - return SmtpReplyReaderFactory.EndReadLines(result); + return TaskToAsyncResult.End(asyncResult); } - internal static LineInfo EndReadLine(IAsyncResult result) + internal LineInfo ReadLine() { - return SmtpReplyReaderFactory.EndReadLine(result); + Task task = ReadLineAsync(); + + Debug.Assert(task.IsCompleted, "ReadLineAsync should be completed synchronously."); + return task.GetAwaiter().GetResult(); } - internal LineInfo[] ReadLines() + internal IAsyncResult BeginReadLine(AsyncCallback callback, object? state) { - return _reader.ReadLines(this); + return TaskToAsyncResult.Begin(ReadLineAsync(), callback, state); } - internal LineInfo ReadLine() + internal static LineInfo EndReadLine(IAsyncResult asyncResult) + { + return TaskToAsyncResult.End(asyncResult); + } + + internal Task ReadLinesAsync() + { + return ReadLinesAsync(); + } + + internal Task ReadLineAsync() + { + return ReadLineAsync(); + } + + internal Task ReadLinesAsync(CancellationToken cancellationToken = default) where TIOAdapter : IReadWriteAdapter + { + return _reader.ReadLinesAsync(this, false, cancellationToken); + } + + internal Task ReadLineAsync(CancellationToken cancellationToken = default) where TIOAdapter : IReadWriteAdapter { - return _reader.ReadLine(this); + return _reader.ReadLineAsync(this, cancellationToken); } } } diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpReplyReaderFactory.cs b/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpReplyReaderFactory.cs index 03d32a7e44d608..66be00167e3f02 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpReplyReaderFactory.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpReplyReaderFactory.cs @@ -3,8 +3,11 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Text; +using System.Threading; +using System.Threading.Tasks; namespace System.Net.Mail { @@ -53,20 +56,6 @@ internal SmtpStatusCode StatusCode } } - internal IAsyncResult BeginReadLines(SmtpReplyReader caller, AsyncCallback? callback, object? state) - { - ReadLinesAsyncResult result = new ReadLinesAsyncResult(this, callback, state); - result.Read(caller); - return result; - } - - internal IAsyncResult BeginReadLine(SmtpReplyReader caller, AsyncCallback? callback, object? state) - { - ReadLinesAsyncResult result = new ReadLinesAsyncResult(this, callback, state, true); - result.Read(caller); - return result; - } - internal void Close(SmtpReplyReader caller) { if (_currentReader == caller) @@ -82,21 +71,6 @@ internal void Close(SmtpReplyReader caller) } } - internal static LineInfo[] EndReadLines(IAsyncResult result) - { - return ReadLinesAsyncResult.End(result); - } - - internal static LineInfo EndReadLine(IAsyncResult result) - { - LineInfo[] info = ReadLinesAsyncResult.End(result); - if (info != null && info.Length > 0) - { - return info[0]; - } - return default; - } - internal SmtpReplyReader GetNextReplyReader() { _currentReader?.Close(); @@ -298,29 +272,48 @@ internal LineInfo[] ReadLines(SmtpReplyReader caller) } internal LineInfo[] ReadLines(SmtpReplyReader caller, bool oneLine) + { + Task task = ReadLinesAsync(caller, oneLine); + Debug.Assert(task.IsCompleted, "ReadLinesAsync should complete synchronously for SyncReadWriteAdapter"); + + return task.GetAwaiter().GetResult(); + } + + internal Task ReadLinesAsync(SmtpReplyReader caller, bool oneLine = false, CancellationToken cancellationToken = default) + { + return ReadLinesAsync(caller, oneLine, cancellationToken); + } + + internal async Task ReadLinesAsync(SmtpReplyReader caller, bool oneLine = false, CancellationToken cancellationToken = default) where TIOAdapter : IReadWriteAdapter { if (caller != _currentReader || _readState == ReadState.Done) { return Array.Empty(); } - _byteBuffer ??= new byte[SmtpReplyReaderFactory.DefaultBufferSize]; - + _byteBuffer ??= new byte[DefaultBufferSize]; System.Diagnostics.Debug.Assert(_readState == ReadState.Status0); var builder = new StringBuilder(); var lines = new List(); int statusRead = 0; - for (int start = 0, read = 0; ;) + int start = 0; + int read = 0; + + while (true) { if (start == read) { - read = _bufferedStream.Read(_byteBuffer); start = 0; + read = await TIOAdapter.ReadAsync(_bufferedStream, _byteBuffer, cancellationToken).ConfigureAwait(false); + if (read == 0) + { + throw new IOException(SR.Format(SR.net_io_readfailure, SR.net_io_connectionclosed)); + } } - int actual = ProcessRead(_byteBuffer.AsSpan(start, read), true); + int actual = ProcessRead(_byteBuffer!.AsSpan(start, read - start), true); if (statusRead < 4) { @@ -340,160 +333,36 @@ internal LineInfo[] ReadLines(SmtpReplyReader caller, bool oneLine) if (_readState == ReadState.Status0) { statusRead = 0; - lines.Add(new LineInfo(_statusCode, builder.ToString(0, builder.Length - 2))); // return everything except CRLF + lines.Add(new LineInfo(_statusCode, builder.ToString(0, builder.Length - 2))); // Exclude CRLF if (oneLine) { - _bufferedStream.Push(_byteBuffer.AsSpan(start, read - start)); + _bufferedStream.Push(_byteBuffer!.AsSpan(start, read - start)); return lines.ToArray(); } - builder = new StringBuilder(); + + builder.Clear(); } else if (_readState == ReadState.Done) { - lines.Add(new LineInfo(_statusCode, builder.ToString(0, builder.Length - 2))); // return everything except CRLF - _bufferedStream.Push(_byteBuffer.AsSpan(start, read - start)); + lines!.Add(new LineInfo(_statusCode, builder.ToString(0, builder.Length - 2))); // return everything except CRLF + _bufferedStream.Push(_byteBuffer!.AsSpan(start, read - start)); return lines.ToArray(); } } + } - private sealed class ReadLinesAsyncResult : LazyAsyncResult + internal async Task ReadLineAsync(SmtpReplyReader caller) { - private StringBuilder? _builder; - private List? _lines; - private readonly SmtpReplyReaderFactory _parent; - private static readonly AsyncCallback s_readCallback = new AsyncCallback(ReadCallback); - private int _read; - private int _statusRead; - private readonly bool _oneLine; - - internal ReadLinesAsyncResult(SmtpReplyReaderFactory parent, AsyncCallback? callback, object? state) : base(null, state, callback) - { - _parent = parent; - } - - internal ReadLinesAsyncResult(SmtpReplyReaderFactory parent, AsyncCallback? callback, object? state, bool oneLine) : base(null, state, callback) - { - _oneLine = oneLine; - _parent = parent; - } - - internal void Read(SmtpReplyReader caller) - { - // if we've already found the delimitter, then return 0 indicating - // end of stream. - if (_parent._currentReader != caller || _parent._readState == ReadState.Done) - { - InvokeCallback(); - return; - } - - _parent._byteBuffer ??= new byte[SmtpReplyReaderFactory.DefaultBufferSize]; - - System.Diagnostics.Debug.Assert(_parent._readState == ReadState.Status0); - - _builder = new StringBuilder(); - _lines = new List(); - - Read(); - } - - internal static LineInfo[] End(IAsyncResult result) - { - ReadLinesAsyncResult thisPtr = (ReadLinesAsyncResult)result; - thisPtr.InternalWaitForCompletion(); - return thisPtr._lines!.ToArray(); - } - - private void Read() - { - do - { - IAsyncResult result = _parent._bufferedStream.BeginRead(_parent._byteBuffer!, 0, _parent._byteBuffer!.Length, s_readCallback, this); - if (!result.CompletedSynchronously) - { - return; - } - _read = _parent._bufferedStream.EndRead(result); - } while (ProcessRead()); - } - - private static void ReadCallback(IAsyncResult result) - { - if (!result.CompletedSynchronously) - { - Exception? exception = null; - ReadLinesAsyncResult thisPtr = (ReadLinesAsyncResult)result.AsyncState!; - try - { - thisPtr._read = thisPtr._parent._bufferedStream.EndRead(result); - if (thisPtr.ProcessRead()) - { - thisPtr.Read(); - } - } - catch (Exception e) - { - exception = e; - } - - if (exception != null) - { - thisPtr.InvokeCallback(exception); - } - } - } - - private bool ProcessRead() - { - if (_read == 0) - { - throw new IOException(SR.Format(SR.net_io_readfailure, SR.net_io_connectionclosed)); - } - - for (int start = 0; start != _read;) - { - int actual = _parent.ProcessRead(_parent._byteBuffer!.AsSpan(start, _read - start), true); - - if (_statusRead < 4) - { - int left = Math.Min(4 - _statusRead, actual); - _statusRead += left; - start += left; - actual -= left; - if (actual == 0) - { - continue; - } - } - - _builder!.Append(Encoding.UTF8.GetString(_parent._byteBuffer!, start, actual)); - start += actual; + LineInfo[] lines = await ReadLinesAsync(caller, oneLine: true).ConfigureAwait(false); + return lines.Length > 0 ? lines[0] : default; + } - if (_parent._readState == ReadState.Status0) - { - _lines!.Add(new LineInfo(_parent._statusCode, _builder.ToString(0, _builder.Length - 2))); // return everything except CRLF - _builder = new StringBuilder(); - _statusRead = 0; - - if (_oneLine) - { - _parent._bufferedStream.Push(_parent._byteBuffer!.AsSpan(start, _read - start)); - InvokeCallback(); - return false; - } - } - else if (_parent._readState == ReadState.Done) - { - _lines!.Add(new LineInfo(_parent._statusCode, _builder.ToString(0, _builder.Length - 2))); // return everything except CRLF - _parent._bufferedStream.Push(_parent._byteBuffer!.AsSpan(start, _read - start)); - InvokeCallback(); - return false; - } - } - return true; - } + internal async Task ReadLineAsync(SmtpReplyReader caller, CancellationToken cancellationToken) where TIOAdapter : IReadWriteAdapter + { + LineInfo[] lines = await ReadLinesAsync(caller, oneLine: true, cancellationToken).ConfigureAwait(false); + return lines.Length > 0 ? lines[0] : default; } } } diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpTransport.cs b/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpTransport.cs index e06de7affa2e93..8370bf8a26c9ef 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpTransport.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpTransport.cs @@ -316,7 +316,7 @@ private void SendToCollection() { while (_toIndex < _toCollection.Count) { - MultiAsyncResult result = (MultiAsyncResult)RecipientCommand.BeginSend(_connection, + IAsyncResult result = RecipientCommand.BeginSend(_connection, _toCollection[_toIndex++].GetSmtpAddress(_allowUnicode) + _deliveryNotify, s_sendToCollectionCompleted, this); if (!result.CompletedSynchronously) diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mime/BaseWriter.cs b/src/libraries/System.Net.Mail/src/System/Net/Mime/BaseWriter.cs index 3b59251a0cccb6..8c0286cf1609eb 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mime/BaseWriter.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mime/BaseWriter.cs @@ -15,7 +15,6 @@ internal abstract class BaseWriter // In MailWriter, all encoding has already been done so this will only fold lines // that are NOT encoded already, which means being less conservative is ok. private const int DefaultLineLength = 76; - private static readonly AsyncCallback s_onWrite = OnWrite; protected readonly BufferBuilder _bufferBuilder; protected readonly Stream _stream; @@ -97,9 +96,7 @@ private void WriteAndFold(string value, int charsAlreadyOnLine, bool allowUnicod #region Content - internal Stream GetContentStream() => GetContentStream(null); - - private ClosableStream GetContentStream(MultiAsyncResult? multiResult) + internal Stream GetContentStream() { if (_isInContent) { @@ -111,84 +108,26 @@ private ClosableStream GetContentStream(MultiAsyncResult? multiResult) CheckBoundary(); _bufferBuilder.Append("\r\n"u8); - Flush(multiResult); + Flush(); ClosableStream cs = new ClosableStream(new EightBitStream(_stream, _shouldEncodeLeadingDots), _onCloseHandler); _contentStream = cs; return cs; } - internal IAsyncResult BeginGetContentStream(AsyncCallback? callback, object? state) - { - MultiAsyncResult multiResult = new MultiAsyncResult(this, callback, state); - - Stream s = GetContentStream(multiResult); - - if (!(multiResult.Result is Exception)) - { - multiResult.Result = s; - } - - multiResult.CompleteSequence(); - - return multiResult; - } - - internal static Stream EndGetContentStream(IAsyncResult result) - { - object o = MultiAsyncResult.End(result)!; - if (o is Exception e) - { - ExceptionDispatchInfo.Throw(e); - } - return (Stream)o; - } - #endregion Content #region Cleanup - protected void Flush(MultiAsyncResult? multiResult) + protected void Flush() { if (_bufferBuilder.Length > 0) { - if (multiResult != null) - { - multiResult.Enter(); - IAsyncResult result = _stream.BeginWrite(_bufferBuilder.GetBuffer(), 0, - _bufferBuilder.Length, s_onWrite, multiResult); - if (result.CompletedSynchronously) - { - _stream.EndWrite(result); - multiResult.Leave(); - } - } - else - { - _stream.Write(_bufferBuilder.GetBuffer(), 0, _bufferBuilder.Length); - } + _stream.Write(_bufferBuilder.GetBuffer(), 0, _bufferBuilder.Length); _bufferBuilder.Reset(); } } - protected static void OnWrite(IAsyncResult result) - { - if (!result.CompletedSynchronously) - { - MultiAsyncResult multiResult = (MultiAsyncResult)result.AsyncState!; - BaseWriter thisPtr = (BaseWriter)multiResult.Context; - try - { - thisPtr._stream.EndWrite(result); - multiResult.Leave(); - } - catch (Exception e) - { - multiResult.Leave(e); - } - } - } - internal abstract void Close(); protected abstract void OnClose(object? sender, EventArgs args); diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mime/MimeBasePart.cs b/src/libraries/System.Net.Mail/src/System/Net/Mime/MimeBasePart.cs index 804c067eb201cb..a8d2e0436faef6 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mime/MimeBasePart.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mime/MimeBasePart.cs @@ -4,10 +4,12 @@ using System.Collections.Specialized; using System.Net.Mail; using System.Text; +using System.Threading; +using System.Threading.Tasks; namespace System.Net.Mime { - internal class MimeBasePart + internal abstract class MimeBasePart { internal const string DefaultCharSet = "utf-8"; @@ -186,46 +188,6 @@ internal void PrepareHeaders(bool allowUnicode) } } - internal virtual void Send(BaseWriter writer, bool allowUnicode) - { - throw new NotImplementedException(); - } - - internal virtual IAsyncResult BeginSend(BaseWriter writer, AsyncCallback? callback, - bool allowUnicode, object? state) - { - throw new NotImplementedException(); - } - - internal void EndSend(IAsyncResult asyncResult) - { - ArgumentNullException.ThrowIfNull(asyncResult); - - LazyAsyncResult? castedAsyncResult = asyncResult as MimePartAsyncResult; - - if (castedAsyncResult == null || castedAsyncResult.AsyncObject != this) - { - throw new ArgumentException(SR.net_io_invalidasyncresult, nameof(asyncResult)); - } - - if (castedAsyncResult.EndCalled) - { - throw new InvalidOperationException(SR.Format(SR.net_io_invalidendcall, nameof(EndSend))); - } - - castedAsyncResult.InternalWaitForCompletion(); - castedAsyncResult.EndCalled = true; - if (castedAsyncResult.Result is Exception) - { - throw (Exception)castedAsyncResult.Result; - } - } - - internal sealed class MimePartAsyncResult : LazyAsyncResult - { - internal MimePartAsyncResult(MimeBasePart part, object? state, AsyncCallback? callback) : base(part, state, callback) - { - } - } + internal abstract Task SendAsync(BaseWriter writer, bool allowUnicode, CancellationToken cancellationToken) where TIOAdapter : IReadWriteAdapter; } } diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mime/MimeMultiPart.cs b/src/libraries/System.Net.Mail/src/System/Net/Mime/MimeMultiPart.cs index b9b2038c507781..e0ffef86590615 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mime/MimeMultiPart.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mime/MimeMultiPart.cs @@ -7,6 +7,7 @@ using System.IO; using System.Runtime.ExceptionServices; using System.Threading; +using System.Threading.Tasks; namespace System.Net.Mime { @@ -14,8 +15,6 @@ internal sealed class MimeMultiPart : MimeBasePart { private Collection? _parts; private static int s_boundary; - private AsyncCallback? _mimePartSentCallback; - private bool _allowUnicode; internal MimeMultiPart(MimeMultiPartType type) { @@ -42,182 +41,7 @@ private void SetType(MimeMultiPartType type) internal Collection Parts => _parts ??= new Collection(); - internal static void Complete(IAsyncResult result, Exception? e) - { - //if we already completed and we got called again, - //it mean's that there was an exception in the callback and we - //should just rethrow it. - - MimePartContext context = (MimePartContext)result.AsyncState!; - - if (context._completed) - { - ExceptionDispatchInfo.Throw(e!); - } - - try - { - context._outputStream!.Close(); - } - catch (Exception ex) - { - e ??= ex; - } - context._completed = true; - context._result.InvokeCallback(e); - } - - internal void MimeWriterCloseCallback(IAsyncResult result) - { - if (result.CompletedSynchronously) - { - return; - } - - ((MimePartContext)result.AsyncState!)._completedSynchronously = false; - - try - { - MimeWriterCloseCallbackHandler(result); - } - catch (Exception e) - { - Complete(result, e); - } - } - - private static void MimeWriterCloseCallbackHandler(IAsyncResult result) - { - MimePartContext context = (MimePartContext)result.AsyncState!; - ((MimeWriter)context._writer).EndClose(result); - Complete(result, null); - } - - internal void MimePartSentCallback(IAsyncResult result) - { - if (result.CompletedSynchronously) - { - return; - } - - ((MimePartContext)result.AsyncState!)._completedSynchronously = false; - - try - { - MimePartSentCallbackHandler(result); - } - catch (Exception e) - { - Complete(result, e); - } - } - - private void MimePartSentCallbackHandler(IAsyncResult result) - { - MimePartContext context = (MimePartContext)result.AsyncState!; - MimeBasePart part = (MimeBasePart)context._partsEnumerator.Current; - part.EndSend(result); - - if (context._partsEnumerator.MoveNext()) - { - part = (MimeBasePart)context._partsEnumerator.Current; - IAsyncResult sendResult = part.BeginSend(context._writer, _mimePartSentCallback!, _allowUnicode, context); - if (sendResult.CompletedSynchronously) - { - MimePartSentCallbackHandler(sendResult); - } - return; - } - else - { - IAsyncResult closeResult = ((MimeWriter)context._writer).BeginClose(new AsyncCallback(MimeWriterCloseCallback), context); - if (closeResult.CompletedSynchronously) - { - MimeWriterCloseCallbackHandler(closeResult); - } - } - } - - internal void ContentStreamCallback(IAsyncResult result) - { - if (result.CompletedSynchronously) - { - return; - } - - ((MimePartContext)result.AsyncState!)._completedSynchronously = false; - - try - { - ContentStreamCallbackHandler(result); - } - catch (Exception e) - { - Complete(result, e); - } - } - - private void ContentStreamCallbackHandler(IAsyncResult result) - { - MimePartContext context = (MimePartContext)result.AsyncState!; - context._outputStream = BaseWriter.EndGetContentStream(result); - context._writer = new MimeWriter(context._outputStream!, ContentType.Boundary!); - if (context._partsEnumerator.MoveNext()) - { - MimeBasePart part = (MimeBasePart)context._partsEnumerator.Current; - - _mimePartSentCallback = new AsyncCallback(MimePartSentCallback); - IAsyncResult sendResult = part.BeginSend(context._writer, _mimePartSentCallback, _allowUnicode, context); - if (sendResult.CompletedSynchronously) - { - MimePartSentCallbackHandler(sendResult); - } - return; - } - else - { - IAsyncResult closeResult = ((MimeWriter)context._writer).BeginClose(new AsyncCallback(MimeWriterCloseCallback), context); - if (closeResult.CompletedSynchronously) - { - MimeWriterCloseCallbackHandler(closeResult); - } - } - } - - internal override IAsyncResult BeginSend(BaseWriter writer, AsyncCallback? callback, bool allowUnicode, - object? state) - { - _allowUnicode = allowUnicode; - PrepareHeaders(allowUnicode); - writer.WriteHeaders(Headers, allowUnicode); - MimePartAsyncResult result = new MimePartAsyncResult(this, state, callback); - MimePartContext context = new MimePartContext(writer, result, Parts.GetEnumerator()); - IAsyncResult contentResult = writer.BeginGetContentStream(new AsyncCallback(ContentStreamCallback), context); - if (contentResult.CompletedSynchronously) - { - ContentStreamCallbackHandler(contentResult); - } - return result; - } - - internal sealed class MimePartContext - { - internal MimePartContext(BaseWriter writer, LazyAsyncResult result, IEnumerator partsEnumerator) - { - _writer = writer; - _result = result; - _partsEnumerator = partsEnumerator; - } - - internal IEnumerator _partsEnumerator; - internal Stream? _outputStream; - internal LazyAsyncResult _result; - internal BaseWriter _writer; - internal bool _completed; - internal bool _completedSynchronously = true; - } - - internal override void Send(BaseWriter writer, bool allowUnicode) + internal override async Task SendAsync(BaseWriter writer, bool allowUnicode, CancellationToken cancellationToken = default) { PrepareHeaders(allowUnicode); writer.WriteHeaders(Headers, allowUnicode); @@ -226,7 +50,7 @@ internal override void Send(BaseWriter writer, bool allowUnicode) foreach (MimeBasePart part in Parts) { - part.Send(mimeWriter, allowUnicode); + await part.SendAsync(mimeWriter, allowUnicode, cancellationToken).ConfigureAwait(false); } mimeWriter.Close(); diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mime/MimePart.cs b/src/libraries/System.Net.Mail/src/System/Net/Mime/MimePart.cs index 85d20815d71f07..c95cf4f0346e27 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mime/MimePart.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mime/MimePart.cs @@ -8,6 +8,8 @@ using System.Net.Mail; using System.Runtime.ExceptionServices; using System.Text; +using System.Threading; +using System.Threading.Tasks; namespace System.Net.Mime { @@ -19,8 +21,6 @@ internal sealed class MimePart : MimeBasePart, IDisposable private Stream? _stream; private bool _streamSet; private bool _streamUsedOnce; - private AsyncCallback? _readCallback; - private AsyncCallback? _writeCallback; private const int maxBufferSize = 0x4400; //seems optimal for send based on perf analysis internal MimePart() { } @@ -139,98 +139,6 @@ internal void SetContent(Stream stream, ContentType? contentType) SetContent(stream); } - internal static void Complete(IAsyncResult result, Exception? e) - { - //if we already completed and we got called again, - //it mean's that there was an exception in the callback and we - //should just rethrow it. - - MimePartContext context = (MimePartContext)result.AsyncState!; - if (context._completed) - { - ExceptionDispatchInfo.Throw(e!); - } - - try - { - context._outputStream?.Close(); - } - catch (Exception ex) - { - e ??= ex; - } - context._completed = true; - context._result.InvokeCallback(e); - } - - - internal void ReadCallback(IAsyncResult result) - { - if (result.CompletedSynchronously) - { - return; - } - - ((MimePartContext)result.AsyncState!)._completedSynchronously = false; - - try - { - ReadCallbackHandler(result); - } - catch (Exception e) - { - Complete(result, e); - } - } - - internal void ReadCallbackHandler(IAsyncResult result) - { - MimePartContext context = (MimePartContext)result.AsyncState!; - context._bytesLeft = Stream!.EndRead(result); - if (context._bytesLeft > 0) - { - IAsyncResult writeResult = context._outputStream!.BeginWrite(context._buffer, 0, context._bytesLeft, _writeCallback, context); - if (writeResult.CompletedSynchronously) - { - WriteCallbackHandler(writeResult); - } - } - else - { - Complete(result, null); - } - } - - internal void WriteCallback(IAsyncResult result) - { - if (result.CompletedSynchronously) - { - return; - } - - ((MimePartContext)result.AsyncState!)._completedSynchronously = false; - - try - { - WriteCallbackHandler(result); - } - catch (Exception e) - { - Complete(result, e); - } - } - - internal void WriteCallbackHandler(IAsyncResult result) - { - MimePartContext context = (MimePartContext)result.AsyncState!; - context._outputStream!.EndWrite(result); - IAsyncResult readResult = Stream!.BeginRead(context._buffer, 0, context._buffer.Length, _readCallback, context); - if (readResult.CompletedSynchronously) - { - ReadCallbackHandler(readResult); - } - } - internal Stream GetEncodedStream(Stream stream) { Stream outputStream = stream; @@ -251,76 +159,7 @@ internal Stream GetEncodedStream(Stream stream) return outputStream; } - internal void ContentStreamCallbackHandler(IAsyncResult result) - { - MimePartContext context = (MimePartContext)result.AsyncState!; - Stream outputStream = BaseWriter.EndGetContentStream(result); - context._outputStream = GetEncodedStream(outputStream); - - _readCallback = new AsyncCallback(ReadCallback); - _writeCallback = new AsyncCallback(WriteCallback); - IAsyncResult readResult = Stream!.BeginRead(context._buffer, 0, context._buffer.Length, _readCallback, context); - if (readResult.CompletedSynchronously) - { - ReadCallbackHandler(readResult); - } - } - - internal void ContentStreamCallback(IAsyncResult result) - { - if (result.CompletedSynchronously) - { - return; - } - - ((MimePartContext)result.AsyncState!)._completedSynchronously = false; - - try - { - ContentStreamCallbackHandler(result); - } - catch (Exception e) - { - Complete(result, e); - } - } - - internal sealed class MimePartContext - { - internal MimePartContext(BaseWriter writer, LazyAsyncResult result) - { - _writer = writer; - _result = result; - _buffer = new byte[maxBufferSize]; - } - - internal Stream? _outputStream; - internal LazyAsyncResult _result; - internal int _bytesLeft; - internal BaseWriter _writer; - internal byte[] _buffer; - internal bool _completed; - internal bool _completedSynchronously = true; - } - - internal override IAsyncResult BeginSend(BaseWriter writer, AsyncCallback? callback, bool allowUnicode, object? state) - { - PrepareHeaders(allowUnicode); - writer.WriteHeaders(Headers, allowUnicode); - MimePartAsyncResult result = new MimePartAsyncResult(this, state, callback); - MimePartContext context = new MimePartContext(writer, result); - - ResetStream(); - _streamUsedOnce = true; - IAsyncResult contentResult = writer.BeginGetContentStream(new AsyncCallback(ContentStreamCallback), context); - if (contentResult.CompletedSynchronously) - { - ContentStreamCallbackHandler(contentResult); - } - return result; - } - - internal override void Send(BaseWriter writer, bool allowUnicode) + internal override async Task SendAsync(BaseWriter writer, bool allowUnicode, CancellationToken cancellationToken = default) { if (Stream != null) { @@ -332,15 +171,15 @@ internal override void Send(BaseWriter writer, bool allowUnicode) Stream outputStream = writer.GetContentStream(); outputStream = GetEncodedStream(outputStream); - int read; - ResetStream(); _streamUsedOnce = true; - while ((read = Stream.Read(buffer, 0, maxBufferSize)) > 0) + int read; + while ((read = await TIOAdapter.ReadAsync(Stream, buffer.AsMemory(0, maxBufferSize), cancellationToken).ConfigureAwait(false)) > 0) { - outputStream.Write(buffer, 0, read); + await TIOAdapter.WriteAsync(outputStream, buffer.AsMemory(0, read), cancellationToken).ConfigureAwait(false); } + outputStream.Close(); } } diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mime/MimeWriter.cs b/src/libraries/System.Net.Mail/src/System/Net/Mime/MimeWriter.cs index 8d9482b8ee1aa9..bb8fd314104cd2 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mime/MimeWriter.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mime/MimeWriter.cs @@ -35,37 +35,13 @@ internal override void WriteHeaders(NameValueCollection headers, bool allowUnico #region Cleanup - internal IAsyncResult BeginClose(AsyncCallback? callback, object? state) - { - MultiAsyncResult multiResult = new MultiAsyncResult(this, callback, state); - - Close(multiResult); - - multiResult.CompleteSequence(); - - return multiResult; - } - - internal void EndClose(IAsyncResult result) - { - MultiAsyncResult.End(result); - - _stream.Close(); - } - internal override void Close() - { - Close(null); - - _stream.Close(); - } - - private void Close(MultiAsyncResult? multiResult) { _bufferBuilder.Append("\r\n--"u8); _bufferBuilder.Append(_boundaryBytes); _bufferBuilder.Append("--\r\n"u8); - Flush(multiResult); + Flush(); + _stream.Close(); } /// diff --git a/src/libraries/System.Net.Mail/tests/Functional/LoggingTest.cs b/src/libraries/System.Net.Mail/tests/Functional/LoggingTest.cs index 188dd1711f52f8..31225bbb60ba5b 100644 --- a/src/libraries/System.Net.Mail/tests/Functional/LoggingTest.cs +++ b/src/libraries/System.Net.Mail/tests/Functional/LoggingTest.cs @@ -36,7 +36,7 @@ await RemoteExecutor.Invoke(() => listener.RunWithCallback(events.Enqueue, () => { // Invoke a test that'll cause some events to be generated - new SmtpClientTest().TestMailDelivery(); + new SmtpClientTest(null!).TestMailDelivery(); }); Assert.DoesNotContain(events, ev => ev.EventId == 0); // errors from the EventSource itself Assert.InRange(events.Count, 1, int.MaxValue); diff --git a/src/libraries/System.Net.Mail/tests/Functional/LoopbackServerTestBase.cs b/src/libraries/System.Net.Mail/tests/Functional/LoopbackServerTestBase.cs index 0d00087e61427f..7c3c170de145a1 100644 --- a/src/libraries/System.Net.Mail/tests/Functional/LoopbackServerTestBase.cs +++ b/src/libraries/System.Net.Mail/tests/Functional/LoopbackServerTestBase.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics; using System.Net.NetworkInformation; using System.Net.Security; using System.Security.Authentication; @@ -45,6 +46,7 @@ public struct SendMailAsyncMethod : ISendMethodProvider public abstract class LoopbackServerTestBase : IDisposable where T : ISendMethodProvider { + private static TimeSpan s_PassingTestTimeout = Debugger.IsAttached ? TimeSpan.FromSeconds(10000) : TimeSpan.FromSeconds(30); protected LoopbackSmtpServer Server { get; private set; } protected ITestOutputHelper Output { get; private set; } @@ -152,13 +154,13 @@ public LoopbackServerTestBase(ITestOutputHelper output) protected async Task SendMail(MailMessage msg, CancellationToken cancellationToken = default) { - Exception? ex = await SendMailInternal(msg, cancellationToken, null); + Exception? ex = await SendMailInternal(msg, cancellationToken, null).WaitAsync(s_PassingTestTimeout); Assert.Null(ex); } protected async Task SendMail(MailMessage msg, CancellationToken cancellationToken = default, bool unwrapException = true, bool asyncDirectException = false) where TException : Exception { - Exception? ex = await SendMailInternal(msg, cancellationToken, asyncDirectException); + Exception? ex = await SendMailInternal(msg, cancellationToken, asyncDirectException).WaitAsync(s_PassingTestTimeout); if (unwrapException && T.SendMethod != SendMethod.Send && typeof(TException) != typeof(SmtpException)) { diff --git a/src/libraries/System.Net.Mail/tests/Functional/LoopbackSmtpServer.cs b/src/libraries/System.Net.Mail/tests/Functional/LoopbackSmtpServer.cs index 29d9a978890119..5cd541638b23b0 100644 --- a/src/libraries/System.Net.Mail/tests/Functional/LoopbackSmtpServer.cs +++ b/src/libraries/System.Net.Mail/tests/Functional/LoopbackSmtpServer.cs @@ -63,10 +63,11 @@ public LoopbackSmtpServer(ITestOutputHelper? output = null) { _output = output; _socketsToDispose = new ConcurrentBag(); - _listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + _listenSocket = new Socket(SocketType.Stream, ProtocolType.Tcp); _socketsToDispose.Add(_listenSocket); - _listenSocket.Bind(new IPEndPoint(IPAddress.Any, 0)); + // if dual socket supported, bind to Ipv6Any, otherwise Any + _listenSocket.Bind(new IPEndPoint(_listenSocket.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0)); Port = ((IPEndPoint)_listenSocket.LocalEndPoint).Port; _listenSocket.Listen(1); diff --git a/src/libraries/System.Net.Mail/tests/Functional/MailMessageTest.cs b/src/libraries/System.Net.Mail/tests/Functional/MailMessageTest.cs index c73daa15422856..b42390d49ada58 100644 --- a/src/libraries/System.Net.Mail/tests/Functional/MailMessageTest.cs +++ b/src/libraries/System.Net.Mail/tests/Functional/MailMessageTest.cs @@ -11,8 +11,10 @@ using System.IO; using System.Reflection; +using System.Linq; using System.Text; using System.Text.RegularExpressions; +using System.Threading; using Xunit; namespace System.Net.Mail.Tests @@ -259,13 +261,14 @@ private static (string Raw, string Attachment) DecodeSentMailMessage(MailMessage culture: null, activationAttributes: null); + var syncSendAdapterType = typeof(MailMessage).Assembly.GetTypes() + .FirstOrDefault(t => t.Name == "SyncReadWriteAdapter"); + // Send the message. - typeof(MailMessage).InvokeMember( - name: "Send", - invokeAttr: BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod, - binder: null, - target: mail, - args: new object[] { mailWriter, true, true }); + typeof(MailMessage) + .GetMethod("SendAsync", BindingFlags.Instance | BindingFlags.NonPublic) + .MakeGenericMethod(syncSendAdapterType) + .Invoke(mail, new object[] { mailWriter, true, true, CancellationToken.None }); // Decode contents. string result = Encoding.UTF8.GetString(stream.ToArray()); diff --git a/src/libraries/System.Net.Mail/tests/Functional/SmtpClientConnectionTest.cs b/src/libraries/System.Net.Mail/tests/Functional/SmtpClientConnectionTest.cs index 4ae8ccf4d692c8..7c52ba6d72cebc 100644 --- a/src/libraries/System.Net.Mail/tests/Functional/SmtpClientConnectionTest.cs +++ b/src/libraries/System.Net.Mail/tests/Functional/SmtpClientConnectionTest.cs @@ -22,6 +22,17 @@ public async Task SocketClosed() await SendMail(new MailMessage("mono@novell.com", "everyone@novell.com", "introduction", "hello")); } + [Fact] + public async Task UnrecognizedReply_Throws() + { + Server.OnCommandReceived = (command, arg) => + { + return "Go away"; + }; + + await SendMail(new MailMessage("mono@novell.com", "everyone@novell.com", "introduction", "hello")); + } + [Fact] public async Task EHelloNotRecognized_RestartWithHello() { diff --git a/src/libraries/System.Net.Mail/tests/Functional/SmtpClientTest.cs b/src/libraries/System.Net.Mail/tests/Functional/SmtpClientTest.cs index 332b14b3baed78..a3b25b27d790a9 100644 --- a/src/libraries/System.Net.Mail/tests/Functional/SmtpClientTest.cs +++ b/src/libraries/System.Net.Mail/tests/Functional/SmtpClientTest.cs @@ -20,6 +20,7 @@ using Microsoft.DotNet.RemoteExecutor; using System.Net.Test.Common; using Xunit; +using Xunit.Abstractions; namespace System.Net.Mail.Tests { @@ -53,6 +54,13 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); } + ITestOutputHelper _output; + + public SmtpClientTest(ITestOutputHelper output) + { + _output = output; + } + [Theory] [InlineData(SmtpDeliveryMethod.SpecifiedPickupDirectory)] [InlineData(SmtpDeliveryMethod.PickupDirectoryFromIis)] @@ -237,7 +245,7 @@ public async Task SendAsync_ServerDoesntExist_Throws() [Fact] public void TestMailDelivery() { - using var server = new LoopbackSmtpServer(); + using var server = new LoopbackSmtpServer(_output); using SmtpClient client = server.CreateClient(); client.Credentials = new NetworkCredential("foo", "bar"); MailMessage msg = new MailMessage("foo@example.com", "bar@example.com", "hello", "howdydoo"); @@ -282,7 +290,7 @@ public void TestZeroTimeout() [Fact] public void SendMailAsync_CanBeCanceled_CancellationToken_SetAlready() { - using var server = new LoopbackSmtpServer(); + using var server = new LoopbackSmtpServer(_output); using SmtpClient client = server.CreateClient(); CancellationTokenSource cts = new CancellationTokenSource(); @@ -299,7 +307,7 @@ public void SendMailAsync_CanBeCanceled_CancellationToken_SetAlready() [Fact] public async Task SendMailAsync_CanBeCanceled_CancellationToken() { - using var server = new LoopbackSmtpServer(); + using var server = new LoopbackSmtpServer(_output); using SmtpClient client = server.CreateClient(); server.ReceiveMultipleConnections = true; diff --git a/src/libraries/System.Net.Mail/tests/Unit/System.Net.Mail.Unit.Tests.csproj b/src/libraries/System.Net.Mail/tests/Unit/System.Net.Mail.Unit.Tests.csproj index 03708443b2ea80..c59d1ab087d1d6 100644 --- a/src/libraries/System.Net.Mail/tests/Unit/System.Net.Mail.Unit.Tests.csproj +++ b/src/libraries/System.Net.Mail/tests/Unit/System.Net.Mail.Unit.Tests.csproj @@ -110,6 +110,8 @@ Link="ProductionCode\MailHeaderInfo.cs" /> + collection) /// public int Capacity => _array.Length; - /// + /// bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; diff --git a/src/libraries/System.Private.CoreLib/src/System/Double.cs b/src/libraries/System.Private.CoreLib/src/System/Double.cs index fe89ca49146caf..5609339bea4063 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Double.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Double.cs @@ -1944,7 +1944,7 @@ public static double RadiansToDegrees(double radians) /// public static (double Sin, double Cos) SinCos(double x) => Math.SinCos(x); - /// + /// public static (double SinPi, double CosPi) SinCosPi(double x) { // This code is based on `cospi` and `sinpi` from amd/aocl-libm-ose diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs index b4c2b88a42894a..e9e7274565bd6d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs @@ -715,11 +715,11 @@ public static Vector2 LoadUnsafe(ref readonly float source, nuint elementOffset) return Unsafe.ReadUnaligned(in address); } - /// + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Log(Vector2 vector) => Vector128.Log(Vector4.Create(vector, 1.0f, 1.0f).AsVector128()).AsVector2(); - /// + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Log2(Vector2 vector) => Vector128.Log2(Vector4.Create(vector, 1.0f, 1.0f).AsVector128()).AsVector2(); diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs index dd92866c93067e..8a3633ccc42f42 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs @@ -748,11 +748,11 @@ public static Vector3 LoadUnsafe(ref readonly float source, nuint elementOffset) return Unsafe.ReadUnaligned(in address); } - /// + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Log(Vector3 vector) => Vector128.Log(Vector4.Create(vector, 1.0f).AsVector128()).AsVector3(); - /// + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Log2(Vector3 vector) => Vector128.Log2(Vector4.Create(vector, 1.0f).AsVector128()).AsVector3(); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.cs index 238b7b42c06dc4..83c3cd0698b55b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Reflection; using System.Runtime.InteropServices; +using System.Runtime.Versioning; using System.Threading; using System.Threading.Tasks; @@ -19,6 +20,7 @@ public static partial class AsyncHelpers // It will not capture/restore any local state that is live across it. [BypassReadyToRun] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.Async)] + [RequiresPreviewFeatures] public static void AwaitAwaiter(TAwaiter awaiter) where TAwaiter : INotifyCompletion { ref AsyncHelpers.RuntimeAsyncAwaitState state = ref AsyncHelpers.t_runtimeAsyncAwaitState; @@ -34,6 +36,7 @@ public static void AwaitAwaiter(TAwaiter awaiter) where TAwaiter : INo // It will not capture/restore any local state that is live across it. [BypassReadyToRun] [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.Async)] + [RequiresPreviewFeatures] public static void UnsafeAwaitAwaiter(TAwaiter awaiter) where TAwaiter : ICriticalNotifyCompletion { ref AsyncHelpers.RuntimeAsyncAwaitState state = ref AsyncHelpers.t_runtimeAsyncAwaitState; @@ -48,6 +51,7 @@ public static void UnsafeAwaitAwaiter(TAwaiter awaiter) where TAwaiter [Intrinsic] [BypassReadyToRun] [MethodImpl(MethodImplOptions.Async)] + [RequiresPreviewFeatures] public static T Await(Task task) { TaskAwaiter awaiter = task.GetAwaiter(); @@ -62,6 +66,7 @@ public static T Await(Task task) [Intrinsic] [BypassReadyToRun] [MethodImpl(MethodImplOptions.Async)] + [RequiresPreviewFeatures] public static void Await(Task task) { TaskAwaiter awaiter = task.GetAwaiter(); @@ -76,6 +81,7 @@ public static void Await(Task task) [Intrinsic] [BypassReadyToRun] [MethodImpl(MethodImplOptions.Async)] + [RequiresPreviewFeatures] public static T Await(ValueTask task) { ValueTaskAwaiter awaiter = task.GetAwaiter(); @@ -90,6 +96,7 @@ public static T Await(ValueTask task) [Intrinsic] [BypassReadyToRun] [MethodImpl(MethodImplOptions.Async)] + [RequiresPreviewFeatures] public static void Await(ValueTask task) { ValueTaskAwaiter awaiter = task.GetAwaiter(); @@ -104,6 +111,7 @@ public static void Await(ValueTask task) [Intrinsic] [BypassReadyToRun] [MethodImpl(MethodImplOptions.Async)] + [RequiresPreviewFeatures] public static void Await(ConfiguredTaskAwaitable configuredAwaitable) { ConfiguredTaskAwaitable.ConfiguredTaskAwaiter awaiter = configuredAwaitable.GetAwaiter(); @@ -118,6 +126,7 @@ public static void Await(ConfiguredTaskAwaitable configuredAwaitable) [Intrinsic] [BypassReadyToRun] [MethodImpl(MethodImplOptions.Async)] + [RequiresPreviewFeatures] public static void Await(ConfiguredValueTaskAwaitable configuredAwaitable) { ConfiguredValueTaskAwaitable.ConfiguredValueTaskAwaiter awaiter = configuredAwaitable.GetAwaiter(); @@ -132,6 +141,7 @@ public static void Await(ConfiguredValueTaskAwaitable configuredAwaitable) [Intrinsic] [BypassReadyToRun] [MethodImpl(MethodImplOptions.Async)] + [RequiresPreviewFeatures] public static T Await(ConfiguredTaskAwaitable configuredAwaitable) { ConfiguredTaskAwaitable.ConfiguredTaskAwaiter awaiter = configuredAwaitable.GetAwaiter(); @@ -146,6 +156,7 @@ public static T Await(ConfiguredTaskAwaitable configuredAwaitable) [Intrinsic] [BypassReadyToRun] [MethodImpl(MethodImplOptions.Async)] + [RequiresPreviewFeatures] public static T Await(ConfiguredValueTaskAwaitable configuredAwaitable) { ConfiguredValueTaskAwaitable.ConfiguredValueTaskAwaiter awaiter = configuredAwaitable.GetAwaiter(); @@ -157,15 +168,25 @@ public static T Await(ConfiguredValueTaskAwaitable configuredAwaitable) return awaiter.GetResult(); } #else + [RequiresPreviewFeatures] public static void UnsafeAwaitAwaiter(TAwaiter awaiter) where TAwaiter : ICriticalNotifyCompletion { throw new NotImplementedException(); } + [RequiresPreviewFeatures] public static void AwaitAwaiter(TAwaiter awaiter) where TAwaiter : INotifyCompletion { throw new NotImplementedException(); } + [RequiresPreviewFeatures] public static void Await(System.Threading.Tasks.Task task) { throw new NotImplementedException(); } + [RequiresPreviewFeatures] public static T Await(System.Threading.Tasks.Task task) { throw new NotImplementedException(); } + [RequiresPreviewFeatures] public static void Await(System.Threading.Tasks.ValueTask task) { throw new NotImplementedException(); } + [RequiresPreviewFeatures] public static T Await(System.Threading.Tasks.ValueTask task) { throw new NotImplementedException(); } + [RequiresPreviewFeatures] public static void Await(System.Runtime.CompilerServices.ConfiguredTaskAwaitable configuredAwaitable) { throw new NotImplementedException(); } + [RequiresPreviewFeatures] public static void Await(System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable configuredAwaitable) { throw new NotImplementedException(); } + [RequiresPreviewFeatures] public static T Await(System.Runtime.CompilerServices.ConfiguredTaskAwaitable configuredAwaitable) { throw new NotImplementedException(); } + [RequiresPreviewFeatures] public static T Await(System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable configuredAwaitable) { throw new NotImplementedException(); } #endif } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeFeature.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeFeature.cs index c3c9e8a8fe191a..eb6afdf66d1512 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeFeature.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeFeature.cs @@ -54,7 +54,15 @@ public static bool IsSupported(string feature) { return feature switch { - PortablePdb or CovariantReturnsOfClasses or ByRefFields or ByRefLikeGenerics or UnmanagedSignatureCallingConvention or DefaultImplementationsOfInterfaces or VirtualStaticsInInterfaces or NumericIntPtr => true, + PortablePdb or + CovariantReturnsOfClasses or + ByRefFields or + ByRefLikeGenerics or + UnmanagedSignatureCallingConvention or + DefaultImplementationsOfInterfaces or + VirtualStaticsInInterfaces or + NumericIntPtr => true, + nameof(IsDynamicCodeSupported) => IsDynamicCodeSupported, nameof(IsDynamicCodeCompiled) => IsDynamicCodeCompiled, _ => false, diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs index 5e2fb905df195c..d542d13b39f07a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs @@ -1247,7 +1247,7 @@ bool IFloatingPoint.TryWriteSignificandLittleEndian(Span destinati /// public static NFloat Clamp(NFloat value, NFloat min, NFloat max) => new NFloat(NativeType.Clamp(value._value, min._value, max._value)); - /// + /// public static NFloat ClampNative(NFloat value, NFloat min, NFloat max) => new NFloat(NativeType.ClampNative(value._value, min._value, max._value)); /// @@ -1889,7 +1889,7 @@ public static (NFloat Sin, NFloat Cos) SinCos(NFloat x) return (new NFloat(sin), new NFloat(cos)); } - /// + /// public static (NFloat SinPi, NFloat CosPi) SinCosPi(NFloat x) { var (sinPi, cosPi) = NativeType.SinCosPi(x._value); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs index e8a8abe86edbbf..c5d877a3be0562 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs @@ -3743,7 +3743,7 @@ public static Vector128 Sin(Vector128 vector) } } - /// + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (Vector128 Sin, Vector128 Cos) SinCos(Vector128 vector) { @@ -3763,7 +3763,7 @@ public static (Vector128 Sin, Vector128 Cos) SinCos(Vector128 + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (Vector128 Sin, Vector128 Cos) SinCos(Vector128 vector) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs index 5387d20943313f..8f8580a1fb11c9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs @@ -3735,7 +3735,7 @@ public static Vector256 Sin(Vector256 vector) } } - /// + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (Vector256 Sin, Vector256 Cos) SinCos(Vector256 vector) { @@ -3755,7 +3755,7 @@ public static (Vector256 Sin, Vector256 Cos) SinCos(Vector256 + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (Vector256 Sin, Vector256 Cos) SinCos(Vector256 vector) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs index c2811af824930d..29b10dba0310aa 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs @@ -3753,7 +3753,7 @@ public static Vector512 Sin(Vector512 vector) } } - /// + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (Vector512 Sin, Vector512 Cos) SinCos(Vector512 vector) { @@ -3773,7 +3773,7 @@ public static (Vector512 Sin, Vector512 Cos) SinCos(Vector512 + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (Vector512 Sin, Vector512 Cos) SinCos(Vector512 vector) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs index e3e4d8c1f55344..68e99650be094e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs @@ -528,7 +528,7 @@ private string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] stri /// static int ISimdVector, T>.Alignment => Vector64.Alignment; - /// + /// static int ISimdVector, T>.ElementCount => Vector64.Count; /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Single.cs b/src/libraries/System.Private.CoreLib/src/System/Single.cs index ce37952076f6b8..400ec426cb9bc2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Single.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Single.cs @@ -1860,7 +1860,7 @@ public static float RadiansToDegrees(float radians) /// public static (float Sin, float Cos) SinCos(float x) => MathF.SinCos(x); - /// + /// public static (float SinPi, float CosPi) SinCosPi(float x) { // This code is based on `cospif` and `sinpif` from amd/aocl-libm-ose diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index ddbfd6ae5682ae..89a5c81e868e40 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -13833,15 +13833,25 @@ public static void RunModuleConstructor(System.ModuleHandle module) { } [System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5007", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] public static partial class AsyncHelpers { + [System.Runtime.Versioning.RequiresPreviewFeaturesAttribute] public static void UnsafeAwaitAwaiter(TAwaiter awaiter) where TAwaiter : ICriticalNotifyCompletion { } + [System.Runtime.Versioning.RequiresPreviewFeaturesAttribute] public static void AwaitAwaiter(TAwaiter awaiter) where TAwaiter : INotifyCompletion { } + [System.Runtime.Versioning.RequiresPreviewFeaturesAttribute] public static void Await(System.Threading.Tasks.Task task) { throw null; } + [System.Runtime.Versioning.RequiresPreviewFeaturesAttribute] public static T Await(System.Threading.Tasks.Task task) { throw null; } + [System.Runtime.Versioning.RequiresPreviewFeaturesAttribute] public static void Await(System.Threading.Tasks.ValueTask task) { throw null; } + [System.Runtime.Versioning.RequiresPreviewFeaturesAttribute] public static T Await(System.Threading.Tasks.ValueTask task) { throw null; } + [System.Runtime.Versioning.RequiresPreviewFeaturesAttribute] public static void Await(System.Runtime.CompilerServices.ConfiguredTaskAwaitable configuredAwaitable) { throw null; } + [System.Runtime.Versioning.RequiresPreviewFeaturesAttribute] public static void Await(System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable configuredAwaitable) { throw null; } + [System.Runtime.Versioning.RequiresPreviewFeaturesAttribute] public static T Await(System.Runtime.CompilerServices.ConfiguredTaskAwaitable configuredAwaitable) { throw null; } + [System.Runtime.Versioning.RequiresPreviewFeaturesAttribute] public static T Await(System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable configuredAwaitable) { throw null; } } public sealed partial class RuntimeWrappedException : System.Exception diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/PrivateKeyAssociationTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/PrivateKeyAssociationTests.cs index 43c94066ee63b7..6ef1d73f8e1d55 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/PrivateKeyAssociationTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/PrivateKeyAssociationTests.cs @@ -751,98 +751,14 @@ public static void CheckCopyWithPrivateKey_MLDSA() } } - [ConditionalFact(typeof(MLKem), nameof(MLKem.IsSupported))] - public static void CheckCopyWithPrivateKey_MLKem() - { - using (X509Certificate2 pubOnly = X509Certificate2.CreateFromPem(MLKemTestData.IetfMlKem512CertificatePem)) - using (MLKem privKey = MLKem.ImportPkcs8PrivateKey(MLKemTestData.IetfMlKem512PrivateKeySeed)) - using (X509Certificate2 wrongAlg = X509CertificateLoader.LoadCertificate(TestData.CertWithEnhancedKeyUsage)) - { - CheckCopyWithPrivateKey( - pubOnly, - wrongAlg, - privKey, - [ - () => MLKem.GenerateKey(MLKemAlgorithm.MLKem512), - () => MLKem.GenerateKey(MLKemAlgorithm.MLKem768), - () => MLKem.GenerateKey(MLKemAlgorithm.MLKem1024), - ], - (cert, key) => cert.CopyWithPrivateKey(key), - cert => cert.GetMLKemPublicKey(), - cert => cert.GetMLKemPrivateKey(), - (priv, pub) => - { - pub.Encapsulate(out byte[] ciphertext, out byte[] pubSharedSecret); - byte[] privSharedSecret = priv.Decapsulate(ciphertext); - AssertExtensions.SequenceEqual(pubSharedSecret, privSharedSecret); - }); - } - } - - [ConditionalFact(typeof(MLKem), nameof(MLKem.IsSupported))] - public static void CheckCopyWithPrivateKey_MLKem_OtherMLKem_Seed() - { - using (X509Certificate2 pubOnly = X509Certificate2.CreateFromPem(MLKemTestData.IetfMlKem512CertificatePem)) - using (MLKemContract contract = new(MLKemAlgorithm.MLKem512)) - { - contract.OnExportPrivateSeedCore = (Span source) => - { - MLKemTestData.IncrementalSeed.CopyTo(source); - }; - - contract.OnExportEncapsulationKeyCore = (Span source) => - { - PublicKey publicKey = PublicKey.CreateFromSubjectPublicKeyInfo(MLKemTestData.IetfMlKem512Spki, out _); - publicKey.EncodedKeyValue.RawData.AsSpan().CopyTo(source); - }; - - using (X509Certificate2 cert = pubOnly.CopyWithPrivateKey(contract)) - { - AssertExtensions.TrueExpression(cert.HasPrivateKey); - - using (MLKem kem = cert.GetMLKemPrivateKey()) - { - AssertExtensions.SequenceEqual(MLKemTestData.IncrementalSeed, kem.ExportPrivateSeed()); - } - } - } - } - - [ConditionalFact(typeof(MLKem), nameof(MLKem.IsSupported))] - public static void CheckCopyWithPrivateKey_MLKem_OtherMLKem_DecapsulationKey() - { - using (X509Certificate2 pubOnly = X509Certificate2.CreateFromPem(MLKemTestData.IetfMlKem512CertificatePem)) - using (MLKemContract contract = new(MLKemAlgorithm.MLKem512)) - { - contract.OnExportPrivateSeedCore = (Span source) => - { - throw new CryptographicException("Should signal to try decaps key"); - }; - - contract.OnExportDecapsulationKeyCore = (Span source) => - { - MLKemTestData.IetfMlKem512PrivateKeyDecapsulationKey.AsSpan().CopyTo(source); - }; - - contract.OnExportEncapsulationKeyCore = (Span source) => - { - PublicKey publicKey = PublicKey.CreateFromSubjectPublicKeyInfo(MLKemTestData.IetfMlKem512Spki, out _); - publicKey.EncodedKeyValue.RawData.AsSpan().CopyTo(source); - }; + private static partial Func CopyWithPrivateKey_MLKem => + (cert, key) => cert.CopyWithPrivateKey(key); - using (X509Certificate2 cert = pubOnly.CopyWithPrivateKey(contract)) - { - AssertExtensions.TrueExpression(cert.HasPrivateKey); + private static partial Func GetMLKemPublicKey => + cert => cert.GetMLKemPublicKey(); - using (MLKem kem = cert.GetMLKemPrivateKey()) - { - AssertExtensions.SequenceEqual( - MLKemTestData.IetfMlKem512PrivateKeyDecapsulationKey, - kem.ExportDecapsulationKey()); - } - } - } - } + private static partial Func GetMLKemPrivateKey => + cert => cert.GetMLKemPrivateKey(); private static partial Func CopyWithPrivateKey_SlhDsa => (cert, key) => cert.CopyWithPrivateKey(key); diff --git a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs index dea63b89318d9e..931b7976199f31 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs +++ b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs @@ -1817,8 +1817,6 @@ void EmitSwitchedBranches() writer.Indent++; // Emit the code for the branch, without the first character that was already matched in the switch. - RegexNode? remainder = null; - HandleChild: switch (child.Kind) { case RegexNodeKind.One: @@ -1830,9 +1828,7 @@ void EmitSwitchedBranches() case RegexNodeKind.Multi: // First character was handled by the switch. Emit matching code for the remainder of the multi string. sliceStaticPos++; - EmitNode(child.Str!.Length == 2 ? - new RegexNode(RegexNodeKind.One, child.Options, child.Str![1]) : - new RegexNode(RegexNodeKind.Multi, child.Options, child.Str!.Substring(1))); + EmitNode(SliceOffMultiFirstChar(child)); writer.WriteLine(); break; @@ -1840,25 +1836,31 @@ void EmitSwitchedBranches() // This is a concatenation where its first node is the starting literal we found and that starting literal // is one of the nodes above that we know how to handle completely. This is a common // enough case that we want to special-case it to avoid duplicating the processing for that character - // unnecessarily. So, we'll shave off that first node from the concatenation and then handle the remainder. - // Note that it's critical startingLiteralNode is something we can fully handle above: if it's not, - // we'll end up losing some of the pattern due to overwriting `remainder`. - remainder = child; - child = child.Child(0); - remainder.ReplaceChild(0, new RegexNode(RegexNodeKind.Empty, remainder.Options)); - goto HandleChild; // reprocess just the first node that was saved; the remainder will then be processed below + // unnecessarily. First slice off the first character that was already handled. If that child is a multi, temporarily + // replace it with a node that doesn't have the already-matched first character; otherwise, replace it with an empty node + // that'll be ignored when rendered. Then emit the new tree, and subsequently restore the original child. + sliceStaticPos++; + RegexNode originalFirst = child.Child(0); + child.ReplaceChild(0, + child.Child(0).Kind is RegexNodeKind.Multi ? + SliceOffMultiFirstChar(child.Child(0)) : // multi, so slice off the first character + new RegexNode(RegexNodeKind.Empty, child.Options)); // single, so removing it yields empty + try + { - default: - Debug.Assert(remainder is null); - remainder = child; + EmitNode(child); + } + finally + { + child.ReplaceChild(0, originalFirst); + } + writer.WriteLine(); break; - } - if (remainder is not null) - { - // Emit a full match for whatever part of the child we haven't yet handled. - EmitNode(remainder); - writer.WriteLine(); + default: + EmitNode(child); + writer.WriteLine(); + break; } // This is only ever used for atomic alternations, so we can simply reset the doneLabel @@ -1882,6 +1884,14 @@ void EmitSwitchedBranches() } } + static RegexNode SliceOffMultiFirstChar(RegexNode multi) + { + Debug.Assert(multi.Kind is RegexNodeKind.Multi, $"Expected a Multi node, got {multi.Kind}"); + return multi.Str!.Length == 2 ? + new(RegexNodeKind.One, multi.Options, multi.Str[1]) : + new(RegexNodeKind.Multi, multi.Options, multi.Str.Substring(1)); + } + void EmitAllBranches() { // Label to jump to when any branch completes successfully. diff --git a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorOutputTests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorOutputTests.cs index 57d4232ee1ed18..e8896708277097 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorOutputTests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/RegexGeneratorOutputTests.cs @@ -754,7 +754,7 @@ void UncaptureUntil(int capturePosition) } /// Helper methods used by generated -derived implementations. - [GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "42.42.42.42")] + [GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "%VERSION%")] file static class Utilities { /// Supports searching for the string "href". @@ -930,6 +930,206 @@ file static class Utilities } """ }; + + yield return new object[] + { + """ + using System.Text.RegularExpressions; + partial class C + { + [GeneratedRegex(@"abcd*e|f")] + public static partial Regex Valid(); + } + """, + + """ + // + #nullable enable + #pragma warning disable CS0162 // Unreachable code + #pragma warning disable CS0164 // Unreferenced label + #pragma warning disable CS0219 // Variable assigned but never used + + partial class C + { + /// + /// Pattern:
+ /// abcd*e|f
+ /// Explanation:
+ /// + /// â—‹ Match with 2 alternative expressions, atomically.
+ /// â—‹ Match a sequence of expressions.
+ /// â—‹ Match the string "abc".
+ /// â—‹ Match 'd' atomically any number of times.
+ /// â—‹ Match 'e'.
+ /// â—‹ Match 'f'.
+ ///
+ ///
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "%VERSION%")] + public static partial global::System.Text.RegularExpressions.Regex Valid() => global::System.Text.RegularExpressions.Generated.Valid_0.Instance; + } + + namespace System.Text.RegularExpressions.Generated + { + using System; + using System.Buffers; + using System.CodeDom.Compiler; + using System.Collections; + using System.ComponentModel; + using System.Globalization; + using System.Runtime.CompilerServices; + using System.Text.RegularExpressions; + using System.Threading; + + /// Custom -derived type for the Valid method. + [GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "%VERSION%")] + [SkipLocalsInit] + file sealed class Valid_0 : Regex + { + /// Cached, thread-safe singleton instance. + internal static readonly Valid_0 Instance = new(); + + /// Initializes the instance. + private Valid_0() + { + base.pattern = "abcd*e|f"; + base.roptions = RegexOptions.None; + ValidateMatchTimeout(Utilities.s_defaultTimeout); + base.internalMatchTimeout = Utilities.s_defaultTimeout; + base.factory = new RunnerFactory(); + base.capsize = 1; + } + + /// Provides a factory for creating instances to be used by methods on . + private sealed class RunnerFactory : RegexRunnerFactory + { + /// Creates an instance of a used by methods on . + protected override RegexRunner CreateInstance() => new Runner(); + + /// Provides the runner that contains the custom logic implementing the specified regular expression. + private sealed class Runner : RegexRunner + { + /// Scan the starting from base.runtextstart for the next match. + /// The text being scanned by the regular expression. + protected override void Scan(ReadOnlySpan inputSpan) + { + // Search until we can't find a valid starting position, we find a match, or we reach the end of the input. + while (TryFindNextPossibleStartingPosition(inputSpan) && + !TryMatchAtCurrentPosition(inputSpan) && + base.runtextpos != inputSpan.Length) + { + base.runtextpos++; + if (Utilities.s_hasTimeout) + { + base.CheckTimeout(); + } + } + } + + /// Search starting from base.runtextpos for the next location a match could possibly start. + /// The text being scanned by the regular expression. + /// true if a possible match was found; false if no more matches are possible. + private bool TryFindNextPossibleStartingPosition(ReadOnlySpan inputSpan) + { + int pos = base.runtextpos; + + // Empty matches aren't possible. + if ((uint)pos < (uint)inputSpan.Length) + { + // The pattern begins with a character in the set [af]. + // Find the next occurrence. If it can't be found, there's no match. + int i = inputSpan.Slice(pos).IndexOfAny('a', 'f'); + if (i >= 0) + { + base.runtextpos = pos + i; + return true; + } + } + + // No match found. + base.runtextpos = inputSpan.Length; + return false; + } + + /// Determine whether at base.runtextpos is a match for the regular expression. + /// The text being scanned by the regular expression. + /// true if the regular expression matches at the current position; otherwise, false. + private bool TryMatchAtCurrentPosition(ReadOnlySpan inputSpan) + { + int pos = base.runtextpos; + int matchStart = pos; + ReadOnlySpan slice = inputSpan.Slice(pos); + + // Match with 2 alternative expressions, atomically. + { + if (slice.IsEmpty) + { + return false; // The input didn't match. + } + + switch (slice[0]) + { + case 'a': + // Match the string "bc". + if (!slice.Slice(1).StartsWith("bc")) + { + return false; // The input didn't match. + } + + // Match 'd' atomically any number of times. + { + int iteration = slice.Slice(3).IndexOfAnyExcept('d'); + if (iteration < 0) + { + iteration = slice.Length - 3; + } + + slice = slice.Slice(iteration); + pos += iteration; + } + + // Match 'e'. + if ((uint)slice.Length < 4 || slice[3] != 'e') + { + return false; // The input didn't match. + } + + pos += 4; + slice = inputSpan.Slice(pos); + break; + + case 'f': + pos++; + slice = inputSpan.Slice(pos); + break; + + default: + return false; // The input didn't match. + } + } + + // The input matched. + base.runtextpos = pos; + base.Capture(0, matchStart, pos); + return true; + } + } + } + + } + + /// Helper methods used by generated -derived implementations. + [GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "%VERSION%")] + file static class Utilities + { + /// Default timeout value set in , or if none was set. + internal static readonly TimeSpan s_defaultTimeout = AppContext.GetData("REGEX_DEFAULT_MATCH_TIMEOUT") is TimeSpan timeout ? timeout : Regex.InfiniteMatchTimeout; + + /// Whether is non-infinite. + internal static readonly bool s_hasTimeout = s_defaultTimeout != Regex.InfiniteMatchTimeout; + } + } + """ + }; } } } diff --git a/src/mono/browser/build/BrowserWasmApp.targets b/src/mono/browser/build/BrowserWasmApp.targets index acf09e80e69440..208ce20563d2d3 100644 --- a/src/mono/browser/build/BrowserWasmApp.targets +++ b/src/mono/browser/build/BrowserWasmApp.targets @@ -321,7 +321,6 @@ <_EmccCommonFlags Include="$(_DefaultEmccFlags)" /> <_EmccCommonFlags Include="$(EmccFlags)" /> - <_EmccCommonFlags Include="-g" Condition="'$(WasmNativeStrip)' == 'false'" /> <_EmccCommonFlags Include="-v" Condition="'$(EmccVerbose)' != 'false'" /> <_EmccCommonFlags Include="-s DISABLE_EXCEPTION_CATCHING=0" Condition="'$(WasmEnableExceptionHandling)' == 'false'" /> <_EmccCommonFlags Include="-fwasm-exceptions" Condition="'$(WasmEnableExceptionHandling)' == 'true'" /> diff --git a/src/mono/browser/runtime/jiterpreter-opcodes.ts b/src/mono/browser/runtime/jiterpreter-opcodes.ts index 974bbaf5233c45..4d3ab5c3930f1c 100644 --- a/src/mono/browser/runtime/jiterpreter-opcodes.ts +++ b/src/mono/browser/runtime/jiterpreter-opcodes.ts @@ -289,6 +289,7 @@ export const enum WasmSimdOpcode { v128_const = 0x0c, i8x16_shuffle = 0x0d, i8x16_swizzle = 0x0e, + i8x16_relaxed_swizzle = 0x100, i8x16_splat = 0x0f, i16x8_splat = 0x10, i32x4_splat = 0x11, @@ -466,6 +467,8 @@ export const enum WasmSimdOpcode { f64x2_pmax = 0xf7, i32x4_trunc_sat_f32x4_s = 0xf8, i32x4_trunc_sat_f32x4_u = 0xf9, + i32x4_relaxed_trunc_f32x4_s = 0x101, + i32x4_relaxed_trunc_f32x4_u = 0x102, f32x4_convert_i32x4_s = 0xfa, f32x4_convert_i32x4_u = 0xfb, v128_load32_zero = 0x5c, @@ -483,6 +486,7 @@ export const enum WasmSimdOpcode { i64x2_extmul_low_i32x4_u = 0xde, i64x2_extmul_high_i32x4_u = 0xdf, i16x8_q15mulr_sat_s = 0x82, + i16x8_relaxed_q15mulr_sat_s = 0x111, v128_any_true = 0x53, v128_load8_lane = 0x54, v128_load16_lane = 0x55, @@ -503,6 +507,8 @@ export const enum WasmSimdOpcode { f64x2_convert_low_i32x4_u = 0xff, i32x4_trunc_sat_f64x2_s_zero = 0xfc, i32x4_trunc_sat_f64x2_u_zero = 0xfd, + i32x4_relaxed_trunc_f64_s_zero = 0x103, + i32x4_relaxed_trunc_f64_u_zero = 0x104, f32x4_demote_f64x2_zero = 0x5e, f64x2_promote_low_f32x4 = 0x5f, i8x16_popcnt = 0x62, @@ -510,6 +516,21 @@ export const enum WasmSimdOpcode { i16x8_extadd_pairwise_i8x16_u = 0x7d, i32x4_extadd_pairwise_i16x8_s = 0x7e, i32x4_extadd_pairwise_i16x8_u = 0x7f, + f32x4_relaxed_madd = 0x105, + f32x4_relaxed_mnadd = 0x106, + f64x2_relaxed_madd = 0x107, + f64x2_relaxed_mnadd = 0x108, + i8x16_relaxed_lane_select = 0x109, + i16x8_relaxed_lane_select = 0x10a, + i32x4_relaxed_lane_select = 0x10b, + i64x2_relaxed_lane_select = 0x10c, + f32x4_relaxed_min = 0x10d, + f32x4_relaxed_max = 0x10e, + f64x2_relaxed_min = 0x10f, + f64x2_relaxed_max = 0x110, + i16x8_relaxed_dot_i8x16_i7x16_s = 0x112, + i16x8_relaxed_dot_i8x16_i7x16_u = 0x113, + i32x4_relaxed_dot_i8x16_i7x16_s = 0x114, } export const enum WasmAtomicOpcode { diff --git a/src/mono/browser/runtime/jiterpreter-trace-generator.ts b/src/mono/browser/runtime/jiterpreter-trace-generator.ts index 8da5b65fad7044..0d619286bea9e8 100644 --- a/src/mono/browser/runtime/jiterpreter-trace-generator.ts +++ b/src/mono/browser/runtime/jiterpreter-trace-generator.ts @@ -3919,7 +3919,11 @@ function emit_shuffle (builder: WasmBuilder, ip: MintOpcodePtr, elementCount: nu for (let j = 0; j < elementSize; j++) builder.appendU8(i); } - builder.appendSimd(WasmSimdOpcode.i8x16_swizzle); + if (runtimeHelpers.featureWasmRelaxedSimd) { + builder.appendSimd(WasmSimdOpcode.i8x16_relaxed_swizzle); + } else { + builder.appendSimd(WasmSimdOpcode.i8x16_swizzle); + } // multiply indices by 2 or 4 to scale from elt indices to byte indices builder.i32_const(elementCount === 4 ? 2 : 1); builder.appendSimd(WasmSimdOpcode.i8x16_shl); diff --git a/src/mono/browser/runtime/loader/globals.ts b/src/mono/browser/runtime/loader/globals.ts index 962d8631cd7c7f..249af3ae84315e 100644 --- a/src/mono/browser/runtime/loader/globals.ts +++ b/src/mono/browser/runtime/loader/globals.ts @@ -4,7 +4,7 @@ /* eslint-disable @typescript-eslint/triple-slash-reference */ /// -import { exceptions, simd } from "wasm-feature-detect"; +import { exceptions, simd, relaxedSimd } from "wasm-feature-detect"; import gitHash from "consts:gitHash"; @@ -133,6 +133,7 @@ export function setLoaderGlobals ( // from wasm-feature-detect npm package exceptions, simd, + relaxedSimd }; Object.assign(runtimeHelpers, rh); Object.assign(loaderHelpers, lh); diff --git a/src/mono/browser/runtime/startup.ts b/src/mono/browser/runtime/startup.ts index 325caeb4cd1a98..be98bde435d3e5 100644 --- a/src/mono/browser/runtime/startup.ts +++ b/src/mono/browser/runtime/startup.ts @@ -519,8 +519,12 @@ async function instantiate_wasm_module ( } async function ensureUsedWasmFeatures () { - runtimeHelpers.featureWasmSimd = await loaderHelpers.simd(); - runtimeHelpers.featureWasmEh = await loaderHelpers.exceptions(); + const simd = loaderHelpers.simd(); + const relaxedSimd = loaderHelpers.relaxedSimd(); + const exceptions = loaderHelpers.exceptions(); + runtimeHelpers.featureWasmSimd = await simd; + runtimeHelpers.featureWasmRelaxedSimd = await relaxedSimd; + runtimeHelpers.featureWasmEh = await exceptions; if (runtimeHelpers.emscriptenBuildOptions.wasmEnableSIMD) { mono_assert(runtimeHelpers.featureWasmSimd, "This browser/engine doesn't support WASM SIMD. Please use a modern version. See also https://aka.ms/dotnet-wasm-features"); } diff --git a/src/mono/browser/runtime/types/internal.ts b/src/mono/browser/runtime/types/internal.ts index 5e132209563ee8..9d5bdc73978754 100644 --- a/src/mono/browser/runtime/types/internal.ts +++ b/src/mono/browser/runtime/types/internal.ts @@ -179,6 +179,7 @@ export type LoaderHelpers = { // from wasm-feature-detect npm package exceptions: () => Promise, simd: () => Promise, + relaxedSimd: () => Promise, } export type RuntimeHelpers = { emscriptenBuildOptions: EmscriptenBuildOptions, @@ -232,6 +233,7 @@ export type RuntimeHelpers = { featureWasmEh: boolean, featureWasmSimd: boolean, + featureWasmRelaxedSimd: boolean, //core stringify_as_error_with_stack?: (error: any) => string, diff --git a/src/native/libs/System.Globalization.Native/CMakeLists.txt b/src/native/libs/System.Globalization.Native/CMakeLists.txt index 496bdb0d33e5cd..e3fa46ac9bc3ec 100644 --- a/src/native/libs/System.Globalization.Native/CMakeLists.txt +++ b/src/native/libs/System.Globalization.Native/CMakeLists.txt @@ -127,7 +127,7 @@ if (CLR_CMAKE_TARGET_APPLE) endif() # time zone names are filtered out of icu data for the browser and associated functionality is disabled -if (NOT CLR_CMAKE_TARGET_BROWSER AND NOT CLR_CMAKE_TARGET_WASI AND NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS) +if (NOT CLR_CMAKE_TARGET_BROWSER AND NOT CLR_CMAKE_TARGET_WASI AND NOT CLR_CMAKE_TARGET_MACCATALYST AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS) set(NATIVEGLOBALIZATION_SOURCES ${NATIVEGLOBALIZATION_SOURCES} pal_timeZoneInfo.c) endif() @@ -192,6 +192,9 @@ if(CLR_CMAKE_TARGET_UNIX OR CLR_CMAKE_TARGET_WASI) endif() install (TARGETS System.Globalization.Native-Static DESTINATION ${STATIC_LIB_DESTINATION} COMPONENT libs) +if(CLR_CMAKE_HOST_ANDROID) + install (TARGETS System.Globalization.Native-Static DESTINATION sharedFramework COMPONENT runtime) +endif() if(NOT CLR_CMAKE_TARGET_WIN32 AND NOT CLR_CMAKE_TARGET_APPLE AND NOT CLR_CMAKE_TARGET_ANDROID AND NOT CLR_CMAKE_TARGET_LINUX_MUSL AND NOT CLR_CMAKE_TARGET_HAIKU) if (GEN_SHARED_LIB) diff --git a/src/native/libs/System.IO.Compression.Native/CMakeLists.txt b/src/native/libs/System.IO.Compression.Native/CMakeLists.txt index 51320228df5ea5..e7cf0355e362c0 100644 --- a/src/native/libs/System.IO.Compression.Native/CMakeLists.txt +++ b/src/native/libs/System.IO.Compression.Native/CMakeLists.txt @@ -210,3 +210,7 @@ else () endif () install (TARGETS System.IO.Compression.Native-Static DESTINATION ${STATIC_LIB_DESTINATION} COMPONENT libs) + +if(CLR_CMAKE_HOST_ANDROID) + install (TARGETS System.IO.Compression.Native-Static DESTINATION sharedFramework COMPONENT runtime) +endif() diff --git a/src/native/libs/System.Native/CMakeLists.txt b/src/native/libs/System.Native/CMakeLists.txt index 7712f255602028..1407d50e04d2c3 100644 --- a/src/native/libs/System.Native/CMakeLists.txt +++ b/src/native/libs/System.Native/CMakeLists.txt @@ -138,3 +138,7 @@ add_library(System.Native-Static set_target_properties(System.Native-Static PROPERTIES OUTPUT_NAME System.Native CLEAN_DIRECT_OUTPUT 1) install (TARGETS System.Native-Static DESTINATION ${STATIC_LIB_DESTINATION} COMPONENT libs) + +if(CLR_CMAKE_HOST_ANDROID) + install (TARGETS System.Native-Static DESTINATION sharedFramework COMPONENT runtime) +endif() diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/CMakeLists.txt b/src/native/libs/System.Security.Cryptography.Native.Android/CMakeLists.txt index 033378d2ee00ae..f860bc26f819a2 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/CMakeLists.txt +++ b/src/native/libs/System.Security.Cryptography.Native.Android/CMakeLists.txt @@ -57,3 +57,7 @@ if (GEN_SHARED_LIB) endif() install (TARGETS System.Security.Cryptography.Native.Android-Static DESTINATION ${STATIC_LIB_DESTINATION} COMPONENT libs) + +if(CLR_CMAKE_HOST_ANDROID) + install (TARGETS System.Security.Cryptography.Native.Android-Static DESTINATION sharedFramework COMPONENT runtime) +endif() diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/Unwinder.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/Unwinder.cs index 925d8d75d8ba0c..617c02af49b0e4 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/Unwinder.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/Unwinder.cs @@ -146,11 +146,16 @@ private static unsafe void GetStackWalkInfo(ulong controlPC, void* pUnwindInfoBa { if (eman.GetCodeBlockHandle(controlPC) is CodeBlockHandle cbh) { - TargetPointer methodDesc = eman.GetMethodDesc(cbh); - TargetPointer unwindInfoBase = eman.GetUnwindInfoBaseAddress(cbh); - TargetPointer unwindInfo = eman.GetUnwindInfo(cbh, controlPC); - if ((nuint)pUnwindInfoBase != 0) *(nuint*)pUnwindInfoBase = (nuint)unwindInfoBase.Value; - if ((nuint)pFuncEntry != 0) *(nuint*)pFuncEntry = (nuint)unwindInfo.Value; + if ((nuint)pUnwindInfoBase != 0) + { + TargetPointer unwindInfoBase = eman.GetUnwindInfoBaseAddress(cbh); + *(nuint*)pUnwindInfoBase = (nuint)unwindInfoBase.Value; + } + if ((nuint)pFuncEntry != 0) + { + TargetPointer unwindInfo = eman.GetUnwindInfo(cbh, controlPC); + *(nuint*)pFuncEntry = (nuint)unwindInfo.Value; + } } } catch (System.Exception ex) diff --git a/src/tasks/AndroidAppBuilder/ApkBuilder.cs b/src/tasks/AndroidAppBuilder/ApkBuilder.cs index 9dc90501b0fe14..9944e69d31e469 100644 --- a/src/tasks/AndroidAppBuilder/ApkBuilder.cs +++ b/src/tasks/AndroidAppBuilder/ApkBuilder.cs @@ -310,21 +310,23 @@ public ApkBuilder(TaskLoggingHelper logger) // due to circular dependency. nativeLibraries += $" {runtimeLib}{Environment.NewLine}"; } - } - if (StaticLinkedRuntime && IsCoreCLR) - { - string[] staticLibs = Directory.GetFiles(AppDir, "*.a") - .Where(lib => !Path.GetFileName(lib).Equals("libcoreclr_static.a", StringComparison.OrdinalIgnoreCase)) - .ToArray(); - - foreach (string lib in staticLibs) + if (StaticLinkedRuntime && IsCoreCLR) { - nativeLibraries += $" {lib}{Environment.NewLine}"; - } + string[] staticMonoStubs = Directory.GetFiles(AppDir, "libmono*.a"); + string[] staticLibs = Directory.GetFiles(AppDir, "*.a") + .Where(lib => !Path.GetFileName(lib).Equals("libcoreclr_static.a", StringComparison.OrdinalIgnoreCase) && + !staticMonoStubs.Contains(lib, StringComparer.OrdinalIgnoreCase)) + .ToArray(); - nativeLibraries += $" libc++abi.a{Environment.NewLine}"; - nativeLibraries += $" libc++_static.a{Environment.NewLine}"; + foreach (string lib in staticLibs) + { + nativeLibraries += $" {lib}{Environment.NewLine}"; + } + + nativeLibraries += $" libc++abi.a{Environment.NewLine}"; + nativeLibraries += $" libc++_static.a{Environment.NewLine}"; + } } StringBuilder extraLinkerArgs = new StringBuilder(); diff --git a/src/tests/Common/Coreclr.TestWrapper/CoreclrTestWrapperLib.cs b/src/tests/Common/Coreclr.TestWrapper/CoreclrTestWrapperLib.cs index 47a0dcad269817..951c557df71c51 100644 --- a/src/tests/Common/Coreclr.TestWrapper/CoreclrTestWrapperLib.cs +++ b/src/tests/Common/Coreclr.TestWrapper/CoreclrTestWrapperLib.cs @@ -681,15 +681,25 @@ public static bool TryPrintStackTraceFromDmp(string dmpFile, TextWriter outputWr // The children are sorted in the order they should be dumped static unsafe IEnumerable FindChildProcessesByName(Process process, string childName) { - Console.WriteLine($"Finding all child processes of '{process.ProcessName}' (ID: {process.Id}) with name '{childName}'"); + process.TryGetProcessName(out string parentProcessName); + process.TryGetProcessId(out int parentProcessId); + Console.WriteLine($"Finding all child processes of '{parentProcessName}' (ID: {parentProcessId}) with name '{childName}'"); var children = new Stack(); Queue childrenToCheck = new Queue(); HashSet seen = new HashSet(); - seen.Add(process.Id); - foreach (var child in process.GetChildren()) - childrenToCheck.Enqueue(child); + seen.Add(parentProcessId); + + try + { + foreach (var child in process.GetChildren()) + childrenToCheck.Enqueue(child); + } + catch + { + // Process exited + } while (childrenToCheck.Count != 0) { @@ -707,8 +717,15 @@ static unsafe IEnumerable FindChildProcessesByName(Process process, str Console.WriteLine($"Checking child process: '{processName}' (ID: {processId})"); seen.Add(processId); - foreach (var grandchild in child.GetChildren()) - childrenToCheck.Enqueue(grandchild); + try + { + foreach (var grandchild in child.GetChildren()) + childrenToCheck.Enqueue(grandchild); + } + catch + { + // Process exited + } if (processName.Equals(childName, StringComparison.OrdinalIgnoreCase)) { @@ -844,7 +861,9 @@ public int RunTest(string executable, string outputFile, string errorFile, strin Console.WriteLine($"\t{"ID",-6} ProcessName"); foreach (var activeProcess in Process.GetProcesses()) { - Console.WriteLine($"\t{activeProcess.Id,-6} {activeProcess.ProcessName}"); + activeProcess.TryGetProcessName(out string activeProcessName); + activeProcess.TryGetProcessId(out int activeProcessId); + Console.WriteLine($"\t{activeProcessId,-6} {activeProcessName}"); } if (OperatingSystem.IsWindows()) diff --git a/src/tests/Directory.Build.props b/src/tests/Directory.Build.props index 136b5db5ae4eb0..fc6ebdb5ed7da6 100644 --- a/src/tests/Directory.Build.props +++ b/src/tests/Directory.Build.props @@ -8,6 +8,11 @@ + + + 5.0.0-1.25259.6 + + true diff --git a/src/tests/async/Directory.Build.props b/src/tests/async/Directory.Build.props index 17e80030ca09de..dda1142e724781 100644 --- a/src/tests/async/Directory.Build.props +++ b/src/tests/async/Directory.Build.props @@ -7,5 +7,9 @@ true $(NoWarn);xUnit1013 false + $(Features);runtime-async=on + + + diff --git a/src/tests/async/RuntimeAsyncMethodGenerationAttribute.cs b/src/tests/async/RuntimeAsyncMethodGenerationAttribute.cs new file mode 100644 index 00000000000000..d12d961ebcf220 --- /dev/null +++ b/src/tests/async/RuntimeAsyncMethodGenerationAttribute.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Runtime.CompilerServices; + +[AttributeUsage(AttributeTargets.Method)] +public class RuntimeAsyncMethodGenerationAttribute(bool runtimeAsync) : Attribute +{ + public bool RuntimeAsync { get; } = runtimeAsync; +} \ No newline at end of file diff --git a/src/tests/async/awaitingnotasync/awaitingnotasync.cs b/src/tests/async/awaitingnotasync/awaitingnotasync.cs index 9f4b1732313ca1..bf8ad8c9cc12a0 100644 --- a/src/tests/async/awaitingnotasync/awaitingnotasync.cs +++ b/src/tests/async/awaitingnotasync/awaitingnotasync.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using System.Threading.Tasks; using Xunit; @@ -14,6 +13,7 @@ public static void TestEntryPoint() AsyncEntryPoint().Wait(); } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] private static async Task GetTask(T arg) { await Task.Yield(); @@ -21,6 +21,7 @@ private static async Task GetTask(T arg) } // TODO: switch every other scenario to use ValueTask + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] private static async ValueTask GetValueTask(T arg) { await Task.Yield(); @@ -33,13 +34,13 @@ private static async ValueTask GetValueTask(T arg) private static T sIdentity(T arg) => arg; - private static async2 Task AsyncEntryPoint() + private static async Task AsyncEntryPoint() { // static field sField = GetTask(5); Assert.Equal(5, await sField); - // property + // property Assert.Equal(6, await sProp); // generic identity diff --git a/src/tests/async/collectible-alc/collectible-alc.cs b/src/tests/async/collectible-alc/collectible-alc.cs index eb7e43309db26a..0feb988d4ac4a4 100644 --- a/src/tests/async/collectible-alc/collectible-alc.cs +++ b/src/tests/async/collectible-alc/collectible-alc.cs @@ -17,7 +17,7 @@ public static void TestEntryPoint() AsyncEntryPoint().Wait(); } - private static async2 Task AsyncEntryPoint() + private static async Task AsyncEntryPoint() { WeakReference wr = await CallFooAsyncAndUnload(); @@ -31,7 +31,7 @@ private static async2 Task AsyncEntryPoint() } [MethodImpl(MethodImplOptions.NoInlining)] - private static async2 Task CallFooAsyncAndUnload() + private static async Task CallFooAsyncAndUnload() { TaskCompletionSource tcs = new(); (Task task, WeakReference wr) = CallFooAsyncInCollectibleALC(tcs.Task); @@ -63,7 +63,7 @@ private static (Task, WeakReference) CallFooAsyncInCollectibleALC(Task t } // Task[] to work around a compiler bug - private static async2 Task FooAsync(Task[] t) + private static async Task FooAsync(Task[] t) { await t[0]; return "done"; diff --git a/src/tests/async/cse-array-index-byref/cse-array-index-byref.cs b/src/tests/async/cse-array-index-byref/cse-array-index-byref.cs index be99722a054bbb..d208c4e7a12c7c 100644 --- a/src/tests/async/cse-array-index-byref/cse-array-index-byref.cs +++ b/src/tests/async/cse-array-index-byref/cse-array-index-byref.cs @@ -16,13 +16,14 @@ public static void TestEntryPoint() Assert.Equal(199_990_000, arr[0]); } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] private static async Task AsyncTestEntryPoint(int[] arr, int index) { await HoistedByref(arr, index); } [MethodImpl(MethodImplOptions.NoInlining)] - private static async2 Task HoistedByref(int[] arr, int index) + private static async Task HoistedByref(int[] arr, int index) { for (int i = 0; i < 20000; i++) { diff --git a/src/tests/async/eh-microbench/eh-microbench.cs b/src/tests/async/eh-microbench/eh-microbench.cs index 994e443cf9e386..2eefa61570a837 100644 --- a/src/tests/async/eh-microbench/eh-microbench.cs +++ b/src/tests/async/eh-microbench/eh-microbench.cs @@ -24,6 +24,7 @@ public static int Main() return 100; } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] public static async Task AsyncEntry() { if (!GCSettings.IsServerGC) @@ -68,6 +69,7 @@ public static async Task AsyncEntry() await RunBench(yieldFrequency, depth, finallyRate, throwOrReturn, "ValueTask"); } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] private static async Task RunBench(int yieldCount, int depth, int finallyRate, bool throwOrReturn, string type) { @@ -104,7 +106,7 @@ public Benchmark(int yieldCount, int depth, int finallyRate, bool throwOrReturn) _throwOrReturn = throwOrReturn; } - public async2 Task Run(string type) + public async Task Run(string type) { if (type == "Async2") return await RunAsync2(_depth); @@ -117,6 +119,7 @@ public async2 Task Run(string type) return 0; } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] public async Task RunTask(int depth) { int liveState1 = depth * 3 + _yieldCount; @@ -182,6 +185,7 @@ public async Task RunTask(int depth) return result; } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] public async ValueTask RunValueTask(int depth) { int liveState1 = depth * 3 + _yieldCount; @@ -267,7 +271,7 @@ public class FakeThread // This case is used to test the impact of save/restore of the sync and execution context on performance // The intent here is to measure what the performance impact of maintaining the current async semantics with // the new implementation. - public async2 Task RunAsync2WithContextSaveRestore(int depth) + public async Task RunAsync2WithContextSaveRestore(int depth) { FakeThread thread = CurrentThread; if (thread == null) @@ -361,7 +365,7 @@ public async2 Task RunAsync2WithContextSaveRestore(int depth) } } - public async2 Task RunAsync2(int depth) + public async Task RunAsync2(int depth) { int liveState1 = depth * 3 + _yieldCount; int liveState2 = depth; diff --git a/src/tests/async/fibonacci-with-yields/fibonacci-with-yields.cs b/src/tests/async/fibonacci-with-yields/fibonacci-with-yields.cs index a51a834fbdd773..814b96eda0b974 100644 --- a/src/tests/async/fibonacci-with-yields/fibonacci-with-yields.cs +++ b/src/tests/async/fibonacci-with-yields/fibonacci-with-yields.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Runtime.CompilerServices; using System.Threading.Tasks; using System.Diagnostics; using Xunit; @@ -22,7 +23,7 @@ public static void Test() System.Console.WriteLine("allocated: " + allocated); } - public static async2 Task AsyncEntry() + public static async Task AsyncEntry() { for (int i = 0; i < iterations; i++) { @@ -34,7 +35,7 @@ public static async2 Task AsyncEntry() } } - static async2 Task Fib(int i) + static async Task Fib(int i) { if (i <= 1) { diff --git a/src/tests/async/fibonacci-with-yields_struct_return/fibonacci-with-yields_struct_return.cs b/src/tests/async/fibonacci-with-yields_struct_return/fibonacci-with-yields_struct_return.cs index eee23a2c16245b..c77caf9d912717 100644 --- a/src/tests/async/fibonacci-with-yields_struct_return/fibonacci-with-yields_struct_return.cs +++ b/src/tests/async/fibonacci-with-yields_struct_return/fibonacci-with-yields_struct_return.cs @@ -6,6 +6,7 @@ using System; using System.Threading.Tasks; using System.Diagnostics; +using System.Runtime.CompilerServices; using Xunit; public class Async2FibonacceWithYields @@ -34,7 +35,7 @@ public struct MyInt public MyInt(int i) => this.i = i; } - public static async2 Task AsyncEntry() + public static async Task AsyncEntry() { for (int i = 0; i < iterations; i++) { @@ -46,7 +47,7 @@ public static async2 Task AsyncEntry() } } - static async2 Task Fib(MyInt n) + static async Task Fib(MyInt n) { int i = n.i; if (i <= 1) diff --git a/src/tests/async/fibonacci-without-yields-config-await/fibonacci-without-yields-config-await.cs b/src/tests/async/fibonacci-without-yields-config-await/fibonacci-without-yields-config-await.cs index 7abf3bac07de57..e3b411b5c3303c 100644 --- a/src/tests/async/fibonacci-without-yields-config-await/fibonacci-without-yields-config-await.cs +++ b/src/tests/async/fibonacci-without-yields-config-await/fibonacci-without-yields-config-await.cs @@ -26,7 +26,7 @@ public static void Test() System.Console.WriteLine("allocated: " + allocated); } - public static async2 Task AsyncEntry() + public static async Task AsyncEntry() { for (int i = 0; i < iterations; i++) { @@ -38,7 +38,7 @@ public static async2 Task AsyncEntry() } } - static async2 Task Fib(int i) + static async Task Fib(int i) { if (i <= 1) { diff --git a/src/tests/async/fibonacci-without-yields/fibonacci-without-yields.cs b/src/tests/async/fibonacci-without-yields/fibonacci-without-yields.cs index 77ff71e8d1ee36..11dd3db5168e47 100644 --- a/src/tests/async/fibonacci-without-yields/fibonacci-without-yields.cs +++ b/src/tests/async/fibonacci-without-yields/fibonacci-without-yields.cs @@ -4,6 +4,7 @@ using System; using System.Threading.Tasks; using System.Diagnostics; +using System.Runtime.CompilerServices; using Xunit; public class Async2FibonacciWithoutYields @@ -22,7 +23,7 @@ public static void Test() System.Console.WriteLine("allocated: " + allocated); } - public static async2 Task AsyncEntry() + public static async Task AsyncEntry() { for (int i = 0; i < iterations; i++) { @@ -34,7 +35,7 @@ public static async2 Task AsyncEntry() } } - static async2 Task Fib(int i) + static async Task Fib(int i) { if (i <= 1) { diff --git a/src/tests/async/gc-roots-scan/gc-roots-scan.cs b/src/tests/async/gc-roots-scan/gc-roots-scan.cs index fffe874af38e50..76d0dfb629fcdf 100644 --- a/src/tests/async/gc-roots-scan/gc-roots-scan.cs +++ b/src/tests/async/gc-roots-scan/gc-roots-scan.cs @@ -4,6 +4,7 @@ using System; using System.Threading.Tasks; using System.Diagnostics; +using System.Runtime.CompilerServices; using Xunit; public class Async2RootReporting @@ -11,6 +12,7 @@ public class Async2RootReporting private static TaskCompletionSource cs; + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] static async Task Recursive1(int n) { Task cTask = cs.Task; @@ -50,7 +52,7 @@ static async Task Recursive1(int n) return result; } - static async2 Task Recursive2(int n) + static async Task Recursive2(int n) { Task cTask = cs.Task; diff --git a/src/tests/async/implement/implement.cs b/src/tests/async/implement/implement.cs index bb8607541d1d49..ddd20d0570c391 100644 --- a/src/tests/async/implement/implement.cs +++ b/src/tests/async/implement/implement.cs @@ -10,11 +10,12 @@ public class Async2Implement { interface IBase1 { - public async2 Task M1(); + public Task M1(); } class Derived1 : IBase1 { + [RuntimeAsyncMethodGeneration(false)] public async Task M1() { await Task.Yield(); @@ -24,7 +25,7 @@ public async Task M1() class Derived1a : IBase1 { - public async2 Task M1() + public async Task M1() { await Task.Yield(); return 3; @@ -38,7 +39,7 @@ interface IBase2 class Derived2 : IBase2 { - public async2 Task M1() + public async Task M1() { await Task.Yield(); return 12; @@ -47,6 +48,7 @@ public async2 Task M1() class Derived2a : IBase2 { + [RuntimeAsyncMethodGeneration(false)] public async Task M1() { await Task.Yield(); diff --git a/src/tests/async/mincallcost-microbench/mincallcost-microbench.cs b/src/tests/async/mincallcost-microbench/mincallcost-microbench.cs index 122994d8061c37..900aad4ba45b0c 100644 --- a/src/tests/async/mincallcost-microbench/mincallcost-microbench.cs +++ b/src/tests/async/mincallcost-microbench/mincallcost-microbench.cs @@ -24,6 +24,7 @@ public static int Main() return 100; } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] public static async Task AsyncEntry() { if (!GCSettings.IsServerGC) @@ -66,6 +67,7 @@ public static async Task AsyncEntry() static double time = 10.0; static bool printResult = false; + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] private static async Task RunBench(string type) { if (printResult) @@ -85,6 +87,7 @@ private static async Task RunBench(string type) Console.WriteLine("Result = {0}", (long)avg); } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] private static async Task Run(string type) { if (type == "AsyncCallingAsync") @@ -114,6 +117,7 @@ private static async Task Run(string type) } #pragma warning disable CS1998 + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] private static async Task AsyncCallingAsync() { Stopwatch timer = Stopwatch.StartNew(); @@ -131,6 +135,7 @@ private static async Task AsyncCallingAsync() return numIters * 10; } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] private static async Task AsyncCallingValueTaskAsync() { Stopwatch timer = Stopwatch.StartNew(); @@ -148,6 +153,7 @@ private static async Task AsyncCallingValueTaskAsync() return numIters * 10; } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] private static async Task AsyncCallingAsync2() { Stopwatch timer = Stopwatch.StartNew(); @@ -165,7 +171,7 @@ private static async Task AsyncCallingAsync2() return numIters * 10; } - private static async2 Task Async2CallingAsync() + private static async Task Async2CallingAsync() { Stopwatch timer = Stopwatch.StartNew(); @@ -182,7 +188,7 @@ private static async2 Task Async2CallingAsync() return numIters * 10; } - private static async2 Task Async2CallingValueTaskAsync() + private static async Task Async2CallingValueTaskAsync() { Stopwatch timer = Stopwatch.StartNew(); @@ -199,7 +205,7 @@ private static async2 Task Async2CallingValueTaskAsync() return numIters * 10; } - private static async2 Task Async2CallingAsync2() + private static async Task Async2CallingAsync2() { Stopwatch timer = Stopwatch.StartNew(); @@ -216,7 +222,7 @@ private static async2 Task Async2CallingAsync2() return numIters * 10; } - private static async2 Task Async2CallingAsync2NoInlining() + private static async Task Async2CallingAsync2NoInlining() { Stopwatch timer = Stopwatch.StartNew(); @@ -233,7 +239,7 @@ private static async2 Task Async2CallingAsync2NoInlining() return numIters * 10; } - private static async2 Task Async2CallingAsync2WithContextSave() + private static async Task Async2CallingAsync2WithContextSave() { FakeThread thread = CurrentThread; if (thread == null) @@ -274,6 +280,7 @@ public class FakeThread public static FakeThread CurrentThread; + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] private static async Task AsyncCallingYield() { Stopwatch timer = Stopwatch.StartNew(); @@ -291,7 +298,7 @@ private static async Task AsyncCallingYield() return numIters * 10; } - private static async2 Task Async2CallingYield() + private static async Task Async2CallingYield() { Stopwatch timer = Stopwatch.StartNew(); @@ -325,6 +332,7 @@ private static long Sync2CallingSync() return numIters * 10; } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] private static async Task EmptyAsync() { // Add some work that forces the method to be a real async method @@ -333,6 +341,7 @@ private static async Task EmptyAsync() return; } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] private static async ValueTask EmptyValueTaskAsync() { // Add some work that forces the method to be a real async method @@ -341,7 +350,7 @@ private static async ValueTask EmptyValueTaskAsync() return; } - private static async2 Task EmptyAsync2() + private static async Task EmptyAsync2() { // Add some work that forces the method to be a real async method if (time == 0) @@ -350,7 +359,7 @@ private static async2 Task EmptyAsync2() } [MethodImpl(MethodImplOptions.NoInlining)] - private static async2 Task EmptyAsync2NoInlining() + private static async Task EmptyAsync2NoInlining() { // Add some work that forces the method to be a real async method if (time == 0) @@ -358,8 +367,8 @@ private static async2 Task EmptyAsync2NoInlining() return; } - // This simulates async2 capturing the same amount of state that existing async needs to capture to handle the current semantics around async locals and synchronizationcontext - private static async2 Task EmptyAsync2WithContextSave() + // This simulates async capturing the same amount of state that existing async needs to capture to handle the current semantics around async locals and synchronizationcontext + private static async Task EmptyAsync2WithContextSave() { FakeThread thread = CurrentThread; FakeExecContext? previousExecutionCtx = thread._execContext; diff --git a/src/tests/async/object/object.cs b/src/tests/async/object/object.cs index fb62588652ae3f..7ebec6207edf91 100644 --- a/src/tests/async/object/object.cs +++ b/src/tests/async/object/object.cs @@ -14,13 +14,14 @@ public static int TestEntryPoint() return (int)AsyncTestEntryPoint(100).Result; } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] private static async Task AsyncTestEntryPoint(int arg) { return await ObjMethod(arg); } [MethodImpl(MethodImplOptions.NoInlining)] - private static async2 Task ObjMethod(int arg) + private static async Task ObjMethod(int arg) { await Task.Yield(); return arg; diff --git a/src/tests/async/objects-captured/objects-captured.cs b/src/tests/async/objects-captured/objects-captured.cs index 197d29f0383d98..07c502b12ee61c 100644 --- a/src/tests/async/objects-captured/objects-captured.cs +++ b/src/tests/async/objects-captured/objects-captured.cs @@ -4,11 +4,12 @@ using System; using System.Threading.Tasks; using System.Diagnostics; +using System.Runtime.CompilerServices; using Xunit; public class Async2ObjectsWithYields { - internal static async2 Task A(object n) + internal static async Task A(object n) { // use string equality so that JIT would not think of hoisting "(int)n" // also to produce some amout of garbage @@ -21,6 +22,7 @@ internal static async2 Task A(object n) return 0; } + [RuntimeAsyncMethodGeneration(false)] private static async Task AsyncEntry() { object result = 0; diff --git a/src/tests/async/override/override.cs b/src/tests/async/override/override.cs index 4ee5d1446b831a..d55d961880ad30 100644 --- a/src/tests/async/override/override.cs +++ b/src/tests/async/override/override.cs @@ -10,7 +10,7 @@ public class Async2Override { class Base { - public virtual async2 Task M1() + public virtual async Task M1() { await Task.Yield(); return 1; @@ -19,6 +19,7 @@ public virtual async2 Task M1() class Derived1 : Base { + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] public override async Task M1() { await Task.Yield(); @@ -28,7 +29,7 @@ public override async Task M1() class Derived2 : Derived1 { - public override async2 Task M1() + public override async Task M1() { await Task.Yield(); return 3; @@ -38,6 +39,7 @@ public override async2 Task M1() class Base1 { + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] public virtual async Task M1() { await Task.Yield(); @@ -47,7 +49,7 @@ public virtual async Task M1() class Derived11 : Base1 { - public override async2 Task M1() + public override async Task M1() { await Task.Yield(); return 12; @@ -56,6 +58,7 @@ public override async2 Task M1() class Derived12 : Derived11 { + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] public override async Task M1() { await Task.Yield(); diff --git a/src/tests/async/pgo/pgo.cs b/src/tests/async/pgo/pgo.cs index 6e3f14caa7bae1..ba5589c07d9117 100644 --- a/src/tests/async/pgo/pgo.cs +++ b/src/tests/async/pgo/pgo.cs @@ -17,7 +17,7 @@ public static void EntryPoint() AsyncEntryPoint().Wait(); } - internal static async2 Task AsyncEntryPoint() + internal static async Task AsyncEntryPoint() { int[] arr = Enumerable.Range(0, 100_000).ToArray(); @@ -36,20 +36,20 @@ internal static async2 Task AsyncEntryPoint() private class AggregateSum : I { #pragma warning disable CS1998 - public async2 Task Aggregate(int a, int b) => a + b; + public async Task Aggregate(int a, int b) => a + b; } - + public interface I { public Task Aggregate(T seed, T val); } - + [MethodImpl(MethodImplOptions.NoInlining)] - public static async2 Task AggregateDelegateAsync(T[] arr, I aggregate, T seed) + public static async Task AggregateDelegateAsync(T[] arr, I aggregate, T seed) { foreach (T val in arr) seed = await aggregate.Aggregate(seed, val); - + return seed; } } diff --git a/src/tests/async/pinvoke/pinvoke.cs b/src/tests/async/pinvoke/pinvoke.cs index df04091cbaf2ff..bbe9e939ad7f8f 100644 --- a/src/tests/async/pinvoke/pinvoke.cs +++ b/src/tests/async/pinvoke/pinvoke.cs @@ -14,7 +14,7 @@ public static void TestEntryPoint() AsyncEntryPoint().Wait(); } - private static async2 Task AsyncEntryPoint() + private static async Task AsyncEntryPoint() { unsafe { diff --git a/src/tests/async/returns/returns.cs b/src/tests/async/returns/returns.cs index 174a66c479a14c..3df7a8a65899bd 100644 --- a/src/tests/async/returns/returns.cs +++ b/src/tests/async/returns/returns.cs @@ -15,7 +15,7 @@ public static void TestEntryPoint() } [MethodImpl(MethodImplOptions.NoInlining)] - private static async2 Task Returns(C c) + private static async Task Returns(C c) { for (int i = 0; i < 20000; i++) { @@ -58,28 +58,28 @@ private static void AssertEqual(T expected, T actual) } [MethodImpl(MethodImplOptions.NoInlining)] - private static async2 Task> ReturnsStruct() + private static async Task> ReturnsStruct() { await Task.Yield(); return new S { A = 42, B = 4242, C = 424242, D = 42424242 }; } [MethodImpl(MethodImplOptions.NoInlining)] - private static async2 Task> ReturnsStructGC() + private static async Task> ReturnsStructGC() { await Task.Yield(); return new S { A = "A", B = "B", C = "C", D = "D" }; } [MethodImpl(MethodImplOptions.NoInlining)] - private static async2 Task> ReturnsBytes() + private static async Task> ReturnsBytes() { await Task.Yield(); return new S { A = 4, B = 40, C = 42, D = 45 }; } [MethodImpl(MethodImplOptions.NoInlining)] - private static async2 Task ReturnsString() + private static async Task ReturnsString() { await Task.Yield(); return "a string!"; diff --git a/src/tests/async/shared-generic/shared-generic.cs b/src/tests/async/shared-generic/shared-generic.cs index e53ce961680450..c75abab84bb410 100644 --- a/src/tests/async/shared-generic/shared-generic.cs +++ b/src/tests/async/shared-generic/shared-generic.cs @@ -51,6 +51,7 @@ public static void TestEntryPoint() Async2EntryPoint?>(typeof(S1?), null).Wait(); } + [RuntimeAsyncMethodGeneration(false)] private static async Task Async1EntryPoint(Type t, T value) { await new GenericClass().InstanceMethod(t); @@ -65,7 +66,7 @@ private static async Task Async1EntryPoint(Type t, T value) Assert.Equal(value, await GenericClass.StaticReturnMethodTypeAsync1(value)); } - private static async2 Task Async2EntryPoint(Type t, T value) + private static async Task Async2EntryPoint(Type t, T value) { await new GenericClass().InstanceMethod(t); await GenericClass.StaticMethod(t); @@ -84,7 +85,7 @@ public class GenericClass { // 'this' is context [MethodImpl(MethodImplOptions.NoInlining)] - public async2 Task InstanceMethod(Type t) + public async Task InstanceMethod(Type t) { Assert.Equal(typeof(T), t); await Task.Yield(); @@ -93,7 +94,7 @@ public async2 Task InstanceMethod(Type t) // Class context [MethodImpl(MethodImplOptions.NoInlining)] - public static async2 Task StaticMethod(Type t) + public static async Task StaticMethod(Type t) { Assert.Equal(typeof(T), t); await Task.Yield(); @@ -102,7 +103,7 @@ public static async2 Task StaticMethod(Type t) // Method context [MethodImpl(MethodImplOptions.NoInlining)] - public static async2 Task StaticMethod(Type t, Type tm) + public static async Task StaticMethod(Type t, Type tm) { Assert.Equal(typeof(T), t); Assert.Equal(typeof(TM), tm); @@ -113,6 +114,7 @@ public static async2 Task StaticMethod(Type t, Type tm) // Class context [MethodImpl(MethodImplOptions.NoInlining)] + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] public static async Task StaticMethodAsync1(Type t) { Assert.Equal(typeof(T), t); @@ -122,6 +124,7 @@ public static async Task StaticMethodAsync1(Type t) // Method context [MethodImpl(MethodImplOptions.NoInlining)] + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] public static async Task StaticMethodAsync1(Type t, Type tm) { Assert.Equal(typeof(T), t); @@ -131,24 +134,26 @@ public static async Task StaticMethodAsync1(Type t, Type tm) Assert.Equal(typeof(TM), tm); } - public static async2 Task StaticReturnClassType(T value) + public static async Task StaticReturnClassType(T value) { await Task.Yield(); return value; } - public static async2 Task StaticReturnMethodType(TM value) + public static async Task StaticReturnMethodType(TM value) { await Task.Yield(); return value; } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] public static async Task StaticReturnClassTypeAsync1(T value) { await Task.Yield(); return value; } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] public static async Task StaticReturnMethodTypeAsync1(TM value) { await Task.Yield(); diff --git a/src/tests/async/simple-eh/simple-eh.cs b/src/tests/async/simple-eh/simple-eh.cs index 8d70af66efc5b4..04b19f132c4208 100644 --- a/src/tests/async/simple-eh/simple-eh.cs +++ b/src/tests/async/simple-eh/simple-eh.cs @@ -18,13 +18,14 @@ public static void Test() Task.Run(AsyncEntry).Wait(); } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] public static async Task AsyncEntry() { int result = await Handler(); Assert.Equal(42, result); } - public static async2 Task Handler() + public static async Task Handler() { try { @@ -37,7 +38,7 @@ public static async2 Task Handler() } [MethodImpl(MethodImplOptions.NoInlining)] - public static async2 Task Throw(int value) + public static async Task Throw(int value) { await Task.Yield(); throw new IntegerException(value); diff --git a/src/tests/async/simple-eh/simple-eh.csproj b/src/tests/async/simple-eh/simple-eh.csproj index de6d5e08882e86..7df4a08ec02b24 100644 --- a/src/tests/async/simple-eh/simple-eh.csproj +++ b/src/tests/async/simple-eh/simple-eh.csproj @@ -1,6 +1,7 @@ True + true diff --git a/src/tests/async/small/small.cs b/src/tests/async/small/small.cs index 5afbbe7bc31ece..bdce432c39b869 100644 --- a/src/tests/async/small/small.cs +++ b/src/tests/async/small/small.cs @@ -15,7 +15,7 @@ public static void TestEntryPoint() } [MethodImpl(MethodImplOptions.NoInlining)] - private static async2 Task SmallType(byte arg) + private static async Task SmallType(byte arg) { await Task.Yield(); Assert.Equal(123, arg); diff --git a/src/tests/async/strength-reduction/strength-reduction.cs b/src/tests/async/strength-reduction/strength-reduction.cs new file mode 100644 index 00000000000000..175a01f09a5af0 --- /dev/null +++ b/src/tests/async/strength-reduction/strength-reduction.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Xunit; + +public class StrengthReductionTest +{ + [Fact] + public static int TestEntryPoint() + { + return StrengthReduction(Enumerable.Range(0, 1000).ToArray()).Result - 499400; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static async Task StrengthReduction(int[] arr) + { + int sum = 0; + foreach (int x in arr) + { + sum += x; + await Task.Yield(); + } + return sum; + } +} diff --git a/src/tests/async/strength-reduction/strength-reduction.csproj b/src/tests/async/strength-reduction/strength-reduction.csproj new file mode 100644 index 00000000000000..de6d5e08882e86 --- /dev/null +++ b/src/tests/async/strength-reduction/strength-reduction.csproj @@ -0,0 +1,8 @@ + + + True + + + + + diff --git a/src/tests/async/struct/struct.cs b/src/tests/async/struct/struct.cs index 76bd0fd35e8fa5..7c5062d499cb42 100644 --- a/src/tests/async/struct/struct.cs +++ b/src/tests/async/struct/struct.cs @@ -17,6 +17,7 @@ public static void TestEntryPoint() Async2().Wait(); } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] private static async Task Async() { S s = new S(100); @@ -24,13 +25,14 @@ private static async Task Async() AssertEqual(100, s.Value); } - private static async2 Task Async2() + private static async Task Async2() { S s = new S(100); await s.Test(); AssertEqual(100, s.Value); } + [MethodImpl(MethodImplOptions.NoInlining)] private static void AssertEqual(int expected, int val) { @@ -43,7 +45,7 @@ private struct S public S(int value) => Value = value; - public async2 Task Test() + public async Task Test() { // TODO: C# compiler is expected to do this, but not in the prototype. S @this = this; @@ -57,7 +59,7 @@ public async2 Task Test() AssertEqual(102, @this.Value); } - private async2 Task InstanceCall() + private async Task InstanceCall() { // TODO: C# compiler is expected to do this, but not in the prototype. S @this = this; diff --git a/src/tests/async/taskbased-asyncfibonacci-with-yields/taskbased-asyncfibonacci-with-yields.cs b/src/tests/async/taskbased-asyncfibonacci-with-yields/taskbased-asyncfibonacci-with-yields.cs index 4829e029636da6..2465903d710a81 100644 --- a/src/tests/async/taskbased-asyncfibonacci-with-yields/taskbased-asyncfibonacci-with-yields.cs +++ b/src/tests/async/taskbased-asyncfibonacci-with-yields/taskbased-asyncfibonacci-with-yields.cs @@ -23,6 +23,7 @@ public static int Main() return 100; } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] public static async Task AsyncEntry() { for (int i = 0; i < iterations; i++) @@ -35,6 +36,7 @@ public static async Task AsyncEntry() } } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] static async Task Fib(int i) { if (i <= 1) diff --git a/src/tests/async/taskbased-asyncfibonacci-without-yields/taskbased-asyncfibonacci-without-yields.cs b/src/tests/async/taskbased-asyncfibonacci-without-yields/taskbased-asyncfibonacci-without-yields.cs index e3e9c7ff21f8f1..2f8ddb5f06658e 100644 --- a/src/tests/async/taskbased-asyncfibonacci-without-yields/taskbased-asyncfibonacci-without-yields.cs +++ b/src/tests/async/taskbased-asyncfibonacci-without-yields/taskbased-asyncfibonacci-without-yields.cs @@ -23,6 +23,7 @@ public static int Main() return 100; } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] public static async Task AsyncEntry() { for (int i = 0; i < iterations; i++) @@ -35,6 +36,7 @@ public static async Task AsyncEntry() } } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] static async Task Fib(int i) { if (i <= 1) diff --git a/src/tests/async/valuetask/valuetask.cs b/src/tests/async/valuetask/valuetask.cs index deff530e9f5d4d..4740181e27394f 100644 --- a/src/tests/async/valuetask/valuetask.cs +++ b/src/tests/async/valuetask/valuetask.cs @@ -19,7 +19,7 @@ private static ValueTask AsyncTestEntryPoint(int arg) return M1(arg); } - private static async2 ValueTask M1(int arg) + private static async ValueTask M1(int arg) { await Task.Yield(); return arg; diff --git a/src/tests/async/valuetaskbased-asyncfibonacci-with-yields/valuetaskbased-asyncfibonacci-with-yields.cs b/src/tests/async/valuetaskbased-asyncfibonacci-with-yields/valuetaskbased-asyncfibonacci-with-yields.cs index ac48372814efb6..f34cc93b1d6bb2 100644 --- a/src/tests/async/valuetaskbased-asyncfibonacci-with-yields/valuetaskbased-asyncfibonacci-with-yields.cs +++ b/src/tests/async/valuetaskbased-asyncfibonacci-with-yields/valuetaskbased-asyncfibonacci-with-yields.cs @@ -23,6 +23,7 @@ public static int Main() return 100; } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] public static async ValueTask AsyncEntry() { for (int i = 0; i < iterations; i++) @@ -35,6 +36,7 @@ public static async ValueTask AsyncEntry() } } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] static async ValueTask Fib(int i) { if (i <= 1) diff --git a/src/tests/async/valuetaskbased-asyncfibonacci-without-yields/valuetaskbased-asyncfibonacci-without-yields.cs b/src/tests/async/valuetaskbased-asyncfibonacci-without-yields/valuetaskbased-asyncfibonacci-without-yields.cs index 1e3aab57ec7da5..64d57c46f8ee56 100644 --- a/src/tests/async/valuetaskbased-asyncfibonacci-without-yields/valuetaskbased-asyncfibonacci-without-yields.cs +++ b/src/tests/async/valuetaskbased-asyncfibonacci-without-yields/valuetaskbased-asyncfibonacci-without-yields.cs @@ -23,6 +23,7 @@ public static int Main() return 100; } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] public static async ValueTask AsyncEntry() { for (int i = 0; i < iterations; i++) @@ -35,6 +36,7 @@ public static async ValueTask AsyncEntry() } } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] static async ValueTask Fib(int i) { if (i <= 1) diff --git a/src/tests/async/varying-yields/varying-yields.cs b/src/tests/async/varying-yields/varying-yields.cs index 6edc30e8118dd7..6194d1890d838a 100644 --- a/src/tests/async/varying-yields/varying-yields.cs +++ b/src/tests/async/varying-yields/varying-yields.cs @@ -22,6 +22,7 @@ public static void TestEntryPoint() Task.Run(AsyncEntry).Wait(); } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] public static async Task AsyncEntry() { if (!GCSettings.IsServerGC) @@ -76,13 +77,14 @@ private class Benchmark public Benchmark(double yieldProbability) => _yieldProbability = yieldProbability; -public #if ASYNC1_TASK - async Task + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] + public async Task #elif ASYNC1_VALUETASK - async ValueTask + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] + public async ValueTask #else - async2 Task + public async Task #endif Run(int depth) { @@ -98,13 +100,14 @@ async2 Task return result; } -private #if ASYNC1_TASK - async Task + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] + private async Task #elif ASYNC1_VALUETASK - async ValueTask + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] + private async ValueTask #else - async2 Task + private async Task #endif Loop() { @@ -124,13 +127,14 @@ async2 Task return numIters; } -private #if ASYNC1_TASK - async Task + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] + private async Task #elif ASYNC1_VALUETASK - async ValueTask + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] + private async ValueTask #else - async2 Task + private async Task #endif DoYields() { diff --git a/src/tests/async/void/void.cs b/src/tests/async/void/void.cs index 8271887731a110..566dbd8e7ccc77 100644 --- a/src/tests/async/void/void.cs +++ b/src/tests/async/void/void.cs @@ -16,13 +16,14 @@ public static void TestEntryPoint() Assert.Equal(199_990_000, arr[0]); } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] private static async Task AsyncTestEntryPoint(int[] arr, int index) { await HoistedByref(arr, index); } [MethodImpl(MethodImplOptions.NoInlining)] - private static async2 Task HoistedByref(int[] arr, int index) + private static async Task HoistedByref(int[] arr, int index) { for (int i = 0; i < 20000; i++) { diff --git a/src/tests/async/with-yields/with-yields.cs b/src/tests/async/with-yields/with-yields.cs index 2f53a60f7c4fc5..7c382b671092d7 100644 --- a/src/tests/async/with-yields/with-yields.cs +++ b/src/tests/async/with-yields/with-yields.cs @@ -8,7 +8,7 @@ public class Async2FibonacceWithYields { - internal static async2 Task B(int n) + internal static async Task B(int n) { int num = 1; await Task.Yield(); @@ -22,7 +22,7 @@ internal static async2 Task B(int n) return num; } - internal static async2 Task A(int n) + internal static async Task A(int n) { int num = n; for (int num2 = 0; num2 < n; num2++) @@ -33,6 +33,7 @@ internal static async2 Task A(int n) return num; } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] private static async Task AsyncEntry() { int result = 0; diff --git a/src/tests/async/without-yields/without-yields.cs b/src/tests/async/without-yields/without-yields.cs index ba1f2aeff0df1f..b0866fda6a79b3 100644 --- a/src/tests/async/without-yields/without-yields.cs +++ b/src/tests/async/without-yields/without-yields.cs @@ -11,12 +11,12 @@ public class Async2FibonacceWithoutYields //This async method lacks 'await' #pragma warning disable 1998 - internal static async2 Task B(int n) + internal static async Task B(int n) { return 100; } - internal static async2 Task A(int n) + internal static async Task A(int n) { int num = n; for (int num2 = 0; num2 < n; num2++) @@ -27,6 +27,7 @@ internal static async2 Task A(int n) return num; } + [System.Runtime.CompilerServices.RuntimeAsyncMethodGeneration(false)] private static async Task AsyncEntry() { int result = 0; diff --git a/src/tests/build.proj b/src/tests/build.proj index eb1c3adbb12340..2a6dc297f2d7da 100644 --- a/src/tests/build.proj +++ b/src/tests/build.proj @@ -443,7 +443,12 @@ - + + Date: Wed, 21 May 2025 02:03:51 +0000 Subject: [PATCH 11/11] Update dependencies from https://github.com/dotnet/dotnet build 268973 No dependency updates to commit --- eng/Version.Details.xml | 142 ++++++++-------- eng/Versions.props | 64 ++++---- eng/common/templates/steps/vmr-sync.yml | 207 ++++++++++++++++++++++++ eng/common/templates/vmr-build-pr.yml | 33 ++++ eng/common/vmr-sync.ps1 | 138 ++++++++++++++++ eng/common/vmr-sync.sh | 205 +++++++++++++++++++++++ global.json | 8 +- 7 files changed, 690 insertions(+), 107 deletions(-) create mode 100644 eng/common/templates/steps/vmr-sync.yml create mode 100644 eng/common/templates/vmr-build-pr.yml create mode 100755 eng/common/vmr-sync.ps1 create mode 100755 eng/common/vmr-sync.sh diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index e8a2ee453aaa30..f6166255017ba9 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,5 +1,5 @@ - + https://github.com/dotnet/icu @@ -41,91 +41,91 @@ https://github.com/dotnet/llvm-project da5dd054a531e6fea65643b7e754285b73eab433 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 https://github.com/dotnet/runtime-assets @@ -263,33 +263,33 @@ https://github.com/dotnet/llvm-project da5dd054a531e6fea65643b7e754285b73eab433 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 https://github.com/dotnet/xharness @@ -303,9 +303,9 @@ https://github.com/dotnet/xharness e85bb14e85357ab678c2bcb0b6f2bac634fdd49b - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization @@ -331,29 +331,29 @@ https://github.com/dotnet/runtime-assets 1cfc6ba21d0377b51f17eac4fdc2557f7b1e8693 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 - + https://github.com/dotnet/dotnet - 170498a9429a5553fe7ac0ec2341d19bbb97cbe8 + d60c3fe894af16cd15dc86420af0fc9d02be4997 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization diff --git a/eng/Versions.props b/eng/Versions.props index 2ee5e9f7799fde..ea479c8ea1d7e6 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -36,17 +36,17 @@ - 10.0.0-preview.25267.102 + 10.0.0-preview.25269.109 - 5.0.0-1.25267.102 + 5.0.0-1.25269.109 - 5.0.0-1.25267.102 - 5.0.0-1.25267.102 - 5.0.0-1.25267.102 + 5.0.0-1.25269.109 + 5.0.0-1.25269.109 + 5.0.0-1.25269.109 - 10.0.100-preview.5.25267.102 + 10.0.100-preview.5.25269.109 - 10.0.0-beta.25267.102 - 10.0.0-beta.25267.102 - 10.0.0-beta.25267.102 - 10.0.0-beta.25267.102 - 2.9.2-beta.25267.102 - 10.0.0-beta.25267.102 - 2.9.2-beta.25267.102 - 10.0.0-beta.25267.102 - 10.0.0-beta.25267.102 - 10.0.0-beta.25267.102 - 10.0.0-beta.25267.102 - 10.0.0-beta.25267.102 - 10.0.0-beta.25267.102 - 10.0.0-beta.25267.102 - 10.0.0-beta.25267.102 - 10.0.0-beta.25267.102 + 10.0.0-beta.25269.109 + 10.0.0-beta.25269.109 + 10.0.0-beta.25269.109 + 10.0.0-beta.25269.109 + 2.9.2-beta.25269.109 + 10.0.0-beta.25269.109 + 2.9.2-beta.25269.109 + 10.0.0-beta.25269.109 + 10.0.0-beta.25269.109 + 10.0.0-beta.25269.109 + 10.0.0-beta.25269.109 + 10.0.0-beta.25269.109 + 10.0.0-beta.25269.109 + 10.0.0-beta.25269.109 + 10.0.0-beta.25269.109 + 10.0.0-beta.25269.109 1.4.0 6.0.0-preview.1.102 - 10.0.0-preview.5.25267.102 + 10.0.0-preview.5.25269.109 6.0.0 - 10.0.0-preview.5.25267.102 - 10.0.0-preview.5.25267.102 + 10.0.0-preview.5.25269.109 + 10.0.0-preview.5.25269.109 6.0.0 4.6.1 @@ -128,16 +128,16 @@ 8.0.0 8.0.1 5.0.0 - 10.0.0-preview.5.25267.102 - 10.0.0-preview.5.25267.102 + 10.0.0-preview.5.25269.109 + 10.0.0-preview.5.25269.109 6.0.0 5.0.0 5.0.0 5.0.0 7.0.0 - 10.0.0-preview.5.25267.102 + 10.0.0-preview.5.25269.109 7.0.0 - 10.0.0-preview.5.25267.102 + 10.0.0-preview.5.25269.109 8.0.0 4.5.1 @@ -180,7 +180,7 @@ 2.0.0 17.10.0-beta1.24272.1 - 2.0.0-beta5.25267.102 + 2.0.0-beta5.25269.109 3.1.16 2.1.0 2.0.3 @@ -226,7 +226,7 @@ 9.0.0-preview-20241010.1 - 0.11.5-alpha.25267.102 + 0.11.5-alpha.25269.109 10.0.0-preview.5.25261.1 @@ -258,7 +258,7 @@ Note: when the name is updated, make sure to update dependency name in eng/pipelines/common/xplat-setup.yml like - DarcDependenciesChanged.Microsoft_NET_Workload_Emscripten_Current_Manifest-10_0_100_Transport --> - 10.0.100-preview.5.25267.102 + 10.0.100-preview.5.25269.109 $(MicrosoftNETWorkloadEmscriptenCurrentManifest100100TransportVersion) 1.1.87-gba258badda diff --git a/eng/common/templates/steps/vmr-sync.yml b/eng/common/templates/steps/vmr-sync.yml new file mode 100644 index 00000000000000..599afb6186b8fd --- /dev/null +++ b/eng/common/templates/steps/vmr-sync.yml @@ -0,0 +1,207 @@ +### These steps synchronize new code from product repositories into the VMR (https://github.com/dotnet/dotnet). +### They initialize the darc CLI and pull the new updates. +### Changes are applied locally onto the already cloned VMR (located in $vmrPath). + +parameters: +- name: targetRef + displayName: Target revision in dotnet/ to synchronize + type: string + default: $(Build.SourceVersion) + +- name: vmrPath + displayName: Path where the dotnet/dotnet is checked out to + type: string + default: $(Agent.BuildDirectory)/vmr + +- name: additionalSyncs + displayName: Optional list of package names whose repo's source will also be synchronized in the local VMR, e.g. NuGet.Protocol + type: object + default: [] + +steps: +- checkout: vmr + displayName: Clone dotnet/dotnet + path: vmr + clean: true + +- checkout: self + displayName: Clone $(Build.Repository.Name) + path: repo + fetchDepth: 0 + +# This step is needed so that when we get a detached HEAD / shallow clone, +# we still pull the commit into the temporary repo clone to use it during the sync. +# Also unshallow the clone so that forwardflow command would work. +- script: | + git branch repo-head + git rev-parse HEAD + displayName: Label PR commit + workingDirectory: $(Agent.BuildDirectory)/repo + +- script: | + vmr_sha=$(grep -oP '(?<=Sha=")[^"]*' $(Agent.BuildDirectory)/repo/eng/Version.Details.xml) + echo "##vso[task.setvariable variable=vmr_sha]$vmr_sha" + displayName: Obtain the vmr sha from Version.Details.xml (Unix) + condition: ne(variables['Agent.OS'], 'Windows_NT') + workingDirectory: $(Agent.BuildDirectory)/repo + +- powershell: | + [xml]$xml = Get-Content -Path $(Agent.BuildDirectory)/repo/eng/Version.Details.xml + $vmr_sha = $xml.SelectSingleNode("//Source").Sha + Write-Output "##vso[task.setvariable variable=vmr_sha]$vmr_sha" + displayName: Obtain the vmr sha from Version.Details.xml (Windows) + condition: eq(variables['Agent.OS'], 'Windows_NT') + workingDirectory: $(Agent.BuildDirectory)/repo + +- script: | + git fetch --all + git checkout $(vmr_sha) + displayName: Checkout VMR at correct sha for repo flow + workingDirectory: ${{ parameters.vmrPath }} + +- script: | + git config --global user.name "dotnet-maestro[bot]" + git config --global user.email "dotnet-maestro[bot]@users.noreply.github.com" + displayName: Set git author to dotnet-maestro[bot] + workingDirectory: ${{ parameters.vmrPath }} + +- script: | + ./eng/common/vmr-sync.sh \ + --vmr ${{ parameters.vmrPath }} \ + --tmp $(Agent.TempDirectory) \ + --azdev-pat '$(dn-bot-all-orgs-code-r)' \ + --ci \ + --debug + + if [ "$?" -ne 0 ]; then + echo "##vso[task.logissue type=error]Failed to synchronize the VMR" + exit 1 + fi + displayName: Sync repo into VMR (Unix) + condition: ne(variables['Agent.OS'], 'Windows_NT') + workingDirectory: $(Agent.BuildDirectory)/repo + +- script: | + git config --global diff.astextplain.textconv echo + git config --system core.longpaths true + displayName: Configure Windows git (longpaths, astextplain) + condition: eq(variables['Agent.OS'], 'Windows_NT') + +- powershell: | + ./eng/common/vmr-sync.ps1 ` + -vmr ${{ parameters.vmrPath }} ` + -tmp $(Agent.TempDirectory) ` + -azdevPat '$(dn-bot-all-orgs-code-r)' ` + -ci ` + -debugOutput + + if ($LASTEXITCODE -ne 0) { + echo "##vso[task.logissue type=error]Failed to synchronize the VMR" + exit 1 + } + displayName: Sync repo into VMR (Windows) + condition: eq(variables['Agent.OS'], 'Windows_NT') + workingDirectory: $(Agent.BuildDirectory)/repo + +- ${{ if eq(variables['Build.Reason'], 'PullRequest') }}: + - task: CopyFiles@2 + displayName: Collect failed patches + condition: failed() + inputs: + SourceFolder: '$(Agent.TempDirectory)' + Contents: '*.patch' + TargetFolder: '$(Build.ArtifactStagingDirectory)/FailedPatches' + + - publish: '$(Build.ArtifactStagingDirectory)/FailedPatches' + artifact: $(System.JobDisplayName)_FailedPatches + displayName: Upload failed patches + condition: failed() + +- ${{ each assetName in parameters.additionalSyncs }}: + # The vmr-sync script ends up staging files in the local VMR so we have to commit those + - script: + git commit --allow-empty -am "Forward-flow $(Build.Repository.Name)" + displayName: Commit local VMR changes + workingDirectory: ${{ parameters.vmrPath }} + + - script: | + set -ex + + echo "Searching for details of asset ${{ assetName }}..." + + # Use darc to get dependencies information + dependencies=$(./.dotnet/dotnet darc get-dependencies --name '${{ assetName }}' --ci) + + # Extract repository URL and commit hash + repository=$(echo "$dependencies" | grep 'Repo:' | sed 's/Repo:[[:space:]]*//' | head -1) + + if [ -z "$repository" ]; then + echo "##vso[task.logissue type=error]Asset ${{ assetName }} not found in the dependency list" + exit 1 + fi + + commit=$(echo "$dependencies" | grep 'Commit:' | sed 's/Commit:[[:space:]]*//' | head -1) + + echo "Updating the VMR from $repository / $commit..." + cd .. + git clone $repository ${{ assetName }} + cd ${{ assetName }} + git checkout $commit + git branch "sync/$commit" + + ./eng/common/vmr-sync.sh \ + --vmr ${{ parameters.vmrPath }} \ + --tmp $(Agent.TempDirectory) \ + --azdev-pat '$(dn-bot-all-orgs-code-r)' \ + --ci \ + --debug + + if [ "$?" -ne 0 ]; then + echo "##vso[task.logissue type=error]Failed to synchronize the VMR" + exit 1 + fi + displayName: Sync ${{ assetName }} into (Unix) + condition: ne(variables['Agent.OS'], 'Windows_NT') + workingDirectory: $(Agent.BuildDirectory)/repo + + - powershell: | + $ErrorActionPreference = 'Stop' + + Write-Host "Searching for details of asset ${{ assetName }}..." + + $dependencies = .\.dotnet\dotnet darc get-dependencies --name '${{ assetName }}' --ci + + $repository = $dependencies | Select-String -Pattern 'Repo:\s+([^\s]+)' | Select-Object -First 1 + $repository -match 'Repo:\s+([^\s]+)' | Out-Null + $repository = $matches[1] + + if ($repository -eq $null) { + Write-Error "Asset ${{ assetName }} not found in the dependency list" + exit 1 + } + + $commit = $dependencies | Select-String -Pattern 'Commit:\s+([^\s]+)' | Select-Object -First 1 + $commit -match 'Commit:\s+([^\s]+)' | Out-Null + $commit = $matches[1] + + Write-Host "Updating the VMR from $repository / $commit..." + cd .. + git clone $repository ${{ assetName }} + cd ${{ assetName }} + git checkout $commit + git branch "sync/$commit" + + .\eng\common\vmr-sync.ps1 ` + -vmr ${{ parameters.vmrPath }} ` + -tmp $(Agent.TempDirectory) ` + -azdevPat '$(dn-bot-all-orgs-code-r)' ` + -ci ` + -debugOutput + + if ($LASTEXITCODE -ne 0) { + echo "##vso[task.logissue type=error]Failed to synchronize the VMR" + exit 1 + } + displayName: Sync ${{ assetName }} into (Windows) + condition: ne(variables['Agent.OS'], 'Windows_NT') + workingDirectory: $(Agent.BuildDirectory)/repo diff --git a/eng/common/templates/vmr-build-pr.yml b/eng/common/templates/vmr-build-pr.yml new file mode 100644 index 00000000000000..670cf32c3bd1fa --- /dev/null +++ b/eng/common/templates/vmr-build-pr.yml @@ -0,0 +1,33 @@ +trigger: none +pr: + branches: + include: + - main + - release/* + paths: + exclude: + - documentation/* + - README.md + - CODEOWNERS + +variables: +- template: /eng/common/templates/variables/pool-providers.yml@self + +- name: skipComponentGovernanceDetection # we run CG on internal builds only + value: true + +- name: Codeql.Enabled # we run CodeQL on internal builds only + value: false + +resources: + repositories: + - repository: vmr + type: github + name: dotnet/dotnet + endpoint: dotnet + +stages: +- template: /eng/pipelines/templates/stages/vmr-build.yml@vmr + parameters: + isBuiltFromVmr: false + scope: lite diff --git a/eng/common/vmr-sync.ps1 b/eng/common/vmr-sync.ps1 new file mode 100755 index 00000000000000..8c3c91ce8dede9 --- /dev/null +++ b/eng/common/vmr-sync.ps1 @@ -0,0 +1,138 @@ +<# +.SYNOPSIS + +This script is used for synchronizing the current repository into a local VMR. +It pulls the current repository's code into the specified VMR directory for local testing or +Source-Build validation. + +.DESCRIPTION + +The tooling used for synchronization will clone the VMR repository into a temporary folder if +it does not already exist. These clones can be reused in future synchronizations, so it is +recommended to dedicate a folder for this to speed up re-runs. + +.EXAMPLE + Synchronize current repository into a local VMR: + ./vmr-sync.ps1 -vmrDir "$HOME/repos/dotnet" -tmpDir "$HOME/repos/tmp" + +.PARAMETER tmpDir +Required. Path to the temporary folder where repositories will be cloned + +.PARAMETER vmrBranch +Optional. Branch of the 'dotnet/dotnet' repo to synchronize. The VMR will be checked out to this branch + +.PARAMETER azdevPat +Optional. Azure DevOps PAT to use for cloning private repositories. + +.PARAMETER vmrDir +Optional. Path to the dotnet/dotnet repository. When null, gets cloned to the temporary folder + +.PARAMETER debugOutput +Optional. Enables debug logging in the darc vmr command. + +.PARAMETER ci +Optional. Denotes that the script is running in a CI environment. +#> +param ( + [Parameter(Mandatory=$true, HelpMessage="Path to the temporary folder where repositories will be cloned")] + [string][Alias('t', 'tmp')]$tmpDir, + [string][Alias('b', 'branch')]$vmrBranch, + [string]$remote, + [string]$azdevPat, + [string][Alias('v', 'vmr')]$vmrDir, + [switch]$ci, + [switch]$debugOutput +) + +function Fail { + Write-Host "> $($args[0])" -ForegroundColor 'Red' +} + +function Highlight { + Write-Host "> $($args[0])" -ForegroundColor 'Cyan' +} + +$verbosity = 'verbose' +if ($debugOutput) { + $verbosity = 'debug' +} +# Validation + +if (-not $tmpDir) { + Fail "Missing -tmpDir argument. Please specify the path to the temporary folder where the repositories will be cloned" + exit 1 +} + +# Sanitize the input + +if (-not $vmrDir) { + $vmrDir = Join-Path $tmpDir 'dotnet' +} + +if (-not (Test-Path -Path $tmpDir -PathType Container)) { + New-Item -ItemType Directory -Path $tmpDir | Out-Null +} + +# Prepare the VMR + +if (-not (Test-Path -Path $vmrDir -PathType Container)) { + Highlight "Cloning 'dotnet/dotnet' into $vmrDir.." + git clone https://github.com/dotnet/dotnet $vmrDir + + if ($vmrBranch) { + git -C $vmrDir switch -c $vmrBranch + } +} +else { + if ((git -C $vmrDir diff --quiet) -eq $false) { + Fail "There are changes in the working tree of $vmrDir. Please commit or stash your changes" + exit 1 + } + + if ($vmrBranch) { + Highlight "Preparing $vmrDir" + git -C $vmrDir checkout $vmrBranch + git -C $vmrDir pull + } +} + +Set-StrictMode -Version Latest + +# Prepare darc + +Highlight 'Installing .NET, preparing the tooling..' +. .\eng\common\tools.ps1 +$dotnetRoot = InitializeDotNetCli -install:$true +$dotnet = "$dotnetRoot\dotnet.exe" +& "$dotnet" tool restore + +Highlight "Starting the synchronization of VMR.." + +# Synchronize the VMR +$darcArgs = ( + "darc", "vmr", "forwardflow", + "--tmp", $tmpDir, + "--$verbosity", + $vmrDir +) + +if ($ci) { + $darcArgs += ("--ci") +} + +if ($azdevPat) { + $darcArgs += ("--azdev-pat", $azdevPat) +} + +& "$dotnet" $darcArgs + +if ($LASTEXITCODE -eq 0) { + Highlight "Synchronization succeeded" +} +else { + Fail "Synchronization of repo to VMR failed!" + Fail "'$vmrDir' is left in its last state (re-run of this script will reset it)." + Fail "Please inspect the logs which contain path to the failing patch file (use -debugOutput to get all the details)." + Fail "Once you make changes to the conflicting VMR patch, commit it locally and re-run this script." + exit 1 +} diff --git a/eng/common/vmr-sync.sh b/eng/common/vmr-sync.sh new file mode 100755 index 00000000000000..86d77ccf5b4822 --- /dev/null +++ b/eng/common/vmr-sync.sh @@ -0,0 +1,205 @@ +#!/bin/bash + +### This script is used for synchronizing the current repository into a local VMR. +### It pulls the current repository's code into the specified VMR directory for local testing or +### Source-Build validation. +### +### The tooling used for synchronization will clone the VMR repository into a temporary folder if +### it does not already exist. These clones can be reused in future synchronizations, so it is +### recommended to dedicate a folder for this to speed up re-runs. +### +### USAGE: +### Synchronize current repository into a local VMR: +### ./vmr-sync.sh --tmp "$HOME/repos/tmp" "$HOME/repos/dotnet" +### +### Options: +### -t, --tmp, --tmp-dir PATH +### Required. Path to the temporary folder where repositories will be cloned +### +### -b, --branch, --vmr-branch BRANCH_NAME +### Optional. Branch of the 'dotnet/dotnet' repo to synchronize. The VMR will be checked out to this branch +### +### --debug +### Optional. Turns on the most verbose logging for the VMR tooling +### +### --remote name:URI +### Optional. Additional remote to use during the synchronization +### This can be used to synchronize to a commit from a fork of the repository +### Example: 'runtime:https://github.com/yourfork/runtime' +### +### --azdev-pat +### Optional. Azure DevOps PAT to use for cloning private repositories. +### +### -v, --vmr, --vmr-dir PATH +### Optional. Path to the dotnet/dotnet repository. When null, gets cloned to the temporary folder + +source="${BASH_SOURCE[0]}" + +# resolve $source until the file is no longer a symlink +while [[ -h "$source" ]]; do + scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" + source="$(readlink "$source")" + # if $source was a relative symlink, we need to resolve it relative to the path where the + # symlink file was located + [[ $source != /* ]] && source="$scriptroot/$source" +done +scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" + +function print_help () { + sed -n '/^### /,/^$/p' "$source" | cut -b 5- +} + +COLOR_RED=$(tput setaf 1 2>/dev/null || true) +COLOR_CYAN=$(tput setaf 6 2>/dev/null || true) +COLOR_CLEAR=$(tput sgr0 2>/dev/null || true) +COLOR_RESET=uniquesearchablestring +FAILURE_PREFIX='> ' + +function fail () { + echo "${COLOR_RED}$FAILURE_PREFIX${1//${COLOR_RESET}/${COLOR_RED}}${COLOR_CLEAR}" >&2 +} + +function highlight () { + echo "${COLOR_CYAN}$FAILURE_PREFIX${1//${COLOR_RESET}/${COLOR_CYAN}}${COLOR_CLEAR}" +} + +tmp_dir='' +vmr_dir='' +vmr_branch='' +additional_remotes='' +verbosity=verbose +azdev_pat='' +ci=false + +while [[ $# -gt 0 ]]; do + opt="$(echo "$1" | tr "[:upper:]" "[:lower:]")" + case "$opt" in + -t|--tmp|--tmp-dir) + tmp_dir=$2 + shift + ;; + -v|--vmr|--vmr-dir) + vmr_dir=$2 + shift + ;; + -b|--branch|--vmr-branch) + vmr_branch=$2 + shift + ;; + --remote) + additional_remotes="$additional_remotes $2" + shift + ;; + --azdev-pat) + azdev_pat=$2 + shift + ;; + --ci) + ci=true + ;; + -d|--debug) + verbosity=debug + ;; + -h|--help) + print_help + exit 0 + ;; + *) + fail "Invalid argument: $1" + print_help + exit 1 + ;; + esac + + shift +done + +# Validation + +if [[ -z "$tmp_dir" ]]; then + fail "Missing --tmp-dir argument. Please specify the path to the temporary folder where the repositories will be cloned" + exit 1 +fi + +# Sanitize the input + +if [[ -z "$vmr_dir" ]]; then + vmr_dir="$tmp_dir/dotnet" +fi + +if [[ ! -d "$tmp_dir" ]]; then + mkdir -p "$tmp_dir" +fi + +if [[ "$verbosity" == "debug" ]]; then + set -x +fi + +# Prepare the VMR + +if [[ ! -d "$vmr_dir" ]]; then + highlight "Cloning 'dotnet/dotnet' into $vmr_dir.." + git clone https://github.com/dotnet/dotnet "$vmr_dir" + + if [[ -n "$vmr_branch" ]]; then + git -C "$vmr_dir" switch -c "$vmr_branch" + fi +else + if ! git -C "$vmr_dir" diff --quiet; then + fail "There are changes in the working tree of $vmr_dir. Please commit or stash your changes" + exit 1 + fi + + if [[ -n "$vmr_branch" ]]; then + highlight "Preparing $vmr_dir" + git -C "$vmr_dir" checkout "$vmr_branch" + git -C "$vmr_dir" pull + fi +fi + +set -e + +# Prepare darc + +highlight 'Installing .NET, preparing the tooling..' +source "./eng/common/tools.sh" +InitializeDotNetCli true +dotnetDir=$( cd ./.dotnet/; pwd -P ) +dotnet=$dotnetDir/dotnet +"$dotnet" tool restore + +highlight "Starting the synchronization of VMR.." +set +e + +if [[ -n "$additional_remotes" ]]; then + additional_remotes="--additional-remotes $additional_remotes" +fi + +if [[ -n "$azdev_pat" ]]; then + azdev_pat="--azdev-pat $azdev_pat" +fi + +ci_arg='' +if [[ "$ci" == "true" ]]; then + ci_arg="--ci" +fi + +# Synchronize the VMR + +"$dotnet" darc vmr forwardflow \ + --tmp "$tmp_dir" \ + $azdev_pat \ + --$verbosity \ + $ci_arg \ + $additional_remotes \ + "$vmr_dir" + +if [[ $? == 0 ]]; then + highlight "Synchronization succeeded" +else + fail "Synchronization of repo to VMR failed!" + fail "'$vmr_dir' is left in its last state (re-run of this script will reset it)." + fail "Please inspect the logs which contain path to the failing patch file (use --debug to get all the details)." + fail "Once you make changes to the conflicting VMR patch, commit it locally and re-run this script." + exit 1 +fi diff --git a/global.json b/global.json index 714fecff2d503a..0b348ef3b456fe 100644 --- a/global.json +++ b/global.json @@ -8,11 +8,11 @@ "dotnet": "10.0.100-preview.5.25265.106" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25267.102", - "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25267.102", - "Microsoft.DotNet.SharedFramework.Sdk": "10.0.0-beta.25267.102", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25269.109", + "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25269.109", + "Microsoft.DotNet.SharedFramework.Sdk": "10.0.0-beta.25269.109", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", - "Microsoft.NET.Sdk.IL": "10.0.0-preview.5.25267.102" + "Microsoft.NET.Sdk.IL": "10.0.0-preview.5.25269.109" } }