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

Implementation of SOSDacApi GetMethodDescName for cDAC #106169

Merged
merged 43 commits into from
Aug 13, 2024

Conversation

davidwrighton
Copy link
Member

@davidwrighton davidwrighton commented Aug 9, 2024

Add a number of new MethodDesc contract definitions

Contract algorithm on RuntimeTypeSystem
IsGenericMethodDefinition
GetGenericMethodInstantiation
GetMethodToken
IsArrayMethod
IsDynamicMethod
IsStoredSigMethodDesc
IsNoMetadataMethod
IsILStub

Update cDAC compat asserts in cDAC to always be enabled by using a tls variable in mscordaccore

Implement GetMethodDescName on ISOSDacInterface in the cdacreader

Stub out an implementation of GetPath in the Loader contract used in a fallback after a fallback. This will need further work, but is included to make sure the code path isn't lost.

Fix the EcmaMetadataReader to be able to find blobs in the metadata

Add ability to read target data from a buffer held on the cdac side using the Target class. This was needed to handle signature containing a CorElementType.Internal.

And finally actually implement the name generation algorithm via a line for line port from the CoreCLR codebase.

Contributes to #99302

davidwrighton and others added 30 commits July 9, 2024 10:11
Add implementations for changes to RuntimeTypeSystem contract
Add SOSDacInterface call into cDac for GetMethodTableName
- Move pointer to Module class
- Replace use of SBuffer abstraction with a simple counted byte memory block
Add metadata details to Loader contract
Add Metadata helper api for use by contracts within the cDAC (and possibly clients of cDAC too)
- Remove TypeHandleArray and MethodTableArray in favor of contract specific logic
Co-Authored-By: David Wrighton <davidwr@microsoft.com>
mock the additional data and globals
Copy link
Contributor

Tagging subscribers to this area: @tommcdon
See info in area-owners.md if you want to be subscribed.

Copy link
Member

@lambdageek lambdageek left a comment

Choose a reason for hiding this comment

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

First set of comments. Didn't look at Ecma or the formatter yet

