Skip to content

Conversation

@fadimounir
Copy link
Contributor

@fadimounir fadimounir commented Nov 18, 2019

Taking @MichalStrehovsky's work from MichalStrehovsky/coreclr@ffc8fff and completing the remaining portions.

Changes include some refactoring work around the signature parsing to compute marshalling requirements. We had two separate implementations after pulling the PInvoke work from the single-exe branch. Consolidated into one implementation.

cc @sergiy-k @dotnet/crossgen-contrib

READYTORUN_FLAG_PLATFORM_NEUTRAL_SOURCE = 0x00000001, // Set if the original IL assembly was platform-neutral
READYTORUN_FLAG_SKIP_TYPE_VALIDATION = 0x00000002, // Set of methods with native code was determined using profile data
READYTORUN_FLAG_PARTIAL = 0x00000004,
READYTORUN_FLAG_CROSSGEN2_IMAGE = 0x00000008, // Set if image was compiled using crossgen2
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The name of this flag will change of course once we settle on the final crossgen2 name

Copy link
Member

Choose a reason for hiding this comment

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

I don't like having a name that is tied to crossgen2 at all. These flags are about the format. Something like AOT_DIRECT_PINVOKE_STUBS seems better to me.

Copy link
Member

Choose a reason for hiding this comment

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

I have suggested this flag to Fadi. My thinking was that the flag will disappear once we get rid of the old crossgen.

Copy link
Contributor Author

@fadimounir fadimounir Nov 19, 2019

Choose a reason for hiding this comment

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

