Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] conditionally assign (exact)contextHandle #45321

Conversation

Rattenkrieg
Copy link
Contributor

@Rattenkrieg Rattenkrieg commented Nov 29, 2020

Fixes #38477

I hacked this in a straightforward manner while I was working on #43668 but I was in doubt that such dumb fix is enough until I saw @AndyAyersMS 's comment

I've ended with similar asm but with System.Object:.ctor() call not eliminated: See EDIT

*************** After end code gen, before unwindEmit()
G_M24375_IG01:        ; func=00, offs=000000H, size=0004H, bbWeight=1    PerfScore 0.25, gcrefRegs=00000000 {}, byrefRegs=00000000 {}, byref, nogc <-- Prolog IG

IN0006: 000000 sub      rsp, 40

G_M24375_IG02:        ; offs=000004H, size=001CH, bbWeight=1    PerfScore 2.75, gcrefRegs=00000000 {}, byrefRegs=00000000 {}, byref

IN0001: 000004 mov      rcx, 0x7FF88E89F850
IN0002: 00000E call     CORINFO_HELP_NEWSFAST
IN0003: 000013 mov      rcx, rax
IN0004: 000016 call     System.Object:.ctor():this
IN0005: 00001B mov      eax, 1

G_M24375_IG03:        ; offs=000020H, size=0005H, bbWeight=1    PerfScore 1.25, epilog, nogc, extend

IN0007: 000020 add      rsp, 40
IN0008: 000024 ret
    Inlines into 06000003 [via DefaultPolicy] Program:Main():int
        [1 IL=0000 TR=000005 06000002] [below ALWAYS_INLINE size] G`1[__Canon][System.__Canon]:.ctor():this
            [0 IL=0001 TR=000016 0600049E] [FAILED: noinline per VM] System.Object:.ctor():this
        [2 IL=0005 TR=000007 06000001] [aggressive inline attribute devirt] G`1[__Canon][System.__Canon]:M():bool:this

Given FAILED: noinline per VM I wonder if @AndyAyersMS was testing this on non-master branch. However non-virtual public bool M() => typeof(T) == typeof(string); jits to

*************** After end code gen, before unwindEmit()
G_M24375_IG01:        ; func=00, offs=000000H, size=0000H, bbWeight=1    PerfScore 0.00, gcrefRegs=00000000 {}, byrefRegs=00000000 {}, byref, nogc <-- Prolog IG
G_M24375_IG02:        ; offs=000000H, size=0005H, bbWeight=1    PerfScore 0.25, gcrefRegs=00000000 {}, byrefRegs=00000000 {}, byref

IN0001: 000000 mov      eax, 100

G_M24375_IG03:        ; offs=000005H, size=0001H, bbWeight=1    PerfScore 1.00, epilog, nogc, extend

IN0002: 000005 ret

So there is definitely an opportunity for me to hack further.

I have issues with crafting jit diffs atm, will submit it soon.

EDIT:
Above asm was produced with debug build where JIT_FLAG_DEBUG_CODE prevents System.Object:.ctor() inlining.
With checked build I have asm similar to @AndyAyersMS

*************** After end code gen, before unwindEmit()
G_M24375_IG01:        ; func=00, offs=000000H, size=0004H, bbWeight=1    PerfScore 0.25, gcrefRegs=00000000 {}, byrefRegs=00000000 {}, byref, nogc <-- Prolog IG

IN0002: 000000 sub      rsp, 40

G_M24375_IG02:        ; offs=000004H, size=0005H, bbWeight=1    PerfScore 0.25, gcrefRegs=00000000 {}, byrefRegs=00000000 {}, byref

IN0001: 000004 mov      eax, 100

G_M24375_IG03:        ; offs=000009H, size=0005H, bbWeight=1    PerfScore 1.25, epilog, nogc, extend

IN0003: 000009 add      rsp, 40
IN0004: 00000D ret
Inlines into 06000003 [via DefaultPolicy] Program:Main():int
  [1 IL=0000 TR=000005 06000002] [below ALWAYS_INLINE size] G`1[__Canon][System.__Canon]:.ctor():this
    [2 IL=0001 TR=000030 0600049E] [below ALWAYS_INLINE size] System.Object:.ctor():this
  [3 IL=0007 TR=000010 06000001] [aggressive inline attribute devirt] G`1[__Canon][System.__Canon]:MVIRT():bool:this

@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Nov 29, 2020

