WIP: Initial implementation of JIT assembly name helpers - #48578

Closed
trylek wants to merge 2 commits into
dotnet:mainfrom
trylek:ModuleHelpersCG2
Closed

WIP: Initial implementation of JIT assembly name helpers#48578
trylek wants to merge 2 commits into
dotnet:mainfrom
trylek:ModuleHelpersCG2

Conversation

@trylek

Copy link
Copy Markdown
Member

According to Bruce these helpers are required in order for SuperPMI to work properly.
I have stitched together a super-simple attempt at their implementations. Right now
I have no idea how to test them. I'm looking forward to any feedback you might have.

Thanks

Tomas

@dotnet/crossgen-contrib

@trylek

Copy link
Copy Markdown
MemberAuthor

Also, @MichalStrehovsky - should these changes be moved to CorInfoImpl.ReadyToRun.cs?

Comment threadsrc/coreclr/tools/Common/JitInterface/CorInfoImpl.cs Outdated
@BruceForstall

Copy link
Copy Markdown
Contributor

I can't review the implementation, but I can tell you more about what the JIT and SuperPMI is doing.

I added these calls from the JIT when we are doing a SuperPMI collection:

info.compCompHnd->getAssemblyName(info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));

The idea is that when I do a SuperPMI collection, we merge lots of function compilation data into one large file (say, all the tests, or all the assemblies in the Core_Root directory), but in doing so we lose the association of a function with an assembly. This adds that assembly name info into the per-function data that we've collected, which can be useful for JIT devs.

(This set of calls can also be used in some altjit scenarios -- those calls have been there for many years.)

The JIT doesn't call these in "normal" scenarios.

To reproduce the failure I was seeing, you can do this (change paths as necessary):

py -3 c:\gh\runtime\src\coreclr\scripts\superpmi.py collect --crossgen2 -assemblies c:\gh\runtime\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\System.Private.CoreLib.dll -output_mch_path c:\bug\lib.cg2.mch

