Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Conversation

briansull
Copy link

@briansull briansull commented Jan 4, 2019

When performing devirtualization we can not do both an unboxing optimization and a tail call optimization

  • Explicit tail calls are now checked for and blocked from performing an unboxing operation in impDevirtualizeCall.
  • If late devirtualization calls impDevirtualizeCall with an IMPLICIT_TAILCALL we will clear this flag if we decide to perform the unboxing operation.

@briansull
Copy link
Author

@AndyAyersMS FYI

@AndyAyersMS
Copy link
Member

You should make it clearer that this restriction is for explicit tail calls only, where presumably the IL producer is confident that at the point of the explicit tail call there aren't any live references to the caller frame, and if we undo the box, we will introduce one.

And I think this could also happen for late devirt though it would require a different kind of test case.

Seems like you could just check for GTF_CALL_M_EXPLICIT_TAILCALL to inhibit the box undo transform, instead of passing in extra info, and handle it more cleanly and more generally.

@briansull
Copy link
Author

briansull commented Jan 4, 2019

The flag GTF_CALL_M_EXPLICIT_TAILCALL is currently not yet set by the importer when we reach this method.
It currently gets set here: importer.cpp line 8753 and the call to devirtualize is on line 8597.

@briansull
Copy link
Author

briansull commented Jan 4, 2019

The IL for the method with the tailcall is:

****** START compiling Program:Test(int):ref:this (MethodHash=f85425b1)
IL to import:
IL_0000  03                ldarg.1     
IL_0001  8c 04 00 00 01    box          0x1000004
IL_0006  fe 14             tail.       
IL_0008  6f 03 00 00 0a    callvirt     0xA000003
IL_000d  2a                ret         

This IL doesn't contain any live references to the caller frame, however the JIT compiler introduces one via:

Compiler::impImportAndPushBox -- handling BOX(value class) via inline allocate/copy sequence
lvaGrabTemp returning 3 (V03 tmp1) called for Single-def Box Helper.

and then we unbox this, which introduces the live references to the caller frame, 

Source code:

using System;
using System.Runtime.CompilerServices;

class Program
{
    [MethodImpl(MethodImplOptions.NoInlining)]
    public String Test(int val)
    {
        return  /* tailcall */ ((Object) val).ToString();
    }

    static void Main(string[] args)
    {
        Program p = new Program();

        String result = p.Test(42);
        Console.WriteLine("result = " + result);
    }
}

@AndyAyersMS
Copy link
Member

Hmm, ok. We should still fix the late devirt path, and that one needs to work with the call flags. So we need to adapt for one convention or the other.

If it was me I'd probably handle this by passing in a bool isExplicitTailCall and returning a bool result indicating if we unboxed, and then adapt the two call sites to suit.

…ization and a tail call optimization

Explicit tail calls are now checked for and blocked from performing an unboxing operation in impDevirtualizeCall

If late devirtualization calls impDevirtualizeCall with an IMPLICIT_TAILCALL we will clear this flag if we
decide to perform the unboxing operation.
@briansull
Copy link
Author

@AndyAyersMS @jashook PTAL

@jashook jashook self-requested a review January 10, 2019 00:02

if (info.compCompHnd->canTailCall(info.compMethodHnd, methHnd, exactCalleeHnd, explicitTailCall))
{
canTailCall = true;
Copy link
Author

Choose a reason for hiding this comment

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

This assignment was redundant (see line 8736 above)

@briansull
Copy link
Author

@dotnet-bot Test Ubuntu x64 Checked Innerloop Build and Test

@briansull
Copy link
Author

@dotnet-bot test Ubuntu x64 Checked Innerloop Build and Test (Jit - TieredCompilation=0)

Copy link
Member

@AndyAyersMS AndyAyersMS left a comment

Choose a reason for hiding this comment

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

Looks good overall, just two small nits.

Would be nice to have a test case here too (probably an IL case...)


if (isTailCall)
{
JITDUMP("Call is an explcit tail call, we cannot perform an unbox\n");
Copy link
Member

Choose a reason for hiding this comment

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

Typo: explcit

// contextHandle -- [IN/OUT] context handle for the call. Updated iff call devirtualized.
// exactContextHnd -- [OUT] updated context handle iff call devirtualized
// isLateDevirtualization -- if devirtualization is happening after importation
// isTailCall -- [IN/OUT] true if we plan on using a tail call
Copy link
Member

Choose a reason for hiding this comment

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

This is no longer [in/out] -- also rename to isExplictTailCall

@briansull
Copy link
Author

Yes, I do have an IL test case that I will add

CORINFO_CONTEXT_HANDLE* exactContextHandle,
bool isLateDevirtualization);
bool isLateDevirtualization,
bool isTailCall);
Copy link

Choose a reason for hiding this comment

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

Is the compiler global isTailCall used?

Copy link
Author

Choose a reason for hiding this comment

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

This parameter is used and it is also renamed as isExplicitTailCall

@briansull briansull mentioned this pull request Jan 10, 2019
@briansull
Copy link
Author

@dotnet-bot Test OSX10.12 x64 Checked Innerloop Build and Test

@briansull
Copy link
Author

@dotnet-bot Test Windows_NT arm Cross Checked Innerloop Build and Test

@briansull briansull merged commit df88b1f into dotnet:master Jan 11, 2019
wtgodbe added a commit that referenced this pull request Feb 13, 2019
 Back patching #21804 to the 2.2 branch
picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
Fix issue with devirtualization and tailcalls

Commit migrated from dotnet/coreclr@df88b1f
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants