-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
JIT: enhance escape analysis to understand local struct fields #113141
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -414,18 +414,80 @@ ClassLayout* Compiler::typGetBlkLayout(unsigned blockSize) | |
return typGetCustomLayout(ClassLayoutBuilder(this, blockSize)); | ||
} | ||
|
||
unsigned Compiler::typGetArrayLayoutNum(CORINFO_CLASS_HANDLE classHandle, unsigned length) | ||
ClassLayout* Compiler::typGetArrayLayout(CORINFO_CLASS_HANDLE classHandle, unsigned length) | ||
{ | ||
ClassLayoutBuilder b = ClassLayoutBuilder::BuildArray(this, classHandle, length); | ||
return typGetCustomLayoutNum(b); | ||
return typGetCustomLayout(b); | ||
} | ||
|
||
ClassLayout* Compiler::typGetArrayLayout(CORINFO_CLASS_HANDLE classHandle, unsigned length) | ||
ClassLayout* Compiler::typGetNonGCLayout(ClassLayout* layout) | ||
{ | ||
ClassLayoutBuilder b = ClassLayoutBuilder::BuildArray(this, classHandle, length); | ||
assert(layout->HasGCPtr()); | ||
ClassLayoutBuilder b(this, layout->GetSize()); | ||
b.CopyPaddingFrom(0, layout); | ||
|
||
#ifdef DEBUG | ||
b.CopyNameFrom(layout, "[nongc] "); | ||
#endif | ||
|
||
return typGetCustomLayout(b); | ||
} | ||
|
||
ClassLayout* Compiler::typGetByrefLayout(ClassLayout* layout) | ||
{ | ||
assert(layout->HasGCPtr()); | ||
ClassLayoutBuilder b(this, layout->GetSize()); | ||
b.CopyPaddingFrom(0, layout); | ||
b.CopyGCInfoFromMakeByref(0, layout); | ||
|
||
#ifdef DEBUG | ||
b.CopyNameFrom(layout, "[byref] "); | ||
#endif | ||
|
||
return typGetCustomLayout(b); | ||
} | ||
|
||
#ifdef DEBUG | ||
//------------------------------------------------------------------------ | ||
// CopyNameFrom: Copy layout names, with optional prefix. | ||
// | ||
// Parameters: | ||
// layout - layout to copy from | ||
// prefix - prefix to add (or nullptr) | ||
// | ||
void ClassLayoutBuilder::CopyNameFrom(ClassLayout* layout, const char* prefix) | ||
{ | ||
const char* layoutName = layout->GetClassName(); | ||
const char* layoutShortName = layout->GetShortClassName(); | ||
|
||
if (prefix != nullptr) | ||
{ | ||
char* newName = nullptr; | ||
char* newShortName = nullptr; | ||
|
||
if (layoutName != nullptr) | ||
{ | ||
size_t len = strlen(prefix) + strlen(layoutName) + 1; | ||
newName = m_compiler->getAllocator(CMK_DebugOnly).allocate<char>(len); | ||
sprintf_s(newName, len, "%s%s", prefix, layoutShortName); | ||
} | ||
|
||
if (layoutShortName != nullptr) | ||
{ | ||
size_t len = strlen(prefix) + strlen(layoutName) + 1; | ||
newShortName = m_compiler->getAllocator(CMK_DebugOnly).allocate<char>(len); | ||
sprintf_s(newShortName, len, "%s%s", prefix, layoutShortName); | ||
} | ||
|
||
SetName(newName, newShortName); | ||
} | ||
else | ||
{ | ||
SetName(layoutName, layoutShortName); | ||
} | ||
Comment on lines
+463
to
+487
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can use |
||
} | ||
#endif // DEBUG | ||
|
||
//------------------------------------------------------------------------ | ||
// Create: Create a ClassLayout from an EE side class handle. | ||
// | ||
|
@@ -646,8 +708,8 @@ const SegmentList& ClassLayout::GetNonPadding(Compiler* comp) | |
// AreCompatible: check if 2 layouts are the same for copying. | ||
// | ||
// Arguments: | ||
// layout1 - the first layout; | ||
// layout2 - the second layout. | ||
// layout1 - the first layout (copy destination) | ||
// layout2 - the second layout (copy source) | ||
// | ||
// Return value: | ||
// true if compatible, false otherwise. | ||
|
@@ -706,8 +768,8 @@ bool ClassLayout::AreCompatible(const ClassLayout* layout1, const ClassLayout* l | |
return true; | ||
} | ||
|
||
assert(clsHnd1 != NO_CLASS_HANDLE); | ||
assert(clsHnd2 != NO_CLASS_HANDLE); | ||
// assert(clsHnd1 != NO_CLASS_HANDLE); | ||
// assert(clsHnd2 != NO_CLASS_HANDLE); | ||
assert(layout1->HasGCPtr() && layout2->HasGCPtr()); | ||
|
||
if (layout1->GetGCPtrCount() != layout2->GetGCPtrCount()) | ||
|
@@ -722,6 +784,13 @@ bool ClassLayout::AreCompatible(const ClassLayout* layout1, const ClassLayout* l | |
{ | ||
if (layout1->GetGCPtrType(i) != layout2->GetGCPtrType(i)) | ||
{ | ||
// Allow a source GC_REF to match a custom GC_BYREF | ||
// | ||
if ((layout2->GetGCPtrType(i) == TYP_REF) && (layout1->GetGCPtrType(i) == TYP_BYREF) && | ||
layout1->IsCustomLayout()) | ||
{ | ||
continue; | ||
} | ||
Comment on lines
+787
to
+793
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changing the definition of layout compatibility seems quite questionable to me. Why is it necessary? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was tempted to retain the class handle in new layout, but didn't. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note allowing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So are you saying that for the object aObj = ...; // doesn't escape
object bObj = ...; // escapes
aObj = bObj; case, today we will produce a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, we will retype This has been there since forever. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, it makes it somewhat more palatable. But it seems like we need to separate the notions of "user facing" layout compatibility, as used by e.g. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm open to suggestions on how to express this better. Perhaps the presence of a custom layout for the dest might be enough? We could get here with custom layouts on both sides:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would just suggest to rename this to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (Maybe |
||
return false; | ||
} | ||
} | ||
|
@@ -791,7 +860,7 @@ ClassLayoutBuilder ClassLayoutBuilder::BuildArray(Compiler* compiler, CORINFO_CL | |
unsigned offset = OFFSETOF__CORINFO_Array__data; | ||
for (unsigned i = 0; i < length; i++) | ||
{ | ||
builder.CopyInfoFrom(offset, elementLayout, /* copy padding */ false); | ||
builder.CopyGCInfoFrom(offset, elementLayout); | ||
offset += elementSize; | ||
} | ||
} | ||
|
@@ -896,14 +965,13 @@ void ClassLayoutBuilder::SetGCPtrType(unsigned slot, var_types type) | |
} | ||
|
||
//------------------------------------------------------------------------ | ||
// CopyInfoFrom: Copy GC pointers and padding information from another layout. | ||
// CopyInfoGCFrom: Copy GC pointers from another layout. | ||
// | ||
// Arguments: | ||
// offset - Offset in this builder to start copy information into. | ||
// layout - Layout to get information from. | ||
// copyPadding - Whether padding info should also be copied from the layout. | ||
// | ||
void ClassLayoutBuilder::CopyInfoFrom(unsigned offset, ClassLayout* layout, bool copyPadding) | ||
void ClassLayoutBuilder::CopyGCInfoFrom(unsigned offset, ClassLayout* layout) | ||
{ | ||
assert(offset + layout->GetSize() <= m_size); | ||
|
||
|
@@ -916,18 +984,53 @@ void ClassLayoutBuilder::CopyInfoFrom(unsigned offset, ClassLayout* layout, bool | |
SetGCPtr(startSlot + slot, layout->GetGCPtr(slot)); | ||
} | ||
} | ||
} | ||
|
||
if (copyPadding) | ||
{ | ||
AddPadding(SegmentList::Segment(offset, offset + layout->GetSize())); | ||
//------------------------------------------------------------------------ | ||
// CopyInfoGCFromMakeByref: Copy GC pointers from another layout,and change | ||
// all gc references to be TYP_BYREF (TYPE_GC_BYREF) | ||
// | ||
// Arguments: | ||
// offset - Offset in this builder to start copy information into. | ||
// layout - Layout to get information from. | ||
// | ||
void ClassLayoutBuilder::CopyGCInfoFromMakeByref(unsigned offset, ClassLayout* layout) | ||
{ | ||
assert(offset + layout->GetSize() <= m_size); | ||
|
||
for (const SegmentList::Segment& nonPadding : layout->GetNonPadding(m_compiler)) | ||
if (layout->GetGCPtrCount() > 0) | ||
{ | ||
assert(offset % TARGET_POINTER_SIZE == 0); | ||
unsigned startSlot = offset / TARGET_POINTER_SIZE; | ||
for (unsigned slot = 0; slot < layout->GetSlotCount(); slot++) | ||
{ | ||
RemovePadding(SegmentList::Segment(offset + nonPadding.Start, offset + nonPadding.End)); | ||
CorInfoGCType gcType = layout->GetGCPtr(slot); | ||
if (gcType == TYPE_GC_REF) | ||
{ | ||
gcType = TYPE_GC_BYREF; | ||
} | ||
SetGCPtr(startSlot + slot, gcType); | ||
} | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This code feels very object stack allocation specific. Put it in objectalloc.cpp? |
||
|
||
//------------------------------------------------------------------------ | ||
// CopyInfoPaddingFrom: Copy padding from another layout. | ||
// | ||
// Arguments: | ||
// offset - Offset in this builder to start copy information into. | ||
// layout - Layout to get information from. | ||
// | ||
void ClassLayoutBuilder::CopyPaddingFrom(unsigned offset, ClassLayout* layout) | ||
{ | ||
AddPadding(SegmentList::Segment(offset, offset + layout->GetSize())); | ||
|
||
for (const SegmentList::Segment& nonPadding : layout->GetNonPadding(m_compiler)) | ||
{ | ||
RemovePadding(SegmentList::Segment(offset + nonPadding.Start, offset + nonPadding.End)); | ||
} | ||
} | ||
|
||
//------------------------------------------------------------------------ | ||
// GetOrCreateNonPadding: Get the non padding segment list, or create it if it | ||
// does not exist. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels like something that only stack allocation is ever going to use, so it would make more sense to me to keep it in objectalloc.h/cpp.