The resulting lib.cg2.mch should be non-zero (before a fix, you'll get crashes).

You can verify there's useful data by doing this:

c:\gh\runtime\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\mcs.exe -dump 1 C:\bug\lib.cg2.mch | findstr /i getassemblyname

and seeing something like:

GetAssemblyName - 1
0-GetAssemblyName assem-000001867C2D2A50, value-4 'System.Private.CoreLib'

@BruceForstall

Copy link
Copy Markdown
Contributor

Related: #48534

@MichalStrehovsky

Copy link
Copy Markdown
Member

Also, @MichalStrehovsky - should these changes be moved to CorInfoImpl.ReadyToRun.cs?

The code looks shareable, so it's fine to keep in the shared file, even though it's unused right now.

private CORINFO_MODULE_STRUCT_* getClassModule(CORINFO_CLASS_STRUCT_* cls)
{ throw new NotImplementedException("getClassModule"); }
{
TypeDesc type = HandleToObject(cls).GetTypeDefinition();

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't come up with a better way to do this either. It's not great.

@BruceForstall looking at places that use this in JIT, they all seem to be:

constchar*methodAssemblyName=info.compCompHnd->getAssemblyName(
info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));

Could we change them to:

constchar*methodAssemblyName=info.compCompHnd->getAssemblyName(
info.compCompHnd->getModuleAssembly(info.compScopeHnd));

so that we can keep not implementing this API? Getting the module handle out of the class is not something we can do (this implementation will work for how JIT uses it, but the path is narrow). We can get modules from methods if needed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Does that work for cross-module inlining?

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.

info.compScopeHnd is the module in which the JIT resolves tokens of the method it's working on right now. So I would expect it does.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Unfortunately, when I change the code like this, crossgen(1) crashes.

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 assume it crashes because compScopeHnd is not always a module.

Can we change this method to `getClassAssembly? It should work for all cases.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@jkotas are you proposing there should be a new JIT-EE interface method

CORINFO_ASSEMBLY_HANDLE getClassAssembly(CORINFO_CLASS_HANDLE cls);

?

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.

Yes, and delete the existing getClassModule and getModuleAssembly methods since all their uses in the JIT can be replaced by getClassAssembly.

@BruceForstallBruceForstallFeb 23, 2021

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

btw, there was operator error: I replaced the case I cared about with the code @MichalStrehovsky gave above, but info.compScopeHnd wasn't yet defined. When I fix that, crossgen1 works. I can't verify that it's the "same" result as before, but it looks reasonable.

Specifically:

diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp
index a8b990d2ed0..3ce9e7fad09 100644
--- a/src/coreclr/jit/compiler.cpp
+++ b/src/coreclr/jit/compiler.cpp
@@ -5587,8 +5587,7 @@ int Compiler::compCompile(CORINFO_MODULE_HANDLE classPtr,
if (JitConfig.EnableExtraSuperPmiQueries())
{
// Get the assembly name, to aid finding any particular SuperPMI method context function
- (void)info.compCompHnd->getAssemblyName(
- info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));
+ (void)info.compCompHnd->getAssemblyName(info.compCompHnd->getModuleAssembly(classPtr));
}
#endif // DEBUG

@BruceForstall

Copy link
Copy Markdown
Contributor

@trylek What is the next step here? Are you ready to merge as-is? Do you need me to change the JIT to not call getClassModule?

@trylek

Copy link
Copy Markdown
MemberAuthor

@BruceForstall - well, the change in its current form is quite hacky. If the JIT interface API can be changed according to JanK's suggestion, that would be probably the best way forward and that would let me simplify the change substantially. If that change is complicated or takes time due to going through some review hoops, it may be more efficient to merge this in and just create a follow-up issue to clean this up once the interface change lands.

@MichalStrehovsky

Copy link
Copy Markdown
Member

If the change to use compScopeHnd instead of info.compCompHnd->getClassModule(info.compClassHnd) works, that would probably be the best course of action. I'm a little bit worried about the "I can't verify that it's the "same" result as before, but it looks reasonable." but based on how I understand the JIT operates, it should be equivalent.

@BruceForstall

Copy link
Copy Markdown
Contributor

If the change to use compScopeHnd instead of info.compCompHnd->getClassModule(info.compClassHnd) works, that would probably be the best course of action. I'm a little bit worried about the "I can't verify that it's the "same" result as before, but it looks reasonable." but based on how I understand the JIT operates, it should be equivalent.

I tried collecting crossgen(1) build of the libraries using the current code, and the code using compScopeHnd, and the set of assembly names generated were different in the two cases. I couldn't track down the reason for the differences; maybe I should try again. It indicated to me that perhaps in some cases we were getting different answers.

@BruceForstall - well, the change in its current form is quite hacky. If the JIT interface API can be changed according to JanK's suggestion, that would be probably the best way forward and that would let me simplify the change substantially. If that change is complicated or takes time due to going through some review hoops, it may be more efficient to merge this in and just create a follow-up issue to clean this up once the interface change lands.

You'll have to decide how hacky is too hacky :-) What would an implementation on the cg2 side look like for the proposed new CORINFO_ASSEMBLY_HANDLE getClassAssembly(CORINFO_CLASS_HANDLE cls); api? It's painful to add/remove JIT/EE APIs, but if that's the way to go, I can look into it.

@trylek

Copy link
Copy Markdown
MemberAuthor

I think that the ugliest part is having to enumerate the methods (around line 1645) just to get to some MethodIL we can represent as a "module". Direct translation of class to module should be as easy as class.GetTypeDefinition().GetClosestDefType() as EcmaType ecmaType followed by extraction of the module information from the ecmaType.Module field.

Base automatically changed from master to mainMarch 1, 2021 09:08
@mangod9

Copy link
Copy Markdown
Member

@trylek@BruceForstall Is this still required?

@BruceForstall

Copy link
Copy Markdown
Contributor

@mangod9Something is still required. I don't know if it is this or an alternative suggested in this issue's comments.

@marek-safar
marek-safar marked this pull request as draft September 27, 2021 07:47
@ghostghost closed this Nov 3, 2021
@ghost

ghost commented Nov 3, 2021

Copy link
Copy Markdown

Draft Pull Request was automatically closed for inactivity. Please let us know if you'd like to reopen it.

@ghostghost locked as resolved and limited conversation to collaborators Dec 3, 2021
@trylek
trylek deleted the ModuleHelpersCG2 branch January 10, 2022 19:39
This pull request was closed.
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.

5 participants

@trylek@BruceForstall@MichalStrehovsky@mangod9@jkotas
, '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

WIP: Initial implementation of JIT assembly name helpers - #48578

Closed
trylek wants to merge 2 commits into
dotnet:mainfrom
trylek:ModuleHelpersCG2
Closed

WIP: Initial implementation of JIT assembly name helpers#48578
trylek wants to merge 2 commits into
dotnet:mainfrom
trylek:ModuleHelpersCG2

Conversation

@trylek

Copy link
Copy Markdown
Member

According to Bruce these helpers are required in order for SuperPMI to work properly.
I have stitched together a super-simple attempt at their implementations. Right now
I have no idea how to test them. I'm looking forward to any feedback you might have.

Thanks

Tomas

@dotnet/crossgen-contrib

@trylek

Copy link
Copy Markdown
MemberAuthor

Also, @MichalStrehovsky - should these changes be moved to CorInfoImpl.ReadyToRun.cs?

Comment threadsrc/coreclr/tools/Common/JitInterface/CorInfoImpl.cs Outdated
@BruceForstall

Copy link
Copy Markdown
Contributor

I can't review the implementation, but I can tell you more about what the JIT and SuperPMI is doing.

I added these calls from the JIT when we are doing a SuperPMI collection:

info.compCompHnd->getAssemblyName(info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));

The idea is that when I do a SuperPMI collection, we merge lots of function compilation data into one large file (say, all the tests, or all the assemblies in the Core_Root directory), but in doing so we lose the association of a function with an assembly. This adds that assembly name info into the per-function data that we've collected, which can be useful for JIT devs.

(This set of calls can also be used in some altjit scenarios -- those calls have been there for many years.)

The JIT doesn't call these in "normal" scenarios.

To reproduce the failure I was seeing, you can do this (change paths as necessary):

py -3 c:\gh\runtime\src\coreclr\scripts\superpmi.py collect --crossgen2 -assemblies c:\gh\runtime\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\System.Private.CoreLib.dll -output_mch_path c:\bug\lib.cg2.mch

The resulting lib.cg2.mch should be non-zero (before a fix, you'll get crashes).

You can verify there's useful data by doing this:

c:\gh\runtime\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\mcs.exe -dump 1 C:\bug\lib.cg2.mch | findstr /i getassemblyname

and seeing something like:

GetAssemblyName - 1
0-GetAssemblyName assem-000001867C2D2A50, value-4 'System.Private.CoreLib'

@BruceForstall

Copy link
Copy Markdown
Contributor

Related: #48534

@MichalStrehovsky

Copy link
Copy Markdown
Member

Also, @MichalStrehovsky - should these changes be moved to CorInfoImpl.ReadyToRun.cs?

The code looks shareable, so it's fine to keep in the shared file, even though it's unused right now.

private CORINFO_MODULE_STRUCT_* getClassModule(CORINFO_CLASS_STRUCT_* cls)
{ throw new NotImplementedException("getClassModule"); }
{
TypeDesc type = HandleToObject(cls).GetTypeDefinition();

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't come up with a better way to do this either. It's not great.

@BruceForstall looking at places that use this in JIT, they all seem to be:

constchar*methodAssemblyName=info.compCompHnd->getAssemblyName(
info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));

Could we change them to:

constchar*methodAssemblyName=info.compCompHnd->getAssemblyName(
info.compCompHnd->getModuleAssembly(info.compScopeHnd));

so that we can keep not implementing this API? Getting the module handle out of the class is not something we can do (this implementation will work for how JIT uses it, but the path is narrow). We can get modules from methods if needed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Does that work for cross-module inlining?

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.

info.compScopeHnd is the module in which the JIT resolves tokens of the method it's working on right now. So I would expect it does.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Unfortunately, when I change the code like this, crossgen(1) crashes.

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 assume it crashes because compScopeHnd is not always a module.

Can we change this method to `getClassAssembly? It should work for all cases.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@jkotas are you proposing there should be a new JIT-EE interface method

CORINFO_ASSEMBLY_HANDLE getClassAssembly(CORINFO_CLASS_HANDLE cls);

?

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.

Yes, and delete the existing getClassModule and getModuleAssembly methods since all their uses in the JIT can be replaced by getClassAssembly.

@BruceForstallBruceForstallFeb 23, 2021

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

btw, there was operator error: I replaced the case I cared about with the code @MichalStrehovsky gave above, but info.compScopeHnd wasn't yet defined. When I fix that, crossgen1 works. I can't verify that it's the "same" result as before, but it looks reasonable.

Specifically:

diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp
index a8b990d2ed0..3ce9e7fad09 100644
--- a/src/coreclr/jit/compiler.cpp
+++ b/src/coreclr/jit/compiler.cpp
@@ -5587,8 +5587,7 @@ int Compiler::compCompile(CORINFO_MODULE_HANDLE classPtr,
if (JitConfig.EnableExtraSuperPmiQueries())
{
// Get the assembly name, to aid finding any particular SuperPMI method context function
- (void)info.compCompHnd->getAssemblyName(
- info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));
+ (void)info.compCompHnd->getAssemblyName(info.compCompHnd->getModuleAssembly(classPtr));
}
#endif // DEBUG

@BruceForstall

Copy link
Copy Markdown
Contributor

@trylek What is the next step here? Are you ready to merge as-is? Do you need me to change the JIT to not call getClassModule?

@trylek

Copy link
Copy Markdown
MemberAuthor

@BruceForstall - well, the change in its current form is quite hacky. If the JIT interface API can be changed according to JanK's suggestion, that would be probably the best way forward and that would let me simplify the change substantially. If that change is complicated or takes time due to going through some review hoops, it may be more efficient to merge this in and just create a follow-up issue to clean this up once the interface change lands.

@MichalStrehovsky

Copy link
Copy Markdown
Member

If the change to use compScopeHnd instead of info.compCompHnd->getClassModule(info.compClassHnd) works, that would probably be the best course of action. I'm a little bit worried about the "I can't verify that it's the "same" result as before, but it looks reasonable." but based on how I understand the JIT operates, it should be equivalent.

@BruceForstall

Copy link
Copy Markdown
Contributor

If the change to use compScopeHnd instead of info.compCompHnd->getClassModule(info.compClassHnd) works, that would probably be the best course of action. I'm a little bit worried about the "I can't verify that it's the "same" result as before, but it looks reasonable." but based on how I understand the JIT operates, it should be equivalent.

I tried collecting crossgen(1) build of the libraries using the current code, and the code using compScopeHnd, and the set of assembly names generated were different in the two cases. I couldn't track down the reason for the differences; maybe I should try again. It indicated to me that perhaps in some cases we were getting different answers.

@BruceForstall - well, the change in its current form is quite hacky. If the JIT interface API can be changed according to JanK's suggestion, that would be probably the best way forward and that would let me simplify the change substantially. If that change is complicated or takes time due to going through some review hoops, it may be more efficient to merge this in and just create a follow-up issue to clean this up once the interface change lands.

You'll have to decide how hacky is too hacky :-) What would an implementation on the cg2 side look like for the proposed new CORINFO_ASSEMBLY_HANDLE getClassAssembly(CORINFO_CLASS_HANDLE cls); api? It's painful to add/remove JIT/EE APIs, but if that's the way to go, I can look into it.

@trylek

Copy link
Copy Markdown
MemberAuthor

I think that the ugliest part is having to enumerate the methods (around line 1645) just to get to some MethodIL we can represent as a "module". Direct translation of class to module should be as easy as class.GetTypeDefinition().GetClosestDefType() as EcmaType ecmaType followed by extraction of the module information from the ecmaType.Module field.

Base automatically changed from master to mainMarch 1, 2021 09:08
@mangod9

Copy link
Copy Markdown
Member

@trylek@BruceForstall Is this still required?

@BruceForstall

Copy link
Copy Markdown
Contributor

@mangod9Something is still required. I don't know if it is this or an alternative suggested in this issue's comments.

@marek-safar
marek-safar marked this pull request as draft September 27, 2021 07:47
@ghostghost closed this Nov 3, 2021
@ghost

ghost commented Nov 3, 2021

Copy link
Copy Markdown

Draft Pull Request was automatically closed for inactivity. Please let us know if you'd like to reopen it.

@ghostghost locked as resolved and limited conversation to collaborators Dec 3, 2021
@trylek
trylek deleted the ModuleHelpersCG2 branch January 10, 2022 19:39
This pull request was closed.
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.

5 participants

@trylek@BruceForstall@MichalStrehovsky@mangod9@jkotas
, '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

WIP: Initial implementation of JIT assembly name helpers - #48578

Closed
trylek wants to merge 2 commits into
dotnet:mainfrom
trylek:ModuleHelpersCG2
Closed

WIP: Initial implementation of JIT assembly name helpers#48578
trylek wants to merge 2 commits into
dotnet:mainfrom
trylek:ModuleHelpersCG2

Conversation

@trylek

Copy link
Copy Markdown
Member

According to Bruce these helpers are required in order for SuperPMI to work properly.
I have stitched together a super-simple attempt at their implementations. Right now
I have no idea how to test them. I'm looking forward to any feedback you might have.

Thanks

Tomas

@dotnet/crossgen-contrib

@trylek

Copy link
Copy Markdown
MemberAuthor

Also, @MichalStrehovsky - should these changes be moved to CorInfoImpl.ReadyToRun.cs?

Comment threadsrc/coreclr/tools/Common/JitInterface/CorInfoImpl.cs Outdated
@BruceForstall

Copy link
Copy Markdown
Contributor

I can't review the implementation, but I can tell you more about what the JIT and SuperPMI is doing.

I added these calls from the JIT when we are doing a SuperPMI collection:

info.compCompHnd->getAssemblyName(info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));

