From 636eb226c552e4a1c821717279556a01cf6550e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 12 Aug 2022 16:35:18 +0900 Subject: [PATCH 1/2] Prevent devirtualization into unallocated types If we were in a situation like in the regression test, we would devirtualize the `GrabObject` call to `SomeUnallocatedClass.GrabObject`. But because `SomeUnallocatedClass` was never allocated, the scanner didn't scan it, and bad things would happen. Prevent devirtualizing into types that were not seen as allocated. This is not a real issue for non-generic (non-shareable) types because the tentative instance method optimization generates throwing bodies for these. But tentative method optimization doesn't run for shared generics: https://github.com/dotnet/runtime/blob/4cbe6f99d23e04c56a89251d49de1b0f14000427/src/coreclr/tools/Common/Compiler/MethodExtensions.cs#L115 This was rare enough that we haven't seen it until I did #73683 and there was one useless constructor that we stopped generating and triggered this. This also includes what is essentially a rollback of https://github.com/dotnet/runtimelab/pull/1700. This should have been rolled back with https://github.com/dotnet/runtime/pull/66145 but I forgot we had this. It was not needed. --- .../ILCompiler.Compiler/Compiler/ILScanner.cs | 25 +++++-------------- .../SmokeTests/UnitTests/Devirtualization.cs | 25 +++++++++++++++++++ 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ILScanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ILScanner.cs index c2caeb24b3341f..da72ea35cb05b0 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ILScanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ILScanner.cs @@ -365,8 +365,8 @@ public override DictionaryLayoutNode GetLayout(TypeSystemEntity methodOrType) private class ScannedDevirtualizationManager : DevirtualizationManager { private HashSet _constructedTypes = new HashSet(); + private HashSet _canonConstructedTypes = new HashSet(); private HashSet _unsealedTypes = new HashSet(); - private HashSet _abstractButNonabstractlyOverriddenTypes = new HashSet(); public ScannedDevirtualizationManager(ImmutableArray> markedNodes) { @@ -390,16 +390,13 @@ public ScannedDevirtualizationManager(ImmutableArray).MakeGenericType(typeof(object))), 456); } } + + class DevirtualizeIntoUnallocatedGenericType + { + class Never { } + + class SomeGeneric + { + public virtual object GrabObject() => null; + } + + sealed class SomeUnallocatedClass : SomeGeneric + { + public override object GrabObject() => new Never(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static SomeUnallocatedClass GrabInst() => null; + + public static void Run() + { + if (GrabInst() != null) + GrabInst().GrabObject(); + } + } } From 92d9b7506dc511959be3e538d2140ddfe4e4ff22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 12 Aug 2022 19:07:04 +0900 Subject: [PATCH 2/2] Update tests.proj --- src/libraries/tests.proj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index 9820d280330719..da787c4710b61c 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -490,6 +490,7 @@ +