docs/design/datacontracts/RuntimeTypeSystem.md Outdated Show resolved Hide resolved
{
get
{
int tokenRemainderBitCount = _target.ReadGlobal<byte>(Constants.Globals.MethodDescTokenRemainderBitCount);
Copy link
Member

Choose a reason for hiding this comment

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

Can we either store the token remainder bit count in the MethodDesc, or just pre-compose the token when creating the MethodDesc instance? I've been avoiding storing Target and contracts in data structures, so they're just dumb value holders, not fancy algorithms.

Copy link
Member

@lambdageek lambdageek left a comment

Choose a reason for hiding this comment

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

LGTM. modulo nits. And it would be really really nice if RuntimeTypeSystem_1.MethodDesc didn't hold on to Target

@@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Net;
Copy link
Member

Choose a reason for hiding this comment

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

nit: unused (presmably) using

1. Rename mcNDirect to mcPInvoke
2. Rename MethodDescClassification to MethodClassification
3. Remove mc prefix from all MethodClassification enum values
4. Move handling of various forms of MethodDescs to using an AsBlah method, and handle the flags in those methods, to make the actual contract methods somewhat simpler.
5. Compute the token eagerly on MethodDesc creation to avoid having to hold a pointer to the Target
// Return true if a MethodDesc represents a dynamically generated method, either an IL Stub dynamically
// generated by the runtime, or a MethodDesc that describes a method represented by the System.Reflection.Emit.DynamicMethod class
// A dynamic method is also a StoredSigMethodDesc
public virtual bool IsDynamicMethod(MethodDescHandle methodDesc, out ReadOnlySpan<byte> methodName);
Copy link
Member

Choose a reason for hiding this comment

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

Would it make sense to just make methodName a string instead of ReadOnlySpan<byte>, so the consumer doesn't have to know the encoding?

Copy link
Member Author

Choose a reason for hiding this comment

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

Not a bad idea. In general, I don't want to expose arrays to contract users, as its far to easy to mutate them, but strings are nice in that they are our only truly immutable type in the BCL, and work nicely for this sort of thing.


// Return true for a MethodDesc that describes a method represented by the System.Reflection.Emit.DynamicMethod class
// A LCG method is also a StoredSigMethodDesc
public virtual bool IsLCGMethod(MethodDescHandle methodDesc);
Copy link
Member

Choose a reason for hiding this comment

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

I know we have IsLCGMethod on the native MethodDesc, but is LCG the term we want to keep using going forwards? Would IsReflectionEmitMethod make more sense?

At least personally, LCG is not a term I use - I just think of it as reflection emit.

Copy link
Member

Choose a reason for hiding this comment

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

DynamicMethod is the public name of the LCG feature.

ReflectionEmit is more general. Some methods emitted using Reflection.Emit are dynamic methods, some are not.

Copy link
Member

Choose a reason for hiding this comment

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

So then would this make sense:

  • IsDynamicMethod -> IsDynamicallyGeneratedMethod
  • IsLCGMethod -> IsDynamicMethod

Copy link
Member Author

Choose a reason for hiding this comment

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

... whereas I think of Reflection.Emit as a thing that only applies to things that generate the full metadata and types which is also not completely accurate... The actual term in the BCL is that an LCGMethod maps to a method represented by the System.Reflection.Emit.DynamicMethod class, but calling it a DynamicMethod... might be extra special confusing, since the runtime has multiple meanings of what a DynamicMethodDesc represents, only 1 of which is a System.Reflection.Emit.DynamicMethod. (And of course LCG stands for Lightweight CodeGen, which is an internal codename that probably doesn't still need to be kept around.) I'd like to hear what @lambdageek, and @AaronRobinsonMSFT think on this, as I know I'm not objective here as I've worked on this stuff for FAR too long to see things reasonably. Possibly the right approach would be to call it DynamicMethod and sometime in .NET 10, rename the DynamicMethodDesc to something like RuntimeILMethodDesc.

Copy link
Member

@AaronRobinsonMSFT AaronRobinsonMSFT Aug 10, 2024

Choose a reason for hiding this comment

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

I like the rename that elinor mentioned above at #106169 (comment).

rename the DynamicMethodDesc to something like RuntimeILMethodDesc.

I also agree with your suggestion above. I could also see GeneratedMethodDesc or ILEmitMethodDesc as options too.

Copy link
Member

Choose a reason for hiding this comment

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

I like IsLCGMethod -> IsDynamicMethod and DynamicMethodDesc ->ILEmitMethodDesc.

Not sure about IsDynamicMethod -> IsDynamicallyGeneratedMethod. Would just IsGeneratedILMethod be too broad?

Copy link
Member

Choose a reason for hiding this comment

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

DynamicMethodDesc ->ILEmitMethodDesc.

How about DynamicMethodDesc ->NoMetadataMethodDesc and IsDynamicMethod -> IsNoMetadata (existing property)?

Part of the codebase uses the NoMetadata name already:

inline DWORD IsNoMetadata() const
{
LIMITED_METHOD_DAC_CONTRACT;
return (mcDynamic == GetClassification());
}
. Notice that MethodDesc::IsDynamicMethod and MethodDesc::IsNoMetadata have the same implementation.

The key property of the DynamicMethodDesc is that it has no ECMA-335 metadata, it has no metadata token, etc.

Dynamic IL generation is not the key property of DynamicMethodDesc. The regular ECMA-335 MethodDescs can have dynamically generated (IL) code too. For example, UnsafeAccessors have dynamically generated IL but they are regular MethodDescs.

Copy link
Member Author

@davidwrighton davidwrighton Aug 12, 2024

Choose a reason for hiding this comment

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

I like @jkotas's idea here. Then the IsDynamicMethod api at the cdac level makes total sense, the existing DynamicMethodDesc translates to NoMetadataMethodDesc and gets a better name that more matches its utility, and we get rid of having both MethodDesc::IsNoMetadata and MethodDesc::IsDynamicMethod which are today exactly the same thing. While I'm at it, I'll rename mcDynamic to mcNoMetadata

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm trending toward the idea of putting this rename in a separate PR. Opinions?

Copy link
Member Author

Choose a reason for hiding this comment

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

Offline discussion is to put together a separate PR for that. I'll just add a commit to update the cdac contract side naming to IsDynamicMethod, and the renaming of the underlying structures to be less confusing will be a separate PR that will probably miss .NET 9.

@davidwrighton davidwrighton merged commit 272a83e into dotnet:main Aug 13, 2024
152 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators Sep 14, 2024
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