The idea is that when I do a SuperPMI collection, we merge lots of function compilation data into one large file (say, all the tests, or all the assemblies in the Core_Root directory), but in doing so we lose the association of a function with an assembly. This adds that assembly name info into the per-function data that we've collected, which can be useful for JIT devs.

(This set of calls can also be used in some altjit scenarios -- those calls have been there for many years.)

The JIT doesn't call these in "normal" scenarios.

To reproduce the failure I was seeing, you can do this (change paths as necessary):

py -3 c:\gh\runtime\src\coreclr\scripts\superpmi.py collect --crossgen2 -assemblies c:\gh\runtime\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\System.Private.CoreLib.dll -output_mch_path c:\bug\lib.cg2.mch

The resulting lib.cg2.mch should be non-zero (before a fix, you'll get crashes).

You can verify there's useful data by doing this:

c:\gh\runtime\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\mcs.exe -dump 1 C:\bug\lib.cg2.mch | findstr /i getassemblyname

and seeing something like:

GetAssemblyName - 1
0-GetAssemblyName assem-000001867C2D2A50, value-4 'System.Private.CoreLib'

@BruceForstall

Copy link
Copy Markdown
Contributor

Related: #48534

@MichalStrehovsky

Copy link
Copy Markdown
Member

Also, @MichalStrehovsky - should these changes be moved to CorInfoImpl.ReadyToRun.cs?

The code looks shareable, so it's fine to keep in the shared file, even though it's unused right now.

private CORINFO_MODULE_STRUCT_* getClassModule(CORINFO_CLASS_STRUCT_* cls)
{ throw new NotImplementedException("getClassModule"); }
{
TypeDesc type = HandleToObject(cls).GetTypeDefinition();

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't come up with a better way to do this either. It's not great.

@BruceForstall looking at places that use this in JIT, they all seem to be:

constchar*methodAssemblyName=info.compCompHnd->getAssemblyName(
info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));

Could we change them to:

constchar*methodAssemblyName=info.compCompHnd->getAssemblyName(
info.compCompHnd->getModuleAssembly(info.compScopeHnd));

so that we can keep not implementing this API? Getting the module handle out of the class is not something we can do (this implementation will work for how JIT uses it, but the path is narrow). We can get modules from methods if needed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Does that work for cross-module inlining?

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.

info.compScopeHnd is the module in which the JIT resolves tokens of the method it's working on right now. So I would expect it does.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Unfortunately, when I change the code like this, crossgen(1) crashes.

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 assume it crashes because compScopeHnd is not always a module.

Can we change this method to `getClassAssembly? It should work for all cases.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@jkotas are you proposing there should be a new JIT-EE interface method

CORINFO_ASSEMBLY_HANDLE getClassAssembly(CORINFO_CLASS_HANDLE cls);

?

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.

Yes, and delete the existing getClassModule and getModuleAssembly methods since all their uses in the JIT can be replaced by getClassAssembly.

@BruceForstallBruceForstallFeb 23, 2021

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

btw, there was operator error: I replaced the case I cared about with the code @MichalStrehovsky gave above, but info.compScopeHnd wasn't yet defined. When I fix that, crossgen1 works. I can't verify that it's the "same" result as before, but it looks reasonable.

Specifically:

diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp
index a8b990d2ed0..3ce9e7fad09 100644
--- a/src/coreclr/jit/compiler.cpp
+++ b/src/coreclr/jit/compiler.cpp
@@ -5587,8 +5587,7 @@ int Compiler::compCompile(CORINFO_MODULE_HANDLE classPtr,
if (JitConfig.EnableExtraSuperPmiQueries())
{
// Get the assembly name, to aid finding any particular SuperPMI method context function
- (void)info.compCompHnd->getAssemblyName(
- info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));
+ (void)info.compCompHnd->getAssemblyName(info.compCompHnd->getModuleAssembly(classPtr));
}
#endif // DEBUG

@BruceForstall

Copy link
Copy Markdown
Contributor

@trylek What is the next step here? Are you ready to merge as-is? Do you need me to change the JIT to not call getClassModule?

@trylek

Copy link
Copy Markdown
MemberAuthor

@BruceForstall - well, the change in its current form is quite hacky. If the JIT interface API can be changed according to JanK's suggestion, that would be probably the best way forward and that would let me simplify the change substantially. If that change is complicated or takes time due to going through some review hoops, it may be more efficient to merge this in and just create a follow-up issue to clean this up once the interface change lands.

@MichalStrehovsky

Copy link
Copy Markdown
Member

If the change to use compScopeHnd instead of info.compCompHnd->getClassModule(info.compClassHnd) works, that would probably be the best course of action. I'm a little bit worried about the "I can't verify that it's the "same" result as before, but it looks reasonable." but based on how I understand the JIT operates, it should be equivalent.

@BruceForstall

Copy link
Copy Markdown
Contributor

If the change to use compScopeHnd instead of info.compCompHnd->getClassModule(info.compClassHnd) works, that would probably be the best course of action. I'm a little bit worried about the "I can't verify that it's the "same" result as before, but it looks reasonable." but based on how I understand the JIT operates, it should be equivalent.

I tried collecting crossgen(1) build of the libraries using the current code, and the code using compScopeHnd, and the set of assembly names generated were different in the two cases. I couldn't track down the reason for the differences; maybe I should try again. It indicated to me that perhaps in some cases we were getting different answers.

@BruceForstall - well, the change in its current form is quite hacky. If the JIT interface API can be changed according to JanK's suggestion, that would be probably the best way forward and that would let me simplify the change substantially. If that change is complicated or takes time due to going through some review hoops, it may be more efficient to merge this in and just create a follow-up issue to clean this up once the interface change lands.

You'll have to decide how hacky is too hacky :-) What would an implementation on the cg2 side look like for the proposed new CORINFO_ASSEMBLY_HANDLE getClassAssembly(CORINFO_CLASS_HANDLE cls); api? It's painful to add/remove JIT/EE APIs, but if that's the way to go, I can look into it.

@trylek

Copy link
Copy Markdown
MemberAuthor

I think that the ugliest part is having to enumerate the methods (around line 1645) just to get to some MethodIL we can represent as a "module". Direct translation of class to module should be as easy as class.GetTypeDefinition().GetClosestDefType() as EcmaType ecmaType followed by extraction of the module information from the ecmaType.Module field.

Base automatically changed from master to mainMarch 1, 2021 09:08
@mangod9

Copy link
Copy Markdown
Member

@trylek@BruceForstall Is this still required?

@BruceForstall

Copy link
Copy Markdown
Contributor

@mangod9Something is still required. I don't know if it is this or an alternative suggested in this issue's comments.

@marek-safar
marek-safar marked this pull request as draft September 27, 2021 07:47
@ghostghost closed this Nov 3, 2021
@ghost

ghost commented Nov 3, 2021

Copy link
Copy Markdown

Draft Pull Request was automatically closed for inactivity. Please let us know if you'd like to reopen it.

@ghostghost locked as resolved and limited conversation to collaborators Dec 3, 2021
@trylek
trylek deleted the ModuleHelpersCG2 branch January 10, 2022 19:39
This pull request was closed.
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.

5 participants

@trylek@BruceForstall@MichalStrehovsky@mangod9@jkotas
, '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

WIP: Initial implementation of JIT assembly name helpers - #48578

Closed
trylek wants to merge 2 commits into
dotnet:mainfrom
trylek:ModuleHelpersCG2
Closed

WIP: Initial implementation of JIT assembly name helpers#48578
trylek wants to merge 2 commits into
dotnet:mainfrom
trylek:ModuleHelpersCG2

Conversation

@trylek

Copy link
Copy Markdown
Member

According to Bruce these helpers are required in order for SuperPMI to work properly.
I have stitched together a super-simple attempt at their implementations. Right now
I have no idea how to test them. I'm looking forward to any feedback you might have.

Thanks

Tomas

@dotnet/crossgen-contrib

@trylek

Copy link
Copy Markdown
MemberAuthor

Also, @MichalStrehovsky - should these changes be moved to CorInfoImpl.ReadyToRun.cs?

Comment threadsrc/coreclr/tools/Common/JitInterface/CorInfoImpl.cs Outdated
@BruceForstall

Copy link
Copy Markdown
Contributor

I can't review the implementation, but I can tell you more about what the JIT and SuperPMI is doing.

I added these calls from the JIT when we are doing a SuperPMI collection:

info.compCompHnd->getAssemblyName(info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));

The idea is that when I do a SuperPMI collection, we merge lots of function compilation data into one large file (say, all the tests, or all the assemblies in the Core_Root directory), but in doing so we lose the association of a function with an assembly. This adds that assembly name info into the per-function data that we've collected, which can be useful for JIT devs.

(This set of calls can also be used in some altjit scenarios -- those calls have been there for many years.)

The JIT doesn't call these in "normal" scenarios.

To reproduce the failure I was seeing, you can do this (change paths as necessary):

py -3 c:\gh\runtime\src\coreclr\scripts\superpmi.py collect --crossgen2 -assemblies c:\gh\runtime\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\System.Private.CoreLib.dll -output_mch_path c:\bug\lib.cg2.mch

The resulting lib.cg2.mch should be non-zero (before a fix, you'll get crashes).

You can verify there's useful data by doing this:

c:\gh\runtime\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\mcs.exe -dump 1 C:\bug\lib.cg2.mch | findstr /i getassemblyname

and seeing something like:

GetAssemblyName - 1
0-GetAssemblyName assem-000001867C2D2A50, value-4 'System.Private.CoreLib'

@BruceForstall

Copy link
Copy Markdown
Contributor

Related: #48534

@MichalStrehovsky

Copy link
Copy Markdown
Member

Also, @MichalStrehovsky - should these changes be moved to CorInfoImpl.ReadyToRun.cs?

The code looks shareable, so it's fine to keep in the shared file, even though it's unused right now.

private CORINFO_MODULE_STRUCT_* getClassModule(CORINFO_CLASS_STRUCT_* cls)
{ throw new NotImplementedException("getClassModule"); }
{
TypeDesc type = HandleToObject(cls).GetTypeDefinition();

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't come up with a better way to do this either. It's not great.

@BruceForstall looking at places that use this in JIT, they all seem to be:

constchar*methodAssemblyName=info.compCompHnd->getAssemblyName(
info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));

Could we change them to:

constchar*methodAssemblyName=info.compCompHnd->getAssemblyName(
info.compCompHnd->getModuleAssembly(info.compScopeHnd));

so that we can keep not implementing this API? Getting the module handle out of the class is not something we can do (this implementation will work for how JIT uses it, but the path is narrow). We can get modules from methods if needed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Does that work for cross-module inlining?

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.

info.compScopeHnd is the module in which the JIT resolves tokens of the method it's working on right now. So I would expect it does.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Unfortunately, when I change the code like this, crossgen(1) crashes.

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 assume it crashes because compScopeHnd is not always a module.

Can we change this method to `getClassAssembly? It should work for all cases.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@jkotas are you proposing there should be a new JIT-EE interface method

CORINFO_ASSEMBLY_HANDLE getClassAssembly(CORINFO_CLASS_HANDLE cls);

?

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.

Yes, and delete the existing getClassModule and getModuleAssembly methods since all their uses in the JIT can be replaced by getClassAssembly.

@BruceForstallBruceForstallFeb 23, 2021

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

btw, there was operator error: I replaced the case I cared about with the code @MichalStrehovsky gave above, but info.compScopeHnd wasn't yet defined. When I fix that, crossgen1 works. I can't verify that it's the "same" result as before, but it looks reasonable.

Specifically:

diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp
index a8b990d2ed0..3ce9e7fad09 100644
--- a/src/coreclr/jit/compiler.cpp
+++ b/src/coreclr/jit/compiler.cpp
@@ -5587,8 +5587,7 @@ int Compiler::compCompile(CORINFO_MODULE_HANDLE classPtr,
if (JitConfig.EnableExtraSuperPmiQueries())
{
// Get the assembly name, to aid finding any particular SuperPMI method context function
- (void)info.compCompHnd->getAssemblyName(
- info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));
+ (void)info.compCompHnd->getAssemblyName(info.compCompHnd->getModuleAssembly(classPtr));
}
#endif // DEBUG

@BruceForstall

Copy link
Copy Markdown
Contributor

@trylek What is the next step here? Are you ready to merge as-is? Do you need me to change the JIT to not call getClassModule?

@trylek

Copy link
Copy Markdown
MemberAuthor

@BruceForstall - well, the change in its current form is quite hacky. If the JIT interface API can be changed according to JanK's suggestion, that would be probably the best way forward and that would let me simplify the change substantially. If that change is complicated or takes time due to going through some review hoops, it may be more efficient to merge this in and just create a follow-up issue to clean this up once the interface change lands.

@MichalStrehovsky

Copy link
Copy Markdown
Member

If the change to use compScopeHnd instead of info.compCompHnd->getClassModule(info.compClassHnd) works, that would probably be the best course of action. I'm a little bit worried about the "I can't verify that it's the "same" result as before, but it looks reasonable." but based on how I understand the JIT operates, it should be equivalent.

@BruceForstall

Copy link
Copy Markdown
Contributor

If the change to use compScopeHnd instead of info.compCompHnd->getClassModule(info.compClassHnd) works, that would probably be the best course of action. I'm a little bit worried about the "I can't verify that it's the "same" result as before, but it looks reasonable." but based on how I understand the JIT operates, it should be equivalent.

I tried collecting crossgen(1) build of the libraries using the current code, and the code using compScopeHnd, and the set of assembly names generated were different in the two cases. I couldn't track down the reason for the differences; maybe I should try again. It indicated to me that perhaps in some cases we were getting different answers.

@BruceForstall - well, the change in its current form is quite hacky. If the JIT interface API can be changed according to JanK's suggestion, that would be probably the best way forward and that would let me simplify the change substantially. If that change is complicated or takes time due to going through some review hoops, it may be more efficient to merge this in and just create a follow-up issue to clean this up once the interface change lands.

You'll have to decide how hacky is too hacky :-) What would an implementation on the cg2 side look like for the proposed new CORINFO_ASSEMBLY_HANDLE getClassAssembly(CORINFO_CLASS_HANDLE cls); api? It's painful to add/remove JIT/EE APIs, but if that's the way to go, I can look into it.

@trylek

Copy link
Copy Markdown
MemberAuthor

I think that the ugliest part is having to enumerate the methods (around line 1645) just to get to some MethodIL we can represent as a "module". Direct translation of class to module should be as easy as class.GetTypeDefinition().GetClosestDefType() as EcmaType ecmaType followed by extraction of the module information from the ecmaType.Module field.

Base automatically changed from master to mainMarch 1, 2021 09:08
@mangod9

Copy link
Copy Markdown
Member

@trylek@BruceForstall Is this still required?

@BruceForstall

Copy link
Copy Markdown
Contributor

@mangod9Something is still required. I don't know if it is this or an alternative suggested in this issue's comments.

@marek-safar
marek-safar marked this pull request as draft September 27, 2021 07:47
@ghostghost closed this Nov 3, 2021
@ghost

ghost commented Nov 3, 2021

Copy link
Copy Markdown

Draft Pull Request was automatically closed for inactivity. Please let us know if you'd like to reopen it.

@ghostghost locked as resolved and limited conversation to collaborators Dec 3, 2021
@trylek
trylek deleted the ModuleHelpersCG2 branch January 10, 2022 19:39
This pull request was closed.
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.

5 participants

@trylek@BruceForstall@MichalStrehovsky@mangod9@jkotas
, '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

WIP: Initial implementation of JIT assembly name helpers - #48578

Closed
trylek wants to merge 2 commits into
dotnet:mainfrom
trylek:ModuleHelpersCG2
Closed

WIP: Initial implementation of JIT assembly name helpers#48578
trylek wants to merge 2 commits into
dotnet:mainfrom
trylek:ModuleHelpersCG2

Conversation

@trylek

Copy link
Copy Markdown
Member

According to Bruce these helpers are required in order for SuperPMI to work properly.
I have stitched together a super-simple attempt at their implementations. Right now
I have no idea how to test them. I'm looking forward to any feedback you might have.

Thanks

Tomas

@dotnet/crossgen-contrib

@trylek

Copy link
Copy Markdown
MemberAuthor

Also, @MichalStrehovsky - should these changes be moved to CorInfoImpl.ReadyToRun.cs?

Comment threadsrc/coreclr/tools/Common/JitInterface/CorInfoImpl.cs Outdated
@BruceForstall

Copy link
Copy Markdown
Contributor

I can't review the implementation, but I can tell you more about what the JIT and SuperPMI is doing.

I added these calls from the JIT when we are doing a SuperPMI collection:

info.compCompHnd->getAssemblyName(info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));

The idea is that when I do a SuperPMI collection, we merge lots of function compilation data into one large file (say, all the tests, or all the assemblies in the Core_Root directory), but in doing so we lose the association of a function with an assembly. This adds that assembly name info into the per-function data that we've collected, which can be useful for JIT devs.

(This set of calls can also be used in some altjit scenarios -- those calls have been there for many years.)

The JIT doesn't call these in "normal" scenarios.

To reproduce the failure I was seeing, you can do this (change paths as necessary):

py -3 c:\gh\runtime\src\coreclr\scripts\superpmi.py collect --crossgen2 -assemblies c:\gh\runtime\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\System.Private.CoreLib.dll -output_mch_path c:\bug\lib.cg2.mch

The resulting lib.cg2.mch should be non-zero (before a fix, you'll get crashes).

You can verify there's useful data by doing this:

c:\gh\runtime\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\mcs.exe -dump 1 C:\bug\lib.cg2.mch | findstr /i getassemblyname

and seeing something like:

GetAssemblyName - 1
0-GetAssemblyName assem-000001867C2D2A50, value-4 'System.Private.CoreLib'

@BruceForstall

Copy link
Copy Markdown
Contributor

Related: #48534

@MichalStrehovsky

Copy link
Copy Markdown
Member

Also, @MichalStrehovsky - should these changes be moved to CorInfoImpl.ReadyToRun.cs?

The code looks shareable, so it's fine to keep in the shared file, even though it's unused right now.

private CORINFO_MODULE_STRUCT_* getClassModule(CORINFO_CLASS_STRUCT_* cls)
{ throw new NotImplementedException("getClassModule"); }
{
TypeDesc type = HandleToObject(cls).GetTypeDefinition();

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't come up with a better way to do this either. It's not great.

@BruceForstall looking at places that use this in JIT, they all seem to be:

constchar*methodAssemblyName=info.compCompHnd->getAssemblyName(
info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));

Could we change them to:

constchar*methodAssemblyName=info.compCompHnd->getAssemblyName(
info.compCompHnd->getModuleAssembly(info.compScopeHnd));

so that we can keep not implementing this API? Getting the module handle out of the class is not something we can do (this implementation will work for how JIT uses it, but the path is narrow). We can get modules from methods if needed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Does that work for cross-module inlining?

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.

info.compScopeHnd is the module in which the JIT resolves tokens of the method it's working on right now. So I would expect it does.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Unfortunately, when I change the code like this, crossgen(1) crashes.

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 assume it crashes because compScopeHnd is not always a module.

Can we change this method to `getClassAssembly? It should work for all cases.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@jkotas are you proposing there should be a new JIT-EE interface method

CORINFO_ASSEMBLY_HANDLE getClassAssembly(CORINFO_CLASS_HANDLE cls);

?

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.

Yes, and delete the existing getClassModule and getModuleAssembly methods since all their uses in the JIT can be replaced by getClassAssembly.

@BruceForstallBruceForstallFeb 23, 2021

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

btw, there was operator error: I replaced the case I cared about with the code @MichalStrehovsky gave above, but info.compScopeHnd wasn't yet defined. When I fix that, crossgen1 works. I can't verify that it's the "same" result as before, but it looks reasonable.

Specifically:

diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp
index a8b990d2ed0..3ce9e7fad09 100644
--- a/src/coreclr/jit/compiler.cpp
+++ b/src/coreclr/jit/compiler.cpp
@@ -5587,8 +5587,7 @@ int Compiler::compCompile(CORINFO_MODULE_HANDLE classPtr,
if (JitConfig.EnableExtraSuperPmiQueries())
{
// Get the assembly name, to aid finding any particular SuperPMI method context function
- (void)info.compCompHnd->getAssemblyName(
- info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));
+ (void)info.compCompHnd->getAssemblyName(info.compCompHnd->getModuleAssembly(classPtr));
}
#endif // DEBUG

@BruceForstall

Copy link
Copy Markdown
Contributor

@trylek What is the next step here? Are you ready to merge as-is? Do you need me to change the JIT to not call getClassModule?

@trylek

Copy link
Copy Markdown
MemberAuthor

@BruceForstall - well, the change in its current form is quite hacky. If the JIT interface API can be changed according to JanK's suggestion, that would be probably the best way forward and that would let me simplify the change substantially. If that change is complicated or takes time due to going through some review hoops, it may be more efficient to merge this in and just create a follow-up issue to clean this up once the interface change lands.

@MichalStrehovsky

Copy link
Copy Markdown
Member

If the change to use compScopeHnd instead of info.compCompHnd->getClassModule(info.compClassHnd) works, that would probably be the best course of action. I'm a little bit worried about the "I can't verify that it's the "same" result as before, but it looks reasonable." but based on how I understand the JIT operates, it should be equivalent.

@BruceForstall

Copy link
Copy Markdown
Contributor

If the change to use compScopeHnd instead of info.compCompHnd->getClassModule(info.compClassHnd) works, that would probably be the best course of action. I'm a little bit worried about the "I can't verify that it's the "same" result as before, but it looks reasonable." but based on how I understand the JIT operates, it should be equivalent.

I tried collecting crossgen(1) build of the libraries using the current code, and the code using compScopeHnd, and the set of assembly names generated were different in the two cases. I couldn't track down the reason for the differences; maybe I should try again. It indicated to me that perhaps in some cases we were getting different answers.

@BruceForstall - well, the change in its current form is quite hacky. If the JIT interface API can be changed according to JanK's suggestion, that would be probably the best way forward and that would let me simplify the change substantially. If that change is complicated or takes time due to going through some review hoops, it may be more efficient to merge this in and just create a follow-up issue to clean this up once the interface change lands.

You'll have to decide how hacky is too hacky :-) What would an implementation on the cg2 side look like for the proposed new CORINFO_ASSEMBLY_HANDLE getClassAssembly(CORINFO_CLASS_HANDLE cls); api? It's painful to add/remove JIT/EE APIs, but if that's the way to go, I can look into it.

@trylek

Copy link
Copy Markdown
MemberAuthor

I think that the ugliest part is having to enumerate the methods (around line 1645) just to get to some MethodIL we can represent as a "module". Direct translation of class to module should be as easy as class.GetTypeDefinition().GetClosestDefType() as EcmaType ecmaType followed by extraction of the module information from the ecmaType.Module field.

Base automatically changed from master to mainMarch 1, 2021 09:08
@mangod9

Copy link
Copy Markdown
Member

@trylek@BruceForstall Is this still required?

@BruceForstall

Copy link
Copy Markdown
Contributor

@mangod9Something is still required. I don't know if it is this or an alternative suggested in this issue's comments.

@marek-safar
marek-safar marked this pull request as draft September 27, 2021 07:47
@ghostghost closed this Nov 3, 2021
@ghost

ghost commented Nov 3, 2021

Copy link
Copy Markdown

Draft Pull Request was automatically closed for inactivity. Please let us know if you'd like to reopen it.

@ghostghost locked as resolved and limited conversation to collaborators Dec 3, 2021
@trylek
trylek deleted the ModuleHelpersCG2 branch January 10, 2022 19:39
This pull request was closed.
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.

5 participants

@trylek@BruceForstall@MichalStrehovsky@mangod9@jkotas
, '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

WIP: Initial implementation of JIT assembly name helpers - #48578

Closed
trylek wants to merge 2 commits into
dotnet:mainfrom
trylek:ModuleHelpersCG2
Closed

WIP: Initial implementation of JIT assembly name helpers#48578
trylek wants to merge 2 commits into
dotnet:mainfrom
trylek:ModuleHelpersCG2

Conversation

@trylek

Copy link
Copy Markdown
Member

According to Bruce these helpers are required in order for SuperPMI to work properly.
I have stitched together a super-simple attempt at their implementations. Right now
I have no idea how to test them. I'm looking forward to any feedback you might have.

Thanks

Tomas

@dotnet/crossgen-contrib

@trylek

Copy link
Copy Markdown
MemberAuthor

Also, @MichalStrehovsky - should these changes be moved to CorInfoImpl.ReadyToRun.cs?

Comment threadsrc/coreclr/tools/Common/JitInterface/CorInfoImpl.cs Outdated
@BruceForstall

Copy link
Copy Markdown
Contributor

I can't review the implementation, but I can tell you more about what the JIT and SuperPMI is doing.

I added these calls from the JIT when we are doing a SuperPMI collection:

info.compCompHnd->getAssemblyName(info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));

The idea is that when I do a SuperPMI collection, we merge lots of function compilation data into one large file (say, all the tests, or all the assemblies in the Core_Root directory), but in doing so we lose the association of a function with an assembly. This adds that assembly name info into the per-function data that we've collected, which can be useful for JIT devs.

(This set of calls can also be used in some altjit scenarios -- those calls have been there for many years.)

The JIT doesn't call these in "normal" scenarios.

To reproduce the failure I was seeing, you can do this (change paths as necessary):

py -3 c:\gh\runtime\src\coreclr\scripts\superpmi.py collect --crossgen2 -assemblies c:\gh\runtime\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\System.Private.CoreLib.dll -output_mch_path c:\bug\lib.cg2.mch

The resulting lib.cg2.mch should be non-zero (before a fix, you'll get crashes).

You can verify there's useful data by doing this:

c:\gh\runtime\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\mcs.exe -dump 1 C:\bug\lib.cg2.mch | findstr /i getassemblyname

and seeing something like:

GetAssemblyName - 1
0-GetAssemblyName assem-000001867C2D2A50, value-4 'System.Private.CoreLib'

@BruceForstall

Copy link
Copy Markdown
Contributor

Related: #48534

@MichalStrehovsky

Copy link
Copy Markdown
Member

Also, @MichalStrehovsky - should these changes be moved to CorInfoImpl.ReadyToRun.cs?

The code looks shareable, so it's fine to keep in the shared file, even though it's unused right now.

private CORINFO_MODULE_STRUCT_* getClassModule(CORINFO_CLASS_STRUCT_* cls)
{ throw new NotImplementedException("getClassModule"); }
{
TypeDesc type = HandleToObject(cls).GetTypeDefinition();

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't come up with a better way to do this either. It's not great.

@BruceForstall looking at places that use this in JIT, they all seem to be:

constchar*methodAssemblyName=info.compCompHnd->getAssemblyName(
info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));

Could we change them to:

constchar*methodAssemblyName=info.compCompHnd->getAssemblyName(
info.compCompHnd->getModuleAssembly(info.compScopeHnd));

so that we can keep not implementing this API? Getting the module handle out of the class is not something we can do (this implementation will work for how JIT uses it, but the path is narrow). We can get modules from methods if needed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Does that work for cross-module inlining?

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.

info.compScopeHnd is the module in which the JIT resolves tokens of the method it's working on right now. So I would expect it does.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Unfortunately, when I change the code like this, crossgen(1) crashes.

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 assume it crashes because compScopeHnd is not always a module.

Can we change this method to `getClassAssembly? It should work for all cases.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@jkotas are you proposing there should be a new JIT-EE interface method

CORINFO_ASSEMBLY_HANDLE getClassAssembly(CORINFO_CLASS_HANDLE cls);

?

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.

Yes, and delete the existing getClassModule and getModuleAssembly methods since all their uses in the JIT can be replaced by getClassAssembly.

@BruceForstallBruceForstallFeb 23, 2021

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

btw, there was operator error: I replaced the case I cared about with the code @MichalStrehovsky gave above, but info.compScopeHnd wasn't yet defined. When I fix that, crossgen1 works. I can't verify that it's the "same" result as before, but it looks reasonable.

Specifically:

diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp
index a8b990d2ed0..3ce9e7fad09 100644
--- a/src/coreclr/jit/compiler.cpp
+++ b/src/coreclr/jit/compiler.cpp
@@ -5587,8 +5587,7 @@ int Compiler::compCompile(CORINFO_MODULE_HANDLE classPtr,
if (JitConfig.EnableExtraSuperPmiQueries())
{
// Get the assembly name, to aid finding any particular SuperPMI method context function
- (void)info.compCompHnd->getAssemblyName(
- info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));
+ (void)info.compCompHnd->getAssemblyName(info.compCompHnd->getModuleAssembly(classPtr));
}
#endif // DEBUG

@BruceForstall

Copy link
Copy Markdown
Contributor

@trylek What is the next step here? Are you ready to merge as-is? Do you need me to change the JIT to not call getClassModule?

@trylek

Copy link
Copy Markdown
MemberAuthor

@BruceForstall - well, the change in its current form is quite hacky. If the JIT interface API can be changed according to JanK's suggestion, that would be probably the best way forward and that would let me simplify the change substantially. If that change is complicated or takes time due to going through some review hoops, it may be more efficient to merge this in and just create a follow-up issue to clean this up once the interface change lands.

@MichalStrehovsky

Copy link
Copy Markdown
Member

If the change to use compScopeHnd instead of info.compCompHnd->getClassModule(info.compClassHnd) works, that would probably be the best course of action. I'm a little bit worried about the "I can't verify that it's the "same" result as before, but it looks reasonable." but based on how I understand the JIT operates, it should be equivalent.

@BruceForstall

Copy link
Copy Markdown
Contributor

If the change to use compScopeHnd instead of info.compCompHnd->getClassModule(info.compClassHnd) works, that would probably be the best course of action. I'm a little bit worried about the "I can't verify that it's the "same" result as before, but it looks reasonable." but based on how I understand the JIT operates, it should be equivalent.

I tried collecting crossgen(1) build of the libraries using the current code, and the code using compScopeHnd, and the set of assembly names generated were different in the two cases. I couldn't track down the reason for the differences; maybe I should try again. It indicated to me that perhaps in some cases we were getting different answers.

@BruceForstall - well, the change in its current form is quite hacky. If the JIT interface API can be changed according to JanK's suggestion, that would be probably the best way forward and that would let me simplify the change substantially. If that change is complicated or takes time due to going through some review hoops, it may be more efficient to merge this in and just create a follow-up issue to clean this up once the interface change lands.

You'll have to decide how hacky is too hacky :-) What would an implementation on the cg2 side look like for the proposed new CORINFO_ASSEMBLY_HANDLE getClassAssembly(CORINFO_CLASS_HANDLE cls); api? It's painful to add/remove JIT/EE APIs, but if that's the way to go, I can look into it.

@trylek

Copy link
Copy Markdown
MemberAuthor

I think that the ugliest part is having to enumerate the methods (around line 1645) just to get to some MethodIL we can represent as a "module". Direct translation of class to module should be as easy as class.GetTypeDefinition().GetClosestDefType() as EcmaType ecmaType followed by extraction of the module information from the ecmaType.Module field.

Base automatically changed from master to mainMarch 1, 2021 09:08
@mangod9

Copy link
Copy Markdown
Member

@trylek@BruceForstall Is this still required?

@BruceForstall

Copy link
Copy Markdown
Contributor

@mangod9Something is still required. I don't know if it is this or an alternative suggested in this issue's comments.

@marek-safar
marek-safar marked this pull request as draft September 27, 2021 07:47
@ghostghost closed this Nov 3, 2021
@ghost

ghost commented Nov 3, 2021

Copy link
Copy Markdown

Draft Pull Request was automatically closed for inactivity. Please let us know if you'd like to reopen it.

@ghostghost locked as resolved and limited conversation to collaborators Dec 3, 2021
@trylek
trylek deleted the ModuleHelpersCG2 branch January 10, 2022 19:39
This pull request was closed.
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.

5 participants

@trylek@BruceForstall@MichalStrehovsky@mangod9@jkotas
, '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

WIP: Initial implementation of JIT assembly name helpers - #48578

Closed
trylek wants to merge 2 commits into
dotnet:mainfrom
trylek:ModuleHelpersCG2
Closed

WIP: Initial implementation of JIT assembly name helpers#48578
trylek wants to merge 2 commits into
dotnet:mainfrom
trylek:ModuleHelpersCG2

Conversation

@trylek

Copy link
Copy Markdown
Member

According to Bruce these helpers are required in order for SuperPMI to work properly.
I have stitched together a super-simple attempt at their implementations. Right now
I have no idea how to test them. I'm looking forward to any feedback you might have.

Thanks

Tomas

@dotnet/crossgen-contrib

@trylek

Copy link
Copy Markdown
MemberAuthor

Also, @MichalStrehovsky - should these changes be moved to CorInfoImpl.ReadyToRun.cs?

Comment threadsrc/coreclr/tools/Common/JitInterface/CorInfoImpl.cs Outdated
@BruceForstall

Copy link
Copy Markdown
Contributor

I can't review the implementation, but I can tell you more about what the JIT and SuperPMI is doing.

I added these calls from the JIT when we are doing a SuperPMI collection:

info.compCompHnd->getAssemblyName(info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));

