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

Adjust managed type system for new function pointer handling #84819

Merged
merged 2 commits into from
Apr 18, 2023

Conversation

MichalStrehovsky
Copy link
Member

After #81006, the calling convention is no longer part of the type system identity of a function pointer type - it serves more like a modopt as far as the type system is concerned. The type system only cares whether the pointer is managed or not. Adjust the managed type system accordingly:

  • If we're reading/representing a standalone method signature, read it as usual. Calling convention is available in flags/modopts.
  • If we're reading/representing a function pointer type, collapse the calling convention information into the managed/unmanaged bit only.

Cc @dotnet/ilc-contrib @dotnet/crossgen-contrib

After dotnet#81006, the calling convention is no longer part of the type system identity of a function pointer type - it serves more like a modopt as far as the type system is concerned. The type system only cares whether the pointer is managed or not. Adjust the managed type system accordingly:

* If we're reading/representing a standalone method signature, read it as usual. Calling convention is available in flags/modopts.
* If we're reading/representing a function pointer type, collapse the calling convention information into the managed/unmanaged bit only.
@ghost
Copy link

ghost commented Apr 14, 2023

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

Issue Details

After #81006, the calling convention is no longer part of the type system identity of a function pointer type - it serves more like a modopt as far as the type system is concerned. The type system only cares whether the pointer is managed or not. Adjust the managed type system accordingly:

  • If we're reading/representing a standalone method signature, read it as usual. Calling convention is available in flags/modopts.
  • If we're reading/representing a function pointer type, collapse the calling convention information into the managed/unmanaged bit only.

Cc @dotnet/ilc-contrib @dotnet/crossgen-contrib

Author: MichalStrehovsky
Assignees: -
Labels:

area-NativeAOT-coreclr

Milestone: -

@@ -371,7 +371,19 @@ private MethodSignature ParseMethodSignatureImpl(bool skipEmbeddedSignatureData)
Debug.Assert((int)MethodSignatureFlags.CallingConventionVarargs == (int)SignatureCallingConvention.VarArgs);
Debug.Assert((int)MethodSignatureFlags.UnmanagedCallingConvention == (int)SignatureCallingConvention.Unmanaged);

flags = (MethodSignatureFlags)signatureCallConv;
// If skipEmbeddedSignatureData is true, we're building the signature for the purposes of building a type.
// We normalize unmanaged calling convention into a single value - "unmanaged".
Copy link
Member

Choose a reason for hiding this comment

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

Not sure I understand why this is safe. You mean that, after the other change, it no longer matters if you have

delegate* unmanaged<int> p

vs.

delegate* unmanaged<[SomeModReq]int> p

We effectively erase custom modifiers for unmanaged function pointers?

Copy link
Member Author

Choose a reason for hiding this comment

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

Modifiers were already erased for runtime pointer types - that's what the existing skipEmbeddedSignatureData argument controls. It distinguishes between "are we parsing a standalone method signature" vs "are we parsing a TypeSpec that is a function pointer typespec". Custom modifiers never matter for type identity - modifiers only matter for signature resolution, but they don't contribute to identity.

We have some tests testing this like:

.method public static hidebysig object TryBoxWithModifiedPointer()
{
.locals init (valuetype GenericStruct`1<int32 modreq (BarModifier)*[]>)
ldloc 0
box valuetype GenericStruct`1<int32 modreq (BarModifier)*[]>
ret
}

The logic I'm adding basically switches specific calling conventions into things that act like modifiers (previously they would be part of the type identity).

The added unit test is then testing two things:

  1. That we still consider signatures that differ by modopts to be different signatures
  2. The fact that asking for the type of the method parameter only distinguishes managed/unmanaged

@MichalStrehovsky
Copy link
Member Author

/azp run runtime-extra-platforms

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@MichalStrehovsky
Copy link
Member Author

@sbomer could the extra-platforms NativeAOT linker failures be related to the build system switchover? (On my phone now and it's going to be weekend so not investigating)

@sbomer
Copy link
Member

sbomer commented Apr 14, 2023

Almost certainly caused by #84148. Taking a look.

@@ -27,7 +27,8 @@ public enum EmbeddedSignatureDataKind
{
RequiredCustomModifier = 0,
OptionalCustomModifier = 1,
ArrayShape = 2
ArrayShape = 2,
UnmanagedCallConv = 3,
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need this as a EmbeddedSignatureDataKind instead of as a MethodSignatureFlags?

I think I might be missing something. It seems like this change applies to the nested arguments of a function pointer, rather than the function pointer itself. Is that right? Does that mean that this is only for function pointers of function pointers?

Copy link
Member Author

Choose a reason for hiding this comment

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

EmbeddedSignatureData is attached to method signatures, but we can decide which method signature it should attach to.

Consider: void Blah(delegate*unmanaged[Cdecl]<void> x);. When we're materializing the topmost parent method signature, we set a flag in the parser that it should generate embedded signature data. Embedded signature data is a sidecar that gets attached to the topmost method signature. It can express things in arbitrary type construction nesting. It's really weird. Back to the signature - we want to attach the modopt (and non-meaningful flags) to the topmost EmbeddedSignatureData. If we were to attach it to the nested signature, it would become part of the identity. But we don't want it part of the identity of the delegate*unmanaged[Cdecl]<void> type because it was decided that for the type system purposes, the only bit that matters is whether the method is unmanaged (and not the exact calling convention).

Copy link
Member

Choose a reason for hiding this comment

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

Ah it was avoiding putting it in the identity that I missed

Copy link
Member

@agocke agocke left a comment

Choose a reason for hiding this comment

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

Lgtm. A little unfortunate that this code used to match up pretty well with the ecma spec but it now has some extra flags. Maybe we can put an implementation note in a copy of the annotated spec sometime in the future

@MichalStrehovsky
Copy link
Member Author

A little unfortunate that this code used to match up pretty well with the ecma spec but it now has some extra flags

That's a good point. We should have updated the ECMA-335 amendments doc in #81006 because that PR changed things. It does seem to affect I.8.7 Assignment compatibility at minimum:

"iii) Any modopt, modreq, or pinned modifiers are ignored; and
iv) Any calling convention is considered part of the type"

I'll make a separate PR for this.

@MichalStrehovsky MichalStrehovsky merged commit eb71e48 into dotnet:main Apr 18, 2023
@MichalStrehovsky MichalStrehovsky deleted the fnptrts branch April 18, 2023 03:11
@ghost ghost locked as resolved and limited conversation to collaborators May 18, 2023
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.

3 participants