Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make JIT<->EE printing methods consistent and support nested classes when printing class names #76505

Merged
merged 53 commits into from
Nov 20, 2022

Conversation

jakobbotsch
Copy link
Member

@jakobbotsch jakobbotsch commented Oct 2, 2022

  • Switch appendClassName/getClassName, getFieldName and getMethodName into respectively printClassName, printFieldName and printMethodName that all are consistent with printObjectDescription in buffer handling, and all use UTF8
  • Change printClassName to support nested classes, fixing the handling of these in the JIT (in particular for method sets)
  • Factor handling in SPMI/ILC/crossgen2 for these methods now that they are consistent
  • Add a JitTypeNameFormatter.cs for crossgen2/ILC that does exactly what printClassName needs to be consistent with the VM
  • Remove concept of "native" CORINFO_METHOD_HANDLE (eeMarkNativeTarget and co.). This was unused before.
  • Remove CEEInfo::getHelperName. We were keeping a list of this in the JIT anyway under FEATURE_SIMD, which is defined practically everywhere.
  • Remove includeNamespaces in JIT printing that was always passed as true
  • Change the hackishX names on missing SPMI data into <unknown X> instead, e.g. <unknown method>

The change does complicate the JIT side slightly since the JIT owns all the buffers now. I have added a buffer argument to the various JIT helper methods (e.g. eeGetFieldName) that ensures we don't unnecessarily allocate memory in common short cases when printing these, so there are a few additional parameters passed, but in general I don't think it looks too bad. In a few recursive functions I have introduced a small lambda to avoid bloating the frame size by a lot (assuming it doesn't just get inlined).
I personally prefer the consistency and flexibility over the slight increase in complexity.

* Switch JIT to use appendClassName instead of getClassNameFromMetadata.
  This way it supports enclosing classes too when printing class names.
* Switch appendClassName to UTF8
* Switch SIMD type recognition to use getTypeInstantiationArgument and
  getClassNameFromMetadata, to use of appendClassName (and depending on
  how it formats instantiations)
* Add TypeString::FormatNoInst to avoid formatting instantiations, and
  use this for appendClassName
* Remove getClassName from JIT-EE interface
* Remove TypeString.cs in favor of JitTypeNameFormatter that does
  exactly what we need
* Bump JIT-EE GUID
@dotnet-issue-labeler dotnet-issue-labeler bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Oct 2, 2022
@ghost ghost assigned jakobbotsch Oct 2, 2022
@ghost
Copy link

ghost commented Oct 2, 2022

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

Issue Details
  • Switch JIT to use appendClassName instead of getClassNameFromMetadata.
    This way it supports enclosing classes too when printing class names.
  • Switch appendClassName to UTF8
  • Switch SIMD type recognition to use getTypeInstantiationArgument and
    getClassNameFromMetadata, to avoid use of appendClassName (and depending on
    how it formats instantiations)
  • Add TypeString::FormatNoInst to avoid formatting instantiations, and
    use this for appendClassName
  • Remove getClassName, it is unused now
  • Remove TypeString.cs in crossgen2/ILC in favor of a new JitTypeNameFormatter.cs that does exactly what appendClassName needs
Author: jakobbotsch
Assignees: -
Labels:

area-CodeGen-coreclr

Milestone: -

{
size = getSIMDVectorRegisterByteLength();
CORINFO_CLASS_HANDLE typeArgHnd = info.compCompHnd->getTypeInstantiationArgument(typeHnd, 0);
simdBaseJitType = info.compCompHnd->asCorInfoType(typeArgHnd);
Copy link
Contributor

Choose a reason for hiding this comment

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

asCorInfoType

Will the case of Vector<MyEnum> be rejected properly?

Copy link
Member Author

Choose a reason for hiding this comment

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

I probably need getTypeForPrimitiveNumericClass instead.

Copy link
Member Author

Choose a reason for hiding this comment

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

In fact, I can see that the code below for hw intrinsics is doing exactly this but with getTypeForPrimitiveNumericClass, so looks like that's definitely the way to go.

Apparently caller expects the size to be right even for unsupported
SIMD types.
@jakobbotsch jakobbotsch changed the title Clean up JIT<->EE "get class name" methods, support nested classes in JitDisasm Clean up JIT<->EE "get class name" methods, support nested classes in method sets Oct 2, 2022
@jkotas
Copy link
Member

jkotas commented Oct 3, 2022

Test failing with:

Assert failure(PID 4100 [0x00001004], Thread: 14536 [0x38c8]): Assertion failed 'sizeBytes == 0' in 'JIT.HardwareIntrinsics.Arm.LoadPairScalarVector64_Int32:RunBasicScenario():this' during 'Importation' (IL size 78; hash 0x426d4f3e; FullOpts)

@jakobbotsch
Copy link
Member Author

Yep, I'm looking into it. The other failure looks like #48798.

@jakobbotsch
Copy link
Member Author

It's very odd that my PR has failed twice with the #48798 symptom now, and that issue has no other failures. I'll try to see if I can repro this tomorrow.

* Avoid multiple calls into EE in common case of short strings
* Remove StringPrinter::AllocToPrint complexity in face of above
* Optimize appendClassName on EE side with inlined implementation of
  what we need from TypeString that avoids multiple roundtrips in and
  out of UTF8. Also copy resulting string directly into final buffer.
* Revert TypeString::FormatNoInst
@jakobbotsch jakobbotsch marked this pull request as ready for review November 14, 2022 16:50

printf("// ProcessName - '%s'\n", mc->cr->repProcessName());
printf(".assembly extern mscorlib{}\n");
printf(".assembly %s{}\n", moduleName);
printf(".assembly dumped_asm\n");
Copy link
Member Author

Choose a reason for hiding this comment

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

This "scope name" was not actually the module name.

vfprintf(jitstdout, fmt, vl);
va_end(vl);
}
#endif
Copy link
Member Author

Choose a reason for hiding this comment

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

This was part of a #else of some #ifdef I ended up removing, so I've moved it here.

Comment on lines +198 to +202
static const char* s_jitHelperNames[CORINFO_HELP_COUNT] = {
#define JITHELPER(code, pfnHelper, sig) #code,
#define DYNAMICJITHELPER(code, pfnHelper, sig) #code,
#include "jithelpers.h"
};
Copy link
Member Author

Choose a reason for hiding this comment

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

This was defined in ee_il_dll.cpp before. I've moved most of this printing into eeinterface.cpp.
It was also conditionally defined, but one of the conditions was FEATURE_SIMD which is included for most of our targets (I think arm32 is the big exception). It seems reasonable to me to have the table unconditionally and remove the JIT-EE function.

Comment on lines +11940 to +11944
auto disp = [&]() {
char buffer[256];
printf(" %s", eeGetFieldName(tree->AsField()->gtFldHnd, true, buffer, sizeof(buffer)));
};
disp();
Copy link
Member Author

Choose a reason for hiding this comment

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

Just avoiding bloating the stack frame here, since gtDispTree is recursive (well, it is left up to the C++ compiler's inlining).

Comment on lines -3625 to -3626
assert(!strcmp(info.compCompHnd->getFieldName(hasValueFldHnd, nullptr),
"hasValue"));
Copy link
Member Author

Choose a reason for hiding this comment

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

We could print this (or better yet, introduce getFieldNameFromMetadata), but I don't think it's worth the effort to have the assert.

@jakobbotsch
Copy link
Member Author

cc @dotnet/jit-contrib for the JIT/SPMI parts, @jkotas for the other parts

I'm going to wait with merging this until one of the other JIT-EE changes in the pipeline go in this week.

Copy link
Member

@jkotas jkotas left a comment

Choose a reason for hiding this comment

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

VM/AOT parts LGTM

@@ -2282,7 +2282,7 @@ class ICorStaticInfo
// from that first attempt was not big enough.
//
// Return Value:
// Bytes written to the given buffer, the range is [0..bufferSize)
// Bytes written to the given buffer excluding the null terminator. The range is [0..bufferSize).
Copy link
Member

Choose a reason for hiding this comment

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

It would be useful to note in the comment above that bufferSize is in bytes, and *pRequiredBufferSize is in bytes (if pRequiredBufferSize is non-nullptr).

Can buffer be nullptr if bufferSize == 0? This would be the one case where buffer can't be null terminated, of course, and where the documented return value range [0..0) makes no sense.

Can *pRequiredBufferSize == 0? Since it needs to include space for a null terminator, I presume it needs to be at least 1.

Can *pRequiredBufferSize == 1? That is, only a null terminator, and no text?

If bufferSize > 0, and the return value is < bufferSize - 1, are we guaranteed that the entire string is written (i.e., there is no truncation)? Does this imply return value == *pRequiredBufferSize - 1? It would be useful to document these conditions.

What happens if handle is illegal? Crash? Null-terminated buffer (if bufferSize > 0)?

Presumably you can do:

size_t actualSize;
size_t sz = printObjectDescription(h, nullptr, 0, &actualSize);
assert(sz == 0);
assert(actualSize > 0);
char* buffer = new char[actualSize];
sz = printObjectDescription(h, buffer, actualSize, &actualSize);
assert(sz == actualSize - 1);

Copy link
Member Author

Choose a reason for hiding this comment

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

Can you please take a look at the extra docs I've added in the latest commits?

src/coreclr/tools/superpmi/superpmi-shared/asmdumper.cpp Outdated Show resolved Hide resolved
src/coreclr/jit/eeinterface.cpp Outdated Show resolved Hide resolved
@ghost ghost added needs-author-action An issue or pull request that requires more info or actions from the author. and removed needs-author-action An issue or pull request that requires more info or actions from the author. labels Nov 15, 2022
Copy link
Member

@BruceForstall BruceForstall left a comment

Choose a reason for hiding this comment

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

LGTM

@jakobbotsch jakobbotsch merged commit df00d19 into dotnet:main Nov 20, 2022
@jakobbotsch jakobbotsch deleted the print-nested-classes branch November 20, 2022 12:28
@ghost ghost locked as resolved and limited conversation to collaborators Dec 20, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants