Implementation of SOSDacApi GetMethodDescName for cDAC - #106169

Merged
davidwrighton merged 43 commits into
dotnet:mainfrom
davidwrighton:cdac-methoddescname
Aug 13, 2024
Merged

Implementation of SOSDacApi GetMethodDescName for cDAC#106169
davidwrighton merged 43 commits into
dotnet:mainfrom
davidwrighton:cdac-methoddescname

Conversation

@davidwrighton

@davidwrightondavidwrighton commented Aug 9, 2024

Copy link
Copy Markdown
Member

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

davidwrightonand 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
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@davidwrightondavidwrighton mentioned this pull request Aug 9, 2024
25 tasks

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

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

Comment threaddocs/design/datacontracts/RuntimeTypeSystem.md Outdated
{
get
{
int tokenRemainderBitCount = _target.ReadGlobal<byte>(Constants.Globals.MethodDescTokenRemainderBitCount);

Copy link
Copy Markdown
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.

Comment threaddocs/design/datacontracts/RuntimeTypeSystem.md Outdated

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

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

using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Net;

Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
MemberAuthor

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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
MemberAuthor

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.

@AaronRobinsonMSFTAaronRobinsonMSFTAug 10, 2024

Copy link
Copy Markdown
Member

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
Copy Markdown
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
Copy Markdown
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:

inlineDWORDIsNoMetadata() 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.

@davidwrightondavidwrightonAug 12, 2024

Copy link
Copy Markdown
MemberAuthor

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
Copy Markdown
MemberAuthor

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
Copy Markdown
MemberAuthor

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.

Sign up for freeto 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

@davidwrighton@lambdageek@jkoritzinsky@jkotas@AaronRobinsonMSFT@elinor-fung
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Implementation of SOSDacApi GetMethodDescName for cDAC - #106169

Merged
davidwrighton merged 43 commits into
dotnet:mainfrom
davidwrighton:cdac-methoddescname
Aug 13, 2024
Merged

Implementation of SOSDacApi GetMethodDescName for cDAC#106169
davidwrighton merged 43 commits into
dotnet:mainfrom
davidwrighton:cdac-methoddescname

Conversation

@davidwrighton

@davidwrightondavidwrighton commented Aug 9, 2024

Copy link
Copy Markdown
Member

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

davidwrightonand 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
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@davidwrightondavidwrighton mentioned this pull request Aug 9, 2024
25 tasks

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

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

Comment threaddocs/design/datacontracts/RuntimeTypeSystem.md Outdated
{
get
{
int tokenRemainderBitCount = _target.ReadGlobal<byte>(Constants.Globals.MethodDescTokenRemainderBitCount);

Copy link
Copy Markdown
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.

Comment threaddocs/design/datacontracts/RuntimeTypeSystem.md Outdated

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

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

using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Net;

Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
MemberAuthor

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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
MemberAuthor

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.

@AaronRobinsonMSFTAaronRobinsonMSFTAug 10, 2024

Copy link
Copy Markdown
Member

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
Copy Markdown
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
Copy Markdown
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:

inlineDWORDIsNoMetadata() 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.

@davidwrightondavidwrightonAug 12, 2024

Copy link
Copy Markdown
MemberAuthor

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
Copy Markdown
MemberAuthor

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
Copy Markdown
MemberAuthor

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.

Sign up for freeto 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

@davidwrighton@lambdageek@jkoritzinsky@jkotas@AaronRobinsonMSFT@elinor-fung
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Implementation of SOSDacApi GetMethodDescName for cDAC - #106169

Merged
davidwrighton merged 43 commits into
dotnet:mainfrom
davidwrighton:cdac-methoddescname
Aug 13, 2024
Merged

Implementation of SOSDacApi GetMethodDescName for cDAC#106169
davidwrighton merged 43 commits into
dotnet:mainfrom
davidwrighton:cdac-methoddescname

Conversation

@davidwrighton

@davidwrightondavidwrighton commented Aug 9, 2024

Copy link
Copy Markdown
Member

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

davidwrightonand 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
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@davidwrightondavidwrighton mentioned this pull request Aug 9, 2024
25 tasks

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

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

Comment threaddocs/design/datacontracts/RuntimeTypeSystem.md Outdated
{
get
{
int tokenRemainderBitCount = _target.ReadGlobal<byte>(Constants.Globals.MethodDescTokenRemainderBitCount);

Copy link
Copy Markdown
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.

Comment threaddocs/design/datacontracts/RuntimeTypeSystem.md Outdated

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

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

using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Net;

Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
MemberAuthor

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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
MemberAuthor

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.

@AaronRobinsonMSFTAaronRobinsonMSFTAug 10, 2024

Copy link
Copy Markdown
Member

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
Copy Markdown
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
Copy Markdown
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:

inlineDWORDIsNoMetadata() 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.

@davidwrightondavidwrightonAug 12, 2024

Copy link
Copy Markdown
MemberAuthor

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
Copy Markdown
MemberAuthor

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
Copy Markdown
MemberAuthor

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.

Sign up for freeto 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

@davidwrighton@lambdageek@jkoritzinsky@jkotas@AaronRobinsonMSFT@elinor-fung
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Implementation of SOSDacApi GetMethodDescName for cDAC - #106169

Merged
davidwrighton merged 43 commits into
dotnet:mainfrom
davidwrighton:cdac-methoddescname
Aug 13, 2024
Merged

Implementation of SOSDacApi GetMethodDescName for cDAC#106169
davidwrighton merged 43 commits into
dotnet:mainfrom
davidwrighton:cdac-methoddescname

Conversation

@davidwrighton

@davidwrightondavidwrighton commented Aug 9, 2024

Copy link
Copy Markdown
Member

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

davidwrightonand 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
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@davidwrightondavidwrighton mentioned this pull request Aug 9, 2024
25 tasks

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

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

Comment threaddocs/design/datacontracts/RuntimeTypeSystem.md Outdated
{
get
{
int tokenRemainderBitCount = _target.ReadGlobal<byte>(Constants.Globals.MethodDescTokenRemainderBitCount);

Copy link
Copy Markdown
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.

Comment threaddocs/design/datacontracts/RuntimeTypeSystem.md Outdated

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

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

using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Net;

Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
MemberAuthor

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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
MemberAuthor

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.

@AaronRobinsonMSFTAaronRobinsonMSFTAug 10, 2024

Copy link
Copy Markdown
Member

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
Copy Markdown
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
Copy Markdown
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:

inlineDWORDIsNoMetadata() 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.

@davidwrightondavidwrightonAug 12, 2024

Copy link
Copy Markdown
MemberAuthor

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
Copy Markdown
MemberAuthor

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
Copy Markdown
MemberAuthor

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.

Sign up for freeto 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

@davidwrighton@lambdageek@jkoritzinsky@jkotas@AaronRobinsonMSFT@elinor-fung
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Implementation of SOSDacApi GetMethodDescName for cDAC - #106169

Merged
davidwrighton merged 43 commits into
dotnet:mainfrom
davidwrighton:cdac-methoddescname
Aug 13, 2024
Merged

Implementation of SOSDacApi GetMethodDescName for cDAC#106169
davidwrighton merged 43 commits into
dotnet:mainfrom
davidwrighton:cdac-methoddescname

Conversation

@davidwrighton

@davidwrightondavidwrighton commented Aug 9, 2024

Copy link
Copy Markdown
Member

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

davidwrightonand 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
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@davidwrightondavidwrighton mentioned this pull request Aug 9, 2024
25 tasks

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

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

Comment threaddocs/design/datacontracts/RuntimeTypeSystem.md Outdated
{
get
{
int tokenRemainderBitCount = _target.ReadGlobal<byte>(Constants.Globals.MethodDescTokenRemainderBitCount);

Copy link
Copy Markdown
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.

Comment threaddocs/design/datacontracts/RuntimeTypeSystem.md Outdated

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

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

using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Net;

Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
MemberAuthor

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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
MemberAuthor

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.

@AaronRobinsonMSFTAaronRobinsonMSFTAug 10, 2024

Copy link
Copy Markdown
Member

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
Copy Markdown
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
Copy Markdown
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:

inlineDWORDIsNoMetadata() 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.

@davidwrightondavidwrightonAug 12, 2024

Copy link
Copy Markdown
MemberAuthor

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
Copy Markdown
MemberAuthor

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
Copy Markdown
MemberAuthor

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.

Sign up for freeto 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

@davidwrighton@lambdageek@jkoritzinsky@jkotas@AaronRobinsonMSFT@elinor-fung
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Implementation of SOSDacApi GetMethodDescName for cDAC - #106169

Merged
davidwrighton merged 43 commits into
dotnet:mainfrom
davidwrighton:cdac-methoddescname
Aug 13, 2024
Merged

Implementation of SOSDacApi GetMethodDescName for cDAC#106169
davidwrighton merged 43 commits into
dotnet:mainfrom
davidwrighton:cdac-methoddescname

Conversation

@davidwrighton

@davidwrightondavidwrighton commented Aug 9, 2024

Copy link
Copy Markdown
Member

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

davidwrightonand 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
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@davidwrightondavidwrighton mentioned this pull request Aug 9, 2024
25 tasks

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

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

Comment threaddocs/design/datacontracts/RuntimeTypeSystem.md Outdated
{
get
{
int tokenRemainderBitCount = _target.ReadGlobal<byte>(Constants.Globals.MethodDescTokenRemainderBitCount);

Copy link
Copy Markdown
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.

Comment threaddocs/design/datacontracts/RuntimeTypeSystem.md Outdated

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

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

using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Net;

Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
MemberAuthor

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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
MemberAuthor

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.

@AaronRobinsonMSFTAaronRobinsonMSFTAug 10, 2024

Copy link
Copy Markdown
Member

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
Copy Markdown
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
Copy Markdown
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:

inlineDWORDIsNoMetadata() 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.

@davidwrightondavidwrightonAug 12, 2024

Copy link
Copy Markdown
MemberAuthor

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
Copy Markdown
MemberAuthor

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
Copy Markdown
MemberAuthor

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.

Sign up for freeto 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

@davidwrighton@lambdageek@jkoritzinsky@jkotas@AaronRobinsonMSFT@elinor-fung
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Implementation of SOSDacApi GetMethodDescName for cDAC - #106169

Merged
davidwrighton merged 43 commits into
dotnet:mainfrom
davidwrighton:cdac-methoddescname
Aug 13, 2024
Merged

Implementation of SOSDacApi GetMethodDescName for cDAC#106169
davidwrighton merged 43 commits into
dotnet:mainfrom
davidwrighton:cdac-methoddescname

Conversation

@davidwrighton

@davidwrightondavidwrighton commented Aug 9, 2024

Copy link
Copy Markdown
Member

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

davidwrightonand 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
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@davidwrightondavidwrighton mentioned this pull request Aug 9, 2024
25 tasks

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

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

Comment threaddocs/design/datacontracts/RuntimeTypeSystem.md Outdated
{
get
{
int tokenRemainderBitCount = _target.ReadGlobal<byte>(Constants.Globals.MethodDescTokenRemainderBitCount);

Copy link
Copy Markdown
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.

Comment threaddocs/design/datacontracts/RuntimeTypeSystem.md Outdated

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

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

using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Net;

Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
MemberAuthor

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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
MemberAuthor

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.

@AaronRobinsonMSFTAaronRobinsonMSFTAug 10, 2024

Copy link
Copy Markdown
Member

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
Copy Markdown
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
Copy Markdown
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:

inlineDWORDIsNoMetadata() 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.

@davidwrightondavidwrightonAug 12, 2024

Copy link
Copy Markdown
MemberAuthor

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
Copy Markdown
MemberAuthor

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
Copy Markdown
MemberAuthor

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.

Sign up for freeto 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

@davidwrighton@lambdageek@jkoritzinsky@jkotas@AaronRobinsonMSFT@elinor-fung
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Implementation of SOSDacApi GetMethodDescName for cDAC - #106169

Merged
davidwrighton merged 43 commits into
dotnet:mainfrom
davidwrighton:cdac-methoddescname
Aug 13, 2024
Merged

Implementation of SOSDacApi GetMethodDescName for cDAC#106169
davidwrighton merged 43 commits into
dotnet:mainfrom
davidwrighton:cdac-methoddescname

Conversation

@davidwrighton

@davidwrightondavidwrighton commented Aug 9, 2024

Copy link
Copy Markdown
Member

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

davidwrightonand 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
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

@davidwrightondavidwrighton mentioned this pull request Aug 9, 2024
25 tasks

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

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

Comment threaddocs/design/datacontracts/RuntimeTypeSystem.md Outdated
{
get
{
int tokenRemainderBitCount = _target.ReadGlobal<byte>(Constants.Globals.MethodDescTokenRemainderBitCount);

Copy link
Copy Markdown
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.

Comment threaddocs/design/datacontracts/RuntimeTypeSystem.md Outdated

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

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

using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Net;

Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
MemberAuthor

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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
MemberAuthor

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.

@AaronRobinsonMSFTAaronRobinsonMSFTAug 10, 2024

Copy link
Copy Markdown
Member

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
Copy Markdown
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
Copy Markdown
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:

inlineDWORDIsNoMetadata() 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.

@davidwrightondavidwrightonAug 12, 2024

Copy link
Copy Markdown
MemberAuthor

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
Copy Markdown
MemberAuthor

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
Copy Markdown
MemberAuthor

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.

Sign up for freeto 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

@davidwrighton@lambdageek@jkoritzinsky@jkotas@AaronRobinsonMSFT@elinor-fung