I completely agree this flag currently looks pretty ugly (i've spent some time thinking about this too as I was writing it), but I do see it as a temporary flag.
We might end up adding some more cases where we do something different with crossgen2 compared to the old crossgen, and it would be better to not add a new flag every time we do that. For this reason, I think we should keep the flag the way it is. @davidwrighton thoughts?

Copy link
Member

Choose a reason for hiding this comment

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

I don't think we'll be rid of this flag any time soon.
I feel that

  1. Crossgen won't disappear within a year
  2. Having the flag be specific to some characteristic of the r2r file is straightforward, and allows us to adjust crossgen if we want to. (For example if we get rid of shared IL stubs in the runtime, we'll probably also want to delete them from crossgen even if we aren't doing active feature development there, and having the crossgen2 flag set by crossgen would be very confusing.)
  3. If we change major version of r2r after we establish crossgen2, we can get rid of the flag then.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Going with READYTORUN_NON_SHARED_PINVOKE_STUBS

return _versionBubbleModuleSet.Contains(((EcmaMethod)method).Module)
&& _versionBubbleModuleSet.Contains(method.Context.SystemModule);

if (((EcmaMethod)method).Module.Equals(method.Context.SystemModule))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've tested a small scenario where we enable these pinvokes that require marshalling when corelib is part of the version bubble, and it works correctly (and gets inlined). I didn't enable this scenario though in this PR based on what @davidwrighton and I were discussing, but it should be totally doable.

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.

Please fix the naming, otherwise, this looks good.

READYTORUN_FLAG_PLATFORM_NEUTRAL_SOURCE = 0x00000001, // Set if the original IL assembly was platform-neutral
READYTORUN_FLAG_SKIP_TYPE_VALIDATION = 0x00000002, // Set of methods with native code was determined using profile data
READYTORUN_FLAG_PARTIAL = 0x00000004,
READYTORUN_FLAG_CROSSGEN2_IMAGE = 0x00000008, // Set if image was compiled using crossgen2
Copy link
Member

Choose a reason for hiding this comment

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

I don't like having a name that is tied to crossgen2 at all. These flags are about the format. Something like AOT_DIRECT_PINVOKE_STUBS seems better to me.

@@ -70,6 +70,8 @@ public enum MarshallerType
// and also argument specific marshalling informaiton
abstract partial class Marshaller
{
static MethodMarshallersCache s_marshallersCache = new MethodMarshallersCache();
Copy link
Member

Choose a reason for hiding this comment

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

changing IL stream addresses has a side effect on the inlining behavior of the JIT

Could you please elaborate on this?

This static cache should not be needed. If it is needed, it is working around about more fundamental problem somewhere else.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I removed the static cache here already. What we had discovered through testing is that having multiple IL streams for the same method has a side effect of having multiple pinning addresses given back to the jit, which could affect inlining behavior.

Copy link
Member

Choose a reason for hiding this comment

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

I removed the static cache here already.

I'm only on my phone but s_marshallersCache I still see here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

:( Sorry for the confusion... I had added 2 caches, one for marshallers and one for the emitted IL. I removed the latter, but thought I removed the one in marshallers too. I'll fix that.

Fadi Hanna added 2 commits November 20, 2019 10:19
This is only for images compiled with crossgen2.

Changes include some refactoring work around the signature parsing to compute marshalling requirements. We had two separate implementations after pulling the PInvoke work from the single-exe branch. Consolidated into one implementation.
@@ -70,6 +70,8 @@ public enum MarshallerType
// and also argument specific marshalling informaiton
abstract partial class Marshaller
{
static MethodMarshallersCache s_marshallersCache = new MethodMarshallersCache();
Copy link
Member

Choose a reason for hiding this comment

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

I removed the static cache here already.

I'm only on my phone but s_marshallersCache I still see here.

{
Debug.Assert(targetMethod.IsPInvoke);

if (targetMethod.GetPInvokeMethodMetadata().Flags.SetLastError)
Copy link
Member

Choose a reason for hiding this comment

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

This should also check for the PreserveSig bit that is getting deleted.

I've added that flag to the type system in #27286

Copy link
Contributor Author

@fadimounir fadimounir Nov 20, 2019

Choose a reason for hiding this comment

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

@MichalStrehovsky, I'm noticing a lot of code from dotnet/coreclr#27286 were never included in your dotnet/coreclr#27585 PR to move the PInvoke stuff out of the single-exe branch. Was that intentional?

The PreserveSig is part of the things that were left out.

If that wasn't intentional, and the changes in dotnet/coreclr#27286 need to be in the master branch as well, I'll port them from single-exe in a separate PR.

Copy link
Member

Choose a reason for hiding this comment

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

Sigh. I don't know how that happened. Yeah, those are all good bugfixes that should be moved over. Everything I touched in the single-exe branch should move.

Copy link
Member

Choose a reason for hiding this comment

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

Can you please check if thats the only thing? I would hate if a bugfix I already did in single-exe ends up having to be reinvestigated because I forgot it in the branch

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, I’ll look at the history and port the missing stuff over in new PRs

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Found the following commits that will need to be ported:
dotnet/coreclr@4684d8f
dotnet/coreclr@7528827
dotnet/coreclr@52714c6
dotnet/coreclr@1d2ef20
dotnet/coreclr@24cdf66

I'll bring them to master. What tests were you running made you find and fix these bugs?

Copy link
Member

Choose a reason for hiding this comment

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

The pinvoke interop tests in the coreclr test tree.

Sorry about this. I must have used a stale version of the single-exe branch. Doing this work in the branch caused nothing but trouble.

@fadimounir fadimounir merged commit 6c93838 into dotnet:master Nov 21, 2019
@fadimounir fadimounir deleted the NonShareablePInvokeStubs branch November 27, 2019 02:04
@karelz karelz added this to the 5.0.0 milestone Aug 18, 2020
MichalStrehovsky added a commit to MichalStrehovsky/runtime that referenced this pull request Oct 12, 2020
Latest Roslyn builds started optimizing (is it really an optimization?) generic virtual method calls into more specific methods.

```diff
.method public hidebysig virtual instance !!T
        Alloc<.ctor T>() cil managed
{
  // Code size       11 (0xb)
  .maxstack  8
  IL_0000:  newobj     instance void My/AllocViaSecondLevelDerived::.ctor()
-   IL_0005:  callvirt   instance !!0 My/AllocViaGVMSecondLevelBase::ActuallyAlloc<!!0>()
+  IL_0005:  callvirt   instance !!0 My/AllocViaSecondLevelDerived::ActuallyAlloc<!!0>()
  IL_000a:  ret
} // end of method AllocViaGVMDerived::Alloc
```

This breaks generic virtual method resolution because the resolution assumes we're looking for the slot defining method.

The fix is to normalize to the handle of the slot defining method during codegen.

I hit this in the DynamicGenerics test, but I'm adding more coverage to the Generics test because the newly added logic that walks base hierarchies wouldn't be covered by the existing test.

This also required a RyuJIT fix, but that one turned out to be a nice simplification.
@ghost ghost locked as resolved and limited conversation to collaborators Dec 11, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants