-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix devirtualization in shared generic context
In circumstances where the JIT doesn't provide exact enough details about the impl type and interface method to identify exactly which method should be called - In particular, when the impl class implements multiple copies of the target interface, and they are canonically compatible with the interface method that is to be called - Simply disable devirtualization for these scenarios Fixes #51982
- Loading branch information
1 parent
1883505
commit 5c875e4
Showing
4 changed files
with
108 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
56 changes: 56 additions & 0 deletions
56
src/tests/JIT/opt/Devirtualization/MultipleCanonicallyCompatibleImplementations.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
using System; | ||
using System.Runtime.CompilerServices; | ||
|
||
|
||
public class MultipleCanonicallyCompatibleImplementations | ||
{ | ||
static int Main() | ||
{ | ||
string atom1Call = Foo<Atom1>.Call(); | ||
string atom2Call = Foo<Atom2>.Call(); | ||
Console.WriteLine($"Atom1Call `{atom1Call}`"); | ||
Console.WriteLine($"Atom2Call `{atom2Call}`"); | ||
|
||
if (atom1Call != "FooBaseFooBaseFoo") | ||
{ | ||
Console.WriteLine("Atom1Call should be FooBaseFooBaseFoo"); | ||
return 1; | ||
} | ||
if (atom2Call != "FooFooFooBaseFoo") | ||
{ | ||
Console.WriteLine("Atom2Call should be FooFooFooBaseFoo"); | ||
return 2; | ||
} | ||
|
||
return 100; | ||
} | ||
} | ||
|
||
interface IFooable<T> | ||
{ | ||
public string DoFoo(T x); | ||
} | ||
|
||
class Base : IFooable<Atom2> | ||
{ | ||
string IFooable<Atom2>.DoFoo(Atom2 x) => "Base"; | ||
} | ||
|
||
sealed class Foo<T> : Base, IFooable<T> | ||
{ | ||
string IFooable<T>.DoFoo(T x) => "Foo"; | ||
|
||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
public static string Call() | ||
{ | ||
var f = new Foo<T>(); | ||
var fA1 = new Foo<Atom1>(); | ||
var fA2 = new Foo<Atom2>(); | ||
return ((IFooable<T>)f).DoFoo(default) + ((IFooable<Atom2>)f).DoFoo(null) | ||
+ ((IFooable<Atom1>)fA1).DoFoo(default) + ((IFooable<Atom2>)fA1).DoFoo(null) | ||
+ ((IFooable<Atom2>)fA2).DoFoo(default); | ||
} | ||
} | ||
|
||
class Atom1 { } | ||
class Atom2 { } |
13 changes: 13 additions & 0 deletions
13
src/tests/JIT/opt/Devirtualization/MultipleCanonicallyCompatibleImplementations.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<CLRTestPriority>1</CLRTestPriority> | ||
</PropertyGroup> | ||
<PropertyGroup> | ||
<DebugType>PdbOnly</DebugType> | ||
<Optimize>True</Optimize> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<Compile Include="MultipleCanonicallyCompatibleImplementations.cs" /> | ||
</ItemGroup> | ||
</Project> |