-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Open
Labels
area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMICLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Milestone
Description
In the below example the call res[0] = this.Do(src[0]);
won't be inlined, whilst res[0] = this.Do('B');
will be inlined.
using System.Linq;
using System.Runtime.CompilerServices;
namespace ConsoleApp1
{
class Program
{
static int Main(string[] args)
{
var foo = new Foo();
var res = Do(foo);
return res[0];
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static char[] Do(Foo foo)
{
//return foo.DoWillDevirt();
return foo.DoWontDevirt();
}
}
public abstract class Base
{
private char[] _src = Enumerable.Repeat('B', 10).ToArray();
private char[] _res = new char[10];
public char[] DoWontDevirt()
{
char[] src = _src;
char[] res = _res;
res[0] = this.Do(src[0]);
return res;
}
public char[] DoWillDevirt()
{
char[] src = _src;
char[] res = _res;
res[0] = this.Do('B');
return res;
}
public abstract char Do(char c);
}
public class Foo : Base
{
public sealed override char Do(char c) => (char)(c + 1);
}
}
Excerpt of JIT dump:
impDevirtualizeCall: Trying to devirtualize virtual call:
class for 'this' is Base (attrib 21000400)
base method is Base::Do
devirt to Base::Do -- inexact or not final
[000021] --C-G------- * CALLV ind int Base.Do
[000019] ------------ this in rdi +--* LCL_VAR ref V00 this
[000020] ------------ arg1 \--* LCL_VAR int V02 loc1
Class not final or exact, and method not final
NOT Marking call [000021] as guarded devirtualization candidate -- disabled by jit config
INLINER: during 'impMarkInlineCandidate' result 'failed this call site' reason 'target not direct' for 'Base:DoWontDevirt():ref:this' calling 'Base:Do(ushort):ushort:this'
INLINER: during 'impMarkInlineCandidate' result 'failed this call site' reason 'target not direct'
For DoWillDevirt
:
impDevirtualizeCall: Trying to devirtualize virtual call:
class for 'this' is Foo (attrib 21000000)
base method is Base::Do
devirt to Foo::Do -- final method
[000022] --C-G------- * CALLV ind int Base.Do
[000020] ------------ this in rdi +--* LCL_VAR ref V00 this
[000021] ------------ arg1 \--* CNS_INT int 66
final method; can devirtualize
So the difference is that in the former case the JIT won't recognize the current type class for 'this' is Base
vs. class for 'this' is Foo
.
In the IL there is nothing special for either case:
.method public hidebysig
instance char[] DoWontDevirt () cil managed
{
// Method begins at RVA 0x2070
// Code size 28 (0x1c)
.maxstack 4
.locals init (
[0] char[],
[1] char
)
IL_0000: ldarg.0
IL_0001: ldfld char[] ConsoleApp1.Base::_src
IL_0006: ldarg.0
IL_0007: ldfld char[] ConsoleApp1.Base::_res
IL_000c: stloc.0
IL_000d: ldc.i4.0
IL_000e: ldelem.u2
IL_000f: stloc.1
IL_0010: ldloc.0
IL_0011: ldc.i4.0
IL_0012: ldarg.0
IL_0013: ldloc.1
IL_0014: callvirt instance char ConsoleApp1.Base::Do(char)
IL_0019: stelem.i2
IL_001a: ldloc.0
IL_001b: ret
}
.method public hidebysig
instance char[] DoWillDevirt () cil managed
{
// Method begins at RVA 0x2098
// Code size 25 (0x19)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld char[] ConsoleApp1.Base::_src
IL_0006: pop
IL_0007: ldarg.0
IL_0008: ldfld char[] ConsoleApp1.Base::_res
IL_000d: dup
IL_000e: ldc.i4.0
IL_000f: ldarg.0
IL_0010: ldc.i4.s 66
IL_0012: callvirt instance char ConsoleApp1.Base::Do(char)
IL_0017: stelem.i2
IL_0018: ret
}
Build for coreclr was done at commit d4cab6e (from yesterday).
If this is already tracked in https://github.com/dotnet/coreclr/issues/9908 please feel free to close this issue here.
/cc: @AndyAyersMS
category:cq
theme:inlining
skill-level:expert
cost:medium
Metadata
Metadata
Assignees
Labels
area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMICLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI