Fix sos for regions (#2112)
authorPeter Sollich <petersol@microsoft.com>
Thu, 25 Mar 2021 22:05:32 +0000 (23:05 +0100)
committerGitHub <noreply@github.com>
Thu, 25 Mar 2021 22:05:32 +0000 (15:05 -0700)
* In the 64-bit implementation, we now use one more bit in the method table pointer, so SOS needs to mask out one more bit as well.

* Update breaking change number

* Initial update for regions.

* Fix !HeapStat for regions.

* More updates for regions:
- GCPrintGenerationInfo
- GCPrintSegmentInfo
- GCHeapTraverse
- FindSegment

* Work around issue with finding coreclr.dll, resolve merge conflicts in GCPrintSegmentInfo.

* Remove bug workaround.

* GCGenUsageStats now takes an additional parameter.

* Fix issues found by checkin tests running region-enabled SOS for non-region cases.

src/SOS/Strike/eeheap.cpp
src/SOS/Strike/gcroot.cpp
src/SOS/Strike/sos.cpp
src/SOS/Strike/sos.h
src/SOS/Strike/util.h

index c0df1e204229e2d81b26e5508d4acba6c11432c7..be5e69b5183c56014d033f9c5c5a37ccccfe6a69 100644 (file)
@@ -443,12 +443,27 @@ size_t AlignLarge(size_t nbytes)
 void GCPrintGenerationInfo(const GCHeapDetails &heap)
 {
     UINT n;
-    for (n = 0; n <= GetMaxGeneration(); n ++)
+    for (n = 0; n <= GetMaxGeneration(); n++)
     {
         if (IsInterrupt())
             return;
-        ExtOut("generation %d starts at 0x%p\n",
-                 n, SOS_PTR(heap.generation_table[n].allocation_start));
+        if (heap.has_regions)
+        {
+            DacpHeapSegmentData segment;
+            DWORD_PTR dwAddrSeg = (DWORD_PTR)heap.generation_table[n].start_segment;
+            if (segment.Request(g_sos, dwAddrSeg, heap.original_heap_details) != S_OK)
+            {
+                ExtOut("Error requesting heap segment %p\n", SOS_PTR(dwAddrSeg));
+                return;
+            }
+            ExtOut("generation %d starts at 0x%p\n",
+                n, SOS_PTR(SOS_PTR(segment.mem)));
+        }
+        else
+        {
+            ExtOut("generation %d starts at 0x%p\n",
+                n, SOS_PTR(heap.generation_table[n].allocation_start));
+        }
     }
 
     // We also need to look at the gen0 alloc context.
@@ -471,48 +486,79 @@ void GCPrintSegmentInfo(const GCHeapDetails &heap, DWORD_PTR &total_allocated_si
     DWORD_PTR dwAddrSeg;
     DacpHeapSegmentData segment;
 
-    dwAddrSeg = (DWORD_PTR)heap.generation_table[GetMaxGeneration()].start_segment;
-    total_allocated_size = 0;
-    total_committed_size = 0;
-    // the loop below will terminate, because we retrieved at most nMaxHeapSegmentCount segments
-    while (dwAddrSeg != (DWORD_PTR)heap.generation_table[0].start_segment)
+    if (heap.has_regions)
     {
-        if (IsInterrupt())
-            return;
+        for (UINT n = 0; n <= GetMaxGeneration(); n++)
+        {
+            ExtOut("generation %d:\n", n);
+            dwAddrSeg = (DWORD_PTR)heap.generation_table[n].start_segment;
+            while (dwAddrSeg != 0)
+            {
+                if (IsInterrupt())
+                    return;
+                if (segment.Request(g_sos, dwAddrSeg, heap.original_heap_details) != S_OK)
+                {
+                    ExtOut("Error requesting heap segment %p\n", SOS_PTR(dwAddrSeg));
+                    return;
+                }
+                ExtOut("%p  %p  %p  %p  0x%" POINTERSIZE_TYPE "x(%" POINTERSIZE_TYPE"d)  0x%" POINTERSIZE_TYPE "x(%" POINTERSIZE_TYPE "d)\n",
+                    SOS_PTR(dwAddrSeg),
+                    SOS_PTR(segment.mem), SOS_PTR(segment.allocated), SOS_PTR(segment.committed),
+                    (ULONG_PTR)(segment.allocated - segment.mem),
+                    (ULONG_PTR)(segment.allocated - segment.mem),
+                    (ULONG_PTR)(segment.committed - segment.mem),
+                    (ULONG_PTR)(segment.committed - segment.mem));
+                total_allocated_size += (DWORD_PTR)(segment.allocated - segment.mem);
+                total_committed_size += (DWORD_PTR)(segment.committed - segment.mem);
+                dwAddrSeg = (DWORD_PTR)segment.next;
+            }
+        }
+    }
+    else
+    {
+        dwAddrSeg = (DWORD_PTR)heap.generation_table[GetMaxGeneration()].start_segment;
+        total_allocated_size = 0;
+        total_committed_size = 0;
+        // the loop below will terminate, because we retrieved at most nMaxHeapSegmentCount segments
+        while (dwAddrSeg != (DWORD_PTR)heap.generation_table[0].start_segment)
+        {
+            if (IsInterrupt())
+                return;
+            if (segment.Request(g_sos, dwAddrSeg, heap.original_heap_details) != S_OK)
+            {
+                ExtOut("Error requesting heap segment %p\n", SOS_PTR(dwAddrSeg));
+                return;
+            }
+            ExtOut("%p  %p  %p  %p  0x%" POINTERSIZE_TYPE "x(%" POINTERSIZE_TYPE"d)  0x%" POINTERSIZE_TYPE "x(%" POINTERSIZE_TYPE "d)\n",
+                    SOS_PTR(dwAddrSeg),
+                    SOS_PTR(segment.mem), SOS_PTR(segment.allocated), SOS_PTR(segment.committed),
+                    (ULONG_PTR)(segment.allocated - segment.mem),
+                    (ULONG_PTR)(segment.allocated - segment.mem),
+                    (ULONG_PTR)(segment.committed - segment.mem),
+                    (ULONG_PTR)(segment.committed - segment.mem));
+            total_allocated_size += (DWORD_PTR) (segment.allocated - segment.mem);
+            total_committed_size += (DWORD_PTR) (segment.committed - segment.mem);
+            dwAddrSeg = (DWORD_PTR)segment.next;
+        }
+
         if (segment.Request(g_sos, dwAddrSeg, heap.original_heap_details) != S_OK)
         {
             ExtOut("Error requesting heap segment %p\n", SOS_PTR(dwAddrSeg));
             return;
         }
+
+        DWORD_PTR end = (DWORD_PTR)heap.alloc_allocated;
         ExtOut("%p  %p  %p  %p  0x%" POINTERSIZE_TYPE "x(%" POINTERSIZE_TYPE"d)  0x%" POINTERSIZE_TYPE "x(%" POINTERSIZE_TYPE "d)\n",
                 SOS_PTR(dwAddrSeg),
-                SOS_PTR(segment.mem), SOS_PTR(segment.allocated), SOS_PTR(segment.committed),
-                (ULONG_PTR)(segment.allocated - segment.mem),
-                (ULONG_PTR)(segment.allocated - segment.mem),
-                (ULONG_PTR)(segment.committed - segment.mem),
-                (ULONG_PTR)(segment.committed - segment.mem));
-        total_allocated_size += (DWORD_PTR) (segment.allocated - segment.mem);
-        total_committed_size += (DWORD_PTR) (segment.committed - segment.mem);
-        dwAddrSeg = (DWORD_PTR)segment.next;
-    }
+                SOS_PTR(segment.mem), SOS_PTR(end), SOS_PTR(segment.committed),
+                (ULONG_PTR)(end - (DWORD_PTR)segment.mem),
+                (ULONG_PTR)(end - (DWORD_PTR)segment.mem),
+                (ULONG_PTR)(segment.committed - (DWORD_PTR)segment.mem),
+                (ULONG_PTR)(segment.committed - (DWORD_PTR)segment.mem));
 
-    if (segment.Request(g_sos, dwAddrSeg, heap.original_heap_details) != S_OK)
-    {
-        ExtOut("Error requesting heap segment %p\n", SOS_PTR(dwAddrSeg));
-        return;
+        total_allocated_size += end - (DWORD_PTR)segment.mem;
+        total_committed_size += (DWORD_PTR)(segment.committed - segment.mem);
     }
-
-    DWORD_PTR end = (DWORD_PTR)heap.alloc_allocated;
-    ExtOut("%p  %p  %p  %p  0x%" POINTERSIZE_TYPE "x(%" POINTERSIZE_TYPE"d)  0x%" POINTERSIZE_TYPE "x(%" POINTERSIZE_TYPE "d)\n",
-            SOS_PTR(dwAddrSeg),
-            SOS_PTR(segment.mem), SOS_PTR(end), SOS_PTR(segment.committed),
-            (ULONG_PTR)(end - (DWORD_PTR)segment.mem),
-            (ULONG_PTR)(end - (DWORD_PTR)segment.mem),
-            (ULONG_PTR)(segment.committed - (DWORD_PTR)segment.mem),
-            (ULONG_PTR)(segment.committed - (DWORD_PTR)segment.mem));
-
-    total_allocated_size += end - (DWORD_PTR)segment.mem;
-    total_committed_size += (DWORD_PTR)(segment.committed - segment.mem);
 }
 
 void GCPrintLargeHeapSegmentInfo(const GCHeapDetails &heap, DWORD_PTR &total_allocated_size, DWORD_PTR &total_committed_size)
@@ -600,6 +646,10 @@ void GCHeapInfo(const GCHeapDetails &heap, DWORD_PTR &total_allocated_size, DWOR
 BOOL GCObjInGeneration(TADDR taddrObj, const GCHeapDetails &heap,
     const TADDR_SEGINFO& /*seg*/, int& gen, TADDR_RANGE& allocCtx)
 {
+    // we will not get here in case of regions as our caller in 
+    // GCObjInSegment already takes care of this
+    assert(!heap.has_regions);
+
     gen = -1;
     for (UINT n = 0; n <= GetMaxGeneration(); n ++)
     {
@@ -633,44 +683,77 @@ BOOL GCObjInSegment(TADDR taddrObj, const GCHeapDetails &heap,
     TADDR taddrSeg;
     DacpHeapSegmentData dacpSeg;
 
-    taddrSeg = (TADDR)heap.generation_table[GetMaxGeneration()].start_segment;
-    // the loop below will terminate, because we retrieved at most nMaxHeapSegmentCount segments
-    while (taddrSeg != (TADDR)heap.generation_table[0].start_segment)
+    if (heap.has_regions)
     {
-        if (IsInterrupt())
-            return FALSE;
-        if (dacpSeg.Request(g_sos, taddrSeg, heap.original_heap_details) != S_OK)
+        // in this case, each generation has its own list
+        for (unsigned gen_num = 0; gen_num <= GetMaxGeneration(); gen_num++)
         {
-            ExtOut("Error requesting heap segment %p\n", SOS_PTR(taddrSeg));
-            return FALSE;
+            taddrSeg = (TADDR)heap.generation_table[gen_num].start_segment;
+
+            // the loop below will terminate, because we retrieved at most nMaxHeapSegmentCount segments
+            while (taddrSeg != NULL)
+            {
+                if (IsInterrupt())
+                    return FALSE;
+                if (dacpSeg.Request(g_sos, taddrSeg, heap.original_heap_details) != S_OK)
+                {
+                    ExtOut("Error requesting heap segment %p\n", SOS_PTR(taddrSeg));
+                    return FALSE;
+                }
+                if (taddrObj >= TO_TADDR(dacpSeg.mem) && taddrObj && taddrObj < TO_TADDR(dacpSeg.allocated))
+                {
+                    rngSeg.segAddr = (TADDR)dacpSeg.segmentAddr;
+                    rngSeg.start = (TADDR)dacpSeg.mem;
+                    rngSeg.end = (TADDR)dacpSeg.allocated;
+                    gen = gen_num;
+                    return TRUE;
+                }
+                taddrSeg = (TADDR)dacpSeg.next;
+            }
         }
-        if (taddrObj >= TO_TADDR(dacpSeg.mem) && taddrObj < TO_TADDR(dacpSeg.allocated))
+        return FALSE;
+    }
+    else
+    {
+        taddrSeg = (TADDR)heap.generation_table[GetMaxGeneration()].start_segment;
+        // the loop below will terminate, because we retrieved at most nMaxHeapSegmentCount segments
+        while (taddrSeg != (TADDR)heap.generation_table[0].start_segment)
         {
-            rngSeg.segAddr = (TADDR)dacpSeg.segmentAddr;
-            rngSeg.start   = (TADDR)dacpSeg.mem;
-            rngSeg.end     = (TADDR)dacpSeg.allocated;
-            gen = 2;
-            allocCtx.start = allocCtx.end = 0;
-            return TRUE;
+            if (IsInterrupt())
+                return FALSE;
+            if (dacpSeg.Request(g_sos, taddrSeg, heap.original_heap_details) != S_OK)
+            {
+                ExtOut("Error requesting heap segment %p\n", SOS_PTR(taddrSeg));
+                return FALSE;
+            }
+            if (taddrObj >= TO_TADDR(dacpSeg.mem) && taddrObj < TO_TADDR(dacpSeg.allocated))
+            {
+                rngSeg.segAddr = (TADDR)dacpSeg.segmentAddr;
+                rngSeg.start   = (TADDR)dacpSeg.mem;
+                rngSeg.end     = (TADDR)dacpSeg.allocated;
+                gen = 2;
+                allocCtx.start = allocCtx.end = 0;
+                return TRUE;
+            }
+            taddrSeg = (TADDR)dacpSeg.next;
         }
-        taddrSeg = (TADDR)dacpSeg.next;
-    }
 
-    // the ephemeral segment
-    if (dacpSeg.Request(g_sos, taddrSeg, heap.original_heap_details) != S_OK)
-    {
-        ExtOut("Error requesting heap segment %p\n", SOS_PTR(taddrSeg));
-        return FALSE;
-    }
+        // the ephemeral segment
+        if (dacpSeg.Request(g_sos, taddrSeg, heap.original_heap_details) != S_OK)
+        {
+            ExtOut("Error requesting heap segment %p\n", SOS_PTR(taddrSeg));
+            return FALSE;
+        }
 
-    if (taddrObj >= TO_TADDR(dacpSeg.mem) && taddrObj < TO_TADDR(heap.alloc_allocated))
-    {
-        if (GCObjInGeneration(taddrObj, heap, rngSeg, gen, allocCtx))
+        if (taddrObj >= TO_TADDR(dacpSeg.mem) && taddrObj < TO_TADDR(heap.alloc_allocated))
         {
-            rngSeg.segAddr = (TADDR)dacpSeg.segmentAddr;
-            rngSeg.start   = (TADDR)dacpSeg.mem;
-            rngSeg.end     = (TADDR)heap.alloc_allocated;
-            return TRUE;
+            if (GCObjInGeneration(taddrObj, heap, rngSeg, gen, allocCtx))
+            {
+                rngSeg.segAddr = (TADDR)dacpSeg.segmentAddr;
+                rngSeg.start   = (TADDR)dacpSeg.mem;
+                rngSeg.end     = (TADDR)heap.alloc_allocated;
+                return TRUE;
+            }
         }
     }
 
@@ -869,60 +952,87 @@ BOOL GCHeapUsageStats(const GCHeapDetails& heap, BOOL bIncUnreachable, HeapUsage
     AllocInfo allocInfo;
     allocInfo.Init();
 
-    // 1. Start with small object segments
+    // this will create the bitmap of rooted objects only if bIncUnreachable is true
+    GCRootImpl gcroot;
+    std::unordered_set<TADDR> emptyLiveObjs;
+    const std::unordered_set<TADDR>& liveObjs = (bIncUnreachable ? gcroot.GetLiveObjects() : emptyLiveObjs);
+
     TADDR taddrSeg;
     DacpHeapSegmentData dacpSeg;
 
-    taddrSeg = (TADDR)heap.generation_table[GetMaxGeneration()].start_segment;
+    if (heap.has_regions)
+    {
+        // 1. Start with small object generations,
+        //    each generation has a list of segments
+        for (UINT n = 0; n <= GetMaxGeneration(); n++)
+        {
+            taddrSeg = (TADDR)heap.generation_table[n].start_segment;
+            while (taddrSeg != NULL)
+            {
+                if (IsInterrupt())
+                    return FALSE;
 
+                if (dacpSeg.Request(g_sos, taddrSeg, heap.original_heap_details) != S_OK)
+                {
+                    ExtErr("Error requesting heap segment %p\n", SOS_PTR(taddrSeg));
+                    return FALSE;
+                }
 #ifndef FEATURE_PAL
-    // this will create the bitmap of rooted objects only if bIncUnreachable is true
-    GCRootImpl gcroot;
-    std::unordered_set<TADDR> emptyLiveObjs;
-    const std::unordered_set<TADDR> &liveObjs = (bIncUnreachable ? gcroot.GetLiveObjects() : emptyLiveObjs);
-
-    // 1a. enumerate all non-ephemeral segments
-    while (taddrSeg != (TADDR)heap.generation_table[0].start_segment)
+                GCGenUsageStats((TADDR)dacpSeg.mem, (TADDR)dacpSeg.allocated, (TADDR)dacpSeg.committed, liveObjs, heap, FALSE, FALSE, &allocInfo, &hpUsage->genUsage[n]);
+#endif
+                taddrSeg = (TADDR)dacpSeg.next;
+            }
+        }
+    }
+    else
     {
-        if (IsInterrupt())
-            return FALSE;
+        // 1. Start with small object segments
+        taddrSeg = (TADDR)heap.generation_table[GetMaxGeneration()].start_segment;
+
+#ifndef FEATURE_PAL
+        // 1a. enumerate all non-ephemeral segments
+        while (taddrSeg != (TADDR)heap.generation_table[0].start_segment)
+        {
+            if (IsInterrupt())
+                return FALSE;
+
+            if (dacpSeg.Request(g_sos, taddrSeg, heap.original_heap_details) != S_OK)
+            {
+                ExtErr("Error requesting heap segment %p\n", SOS_PTR(taddrSeg));
+                return FALSE;
+            }
+            GCGenUsageStats((TADDR)dacpSeg.mem, (TADDR)dacpSeg.allocated, (TADDR)dacpSeg.committed, liveObjs, heap, FALSE, FALSE, &allocInfo, &hpUsage->genUsage[2]);
+            taddrSeg = (TADDR)dacpSeg.next;
+        }
+#endif
 
+        // 1b. now handle the ephemeral segment
         if (dacpSeg.Request(g_sos, taddrSeg, heap.original_heap_details) != S_OK)
         {
             ExtErr("Error requesting heap segment %p\n", SOS_PTR(taddrSeg));
             return FALSE;
         }
-        GCGenUsageStats((TADDR)dacpSeg.mem, (TADDR)dacpSeg.allocated, (TADDR)dacpSeg.committed, liveObjs, heap, FALSE, FALSE, &allocInfo, &hpUsage->genUsage[2]);
-        taddrSeg = (TADDR)dacpSeg.next;
-    }
-#endif
 
-    // 1b. now handle the ephemeral segment
-    if (dacpSeg.Request(g_sos, taddrSeg, heap.original_heap_details) != S_OK)
-    {
-        ExtErr("Error requesting heap segment %p\n", SOS_PTR(taddrSeg));
-        return FALSE;
-    }
-
-    TADDR endGen = TO_TADDR(heap.alloc_allocated);
+        TADDR endGen = TO_TADDR(heap.alloc_allocated);
 
-    for (UINT n = 0; n <= GetMaxGeneration(); n ++)
-    {
-        TADDR startGen;
-        // gen 2 starts at the beginning of the segment
-        if (n == GetMaxGeneration())
+        for (UINT n = 0; n <= GetMaxGeneration(); n++)
         {
-            startGen = TO_TADDR(dacpSeg.mem);
-        }
-        else
-        {
-            startGen = TO_TADDR(heap.generation_table[n].allocation_start);
-        }
+            TADDR startGen;
+            // gen 2 starts at the beginning of the segment
+            if (n == GetMaxGeneration())
+            {
+                startGen = TO_TADDR(dacpSeg.mem);
+            }
+            else
+            {
+                startGen = TO_TADDR(heap.generation_table[n].allocation_start);
+            }
 
 #ifndef FEATURE_PAL
-        GCGenUsageStats(startGen, endGen, (TADDR)dacpSeg.committed, liveObjs, heap, FALSE, FALSE, &allocInfo, &hpUsage->genUsage[n]);
+            GCGenUsageStats(startGen, endGen, (TADDR)dacpSeg.committed, liveObjs, heap, FALSE, FALSE, &allocInfo, &hpUsage->genUsage[n]);
 #endif
-        endGen = startGen;
+            endGen = startGen;
+        }
     }
 
     // 2. Now process LOH
@@ -1144,148 +1254,281 @@ void GatherOneHeapFinalization(DacpGcHeapDetails& heapDetails, HeapStat *stat, B
 
 BOOL GCHeapTraverse(const GCHeapDetails &heap, AllocInfo* pallocInfo, VISITGCHEAPFUNC pFunc, LPVOID token, BOOL verify)
 {
-    DWORD_PTR begin_youngest;
-    DWORD_PTR end_youngest;
+    DWORD_PTR dwAddrSeg = 0;
+    DWORD_PTR dwAddr = 0;
+    DWORD_PTR dwAddrCurrObj = 0;
+    DWORD_PTR dwAddrPrevObj = 0;
+    size_t s, sPrev = 0;
 
-    begin_youngest = (DWORD_PTR)heap.generation_table[0].allocation_start;
-    DWORD_PTR dwAddr = (DWORD_PTR)heap.ephemeral_heap_segment;
     DacpHeapSegmentData segment;
+    if (heap.has_regions)
+    {
+        DWORD_PTR end_youngest = (DWORD_PTR)heap.alloc_allocated;
+        BOOL bPrevFree = FALSE;
+        for (UINT n = 0; n <= GetMaxGeneration(); n++)
+        {
+            dwAddrSeg = (DWORD_PTR)heap.generation_table[n].start_segment;
+            while (dwAddrSeg != 0)
+            {
+                if (IsInterrupt())
+                {
+                    ExtOut("<heap walk interrupted>\n");
+                    return FALSE;
+                }
+                if (segment.Request(g_sos, dwAddrSeg, heap.original_heap_details) != S_OK)
+                {
+                    ExtOut("Error requesting heap segment %p\n", SOS_PTR(dwAddrSeg));
+                    return FALSE;
+                }
+                dwAddrCurrObj = (DWORD_PTR)segment.mem;
+                DWORD_PTR end_of_segment = (DWORD_PTR)segment.allocated;
+                if (dwAddrSeg == (DWORD_PTR)heap.ephemeral_heap_segment)
+                {
+                    end_of_segment = end_youngest;
+                }
 
-    end_youngest = (DWORD_PTR)heap.alloc_allocated;
+                while (true)
+                {
+                    if (dwAddrCurrObj - SIZEOF_OBJHEADER == end_youngest - Align(min_obj_size))
+                        break;
 
-    DWORD_PTR dwAddrSeg = (DWORD_PTR)heap.generation_table[GetMaxGeneration()].start_segment;
-    dwAddr = dwAddrSeg;
+                    if (dwAddrCurrObj >= (DWORD_PTR)end_of_segment)
+                    {
+                        if (dwAddrCurrObj > (DWORD_PTR)end_of_segment)
+                        {
+                            ExtOut("curr_object: %p > heap_segment_allocated (seg: %p)\n",
+                                SOS_PTR(dwAddrCurrObj), SOS_PTR(dwAddrSeg));
+                            if (dwAddrPrevObj) 
+                            {
+                                ExtOut("Last good object: %p\n", SOS_PTR(dwAddrPrevObj));
+                            }
+                            return FALSE;
+                        }
+                        // done with this segment
+                        break;
+                    }
 
-    if (segment.Request(g_sos, dwAddr, heap.original_heap_details) != S_OK)
-    {
-        ExtOut("Error requesting heap segment %p\n", SOS_PTR(dwAddr));
-        return FALSE;
-    }
+                    if (dwAddrSeg == (DWORD_PTR)heap.ephemeral_heap_segment
+                        && dwAddrCurrObj >= end_youngest)
+                    {
+                        if (dwAddrCurrObj > end_youngest)
+                        {
+                            // prev_object length is too long
+                            ExtOut("curr_object: %p > end_youngest: %p\n",
+                                SOS_PTR(dwAddrCurrObj), SOS_PTR(end_youngest));
+                            if (dwAddrPrevObj) 
+                            {
+                                DMLOut("Last good object: %s\n", DMLObject(dwAddrPrevObj));
+                            }
+                            return FALSE;
+                        }
+                        return FALSE;
+                    }
+
+                    DWORD_PTR dwAddrMethTable = 0;
+                    if (FAILED(GetMTOfObject(dwAddrCurrObj, &dwAddrMethTable)))
+                    {
+                        return FALSE;
+                    }
 
-    // DWORD_PTR dwAddrCurrObj = (DWORD_PTR)heap.generation_table[GetMaxGeneration()].allocation_start;
-    DWORD_PTR dwAddrCurrObj = (DWORD_PTR)segment.mem;
+                    dwAddrMethTable = dwAddrMethTable & ~sos::Object::METHODTABLE_PTR_LOW_BITMASK;
+                    if (dwAddrMethTable == 0)
+                    {
+                        // Is this the beginning of an allocation context?
+                        int i;
+                        for (i = 0; i < pallocInfo->num; i++)
+                        {
+                            if (dwAddrCurrObj == (DWORD_PTR)pallocInfo->array[i].alloc_ptr)
+                            {
+                                dwAddrCurrObj =
+                                    (DWORD_PTR)pallocInfo->array[i].alloc_limit + Align(min_obj_size);
+                                break;
+                            }
+                        }
+                        if (i < pallocInfo->num)
+                            continue;
+
+                        // We also need to look at the gen0 alloc context.
+                        if (dwAddrCurrObj == (DWORD_PTR)heap.generation_table[0].allocContextPtr)
+                        {
+                            dwAddrCurrObj = (DWORD_PTR)heap.generation_table[0].allocContextLimit + Align(min_obj_size);
+                            continue;
+                        }
+                    }
 
-    size_t s, sPrev=0;
-    BOOL bPrevFree=FALSE;
-    BOOL bPinnedDone = FALSE;
-    DWORD_PTR dwAddrMethTable;
-    DWORD_PTR dwAddrPrevObj=0;
+                    BOOL bContainsPointers;
+                    size_t s;
+                    BOOL bMTOk = GetSizeEfficient(dwAddrCurrObj, dwAddrMethTable, FALSE, s, bContainsPointers);
+                    if (verify && bMTOk)
+                        bMTOk = VerifyObject(heap, dwAddrCurrObj, dwAddrMethTable, s, TRUE);
+                    if (!bMTOk)
+                    {
+                        DMLOut("curr_object:      %s\n", DMLListNearObj(dwAddrCurrObj));
+                        if (dwAddrPrevObj)
+                            DMLOut("Last good object: %s\n", DMLObject(dwAddrPrevObj));
 
-    while(1)
+                        ExtOut("----------------\n");
+                        return FALSE;
+                    }
+
+                    pFunc(dwAddrCurrObj, s, dwAddrMethTable, token);
+
+                    // We believe we did this alignment in ObjectSize above.
+                    assert((s & ALIGNCONST) == 0);
+                    dwAddrPrevObj = dwAddrCurrObj;
+                    sPrev = s;
+                    bPrevFree = IsMTForFreeObj(dwAddrMethTable);
+
+                    dwAddrCurrObj += s;
+                }
+                dwAddrSeg = (DWORD_PTR)segment.next;
+            }
+        }
+    }
+    else
     {
-        if (IsInterrupt())
+        DWORD_PTR begin_youngest;
+        DWORD_PTR end_youngest;
+
+        begin_youngest = (DWORD_PTR)heap.generation_table[0].allocation_start;
+        dwAddr = (DWORD_PTR)heap.ephemeral_heap_segment;
+
+        end_youngest = (DWORD_PTR)heap.alloc_allocated;
+
+        dwAddrSeg = (DWORD_PTR)heap.generation_table[GetMaxGeneration()].start_segment;
+        dwAddr = dwAddrSeg;
+
+        if (segment.Request(g_sos, dwAddr, heap.original_heap_details) != S_OK)
         {
-            ExtOut("<heap walk interrupted>\n");
+            ExtOut("Error requesting heap segment %p\n", SOS_PTR(dwAddr));
             return FALSE;
         }
-        DWORD_PTR end_of_segment = (DWORD_PTR)segment.allocated;
-        if (dwAddrSeg == (DWORD_PTR)heap.ephemeral_heap_segment)
-        {
-            end_of_segment = end_youngest;
-            if (dwAddrCurrObj - SIZEOF_OBJHEADER == end_youngest - Align(min_obj_size))
-                break;
-        }
-        if (dwAddrCurrObj >= (DWORD_PTR)end_of_segment)
+
+        // DWORD_PTR dwAddrCurrObj = (DWORD_PTR)heap.generation_table[GetMaxGeneration()].allocation_start;
+        dwAddrCurrObj = (DWORD_PTR)segment.mem;
+
+        BOOL bPrevFree = FALSE;
+
+        while (1)
         {
-            if (dwAddrCurrObj > (DWORD_PTR)end_of_segment)
+            if (IsInterrupt())
             {
-                ExtOut ("curr_object: %p > heap_segment_allocated (seg: %p)\n",
-                         SOS_PTR(dwAddrCurrObj), SOS_PTR(dwAddrSeg));
-                if (dwAddrPrevObj) {
-                    ExtOut ("Last good object: %p\n", SOS_PTR(dwAddrPrevObj));
-                }
+                ExtOut("<heap walk interrupted>\n");
                 return FALSE;
             }
-            dwAddrSeg = (DWORD_PTR)segment.next;
-            if (dwAddrSeg)
+            DWORD_PTR end_of_segment = (DWORD_PTR)segment.allocated;
+            if (dwAddrSeg == (DWORD_PTR)heap.ephemeral_heap_segment)
             {
-                dwAddr = dwAddrSeg;
-                if (segment.Request(g_sos, dwAddr, heap.original_heap_details) != S_OK)
+                end_of_segment = end_youngest;
+                if (dwAddrCurrObj - SIZEOF_OBJHEADER == end_youngest - Align(min_obj_size))
+                    break;
+            }
+            if (dwAddrCurrObj >= (DWORD_PTR)end_of_segment)
+            {
+                if (dwAddrCurrObj > (DWORD_PTR)end_of_segment)
                 {
-                    ExtOut("Error requesting heap segment %p\n", SOS_PTR(dwAddr));
+                    ExtOut ("curr_object: %p > heap_segment_allocated (seg: %p)\n",
+                        SOS_PTR(dwAddrCurrObj), SOS_PTR(dwAddrSeg));
+                    if (dwAddrPrevObj) {
+                        ExtOut ("Last good object: %p\n", SOS_PTR(dwAddrPrevObj));
+                    }
                     return FALSE;
                 }
-                dwAddrCurrObj = (DWORD_PTR)segment.mem;
-                continue;
-            }
-            else
-            {
-                break;  // Done Verifying Heap
+                dwAddrSeg = (DWORD_PTR)segment.next;
+                if (dwAddrSeg)
+                {
+                    dwAddr = dwAddrSeg;
+                    if (segment.Request(g_sos, dwAddr, heap.original_heap_details) != S_OK)
+                    {
+                        ExtOut("Error requesting heap segment %p\n", SOS_PTR(dwAddr));
+                        return FALSE;
+                    }
+                    dwAddrCurrObj = (DWORD_PTR)segment.mem;
+                    continue;
+                }
+                else
+                {
+                    break;  // Done Verifying Heap
+                }
             }
-        }
 
-        if (dwAddrSeg == (DWORD_PTR)heap.ephemeral_heap_segment
-            && dwAddrCurrObj >= end_youngest)
-        {
-            if (dwAddrCurrObj > end_youngest)
+            if (dwAddrSeg == (DWORD_PTR)heap.ephemeral_heap_segment
+                && dwAddrCurrObj >= end_youngest)
             {
-                // prev_object length is too long
-                ExtOut("curr_object: %p > end_youngest: %p\n",
-                         SOS_PTR(dwAddrCurrObj), SOS_PTR(end_youngest));
-                if (dwAddrPrevObj) {
-                    DMLOut("Last good object: %s\n", DMLObject(dwAddrPrevObj));
+                if (dwAddrCurrObj > end_youngest)
+                {
+                    // prev_object length is too long
+                    ExtOut("curr_object: %p > end_youngest: %p\n",
+                        SOS_PTR(dwAddrCurrObj), SOS_PTR(end_youngest));
+                    if (dwAddrPrevObj) {
+                        DMLOut("Last good object: %s\n", DMLObject(dwAddrPrevObj));
+                    }
+                    return FALSE;
                 }
                 return FALSE;
             }
-            return FALSE;
-        }
 
-        if (FAILED(GetMTOfObject(dwAddrCurrObj, &dwAddrMethTable)))
-        {
-            return FALSE;
-        }
+            DWORD_PTR dwAddrMethTable = 0;
+            if (FAILED(GetMTOfObject(dwAddrCurrObj, &dwAddrMethTable)))
+            {
+                return FALSE;
+            }
 
-        dwAddrMethTable = dwAddrMethTable & ~sos::Object::METHODTABLE_PTR_LOW_BITMASK;
-        if (dwAddrMethTable == 0)
-        {
-            // Is this the beginning of an allocation context?
-            int i;
-            for (i = 0; i < pallocInfo->num; i ++)
+            dwAddrMethTable = dwAddrMethTable & ~sos::Object::METHODTABLE_PTR_LOW_BITMASK;
+            if (dwAddrMethTable == 0)
             {
-                if (dwAddrCurrObj == (DWORD_PTR)pallocInfo->array[i].alloc_ptr)
+                // Is this the beginning of an allocation context?
+                int i;
+                for (i = 0; i < pallocInfo->num; i ++)
                 {
-                    dwAddrCurrObj =
-                        (DWORD_PTR)pallocInfo->array[i].alloc_limit + Align(min_obj_size);
-                    break;
+                    if (dwAddrCurrObj == (DWORD_PTR)pallocInfo->array[i].alloc_ptr)
+                    {
+                        dwAddrCurrObj =
+                            (DWORD_PTR)pallocInfo->array[i].alloc_limit + Align(min_obj_size);
+                        break;
+                    }
                 }
-            }
-            if (i < pallocInfo->num)
-                continue;
+                if (i < pallocInfo->num)
+                    continue;
 
-            // We also need to look at the gen0 alloc context.
-            if (dwAddrCurrObj == (DWORD_PTR) heap.generation_table[0].allocContextPtr)
-            {
-                dwAddrCurrObj = (DWORD_PTR) heap.generation_table[0].allocContextLimit + Align(min_obj_size);
-                continue;
+                // We also need to look at the gen0 alloc context.
+                if (dwAddrCurrObj == (DWORD_PTR) heap.generation_table[0].allocContextPtr)
+                {
+                    dwAddrCurrObj = (DWORD_PTR) heap.generation_table[0].allocContextLimit + Align(min_obj_size);
+                    continue;
+                }
             }
-        }
 
-        BOOL bContainsPointers;
-        BOOL bMTOk = GetSizeEfficient(dwAddrCurrObj, dwAddrMethTable, FALSE, s, bContainsPointers);
-        if (verify && bMTOk)
-             bMTOk = VerifyObject (heap, dwAddrCurrObj, dwAddrMethTable, s, TRUE);
-        if (!bMTOk)
-        {
-            DMLOut("curr_object:      %s\n", DMLListNearObj(dwAddrCurrObj));
-            if (dwAddrPrevObj)
-                DMLOut("Last good object: %s\n", DMLObject(dwAddrPrevObj));
+            BOOL bContainsPointers;
+            BOOL bMTOk = GetSizeEfficient(dwAddrCurrObj, dwAddrMethTable, FALSE, s, bContainsPointers);
+            if (verify && bMTOk)
+                bMTOk = VerifyObject (heap, dwAddrCurrObj, dwAddrMethTable, s, TRUE);
+            if (!bMTOk)
+            {
+                DMLOut("curr_object:      %s\n", DMLListNearObj(dwAddrCurrObj));
+                if (dwAddrPrevObj)
+                    DMLOut("Last good object: %s\n", DMLObject(dwAddrPrevObj));
 
-            ExtOut ("----------------\n");
-            return FALSE;
-        }
+                ExtOut ("----------------\n");
+                return FALSE;
+            }
 
-        pFunc (dwAddrCurrObj, s, dwAddrMethTable, token);
+            pFunc (dwAddrCurrObj, s, dwAddrMethTable, token);
 
-        // We believe we did this alignment in ObjectSize above.
-        assert((s & ALIGNCONST) == 0);
-        dwAddrPrevObj = dwAddrCurrObj;
-        sPrev = s;
-        bPrevFree = IsMTForFreeObj(dwAddrMethTable);
+            // We believe we did this alignment in ObjectSize above.
+            assert((s & ALIGNCONST) == 0);
+            dwAddrPrevObj = dwAddrCurrObj;
+            sPrev = s;
+            bPrevFree = IsMTForFreeObj(dwAddrMethTable);
 
-        dwAddrCurrObj += s;
+            dwAddrCurrObj += s;
+        }
     }
 
     // Now for the large object and pinned object generations:
+
+    BOOL bPinnedDone = FALSE;
+
     dwAddrSeg = (DWORD_PTR)heap.generation_table[GetMaxGeneration()+1].start_segment;
     dwAddr = dwAddrSeg;
 
@@ -1315,7 +1558,7 @@ BOOL GCHeapTraverse(const GCHeapDetails &heap, AllocInfo* pallocInfo, VISITGCHEA
             if (dwAddrCurrObj > (DWORD_PTR)end_of_segment)
             {
                 ExtOut("curr_object: %p > heap_segment_allocated (seg: %p)\n",
-                         SOS_PTR(dwAddrCurrObj), SOS_PTR(dwAddrSeg));
+                            SOS_PTR(dwAddrCurrObj), SOS_PTR(dwAddrSeg));
                 if (dwAddrPrevObj) {
                     ExtOut("Last good object: %p\n", SOS_PTR(dwAddrPrevObj));
                 }
@@ -1354,6 +1597,7 @@ BOOL GCHeapTraverse(const GCHeapDetails &heap, AllocInfo* pallocInfo, VISITGCHEA
             }
         }
 
+        DWORD_PTR dwAddrMethTable = 0;
         if (FAILED(GetMTOfObject(dwAddrCurrObj, &dwAddrMethTable)))
         {
             return FALSE;
@@ -1640,18 +1884,34 @@ BOOL GCHeapSnapshot::AddSegments(const GCHeapDetails& details)
     int n = 0;
     DacpHeapSegmentData segment;
 
-    // This array of two addresses gives us access to all the segments. The generation segments are linked
-    // to each other, starting with the maxGeneration segment. The second address gives us the large object heap.
-    CLRDATA_ADDRESS AddrSegs[]=
+    // This array of addresses gives us access to all the segments.
+    CLRDATA_ADDRESS AddrSegs[5];
+    if (details.has_regions)
     {
-        details.generation_table[GetMaxGeneration()].start_segment,
-        details.generation_table[GetMaxGeneration() + 1].start_segment, // large object heap
-        NULL
-    };
-
-    if (details.has_poh)
+        // with regions, each generation has its own list of segments
+        for (unsigned gen = 0; gen <= GetMaxGeneration() + 1; gen++)
+        {
+            AddrSegs[gen] = details.generation_table[gen].start_segment;
+        }
+        if (details.has_poh)
+        {
+            AddrSegs[4] = details.generation_table[GetMaxGeneration() + 2].start_segment; // pinned object heap
+        }
+    }
+    else
     {
-        AddrSegs[2] = details.generation_table[GetMaxGeneration() + 2].start_segment; // pinned object heap
+        // The generation segments are linked to each other, starting with the maxGeneration segment. 
+        // The second address gives us the large object heap, the third the pinned object heap
+
+        AddrSegs[0] = details.generation_table[GetMaxGeneration()].start_segment;
+        AddrSegs[1] = details.generation_table[GetMaxGeneration() + 1].start_segment;
+        AddrSegs[2] = NULL;
+        if (details.has_poh)
+        {
+            AddrSegs[2] = details.generation_table[GetMaxGeneration() + 2].start_segment; // pinned object heap
+        }
+        AddrSegs[3] = NULL;
+        AddrSegs[4] = NULL;
     }
 
     // this loop will get information for all the heap segments in this heap. The outer loop iterates once
@@ -1679,7 +1939,7 @@ BOOL GCHeapSnapshot::AddSegments(const GCHeapDetails& details)
                 ExtOut("Error requesting heap segment %p\n", SOS_PTR(AddrSeg));
                 return FALSE;
             }
-            if (n++ > nMaxHeapSegmentCount) // that would be insane
+            if (n++ > nMaxHeapSegmentCount && !details.has_regions) // that would be insane
             {
                 ExtOut("More than %d heap segments, there must be an error\n", nMaxHeapSegmentCount);
                 return FALSE;
index ba598df4e3eef1f61d68dd3d23b8650913e58b2b..f654d642e07ca2e3f0d078ca45cd97ee23215dfd 100644 (file)
@@ -1641,31 +1641,60 @@ BOOL VerifyObject(const GCHeapDetails &heap, const DacpHeapSegmentData &seg, DWO
 
 BOOL FindSegment(const GCHeapDetails &heap, DacpHeapSegmentData &seg, CLRDATA_ADDRESS addr)
 {
-    CLRDATA_ADDRESS dwAddrSeg = heap.generation_table[GetMaxGeneration()].start_segment;
-
-    // Request the inital segment.
-    if (seg.Request(g_sos, dwAddrSeg, heap.original_heap_details) != S_OK)
+    if (heap.has_regions)
     {
-        ExtOut("Error requesting heap segment %p.\n", SOS_PTR(dwAddrSeg));
-        return FALSE;
+        CLRDATA_ADDRESS dwAddrSeg;
+        for (UINT n = 0; n <= GetMaxGeneration(); n++)
+        {
+            dwAddrSeg = (DWORD_PTR)heap.generation_table[n].start_segment;
+            while (dwAddrSeg != 0)
+            {
+                if (IsInterrupt())
+                    return FALSE;
+                if (seg.Request(g_sos, dwAddrSeg, heap.original_heap_details) != S_OK)
+                {
+                    ExtOut("Error requesting heap segment %p\n", SOS_PTR(dwAddrSeg));
+                    return FALSE;
+                }
+                if (addr >= TO_TADDR(seg.mem) &&
+                    addr < (dwAddrSeg == heap.ephemeral_heap_segment ? heap.alloc_allocated : TO_TADDR(seg.allocated)))
+                {
+                    break;
+                }
+                dwAddrSeg = (DWORD_PTR)seg.next;
+            }
+            if (dwAddrSeg != 0)
+                break;
+        }
     }
-
-    // Loop while the object is not in range of the segment.
-    while (addr < TO_TADDR(seg.mem) ||
-           addr >= (dwAddrSeg == heap.ephemeral_heap_segment ? heap.alloc_allocated : TO_TADDR(seg.allocated)))
+    else
     {
-        // get the next segment
-        dwAddrSeg = seg.next;
-
-        // We reached the last segment without finding the object.
-        if (dwAddrSeg == NULL)
-            return FALSE;
+        CLRDATA_ADDRESS dwAddrSeg = heap.generation_table[GetMaxGeneration()].start_segment;
 
+        // Request the inital segment.
         if (seg.Request(g_sos, dwAddrSeg, heap.original_heap_details) != S_OK)
         {
             ExtOut("Error requesting heap segment %p.\n", SOS_PTR(dwAddrSeg));
             return FALSE;
         }
+
+        // Loop while the object is not in range of the segment.
+        while (addr < TO_TADDR(seg.mem) ||
+            addr >= (dwAddrSeg == heap.ephemeral_heap_segment ? heap.alloc_allocated : TO_TADDR(seg.allocated)))
+        {
+            // get the next segment
+            dwAddrSeg = seg.next;
+
+            // We reached the last segment without finding the object.
+            if (dwAddrSeg == NULL)
+                return FALSE;
+
+            if (seg.Request(g_sos, dwAddrSeg, heap.original_heap_details) != S_OK)
+            {
+                ExtOut("Error requesting heap segment %p.\n", SOS_PTR(dwAddrSeg));
+                return FALSE;
+            }
+        }
     }
 
     return TRUE;
index cc719fb4e666520802f9b7e44e0e9b7ec8ad0d33..534ca7b9458cf310aa3767f167967bb18a0fac4e 100644 (file)
@@ -25,6 +25,8 @@ namespace sos
     static bool MemOverlap(T beg1, T end1, // first range
                            T beg2, T end2) // second range
     {
+        if (beg1 >= end1 || beg2 >= end2)       // one of the ranges is empty
+            return false;
         if (beg2 >= beg1 && beg2 <= end1)       // second range starts within first range
             return true;
         else if (end2 >= beg1 && end2 <= end1)  // second range ends within first range
@@ -573,12 +575,21 @@ namespace sos
 
     ObjectIterator::ObjectIterator(const GCHeapDetails *heap, int numHeaps, TADDR start, TADDR stop)
     : bLarge(false), bPinned(false), mCurrObj(0), mLastObj(0), mStart(start), mEnd(stop), mSegmentEnd(0), mHeaps(heap),
-      mNumHeaps(numHeaps), mCurrHeap(0)
+      mNumHeaps(numHeaps), mCurrHeap(0), mCurrRegionGen(0)
     {
         mAllocInfo.Init();
         SOS_Assert(numHeaps > 0);
 
-        TADDR segStart = TO_TADDR(mHeaps[0].generation_table[GetMaxGeneration()].start_segment);
+        TADDR segStart;
+        if (heap->has_regions)
+        {
+            // with regions, we have a null terminated list for each generation
+            segStart = TO_TADDR(mHeaps[0].generation_table[mCurrRegionGen].start_segment);
+        }
+        else
+        {
+            segStart = TO_TADDR(mHeaps[0].generation_table[GetMaxGeneration()].start_segment);
+        }
         if (FAILED(mSegment.Request(g_sos, segStart, mHeaps[0].original_heap_details)))
         {
             sos::Throw<DataRead>("Could not request segment data at %p.", segStart);
@@ -602,7 +613,22 @@ namespace sos
         TADDR next = TO_TADDR(mSegment.next);
         if (next == NULL)
         {
-            if (bPinned || (bLarge && !mHeaps[mCurrHeap].has_poh))
+            if (mHeaps[mCurrHeap].has_regions)
+            {
+                mCurrRegionGen++;
+                if ((mCurrRegionGen > GetMaxGeneration() + 2) ||
+                    (mCurrRegionGen > GetMaxGeneration() + 1 && !mHeaps[mCurrHeap].has_poh))
+                {
+                    mCurrHeap++;
+                    if (mCurrHeap == mNumHeaps)
+                    {
+                        return false;
+                    }
+                    mCurrRegionGen = 0;
+                }
+                next = TO_TADDR(mHeaps[mCurrHeap].generation_table[mCurrRegionGen].start_segment);
+            }
+            else if (bPinned || (bLarge && !mHeaps[mCurrHeap].has_poh))
             {
                 mCurrHeap++;
                 if (mCurrHeap == mNumHeaps)
index 0c8974e54f912223522b3f8827a28bf144bda1d6..21752c9ab8e74182523920e09d32074d1639c6ce 100644 (file)
@@ -641,6 +641,7 @@ namespace sos
         const GCHeapDetails *mHeaps;
         int mNumHeaps;
         int mCurrHeap;
+        unsigned mCurrRegionGen;
     };
 
     /* Reprensents an entry in the sync block table.
index b7a45d4e2b72d695a2c9601d36d3ba0fff1a2d83..277b502741f5a6df6413b7f8fc9c6820c77a12fa 100644 (file)
@@ -484,10 +484,12 @@ public:
         lowest_address = dacGCDetails.lowest_address;
         highest_address = dacGCDetails.highest_address;
         card_table = dacGCDetails.card_table;
+        has_regions = saved_sweep_ephemeral_seg == -1;
     }
 
     DacpGcHeapDetails original_heap_details;
     bool has_poh;
+    bool has_regions;
     CLRDATA_ADDRESS heapAddr; // Only filled in in server mode, otherwise NULL
     CLRDATA_ADDRESS alloc_allocated;