// Update context handle.
if ((exactContextHandle != nullptr) && (*exactContextHandle != nullptr))
{
*exactContextHandle = MAKE_METHODCONTEXT(derivedMethod);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why it didn't work that way:

info.compCompHnd->getClassName(objClass):	  "G`1[[System.String, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]"
info.compCompHnd->getClassName(baseClass):	  "G`1[__Canon]"
info.compCompHnd->getClassName(derivedClass): "G`1[__Canon]"

@Rattenkrieg
Copy link
Contributor Author

Here is the failing assert:

_ASSERTE(CheckContext(pResolvedToken->tokenScope, pResolvedToken->tokenContext));

@Rattenkrieg
Copy link
Contributor Author

Rattenkrieg commented Nov 30, 2020

Fun fact:

Checked run with removed

_ASSERTE(CheckContext(pResolvedToken->tokenScope, pResolvedToken->tokenContext));

produces only single failure:

ERROR: Input redirection is not supported, exiting the process immediately.
***thousands of times repeated***
Waiting for concurrent Crossgen2 compilation: C:\Users\sergey\source\repos\runtime\artifacts\tests\coreclr\windows.x64.Checked\readytorun\crossgen2\crossgen2smoke\IL-CG2\done
***thousands of times repeated***


cmdLine:C:\Users\sergey\source\repos\runtime\artifacts\tests\coreclr\windows.x64.Checked\readytorun\crossgen2\crossgen2smoke\crossgen2smoke.cmd Timed Out (timeout in milliseconds: 900000 from variable __TestTimeout, start: 11/30/2020 10:26:54 PM, end: 11/30/2020 10:41:54 PM)

EDIT
Failure is not consistent, test suite passed on second run.

@AndyAyersMS
Copy link
Member

@Rattenkrieg I suspect fixing this also requires runtime changes.

Ignoring generic methods for the moment, I think the context must always be set to the derived class, but currently the jit does not have the exact version. You can get away with using the object class times (since often the derived and object class are the same), but I suspect this won't always work.

Interesting test cases are those where we shift from generic to non-generic (and vice versa) as we move up the hierarchy.

@AndyAyersMS
Copy link
Member

@jkotas @Rattenkrieg I think this is a plausible fix:
master...AndyAyersMS:ExactContextAfterDevirt

(SPMI/Crossgen2 handling not fully there yet)

We were losing the exactness because GetMethodDescForSlot always returns the canonical method desc, even if you call it on an exact class type. To provide the missing info, we need to pass back multiple values from resolveVirtualMethod. Similar things came up in #43668, so we should probably reconcile the two changes.

We won't see generic virtual methods in impDevirtualizeCall as they currently don't get handled in the same manner as interface and virtual calls, so the exact context is always a class context today.

It handles cases like the following:

using System;
using System.Runtime.CompilerServices;

class B
{
    public virtual int F() => 33;
}

class D<T> : B
{
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public override int F() => typeof(T) == typeof(string) ? 44 : 55;
}

class E : D<string>
{

}

class G<T> : E
{
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public override int F() => typeof(T) == typeof(string) ? 66 : 77;
}

class Program
{
    public static void Main()
    {
        B b = new B();
        D<string> ds = new D<string>();
        E e = new E();
        G<string> gs = new G<string>();
        
        Console.WriteLine($"B.F() = {b.F()}");    
        Console.WriteLine($"D<string>.F() = {ds.F()}");    
        Console.WriteLine($"E.F() = {e.F()}");    
        Console.WriteLine($"G<string>.F() = {gs.F()}");
    }
}

But it does not seem to crop up all that often.

PMI only shows 19 diffs out of 259k methods. Many of those just replace one level of call with another, though there is a good diff in Roslyn's PEModuleBuilder:ValidateReferencedAssembly(AssemblySymbol,AssemblyReference,DiagnosticBag):this

where we go from

G_M5034_IG17:
       cmp      gword ptr [rdi+264], 0
       je       SHORT G_M5034_IG20
						;; bbWeight=1    PerfScore 3.00
G_M5034_IG18:
       mov      rcx, gword ptr [rdi+264]
       mov      rax, 0xD1FFAB1E
       cmp      dword ptr [rcx], ecx
       call     qword ptr [rax]EmbeddedTypesManager`21:get_IsFrozen():bool:this
       test     eax, eax
       je       SHORT G_M5034_IG20
       mov      rcx, gword ptr [rdi+264]
       mov      rdx, rsi
       mov      r8, rbx
       mov      rax, 0xD1FFAB1E
       mov      rax, qword ptr [rax]
       cmp      dword ptr [rcx], ecx

to

G_M5034_IG17:
       mov      rcx, gword ptr [rdi+264]
       test     rcx, rcx
       je       SHORT G_M5034_IG20
						;; bbWeight=1    PerfScore 3.25
G_M5034_IG18:
       mov      rdx, rcx
       cmp      dword ptr [rdx], edx
       add      rdx, 56
       cmp      gword ptr [rdx], 0
       je       SHORT G_M5034_IG20
       mov      rdx, rsi
       mov      r8, rbx
       mov      rax, 0xD1FFAB1E
       mov      rax, qword ptr [rax]
       cmp      dword ptr [rcx], ecx

@AndyAyersMS
Copy link
Member

@Rattenkrieg I am going to rework my changes to use the same kind of struct you were considering ... also rebasing on top of #45044 to simplify some of the interface plumbing.

@Rattenkrieg
Copy link
Contributor Author

@AndyAyersMS sure! Since I cannot dedicate enough time to hack runtime on any other day than weekends I don't want to block you in case you willing to work on this issue at the moment or just have a better idea. I can close this PR in favor of your branch.

@Rattenkrieg
Copy link
Contributor Author

Closing in favor of #45526

@Rattenkrieg Rattenkrieg closed this Dec 3, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Jan 2, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Compute precise generic context after de-virtualization
3 participants