Proposed: C# compiler could use flow analysis to track types in variables permitting the use of a `constrained` instruction on virtual calls.
See original GitHub issueBoxing for isinst
aside https://github.com/dotnet/coreclr/issues/12877 it would be nice if Pattern Matching issued a constrained
instruction prior to callvirt
where a generic type was matched to an interface
Version Used:
Microsoft Visual Studio Enterprise 2017 Version 15.3.4 VisualStudio.15.Release/15.3.4+26730.15 C#7
Steps to Reproduce:
int key0, key1;
PatternMatchEquality<int>.Equals(key0, key1)
Where
public class PatternMatchEquality<TKey>
{
private static readonly EqualityComparer<TKey> _defaultComparer = EqualityComparer<TKey>.Default;
public static bool Equals(TKey key0, TKey key1)
{
switch (key0)
{
case IEquatable<TKey> key:
return key.Equals(key1);
default:
//return _defaultComparer.Equals(key0, key1);
throw new Exception();
}
}
}
Expected Behavior:
il output
ldarg.1 // key1
constrained. !0/*TKey*/ <--------
callvirt instance bool class [System.Runtime]System.IEquatable`1<!0/*TKey*/>::Equals(!0/*TKey*/)
ret
Actual Behavior:
il output
.method public hidebysig static bool
Equals(
!0/*TKey*/ key0,
!0/*TKey*/ key1
) cil managed
{
.maxstack 2
.locals init (
[0] !0/*TKey*/ V_0,
[1] class [System.Runtime]System.IEquatable`1<!0/*TKey*/> V_1
)
// [185 13 - 185 26]
IL_0000: ldarg.0 // key0
IL_0001: stloc.0 // V_0
IL_0002: ldloc.0 // V_0
IL_0003: box !0/*TKey*/
IL_0008: brfalse.s IL_0021
IL_000a: ldloc.0 // V_0
IL_000b: box !0/*TKey*/
IL_0010: isinst class [System.Runtime]System.IEquatable`1<!0/*TKey*/>
IL_0015: dup
IL_0016: stloc.1 // V_1
IL_0017: brfalse.s IL_0021
IL_0019: ldloc.1 // V_1
// [188 21 - 188 45]
IL_001a: ldarg.1 // key1
// <------- No constrained. !0
IL_001b: callvirt instance bool class [System.Runtime]System.IEquatable`1<!0/*TKey*/>::Equals(!0/*TKey*/)
IL_0020: ret
// [190 22 - 190 44]
IL_0021: newobj instance void [System.Runtime]System.Exception::.ctor()
IL_0026: throw
} // end of method PatternMatchEquality`1::Equals
/cc @gafter @alekseyts @agocke
Issue Analytics
- State:
- Created 6 years ago
- Comments:10 (10 by maintainers)
Top Results From Across the Web
Trade-offs in Control Flow Analysis · Issue #9998
How about tracking variable changes of functions? The basic idea is that we know a constraint before a function call and that we...
Read more >Static data-flow analysis for software product lines in C
Many critical codebases are written in C, and most of them use ... is a static analysis that tracks variables of a certain...
Read more >The LLVM Instruction Set and Compilation Strategy
LLVM (Low Level Virtual Machine) is a compilation strategy that uses a low-level virtual instruction set with rich type information as a common...
Read more >Control-Flow Analysis of Higher-Order Languages
In this dissertation, I present a technique for recovering the control-flow graph of a Scheme program at compile time. I give examples of...
Read more >Cloning-Based Context-Sensitive Pointer Alias Analysis Using ...
ABSTRACT. This paper presents the first scalable context-sensitive, inclusion- based pointer alias analysis for Java programs. Our approach to.
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
As background… (from https://github.com/dotnet/coreclr/issues/12877#issuecomment-329247453)
The scenario I’m trying to cover is calling struct generics if the type implements the the interface; so in effect getting the benefit of having a generic constraint without one being present.
The example I was looking at was the default comparer on dictionary; which currently goes via hoops and inheritance to implement the constrained
EqualityComparer
sinceTKey
itself is not constrained.However while that works, it also ends up with virtual calls for
Equals
andGetHashCode
that can’t be inlinedAs highlighted by ravendb in their fast-dictionary blog post; and the same thing could be achieved with the default comparer and struct keys in the regular dictionary.
Using a non-inherited
Equatable
as a static default and then with an override when the instance comparer is not null; gets most of the way there (second test)However can’t be used in dictionary as
TKey
is not constrained.So was looking to see if pattern matching could solve it; as at Jit time everything is known about the key type (if struct; i.e. whether it implements
IEquatable
) so it could elide everything out in a method; rather than on an object. Essentially applying a generic constraint; and binding to the interface methods (rather than the interface) after the fact/internally.That was the hope and motivation anyway 😃
Loosing the perf wins at
Will raise something over at csharplang
Thank you for looking at it