From 1a67e84aca889cf94c716a7847cfe0b4d1ee62d6 Mon Sep 17 00:00:00 2001 From: Koundinya Veluri Date: Mon, 6 Nov 2017 14:28:41 -0800 Subject: Fix GC reporting for slow tail call arguments of type `Span` (#14826) Fix GC reporting for slow tail call arguments of type `Span` Fixes https://github.com/dotnet/coreclr/issues/9032: - Refactored by-ref-like method table walking to find offsets of by-ref pointers in siginfo.hpp/cpp - Reused that for appending GC layout when creating the copy-args helper for a slow tail call --- src/vm/i386/stublinkerx86.cpp | 11 +++++++++++ src/vm/object.inl | 37 ++++++++++++++++++++++++++++++++++ src/vm/siginfo.cpp | 46 ++++++++----------------------------------- src/vm/siginfo.hpp | 1 - 4 files changed, 56 insertions(+), 39 deletions(-) (limited to 'src/vm') diff --git a/src/vm/i386/stublinkerx86.cpp b/src/vm/i386/stublinkerx86.cpp index e07b6e1c37..14b9701a29 100644 --- a/src/vm/i386/stublinkerx86.cpp +++ b/src/vm/i386/stublinkerx86.cpp @@ -5925,6 +5925,17 @@ static void AppendGCLayout(ULONGARRAY &gcLayout, size_t baseOffset, BOOL fIsType _ASSERTE(pMT); _ASSERTE(pMT->IsValueType()); + if (pMT->IsByRefLike()) + { + FindByRefPointerOffsetsInByRefLikeObject( + pMT, + baseOffset, + [&](size_t pointerOffset) + { + *gcLayout.AppendThrowing() = (ULONG)(pointerOffset | 1); // "| 1" to mark it as an interior pointer + }); + } + // walk the GC descriptors, reporting the correct offsets if (pMT->ContainsPointers()) { diff --git a/src/vm/object.inl b/src/vm/object.inl index 5dc3d6d116..495f7bff71 100644 --- a/src/vm/object.inl +++ b/src/vm/object.inl @@ -325,4 +325,41 @@ inline TypeHandle Object::GetGCSafeTypeHandle() const return TypeHandle(pMT); } +template +inline void FindByRefPointerOffsetsInByRefLikeObject(PTR_MethodTable pMT, SIZE_T baseOffset, const F processPointerOffset) +{ + WRAPPER_NO_CONTRACT; + _ASSERTE(pMT != nullptr); + _ASSERTE(pMT->IsByRefLike()); + + // TODO: TypedReference should ideally be implemented as a by-ref-like struct containing a ByReference field, + // in which case the check for g_TypedReferenceMT below would not be necessary + if (pMT == g_TypedReferenceMT || pMT->HasSameTypeDefAs(g_pByReferenceClass)) + { + processPointerOffset(baseOffset); + return; + } + + ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS); + for (FieldDesc *pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next()) + { + if (pFD->GetFieldType() != ELEMENT_TYPE_VALUETYPE) + { + continue; + } + + // TODO: GetApproxFieldTypeHandleThrowing may throw. This is a potential stress problem for fragile NGen of non-CoreLib + // assemblies. It won't ever throw for CoreCLR with R2R. Figure out if anything needs to be done to deal with the + // exception. + PTR_MethodTable pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable(); + if (!pFieldMT->IsByRefLike()) + { + continue; + } + + SIZE_T fieldStartIndex = pFD->GetOffset() / sizeof(void *); + FindByRefPointerOffsetsInByRefLikeObject(pFieldMT, baseOffset + fieldStartIndex, processPointerOffset); + } +} + #endif // _OBJECT_INL_ diff --git a/src/vm/siginfo.cpp b/src/vm/siginfo.cpp index be919c8b7e..bc16bdffda 100644 --- a/src/vm/siginfo.cpp +++ b/src/vm/siginfo.cpp @@ -4946,50 +4946,20 @@ void PromoteCarefully(promote_func fn, (*fn) (ppObj, sc, flags); } -void ReportByRefPointersFromByRefLikeObject(promote_func *fn, ScanContext *sc, PTR_MethodTable pMT, PTR_VOID pSrc) -{ - WRAPPER_NO_CONTRACT; - - _ASSERTE(pMT->IsByRefLike()); - - // TODO: TypedReference should ideally be implemented as a by-ref-like struct containing a ByReference field, - // in which case the check for g_TypedReferenceMT below would not be necessary - if (pMT == g_TypedReferenceMT || pMT->HasSameTypeDefAs(g_pByReferenceClass)) - { - (*fn)(dac_cast(pSrc), sc, GC_CALL_INTERIOR); - return; - } - - ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS); - for (FieldDesc *pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next()) - { - if (pFD->GetFieldType() != ELEMENT_TYPE_VALUETYPE) - { - continue; - } - - // TODO: GetApproxFieldTypeHandleThrowing may throw. This is a potential stress problem for fragile NGen of non-CoreLib - // assemblies. It won't ever throw for CoreCLR with R2R. Figure out if anything needs to be done to deal with the - // exception. - PTR_MethodTable pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable(); - if (!pFieldMT->IsByRefLike()) - { - continue; - } - - int fieldStartIndex = pFD->GetOffset() / sizeof(void *); - PTR_PTR_Object fieldRef = dac_cast(PTR_BYTE(pSrc) + fieldStartIndex); - ReportByRefPointersFromByRefLikeObject(fn, sc, pFieldMT, fieldRef); - } -} - void ReportPointersFromValueType(promote_func *fn, ScanContext *sc, PTR_MethodTable pMT, PTR_VOID pSrc) { WRAPPER_NO_CONTRACT; if (pMT->IsByRefLike()) { - ReportByRefPointersFromByRefLikeObject(fn, sc, pMT, pSrc); + FindByRefPointerOffsetsInByRefLikeObject( + pMT, + 0 /* baseOffset */, + [&](SIZE_T pointerOffset) + { + PTR_PTR_Object fieldRef = dac_cast(PTR_BYTE(pSrc) + pointerOffset); + (*fn)(fieldRef, sc, GC_CALL_INTERIOR); + }); } if (!pMT->ContainsPointers()) diff --git a/src/vm/siginfo.hpp b/src/vm/siginfo.hpp index 52b05928db..4cfa548270 100644 --- a/src/vm/siginfo.hpp +++ b/src/vm/siginfo.hpp @@ -1191,4 +1191,3 @@ BOOL IsTypeDefExternallyVisible(mdToken tk, Module *pModule, DWORD dwAttrs); void ReportPointersFromValueType(promote_func *fn, ScanContext *sc, PTR_MethodTable pMT, PTR_VOID pSrc); #endif /* _H_SIGINFO */ - -- cgit v1.2.3