The idea is that when I do a SuperPMI collection, we merge lots of function compilation data into one large file (say, all the tests, or all the assemblies in the Core_Root directory), but in doing so we lose the association of a function with an assembly. This adds that assembly name info into the per-function data that we've collected, which can be useful for JIT devs.

(This set of calls can also be used in some altjit scenarios -- those calls have been there for many years.)

The JIT doesn't call these in "normal" scenarios.

To reproduce the failure I was seeing, you can do this (change paths as necessary):

py -3 c:\gh\runtime\src\coreclr\scripts\superpmi.py collect --crossgen2 -assemblies c:\gh\runtime\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\System.Private.CoreLib.dll -output_mch_path c:\bug\lib.cg2.mch

The resulting lib.cg2.mch should be non-zero (before a fix, you'll get crashes).

You can verify there's useful data by doing this:

c:\gh\runtime\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\mcs.exe -dump 1 C:\bug\lib.cg2.mch | findstr /i getassemblyname

and seeing something like:

GetAssemblyName - 1
0-GetAssemblyName assem-000001867C2D2A50, value-4 'System.Private.CoreLib'

@BruceForstall

Copy link
Copy Markdown
Contributor

Related: #48534

@MichalStrehovsky

Copy link
Copy Markdown
Member

Also, @MichalStrehovsky - should these changes be moved to CorInfoImpl.ReadyToRun.cs?

The code looks shareable, so it's fine to keep in the shared file, even though it's unused right now.

private CORINFO_MODULE_STRUCT_* getClassModule(CORINFO_CLASS_STRUCT_* cls)
{ throw new NotImplementedException("getClassModule"); }
{
TypeDesc type = HandleToObject(cls).GetTypeDefinition();

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't come up with a better way to do this either. It's not great.

@BruceForstall looking at places that use this in JIT, they all seem to be:

constchar*methodAssemblyName=info.compCompHnd->getAssemblyName(
info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));

Could we change them to:

constchar*methodAssemblyName=info.compCompHnd->getAssemblyName(
info.compCompHnd->getModuleAssembly(info.compScopeHnd));

so that we can keep not implementing this API? Getting the module handle out of the class is not something we can do (this implementation will work for how JIT uses it, but the path is narrow). We can get modules from methods if needed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Does that work for cross-module inlining?

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.

info.compScopeHnd is the module in which the JIT resolves tokens of the method it's working on right now. So I would expect it does.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Unfortunately, when I change the code like this, crossgen(1) crashes.

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 assume it crashes because compScopeHnd is not always a module.

Can we change this method to `getClassAssembly? It should work for all cases.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@jkotas are you proposing there should be a new JIT-EE interface method

CORINFO_ASSEMBLY_HANDLE getClassAssembly(CORINFO_CLASS_HANDLE cls);

?

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.

Yes, and delete the existing getClassModule and getModuleAssembly methods since all their uses in the JIT can be replaced by getClassAssembly.

@BruceForstallBruceForstallFeb 23, 2021

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

btw, there was operator error: I replaced the case I cared about with the code @MichalStrehovsky gave above, but info.compScopeHnd wasn't yet defined. When I fix that, crossgen1 works. I can't verify that it's the "same" result as before, but it looks reasonable.

Specifically:

diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp
index a8b990d2ed0..3ce9e7fad09 100644
--- a/src/coreclr/jit/compiler.cpp
+++ b/src/coreclr/jit/compiler.cpp
@@ -5587,8 +5587,7 @@ int Compiler::compCompile(CORINFO_MODULE_HANDLE classPtr,
if (JitConfig.EnableExtraSuperPmiQueries())
{
// Get the assembly name, to aid finding any particular SuperPMI method context function
- (void)info.compCompHnd->getAssemblyName(
- info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));
+ (void)info.compCompHnd->getAssemblyName(info.compCompHnd->getModuleAssembly(classPtr));
}
#endif // DEBUG

@BruceForstall

Copy link
Copy Markdown
Contributor

@trylek What is the next step here? Are you ready to merge as-is? Do you need me to change the JIT to not call getClassModule?

@trylek

Copy link
Copy Markdown
MemberAuthor

@BruceForstall - well, the change in its current form is quite hacky. If the JIT interface API can be changed according to JanK's suggestion, that would be probably the best way forward and that would let me simplify the change substantially. If that change is complicated or takes time due to going through some review hoops, it may be more efficient to merge this in and just create a follow-up issue to clean this up once the interface change lands.

@MichalStrehovsky

Copy link
Copy Markdown
Member

If the change to use compScopeHnd instead of info.compCompHnd->getClassModule(info.compClassHnd) works, that would probably be the best course of action. I'm a little bit worried about the "I can't verify that it's the "same" result as before, but it looks reasonable." but based on how I understand the JIT operates, it should be equivalent.

@BruceForstall

Copy link
Copy Markdown
Contributor

If the change to use compScopeHnd instead of info.compCompHnd->getClassModule(info.compClassHnd) works, that would probably be the best course of action. I'm a little bit worried about the "I can't verify that it's the "same" result as before, but it looks reasonable." but based on how I understand the JIT operates, it should be equivalent.

I tried collecting crossgen(1) build of the libraries using the current code, and the code using compScopeHnd, and the set of assembly names generated were different in the two cases. I couldn't track down the reason for the differences; maybe I should try again. It indicated to me that perhaps in some cases we were getting different answers.

@BruceForstall - well, the change in its current form is quite hacky. If the JIT interface API can be changed according to JanK's suggestion, that would be probably the best way forward and that would let me simplify the change substantially. If that change is complicated or takes time due to going through some review hoops, it may be more efficient to merge this in and just create a follow-up issue to clean this up once the interface change lands.

You'll have to decide how hacky is too hacky :-) What would an implementation on the cg2 side look like for the proposed new CORINFO_ASSEMBLY_HANDLE getClassAssembly(CORINFO_CLASS_HANDLE cls); api? It's painful to add/remove JIT/EE APIs, but if that's the way to go, I can look into it.

@trylek

Copy link
Copy Markdown
MemberAuthor

I think that the ugliest part is having to enumerate the methods (around line 1645) just to get to some MethodIL we can represent as a "module". Direct translation of class to module should be as easy as class.GetTypeDefinition().GetClosestDefType() as EcmaType ecmaType followed by extraction of the module information from the ecmaType.Module field.

Base automatically changed from master to mainMarch 1, 2021 09:08
@mangod9

Copy link
Copy Markdown
Member

@trylek@BruceForstall Is this still required?

@BruceForstall

Copy link
Copy Markdown
Contributor

@mangod9Something is still required. I don't know if it is this or an alternative suggested in this issue's comments.

@marek-safar
marek-safar marked this pull request as draft September 27, 2021 07:47
@ghostghost closed this Nov 3, 2021
@ghost

ghost commented Nov 3, 2021

Copy link
Copy Markdown

Draft Pull Request was automatically closed for inactivity. Please let us know if you'd like to reopen it.

@ghostghost locked as resolved and limited conversation to collaborators Dec 3, 2021
@trylek
trylek deleted the ModuleHelpersCG2 branch January 10, 2022 19:39
This pull request was closed.
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.

5 participants

@trylek@BruceForstall@MichalStrehovsky@mangod9@jkotas
, '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

WIP: Initial implementation of JIT assembly name helpers - #48578

Closed
trylek wants to merge 2 commits into
dotnet:mainfrom
trylek:ModuleHelpersCG2
Closed

WIP: Initial implementation of JIT assembly name helpers#48578
trylek wants to merge 2 commits into
dotnet:mainfrom
trylek:ModuleHelpersCG2

Conversation

@trylek

Copy link
Copy Markdown
Member

According to Bruce these helpers are required in order for SuperPMI to work properly.
I have stitched together a super-simple attempt at their implementations. Right now
I have no idea how to test them. I'm looking forward to any feedback you might have.

Thanks

Tomas

@dotnet/crossgen-contrib

@trylek

Copy link
Copy Markdown
MemberAuthor

Also, @MichalStrehovsky - should these changes be moved to CorInfoImpl.ReadyToRun.cs?

Comment threadsrc/coreclr/tools/Common/JitInterface/CorInfoImpl.cs Outdated
@BruceForstall

Copy link
Copy Markdown
Contributor

I can't review the implementation, but I can tell you more about what the JIT and SuperPMI is doing.

I added these calls from the JIT when we are doing a SuperPMI collection:

info.compCompHnd->getAssemblyName(info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));

The idea is that when I do a SuperPMI collection, we merge lots of function compilation data into one large file (say, all the tests, or all the assemblies in the Core_Root directory), but in doing so we lose the association of a function with an assembly. This adds that assembly name info into the per-function data that we've collected, which can be useful for JIT devs.

(This set of calls can also be used in some altjit scenarios -- those calls have been there for many years.)

The JIT doesn't call these in "normal" scenarios.

To reproduce the failure I was seeing, you can do this (change paths as necessary):

py -3 c:\gh\runtime\src\coreclr\scripts\superpmi.py collect --crossgen2 -assemblies c:\gh\runtime\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\System.Private.CoreLib.dll -output_mch_path c:\bug\lib.cg2.mch

The resulting lib.cg2.mch should be non-zero (before a fix, you'll get crashes).

You can verify there's useful data by doing this:

c:\gh\runtime\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\mcs.exe -dump 1 C:\bug\lib.cg2.mch | findstr /i getassemblyname

and seeing something like:

GetAssemblyName - 1
0-GetAssemblyName assem-000001867C2D2A50, value-4 'System.Private.CoreLib'

@BruceForstall

Copy link
Copy Markdown
Contributor

Related: #48534

@MichalStrehovsky

Copy link
Copy Markdown
Member

Also, @MichalStrehovsky - should these changes be moved to CorInfoImpl.ReadyToRun.cs?

The code looks shareable, so it's fine to keep in the shared file, even though it's unused right now.

private CORINFO_MODULE_STRUCT_* getClassModule(CORINFO_CLASS_STRUCT_* cls)
{ throw new NotImplementedException("getClassModule"); }
{
TypeDesc type = HandleToObject(cls).GetTypeDefinition();

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't come up with a better way to do this either. It's not great.

@BruceForstall looking at places that use this in JIT, they all seem to be:

constchar*methodAssemblyName=info.compCompHnd->getAssemblyName(
info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));

Could we change them to:

constchar*methodAssemblyName=info.compCompHnd->getAssemblyName(
info.compCompHnd->getModuleAssembly(info.compScopeHnd));

so that we can keep not implementing this API? Getting the module handle out of the class is not something we can do (this implementation will work for how JIT uses it, but the path is narrow). We can get modules from methods if needed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Does that work for cross-module inlining?

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.

info.compScopeHnd is the module in which the JIT resolves tokens of the method it's working on right now. So I would expect it does.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Unfortunately, when I change the code like this, crossgen(1) crashes.

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 assume it crashes because compScopeHnd is not always a module.

Can we change this method to `getClassAssembly? It should work for all cases.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@jkotas are you proposing there should be a new JIT-EE interface method

CORINFO_ASSEMBLY_HANDLE getClassAssembly(CORINFO_CLASS_HANDLE cls);

?

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.

Yes, and delete the existing getClassModule and getModuleAssembly methods since all their uses in the JIT can be replaced by getClassAssembly.

@BruceForstallBruceForstallFeb 23, 2021

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

btw, there was operator error: I replaced the case I cared about with the code @MichalStrehovsky gave above, but info.compScopeHnd wasn't yet defined. When I fix that, crossgen1 works. I can't verify that it's the "same" result as before, but it looks reasonable.

Specifically:

diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp
index a8b990d2ed0..3ce9e7fad09 100644
--- a/src/coreclr/jit/compiler.cpp
+++ b/src/coreclr/jit/compiler.cpp
@@ -5587,8 +5587,7 @@ int Compiler::compCompile(CORINFO_MODULE_HANDLE classPtr,
if (JitConfig.EnableExtraSuperPmiQueries())
{
// Get the assembly name, to aid finding any particular SuperPMI method context function
- (void)info.compCompHnd->getAssemblyName(
- info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));
+ (void)info.compCompHnd->getAssemblyName(info.compCompHnd->getModuleAssembly(classPtr));
}
#endif // DEBUG

@BruceForstall

Copy link
Copy Markdown
Contributor

@trylek What is the next step here? Are you ready to merge as-is? Do you need me to change the JIT to not call getClassModule?

@trylek

Copy link
Copy Markdown
MemberAuthor

@BruceForstall - well, the change in its current form is quite hacky. If the JIT interface API can be changed according to JanK's suggestion, that would be probably the best way forward and that would let me simplify the change substantially. If that change is complicated or takes time due to going through some review hoops, it may be more efficient to merge this in and just create a follow-up issue to clean this up once the interface change lands.

@MichalStrehovsky

Copy link
Copy Markdown
Member

If the change to use compScopeHnd instead of info.compCompHnd->getClassModule(info.compClassHnd) works, that would probably be the best course of action. I'm a little bit worried about the "I can't verify that it's the "same" result as before, but it looks reasonable." but based on how I understand the JIT operates, it should be equivalent.

@BruceForstall

Copy link
Copy Markdown
Contributor

If the change to use compScopeHnd instead of info.compCompHnd->getClassModule(info.compClassHnd) works, that would probably be the best course of action. I'm a little bit worried about the "I can't verify that it's the "same" result as before, but it looks reasonable." but based on how I understand the JIT operates, it should be equivalent.

I tried collecting crossgen(1) build of the libraries using the current code, and the code using compScopeHnd, and the set of assembly names generated were different in the two cases. I couldn't track down the reason for the differences; maybe I should try again. It indicated to me that perhaps in some cases we were getting different answers.

@BruceForstall - well, the change in its current form is quite hacky. If the JIT interface API can be changed according to JanK's suggestion, that would be probably the best way forward and that would let me simplify the change substantially. If that change is complicated or takes time due to going through some review hoops, it may be more efficient to merge this in and just create a follow-up issue to clean this up once the interface change lands.

You'll have to decide how hacky is too hacky :-) What would an implementation on the cg2 side look like for the proposed new CORINFO_ASSEMBLY_HANDLE getClassAssembly(CORINFO_CLASS_HANDLE cls); api? It's painful to add/remove JIT/EE APIs, but if that's the way to go, I can look into it.

@trylek

Copy link
Copy Markdown
MemberAuthor

I think that the ugliest part is having to enumerate the methods (around line 1645) just to get to some MethodIL we can represent as a "module". Direct translation of class to module should be as easy as class.GetTypeDefinition().GetClosestDefType() as EcmaType ecmaType followed by extraction of the module information from the ecmaType.Module field.

Base automatically changed from master to mainMarch 1, 2021 09:08
@mangod9

Copy link
Copy Markdown
Member

@trylek@BruceForstall Is this still required?

@BruceForstall

Copy link
Copy Markdown
Contributor

@mangod9Something is still required. I don't know if it is this or an alternative suggested in this issue's comments.

@marek-safar
marek-safar marked this pull request as draft September 27, 2021 07:47
@ghostghost closed this Nov 3, 2021
@ghost

ghost commented Nov 3, 2021

Copy link
Copy Markdown

Draft Pull Request was automatically closed for inactivity. Please let us know if you'd like to reopen it.

@ghostghost locked as resolved and limited conversation to collaborators Dec 3, 2021
@trylek
trylek deleted the ModuleHelpersCG2 branch January 10, 2022 19:39
This pull request was closed.
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.

5 participants

@trylek@BruceForstall@MichalStrehovsky@mangod9@jkotas