-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Report by-ref-like types to the GC (SpanOfT) #9034
Conversation
Fixes #8517
|
||
_ASSERTE(pMT->IsByRefLike()); | ||
|
||
if (pMT == g_TypedReferenceMT) |
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 should do the same thing as g_pByReferenceClass
:
if (pMT->HasSameTypeDefAs(g_pByReferenceClass) || pMT == g_TypedReferenceMT)
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.
I don't understand, could you please elaborate?
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.
Once the rules for byref-like type in C# compiler are relaxed, it should be possible to write:
struct MyStruct
{
TypedReference field1;
Span<byte> field2;
TypedReference field3;
}
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.
field1
and field3
won't be reported correctly because of the early out.
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.
CEEInfo::getClassGClayout
has the same bug
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.
It looks to me like CEEInfo::getClassGClayout
would only return early if the topmost object is a TypedReference
, which seems acceptable. If a by-ref-like object contains a TypedReference
as in your example, it would call ComputeGCLayout
, which would iterate over all fields in the by-ref-like type. I'm not seeing an issue there either.
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.
The first field of TypedReference is actually byref, but it is not recorded as byref in metadata. It has been special cased for GC reporting in multiple places. This is yet another places that should be special cased for it.
Ideally, we would change the implementation of TypedReference to:
struct TypedReference
{
ByReference<byte> _value;
IntPtr _type;
...
}
and get rid of the special casing. But until/if that happens, we should continue special casing it.
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.
If TypedReference
is not recorded as byref, then it seems to me like it would have already had an issue before this change - it seems then that TypedRefernece
would not have been reported properly to the GC. Are you suggesting that there is an issue with the reporting for TypedReference
as well? If so, I'll need to test with TypedReference
as well to see the problem before fixing it.
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.
The TypedReference has not been allowed as a field and so there is no problem today. They have been only allowed as regular arguments. We should not come for regular TypedReference arguments at all because of they are special cased above ReportPointersFromValueType.
Since you have added the special case for TypedReference here, I thought you want to prepare this code for case where TypedReference are allowed as fields of other byref-like types. There is a good chance that TypedReferences are going to be allowed as fields as natural fallout from the relaxations of rules for byref-like types in C#.
Either of these two options would sound reasonable to me:
- Do not prepare this for TypedReference fields - do not handle TypedReference at all here
- Prepare this for TypedReference fields - handle TypedReference same way as
ByReference<T>
here
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.
Ok how does 797ec39 look? I kept the check considering TypedReference is currently not implemented the way in which you suggest, but the new code treats it similarly to ByReferece in the sense the first field of both is the pointer, which should conform to the way in which TypedReference is currently implemented.
if (!pMT->ContainsPointers()) | ||
return; | ||
|
||
if(pMT->ContainsPointers()) |
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.
Why can't this be just
if (!pMT->ContainsPointers() && !pMT->IsByRefLike())
return;
... existing code...
?
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.
(I would be useful to add some comments if it needs to be what you have written.)
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.
As I currently do not have a complete understanding of GC holes with respect to Unix and structs passed in registers, I'm conservatively preserving the previous behavior by calling ReportPointersFromStructInRegisters
only under the previous conditions. #9033 is intended to track potential issues on Unix, a fix for which should hopefully resolve the question.
ba18db1
to
797ec39
Compare
|
||
_ASSERTE(pMT->IsByRefLike()); | ||
|
||
// TODO: TypedReference should ideally be implemneted as a by-ref-like struct containing a ByReference<T> field, |
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.
Nit: typo implemneted
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.
Fixed
It would be nice to make a matching change in
|
LGTM otherwise. Thanks! |
It looks like
I don't see where this array is initialized to some default value, so I have omitted this part as well. Simplified to: if (pMT == g_TypedReferenceMT)
{
gcPtrs[0] = TYPE_GC_BYREF;
gcPtrs[1] = TYPE_GC_NONE;
return 1;
} And added the comment to |
@dotnet-bot test this please |
1 similar comment
@dotnet-bot test this please |
Report by-ref-like types to the GC (SpanOfT) Fixes dotnet/coreclr#8517 Commit migrated from dotnet/coreclr@62ac5f0
Fixes #8517