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

Make sure we tell the same lie to the JIT for default interface methods #708

Merged
merged 2 commits into from Dec 12, 2019

Conversation

cshung
Copy link
Member

@cshung cshung commented Dec 9, 2019

This pull request is intended to fix the crossgen2 compilation crash of constrained2.ilproj.

The compilation failure was found by @janvorli by running all the CoreCLR Pri 1 test on Linux under crossgen2 using SuperIlc.

Luckily, the failure reproduces itself on Windows when building a non-optimized build. The compilation crashed with an assertion here:

assert(call->AsCall()->gtCallType == CT_USER_FUNC);

My first attempt was to comment out the assertion and see what happened, the test case passed. That mislead me to think the assertion could be wrong. Indeed, when I read the code around that function, I have no idea why the JIT can assert that fact, it looks like it should be handling whatever input that the getCallInfo() produces.

Turn out, that was wrong. The assert was meant for detecting wrong data from getCallInfo(). The first few comments below were reacting to my wrong attempt to remove the assertion, and they are obsolete by now.

A comparative study with crossgen revealed that the real root cause for the assert is that the VM was lying to the JIT in crossgen but crossgen2 wasn't lying the same way. In particular, we have this gem:

// If we are making a virtual call to an instance method on an interface, we need to lie to the JIT.
// The reason being that we already made sure target is always directly callable (through instantiation stubs),
// JIT should not generate shared generics aware call code and insert the secret argument again at the callsite.
// Otherwise we would end up with two secret generic dictionary arguments (since the stub also provides one).

Because of the above, the CORINFO_CALLCONV_PARAMTYPE was not specified when crossgen compile the same test case, no wonder the assert is not a problem from crossgen.

It would be nice if we can come up with a little comment in the JIT about the handling of default interface method, the lie is just far from obvious.

@dotnet/jit-contrib
@dotnet/crossgen-contrib

@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 Dec 9, 2019
@jakobbotsch
Copy link
Member

jakobbotsch commented Dec 9, 2019

it could be reached by having an interface dispatch that requires a runtime lookup (i.e. line 7640 of importer.cpp)

Does this line not just deal with the stub itself requiring runtime lookup? Is that not orthogonal to the generic context?

This issue is found by running constaintedcall2 test case on Linux under crossgen2. The test passed after removig the assert.

I wasn't able to find this test, can you link it? Does this test use the generic context for anything?

@MichalStrehovsky
Copy link
Member

I wasn't able to find this test, can you link it?

Is it this one? https://github.com/dotnet/runtime/blob/master/src/coreclr/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrained2.il

Note that's a default interface method test. Crossgen2 lacks a bunch of DIM fixes still. Why is the assert not a problem for crossgen? Is this just crossgen2 sending bad input to RyuJIT because of missing DIM handling?

@jakobbotsch
Copy link
Member

jakobbotsch commented Dec 9, 2019

Is this just crossgen2 sending bad input to RyuJIT because of missing DIM handling?

I know you are asking @cshung, but this is what I would suspect. I think the following is true but please correct me if I am wrong:

  • Generic interface methods are always called through instantiating stub so no generic context is required for those.
  • Non-generic interface methods go through VSD, even if the interface itself is generic. Because classes can implement multiple interfaces of different type parameters we need runtime lookup for the VSD stub to use in certain cases, for example:
class C : IEnumerable<string>, IEnumerable<object>
{
  ...
}

...
static void Foo<T>(C c) => ((IEnumerable<T>)c).GetEnumerator();

This is what the code you linked to is handling I believe. However, these never need generic context I believe.

  • Nevertheless, for non-generic default interface method on a generic interface a generic context is still needed. However these can be done as direct calls, so this does not make the assert wrong.

@fadimounir
Copy link
Contributor

Why are we just hitting this assert in crossgen2, and not crossgen1, even though they use the same JIT?

@cshung cshung force-pushed the dev/andrewau/remove-incorrect-assert branch from e770de2 to 8370249 Compare December 11, 2019 06:01
@cshung cshung changed the title [WIP] Removing an incorrect assert [WIP] Make sure we tell the same lie to the JIT for default interface methods Dec 11, 2019
@cshung cshung force-pushed the dev/andrewau/remove-incorrect-assert branch from 8370249 to 7b6e294 Compare December 11, 2019 15:43
Copy link
Member

@davidwrighton davidwrighton left a comment

Choose a reason for hiding this comment

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

Looks ok

@cshung cshung changed the title [WIP] Make sure we tell the same lie to the JIT for default interface methods Make sure we tell the same lie to the JIT for default interface methods Dec 12, 2019
@cshung cshung merged commit 9a54db9 into dotnet:master Dec 12, 2019
@cshung cshung deleted the dev/andrewau/remove-incorrect-assert branch December 12, 2019 15:18
@dotnet dotnet locked as resolved and limited conversation to collaborators Dec 11, 2020
MichalStrehovsky added a commit to MichalStrehovsky/runtime that referenced this pull request Mar 25, 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 area-crossgen2-coreclr
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants