-
Notifications
You must be signed in to change notification settings - Fork 4.7k
/
Devirtualization.cs
139 lines (113 loc) · 3.68 KB
/
Devirtualization.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// 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.Runtime.CompilerServices;
using System.Runtime.InteropServices;
class Devirtualization
{
internal static int Run()
{
RegressionBug73076.Run();
DevirtualizationCornerCaseTests.Run();
DevirtualizeIntoUnallocatedGenericType.Run();
return 100;
}
class RegressionBug73076
{
interface IFactory
{
BaseFtnn<T> Make<T>();
}
class Factory : IFactory
{
[MethodImpl(MethodImplOptions.NoInlining)]
public BaseFtnn<T> Make<T>() => new DerivedFtnn<T>();
}
class BaseFtnn<T>
{
public virtual string GetId() => "Base";
}
class DerivedFtnn<T> : BaseFtnn<T>
{
public override string GetId() => "Derived";
}
public static void Run()
{
IFactory factory = new Factory();
// This is a generic virtual method call so we'll only ever see BaseFtnn and DerivedFtnn instantiated
// over __Canon at compile time.
var made = factory.Make<object>();
if (made.GetId() != "Derived")
throw new Exception();
}
}
class DevirtualizationCornerCaseTests
{
interface IIntf1
{
int GetValue();
}
class Intf1Impl : IIntf1
{
public virtual int GetValue() => 123;
}
[DynamicInterfaceCastableImplementation]
interface IIntf1Impl : IIntf1
{
int IIntf1.GetValue() => 456;
}
class Intf1CastableImpl : IDynamicInterfaceCastable
{
public RuntimeTypeHandle GetInterfaceImplementation(RuntimeTypeHandle interfaceType) => typeof(IIntf1Impl).TypeHandle;
public bool IsInterfaceImplemented(RuntimeTypeHandle interfaceType, bool throwIfNotImplemented) => true;
}
interface IIntf2
{
int GetValue();
}
class Intf2Impl1 : IIntf2
{
public virtual int GetValue() => 123;
}
class Intf2Impl2<T> : IIntf2
{
public virtual int GetValue() => 456;
}
static void AssertEqual<T>(T expected, T actual)
{
if (!object.Equals(expected, actual))
throw new Exception();
}
[MethodImpl(MethodImplOptions.NoInlining)]
static void TestIntf1(IIntf1 o, int expected) => AssertEqual(expected, o.GetValue());
[MethodImpl(MethodImplOptions.NoInlining)]
static void TestIntf2(IIntf2 o, int expected) => AssertEqual(expected, o.GetValue());
public static void Run()
{
TestIntf1(new Intf1Impl(), 123);
TestIntf1((IIntf1)new Intf1CastableImpl(), 456);
TestIntf2(new Intf2Impl1(), 123);
TestIntf2((IIntf2)Activator.CreateInstance(typeof(Intf2Impl2<>).MakeGenericType(typeof(object))), 456);
}
}
class DevirtualizeIntoUnallocatedGenericType
{
class Never { }
class SomeGeneric<T>
{
public virtual object GrabObject() => null;
}
sealed class SomeUnallocatedClass<T> : SomeGeneric<T>
{
public override object GrabObject() => new Never();
}
[MethodImpl(MethodImplOptions.NoInlining)]
static SomeUnallocatedClass<object> GrabInst() => null;
public static void Run()
{
if (GrabInst() != null)
GrabInst().GrabObject();
}
}
}