Report by-ref-like types to the GC (SpanOfT) (#9034)
authorKoundinya Veluri <kouvel@microsoft.com>
Mon, 23 Jan 2017 07:10:14 +0000 (23:10 -0800)
committerGitHub <noreply@github.com>
Mon, 23 Jan 2017 07:10:14 +0000 (23:10 -0800)
Report by-ref-like types to the GC (SpanOfT)

Fixes #8517

src/vm/jitinterface.cpp
src/vm/siginfo.cpp

index ee22e72..75a228f 100644 (file)
@@ -2294,6 +2294,15 @@ static unsigned ComputeGCLayout(MethodTable * pMT, BYTE* gcPtrs)
 
     _ASSERTE(pMT->IsValueType());
 
+    // TODO: TypedReference should ideally be implemented as a by-ref-like struct containing a ByReference<T> field, in which
+    // case the check for g_TypedReferenceMT below would not be necessary
+    if (pMT == g_TypedReferenceMT)
+    {
+        gcPtrs[0] = TYPE_GC_BYREF;
+        gcPtrs[1] = TYPE_GC_NONE;
+        return 1;
+    }
+
     ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
     for (FieldDesc *pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
     {
@@ -2357,6 +2366,8 @@ unsigned CEEInfo::getClassGClayout (CORINFO_CLASS_HANDLE clsHnd, BYTE* gcPtrs)
 
     if (pMT->IsByRefLike())
     {
+        // TODO: TypedReference should ideally be implemented as a by-ref-like struct containing a ByReference<T> field, in
+        // which case the check for g_TypedReferenceMT below would not be necessary
         if (pMT == g_TypedReferenceMT)
         {
             gcPtrs[0] = TYPE_GC_BYREF;
index 12803ec..2c2c4f4 100644 (file)
@@ -4953,11 +4953,51 @@ 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<T> 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<PTR_PTR_Object>(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\92t 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_PTR_Object>(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;
 
-    // SPAN-TODO: GC reporting - https://github.com/dotnet/coreclr/issues/8517
+    if (pMT->IsByRefLike())
+    {
+        ReportByRefPointersFromByRefLikeObject(fn, sc, pMT, pSrc);
+    }
 
     if (!pMT->ContainsPointers())
         return;
@@ -4987,16 +5027,21 @@ void ReportPointersFromValueType(promote_func *fn, ScanContext *sc, PTR_MethodTa
 void ReportPointersFromValueTypeArg(promote_func *fn, ScanContext *sc, PTR_MethodTable pMT, ArgDestination *pSrc)
 {
     WRAPPER_NO_CONTRACT;
-    
-    if (!pMT->ContainsPointers())
-        return;
+
+    if(pMT->ContainsPointers())
+    {
 #if defined(UNIX_AMD64_ABI) && defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)    
-    if (pSrc->IsStructPassedInRegs())
+        if (pSrc->IsStructPassedInRegs())
+        {
+            pSrc->ReportPointersFromStructInRegisters(fn, sc, pMT->GetNumInstanceFieldBytes());
+            return;
+        }
+#endif // UNIX_AMD64_ABI && FEATURE_UNIX_AMD64_STRUCT_PASSING
+    }
+    else if (!pMT->IsByRefLike())
     {
-        pSrc->ReportPointersFromStructInRegisters(fn, sc, pMT->GetNumInstanceFieldBytes());
         return;
     }
-#endif // UNIX_AMD64_ABI && FEATURE_UNIX_AMD64_STRUCT_PASSING
 
     ReportPointersFromValueType(fn, sc, pMT, pSrc->GetDestinationAddress());
 }