Fix GC reporting for Span<T> passed in registers on Unix (dotnet/coreclr#9247)
authorKoundinya Veluri <kouvel@microsoft.com>
Wed, 1 Feb 2017 14:20:12 +0000 (06:20 -0800)
committerJan Kotas <jkotas@microsoft.com>
Wed, 1 Feb 2017 14:20:12 +0000 (06:20 -0800)
Part of fix for dotnet/coreclr#9033

Test coverage is already there in CoreFX's span tests.

Commit migrated from https://github.com/dotnet/coreclr/commit/7ced6b540e5c2fd7ed49661dc0b182d65a413949

src/coreclr/src/vm/appdomain.cpp
src/coreclr/src/vm/argdestination.h
src/coreclr/src/vm/methodtable.cpp
src/coreclr/src/vm/siginfo.cpp

index ab51eb5..8be965b 100644 (file)
@@ -2874,6 +2874,9 @@ void SystemDomain::LoadBaseSystemClasses()
 
 #ifdef FEATURE_SPAN_OF_T
     // Load ByReference class
+    //
+    // NOTE: ByReference<T> must be the first by-ref-like system type to be loaded,
+    //       because MethodTable::ClassifyEightBytesWithManagedLayout depends on it.
     g_pByReferenceClass = MscorlibBinder::GetClass(CLASS__BYREFERENCE);
 #endif
 
index e90217f..8a3fb4f 100644 (file)
@@ -201,7 +201,8 @@ public:
                     _ASSERTE(eightByteSize == 8);
                     _ASSERTE(IS_ALIGNED((SIZE_T)genRegDest, 8));
 
-                    (*fn)(dac_cast<PTR_PTR_Object>(genRegDest), sc, 0);
+                    uint32_t flags = eightByteClassification == SystemVClassificationTypeIntegerByRef ? GC_CALL_INTERIOR : 0;
+                    (*fn)(dac_cast<PTR_PTR_Object>(genRegDest), sc, flags);
                 }
 
                 genRegDest += eightByteSize;
index 52a2ce4..6fee50b 100644 (file)
@@ -2404,6 +2404,12 @@ bool MethodTable::ClassifyEightBytesWithManagedLayout(SystemVStructRegisterPassi
     FieldDesc *pField = GetApproxFieldDescListRaw();
     FieldDesc *pFieldEnd = pField + numIntroducedFields;
 
+    // System types are loaded before others, so ByReference<T> would be loaded before Span<T> or any other type that has a
+    // ByReference<T> field. ByReference<T> is the first by-ref-like system type to be loaded (see
+    // SystemDomain::LoadBaseSystemClasses), so if the current method table is marked as by-ref-like and g_pByReferenceClass is
+    // null, it must be the initial load of ByReference<T>.
+    bool isThisByReferenceOfT = IsByRefLike() && (g_pByReferenceClass == nullptr || HasSameTypeDefAs(g_pByReferenceClass));
+
     for (; pField < pFieldEnd; pField++)
     {
 #ifdef _DEBUG
@@ -2425,7 +2431,19 @@ bool MethodTable::ClassifyEightBytesWithManagedLayout(SystemVStructRegisterPassi
 
         CorElementType fieldType = pField->GetFieldType();
 
-        SystemVClassificationType fieldClassificationType = CorInfoType2UnixAmd64Classification(fieldType);
+        SystemVClassificationType fieldClassificationType;
+        if (isThisByReferenceOfT)
+        {
+            // ByReference<T> is a special type whose single IntPtr field holds a by-ref potentially interior pointer to GC
+            // memory, so classify its field as such
+            _ASSERTE(numIntroducedFields == 1);
+            _ASSERTE(fieldType == CorElementType::ELEMENT_TYPE_I);
+            fieldClassificationType = SystemVClassificationTypeIntegerByRef;
+        }
+        else
+        {
+            fieldClassificationType = CorInfoType2UnixAmd64Classification(fieldType);
+        }
 
 #ifdef _DEBUG
         LPCUTF8 fieldName;
index 2c2c4f4..b9955ec 100644 (file)
@@ -5028,20 +5028,18 @@ void ReportPointersFromValueTypeArg(promote_func *fn, ScanContext *sc, PTR_Metho
 {
     WRAPPER_NO_CONTRACT;
 
-    if(pMT->ContainsPointers())
+    if (!pMT->ContainsPointers() && !pMT->IsByRefLike())
     {
-#if defined(UNIX_AMD64_ABI) && defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)    
-        if (pSrc->IsStructPassedInRegs())
-        {
-            pSrc->ReportPointersFromStructInRegisters(fn, sc, pMT->GetNumInstanceFieldBytes());
-            return;
-        }
-#endif // UNIX_AMD64_ABI && FEATURE_UNIX_AMD64_STRUCT_PASSING
+        return;
     }
-    else if (!pMT->IsByRefLike())
+
+#if defined(UNIX_AMD64_ABI) && defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)    
+    if (pSrc->IsStructPassedInRegs())
     {
+        pSrc->ReportPointersFromStructInRegisters(fn, sc, pMT->GetNumInstanceFieldBytes());
         return;
     }
+#endif // UNIX_AMD64_ABI && FEATURE_UNIX_AMD64_STRUCT_PASSING
 
     ReportPointersFromValueType(fn, sc, pMT, pSrc->GetDestinationAddress());
 }