singrdk/base/Imported/Bartok/runtime/shared/GCs/SlidingCollector.cs

783 lines
37 KiB
C#
Raw Normal View History

2008-11-17 18:29:00 -05:00
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
/*******************************************************************/
/* WARNING */
/* This file should be identical in the Bartok and Singularity */
/* depots. Master copy resides in Bartok Depot. Changes should be */
/* made to Bartok Depot and propagated to Singularity Depot. */
/*******************************************************************/
namespace System.GCs {
using Microsoft.Bartok.Runtime;
using System.Runtime.CompilerServices;
using System.Threading;
#if SINGULARITY_KERNEL
using Microsoft.Singularity;
#endif
[NoCCtor]
internal class SlidingCollector: GenerationalCollector {
internal static SlidingCollector instance;
// Visitor instances used for marking objects
private static MarkReferenceVisitor markReferenceVisitor;
private static RegisterThreadReference registerThreadReferenceVisitor;
private static RegisterPinnedReference registerPinnedReferenceVisitor;
private static UpdateThreadReference updateThreadReferenceVisitor;
private static ForwardReferenceVisitor forwardReferenceVisitor;
// Internally used data structures
private UIntPtrQueue skippedPageQueue = new UIntPtrQueue();
private UIntPtrQueue relocationQueue = new UIntPtrQueue();
// WARNING: don't initialize any static fields in this class
// without manually running the class constructor at startup!
private SlidingCollector() {
}
public static new void Initialize() {
GenerationalCollector.Initialize();
// SlidingCollector.instance = new SlidingCollector();
SlidingCollector.instance = (SlidingCollector)
BootstrapMemory.Allocate(typeof(SlidingCollector));
// markReferenceVisitor = new MarkReferenceVisitor();
markReferenceVisitor = (MarkReferenceVisitor)
BootstrapMemory.Allocate(typeof(MarkReferenceVisitor));
// registerThreadReferenceVisitor = new RegisterThreadReference();
registerThreadReferenceVisitor = (RegisterThreadReference)
BootstrapMemory.Allocate(typeof(RegisterThreadReference));
// registerPinnedReferenceVisitor = new RegisterPinnedReference();
registerPinnedReferenceVisitor = (RegisterPinnedReference)
BootstrapMemory.Allocate(typeof(RegisterPinnedReference));
// updateThreadReferenceVisitor = new UpdateThreadReference();
updateThreadReferenceVisitor = (UpdateThreadReference)
BootstrapMemory.Allocate(typeof(UpdateThreadReference));
// forwardReferenceVisitor = new ForwardReferenceVisitor();
forwardReferenceVisitor = (ForwardReferenceVisitor)
BootstrapMemory.Allocate(typeof(ForwardReferenceVisitor));
}
internal override void TruncateOlderAllocationAreas(int generation) {
// We don't use any allocators for the older generation,
// so there is nothing to do
}
internal override void CollectGeneration(int generation,
UIntPtr generationPageCount)
{
VTable.Assert(IsValidGeneration(generation));
// 1) Mark the live objects
CollectorStatistics.Event(GCEvent.TraceStart);
MultiUseWord.PreGCHook(true /* use shadows */);
Finalizer.PrepareCollectFinalizers();
CallStack.ScanStacks(registerThreadReferenceVisitor,
registerPinnedReferenceVisitor);
registerThreadReferenceVisitor.ForwardReferences();
if (generation < (int)MAX_GENERATION) {
// These calls must be done early, as they rely on the
// contents of Thread.threadTable being intact.
installedRemSet.Clean();
installedRemSet.Uniquify();
this.ScanRemSet((PageType) generation);
}
// Process runtime data that is allocated from SystemMemory
Thread.VisitBootstrapData(markReferenceVisitor);
#if SINGULARITY_KERNEL
Kernel.VisitSpecialData(markReferenceVisitor);
#endif
MultiUseWord.VisitStrongRefs(markReferenceVisitor,
true /* use shadows */);
StaticData.ScanStaticData(markReferenceVisitor);
CollectorStatistics.Event(GCEvent.TraceSpecial);
WeakReference.Process(forwardReferenceVisitor, false, true);
Finalizer.ResurrectCandidates(forwardReferenceVisitor,
markReferenceVisitor,
false);
markReferenceVisitor.Cleanup();
// 2) Forward pointers and compact the live objects
CollectorStatistics.Event(GCEvent.SweepStart, TotalMemory);
WeakReference.Process(forwardReferenceVisitor, false, false);
MultiUseWord.VisitWeakRefs(forwardReferenceVisitor,
true /* use shadows */);
UIntPtr oldAllocPtr;
UIntPtr newLimit = this.ForwardReferences((PageType)generation,
out oldAllocPtr);
this.CompactHeapObjects(oldAllocPtr);
#if SINGULARITY
Thread.UpdateAfterGC();
#endif
Thread currentThread = Thread.threadTable[collectorThreadIndex];
#if SINGULARITY_KERNEL
Kernel.UpdateAfterGC(currentThread);
#endif
CallStack.ScanStacks(updateThreadReferenceVisitor,
updateThreadReferenceVisitor);
this.CompactPhaseCleanup(currentThread,
(PageType)generation,
newLimit);
// Resetting the GC state
CollectorStatistics.Event(GCEvent.SweepSpecial);
installedRemSet.Reset();
MultiUseWord.PostGCHook();
Finalizer.ReleaseCollectFinalizers();
CollectorStatistics.Event(GCEvent.CollectionComplete, TotalMemory);
}
// Internal workings of the collector
// Scan is large and will be inlined here. This is a performance
// workaround that performs manual specialization of the Scan method.
[NoInline]
private void ScanRemSet(PageType generation) {
installedRemSet.Scan(markReferenceVisitor, generation);
}
// Routines for updating pointers to new locations of marked objects
// No objects can be resurrected using this mechanism
private class ForwardReferenceVisitor : NonNullReferenceVisitor {
internal unsafe override void Visit(UIntPtr *loc) {
UIntPtr addr = *loc;
UIntPtr page = PageTable.Page(addr);
PageType pageType = PageTable.Type(page);
if (!PageTable.IsZombiePage(pageType)) {
VTable.Assert(PageTable.IsGcPage(pageType) ||
PageTable.IsNonGcPage(pageType) ||
PageTable.IsStackPage(pageType) ||
PageTable.IsSharedPage(pageType));
return;
}
UIntPtr vtableAddr = Allocator.GetObjectVTable(addr);
if ((vtableAddr & 0x1) == 0x1) {
// Link this field to be updated
*loc = vtableAddr;
Allocator.SetObjectVTable(addr, (UIntPtr) loc+1);
} else {
// Zero the reference (not marked)
*loc = UIntPtr.Zero;
}
}
}
// Routines for marking objects and linking object references
private class MarkReferenceVisitor : NonNullReferenceVisitor {
internal unsafe override void Visit(UIntPtr *loc) {
UIntPtr addr = *loc;
UIntPtr page = PageTable.Page(addr);
PageType pageType = PageTable.Type(page);
if (!PageTable.IsZombiePage(pageType)) {
VTable.Assert(PageTable.IsGcPage(pageType) ||
PageTable.IsNonGcPage(pageType) ||
PageTable.IsStackPage(pageType) ||
PageTable.IsSharedPage(pageType));
return;
}
UIntPtr vtableAddr = Allocator.GetObjectVTable(addr);
// Mark object
if (vtableAddr == UIntPtr.Zero) {
VTable.DebugPrint("Found null vtable in MarkReference (loc = 0x{0:x8}, addr = 0x{1:x8})\n",
__arglist(((UIntPtr)loc), addr));
VTable.NotReached();
}
*loc = vtableAddr;
Allocator.SetObjectVTable(addr, (UIntPtr) loc+1);
// If first visit to the object, schedule visit of fields
if ((vtableAddr & 0x1) == 0) {
MarkVisit(addr, vtableAddr & (UIntPtr) ~2U);
}
}
private void MarkVisit(UIntPtr addr, UIntPtr vtableAddr) {
// Mark scheduling
if (fMarkInProgress) {
ScheduleMarkedObject(addr, vtableAddr);
} else {
fMarkInProgress = true;
VTable vtable =
Magic.toVTable(Magic.fromAddress(vtableAddr));
this.VisitReferenceFields(addr, vtable);
this.ProcessScheduledObjects();
fMarkInProgress = false;
}
}
private void ScheduleMarkedObject(UIntPtr addr,
UIntPtr vtableAddr) {
this.markQueue.Write(addr);
this.markQueue.Write(vtableAddr);
}
private void ProcessScheduledObjects() {
while (!this.markQueue.IsEmpty) {
UIntPtr addr = this.markQueue.Read();
UIntPtr vtableAddr = this.markQueue.Read();
VTable vtable =
Magic.toVTable(Magic.fromAddress(vtableAddr));
this.VisitReferenceFields(addr, vtable);
}
}
internal void Cleanup() {
VTable.Assert(this.markQueue.IsEmpty);
this.markQueue.Cleanup(true);
}
private bool fMarkInProgress;
private UIntPtrQueue markQueue = new UIntPtrQueue();
}
// Routines for linking and updating thread pointers
private class RegisterThreadReference : NonNullReferenceVisitor {
internal unsafe override void Visit(UIntPtr *loc) {
UIntPtr addr = *loc;
UIntPtr page = PageTable.Page(addr);
PageType pageType = PageTable.Type(page);
if (!PageTable.IsZombiePage(pageType)) {
VTable.Assert(PageTable.IsGcPage(pageType) ||
PageTable.IsNonGcPage(pageType) ||
PageTable.IsStackPage(pageType) ||
PageTable.IsSharedPage(pageType));
return;
}
UIntPtr objectAddr = InteriorPtrTable.Find(addr);
this.threadPtrQueue.Write(objectAddr);
this.threadPtrQueue.Write(addr - objectAddr);
}
internal unsafe void ForwardReferences() {
UIntPtrQueue.Enumerator queueEnumerator =
new UIntPtrQueue.Enumerator(ref this.threadPtrQueue);
while (queueEnumerator.MoveNext()) {
markReferenceVisitor.Visit(queueEnumerator.CurrentAddr);
queueEnumerator.MoveNext();
}
}
internal void Cleanup() {
// Free up the last thread pointer page
this.threadPtrQueue.Cleanup(true);
}
internal UIntPtrQueue threadPtrQueue = new UIntPtrQueue();
}
private class RegisterPinnedReference : NonNullReferenceVisitor {
internal unsafe override void Visit(UIntPtr *loc) {
UIntPtr addr = *loc;
UIntPtr page = PageTable.Page(addr);
PageType pageType = PageTable.Type(page);
if (!PageTable.IsZombiePage(pageType)) {
VTable.Assert(PageTable.IsGcPage(pageType) ||
PageTable.IsNonGcPage(pageType) ||
PageTable.IsStackPage(pageType) ||
PageTable.IsSharedPage(pageType));
return;
}
UIntPtr objectAddr = InteriorPtrTable.Find(addr);
registerThreadReferenceVisitor.threadPtrQueue.Write(objectAddr);
registerThreadReferenceVisitor.threadPtrQueue.Write(addr-objectAddr);
*Allocator.GetObjectVTableAddress(objectAddr) |= (UIntPtr) 2U;
}
}
private class UpdateThreadReference : NonNullReferenceVisitor {
internal unsafe override void Visit(UIntPtr *loc) {
UIntPtr addr = *loc;
UIntPtr page = PageTable.Page(addr);
if (!PageTable.IsZombiePage(PageTable.Type(page))) {
return;
}
UIntPtr objectAddr =
registerThreadReferenceVisitor.threadPtrQueue.Read();
UIntPtr addressDelta =
registerThreadReferenceVisitor.threadPtrQueue.Read();
*loc = objectAddr + addressDelta;
}
}
// Reference updates and object relocation
private unsafe UIntPtr ForwardReferences(PageType generation,
out UIntPtr oldAllocPtr)
{
VTable.Assert(IsValidGeneration((int)generation));
UIntPtr destPage = UIntPtr.Zero;
UIntPtr destCursor;
UIntPtr destLimit;
PageType destGeneration;
if (generation < MAX_GENERATION) {
destGeneration = generation + 1;
} else {
destGeneration = MAX_GENERATION;
}
destCursor = UIntPtr.Zero;
destLimit = UIntPtr.Zero;
oldAllocPtr = destCursor;
UIntPtr runLength = UIntPtr.Zero;
for (UIntPtr i=UIntPtr.Zero; i < PageTable.pageTableCount; i++) {
if (!IsMyZombiePage(i)) {
continue;
}
UIntPtr deltaBytes = (UIntPtr) 0x80000000;
UIntPtr sourceCursor = PageTable.PageAddr(i);
do {
i++;
} while (i < PageTable.pageTableCount && IsMyZombiePage(i));
UIntPtr sourceLimit = PageTable.PageAddr(i);
while (true) {
if (sourceCursor >= sourceLimit) {
break;
}
if (Allocator.IsAlignmentMarkerAddr(sourceCursor)) {
sourceCursor += UIntPtr.Size;
deltaBytes += UIntPtr.Size;
continue;
}
if (BumpAllocator.IsUnusedMarkerAddr(sourceCursor)) {
sourceCursor += UIntPtr.Size;
sourceCursor = PageTable.PagePad(sourceCursor);
deltaBytes = (UIntPtr) 0x80000000;
continue;
}
UIntPtr objectAddr = sourceCursor + PreHeader.Size;
UIntPtr vtableOrMarker =
Allocator.GetObjectVTable(objectAddr);
if (vtableOrMarker == UIntPtr.Zero) {
// We found the end of an allocation page
sourceCursor = PageTable.PagePad(sourceCursor);
deltaBytes = (UIntPtr) 0x80000000;
continue;
}
UIntPtr vtableAddr;
if ((vtableOrMarker & 1) != 0) {
UIntPtr temp = *(UIntPtr *) (vtableOrMarker - 1);
while ((temp & 1) != 0) {
temp = *(UIntPtr *) (temp-1);
}
VTable.Assert(PageTable.IsNonGcPage(PageTable.Type(PageTable.Page(temp))));
vtableAddr = temp;
if ((temp & 2) != 0) {
// Found pinned object
SkipDestinationAreas(ref destPage, destCursor,
ref destLimit,
sourceCursor);
deltaBytes -= (sourceCursor - destCursor);
destCursor = sourceCursor;
vtableAddr -= 2; // Remove "pinned" bit
}
Allocator.SetObjectVTable(objectAddr, vtableAddr);
} else {
vtableAddr = vtableOrMarker;
}
VTable vtable =
Magic.toVTable(Magic.fromAddress(vtableAddr));
UIntPtr objectSize =
ObjectLayout.ObjectSize(objectAddr, vtable);
VTable.Assert(objectSize > 0);
if ((vtableOrMarker & 1) != 0) {
if (GenerationalCollector.IsLargeObjectSize
(objectSize)) {
// Don't move large objects
SkipDestinationAreas(ref destPage,
destCursor,
ref destLimit,
sourceCursor);
UIntPtr localDelta =
sourceCursor - destCursor;
deltaBytes -= localDelta;
if (deltaBytes == UIntPtr.Zero &&
runLength != UIntPtr.Zero) {
runLength += localDelta;
}
destCursor = sourceCursor;
UIntPtr objLimit = sourceCursor + objectSize;
UIntPtr pageEndAddr = PageTable.PagePad(objLimit);
objectSize = (pageEndAddr - sourceCursor);
} else if (destCursor + objectSize > destLimit) {
UIntPtr oldDestCursor = destCursor;
FindDestinationArea(ref destPage,
ref destCursor,
ref destLimit,
objectSize,
destGeneration);
VTable.Assert(destCursor <= sourceCursor);
VTable.Assert(destCursor + objectSize <=
destLimit);
deltaBytes -= (destCursor - oldDestCursor);
} else if (vtable.baseAlignment > UIntPtr.Size) {
uint alignmentMask = vtable.baseAlignment - 1;
int offset = PreHeader.Size + UIntPtr.Size;
while (((destCursor+offset) & alignmentMask) != 0) {
destCursor += UIntPtr.Size;
deltaBytes -= UIntPtr.Size;
if (deltaBytes == UIntPtr.Zero &&
runLength != UIntPtr.Zero) {
runLength += UIntPtr.Size;
}
}
}
if (runLength == UIntPtr.Zero ||
deltaBytes != UIntPtr.Zero) {
if (runLength != UIntPtr.Zero) {
RegisterRelocationEnd(runLength);
}
RegisterRelocationStart(sourceCursor,
destCursor);
deltaBytes = UIntPtr.Zero;
runLength = UIntPtr.Zero;
}
UIntPtr newObjectAddr = destCursor + PreHeader.Size;
do {
UIntPtr *ptrAddr = (UIntPtr*) (vtableOrMarker-1);
vtableOrMarker = *ptrAddr;
*ptrAddr = newObjectAddr;
} while ((vtableOrMarker & 1) != 0);
destCursor += objectSize;
runLength += objectSize;
} else {
deltaBytes += objectSize;
if (runLength != UIntPtr.Zero) {
RegisterRelocationEnd(runLength);
}
runLength = UIntPtr.Zero;
}
sourceCursor += objectSize;
}
}
if (runLength != UIntPtr.Zero) {
RegisterRelocationEnd(runLength);
}
return destCursor;
}
private unsafe void SkipDestinationAreas(ref UIntPtr destPage,
UIntPtr destCursor,
ref UIntPtr destLimit,
UIntPtr sourceCursor)
{
UIntPtr cursorPage = PageTable.Page(destCursor);
UIntPtr sourcePage = PageTable.Page(sourceCursor);
if (cursorPage != sourcePage) {
UIntPtr destPageLimit = PageTable.PagePad(destCursor);
if (destPageLimit != destCursor) {
cursorPage++;
}
VTable.Assert(PageTable.PageAligned(destLimit));
UIntPtr limitPage = PageTable.Page(destLimit);
while (destPage < sourcePage) {
if (cursorPage < limitPage) {
this.RegisterSkippedPages(cursorPage, limitPage);
}
do {
destPage++;
} while (!IsMyZombiePage(destPage));
cursorPage = destPage;
do {
destPage++;
} while (IsMyZombiePage(destPage));
limitPage = destPage;
}
destLimit = PageTable.PageAddr(limitPage);
VTable.Assert(destPage > sourcePage);
VTable.Assert(cursorPage <= sourcePage);
if (cursorPage < sourcePage) {
this.RegisterSkippedPages(cursorPage, sourcePage);
cursorPage = sourcePage;
}
InteriorPtrTable.ClearFirst(cursorPage, destPage);
InteriorPtrTable.SetFirst(sourceCursor + PreHeader.Size);
if (GC.remsetType == RemSetType.Cards) {
OffsetTable.ClearLast(PageTable.PageAddr(cursorPage),
PageTable.PageAddr(destPage)-1);
}
}
}
private unsafe void FindDestinationArea(ref UIntPtr destPage,
ref UIntPtr destCursor,
ref UIntPtr destLimit,
UIntPtr objectSize,
PageType destGeneration)
{
VTable.Assert(IsValidGeneration((int)destGeneration));
UIntPtr cursorPage = PageTable.Page(destCursor);
UIntPtr limitPage = PageTable.Page(destLimit);
UIntPtr pageAddr = PageTable.PagePad(destCursor);
UIntPtr testPage = limitPage;
UIntPtr endTestPage = PageTable.PageCount(destCursor+objectSize);
if (destCursor > UIntPtr.Zero &&
IsMyZombiePage(PageTable.Page(destCursor-1))) {
VTable.Assert(destPage == limitPage);
while (IsMyZombiePage(testPage) ||
(testPage < endTestPage &&
(PageTable.IsUnusedPage(testPage)))) {
testPage++;
}
if (testPage >= endTestPage) {
// We can expand the current region
endTestPage = testPage;
VTable.Assert(PageTable.PageAligned(destLimit));
InteriorPtrTable.ClearFirst(limitPage, testPage);
if (GC.remsetType == RemSetType.Cards) {
OffsetTable.ClearLast(PageTable.PageAddr(limitPage),
PageTable.PageAddr(testPage)-1);
}
while (limitPage != endTestPage) {
VTable.Assert(PageTable.IsUnusedPage(destPage));
do {
destPage++;
} while (destPage < endTestPage &&
PageTable.IsUnusedPage(destPage));
bool fCleanPages = true;
bool status =
PageManager.TryReserveUnusedPages(null, limitPage,
destPage-limitPage,
nurseryGeneration,
ref fCleanPages);
VTable.Assert(status);
MakeZombiePages(limitPage, destPage - limitPage,
destGeneration);
while (destPage < endTestPage &&
IsMyZombiePage(destPage)) {
destPage++;
}
limitPage = destPage;
}
destLimit = PageTable.PageAddr(limitPage);
return;
}
}
if (destCursor != pageAddr) {
cursorPage++;
}
if (cursorPage != limitPage) {
this.RegisterSkippedPages(cursorPage, limitPage);
}
// Find new region big enough to contain object
UIntPtr neededPages = PageTable.PageCount(objectSize);
UIntPtr prefixPage;
while (true) {
do {
destPage++;
} while (!IsMyZombiePage(destPage));
cursorPage = destPage;
prefixPage = cursorPage;
do {
destPage++;
} while (IsMyZombiePage(destPage));
limitPage = destPage;
if (neededPages <= limitPage - cursorPage) {
break;
}
// Check for following unused pages
endTestPage = cursorPage + neededPages;
VTable.Assert(endTestPage <= PageTable.pageTableCount);
while (destPage < endTestPage &&
(PageTable.IsUnusedPage(destPage) ||
(IsMyZombiePage(destPage)))) {
destPage++;
}
if (destPage == endTestPage) {
break;
}
// Check for preceding unused pages
if (destPage >= neededPages) {
endTestPage = destPage - neededPages;
prefixPage = cursorPage - 1;
while (prefixPage >= UIntPtr.Zero &&
PageTable.IsUnusedPage(prefixPage)) {
prefixPage--;
}
prefixPage++;
if (prefixPage == endTestPage) {
break;
}
}
// Register any skipped regions of pages
this.RegisterSkippedPages(cursorPage, limitPage);
while (limitPage < destPage) {
VTable.Assert(PageTable.IsUnusedPage(limitPage));
do {
limitPage++;
} while (limitPage < destPage &&
PageTable.IsUnusedPage(limitPage));
cursorPage = limitPage;
while (limitPage < destPage && IsMyZombiePage(limitPage)) {
limitPage++;
}
if (cursorPage != limitPage) {
this.RegisterSkippedPages(cursorPage, limitPage);
}
}
}
// We found an area big enough. Commit the pre- and
// postfix areas of unused pages
if (prefixPage != cursorPage) {
bool fCleanPages = true;
bool status =
PageManager.TryReserveUnusedPages(null, prefixPage,
cursorPage-prefixPage,
nurseryGeneration,
ref fCleanPages);
VTable.Assert(status);
MakeZombiePages(prefixPage, cursorPage - prefixPage,
destGeneration);
}
while (destPage != limitPage) {
// Mark the region of unused pages as fromspace
UIntPtr unusedPage = limitPage;
VTable.Assert(PageTable.IsUnusedPage(unusedPage));
do {
unusedPage++;
} while (unusedPage < destPage &&
PageTable.IsUnusedPage(unusedPage));
bool fCleanPages = true;
bool status =
PageManager.TryReserveUnusedPages(null, limitPage,
unusedPage-limitPage,
nurseryGeneration,
ref fCleanPages);
VTable.Assert(status);
MakeZombiePages(limitPage, unusedPage - limitPage,
destGeneration);
// Skip any sections of pages already marked as fromspace
limitPage = unusedPage;
while (limitPage < destPage && IsMyZombiePage(limitPage)) {
limitPage++;
}
}
destCursor = PageTable.PageAddr(prefixPage);
destLimit = PageTable.PageAddr(limitPage);
// Take ownership of the new pages
InteriorPtrTable.ClearFirst(prefixPage, limitPage);
InteriorPtrTable.SetFirst(destCursor + PreHeader.Size);
if (GC.remsetType == RemSetType.Cards) {
OffsetTable.ClearLast(PageTable.PageAddr(prefixPage),
PageTable.PageAddr(limitPage)-1);
}
}
private void RegisterSkippedPages(UIntPtr startPage,
UIntPtr limitPage)
{
this.skippedPageQueue.Write(startPage);
this.skippedPageQueue.Write(limitPage);
}
private void RegisterRelocationStart(UIntPtr sourceAddress,
UIntPtr destinationAddress)
{
this.relocationQueue.Write(sourceAddress);
this.relocationQueue.Write(destinationAddress);
}
private void RegisterRelocationEnd(UIntPtr runLength)
{
this.relocationQueue.Write(runLength);
}
private unsafe void CompactHeapObjects(UIntPtr previousEnd) {
while (!this.relocationQueue.IsEmpty) {
UIntPtr sourceAddress = this.relocationQueue.Read();
UIntPtr destinationAddress = this.relocationQueue.Read();
UIntPtr runLength = this.relocationQueue.Read();
if (previousEnd != destinationAddress) {
VTable.Assert(previousEnd < destinationAddress);
if (PageTable.Page(destinationAddress) !=
PageTable.Page(previousEnd+PreHeader.Size)) {
if (!PageTable.PageAligned(previousEnd)) {
UIntPtr pageLimit = PageTable.PagePad(previousEnd);
BumpAllocator.WriteUnusedMarker(previousEnd);
previousEnd += UIntPtr.Size;
Util.MemClear(previousEnd,
pageLimit - previousEnd);
}
if (!PageTable.PageAligned(destinationAddress)) {
// This only happens before pinned objects and
// large objects
UIntPtr start =
PageTable.PageAlign(destinationAddress);
VTable.Assert(previousEnd <= start);
while (start < destinationAddress) {
Allocator.WriteAlignment(start);
start += UIntPtr.Size;
}
}
UIntPtr objAddr = destinationAddress + PreHeader.Size;
InteriorPtrTable.SetFirst(objAddr);
} else {
VTable.Assert(previousEnd < destinationAddress);
UIntPtr start = previousEnd;
while (start < destinationAddress) {
Allocator.WriteAlignment(start);
start += UIntPtr.Size;
}
}
}
Util.MemCopy(destinationAddress, sourceAddress, runLength);
previousEnd = destinationAddress + runLength;
}
// Zero out the end of the allocation page
if (!PageTable.PageAligned(previousEnd)) {
UIntPtr pageLimit = PageTable.PagePad(previousEnd);
Util.MemClear(previousEnd, pageLimit - previousEnd);
}
this.relocationQueue.Cleanup(true);
}
private void CompactPhaseCleanup(Thread currentThread,
PageType generation,
UIntPtr newLimitPtr)
{
VTable.Assert(IsValidGeneration((int)generation));
registerThreadReferenceVisitor.Cleanup();
// Free up skipped pages
while (!this.skippedPageQueue.IsEmpty) {
UIntPtr start = this.skippedPageQueue.Read();
UIntPtr finish = this.skippedPageQueue.Read();
InteriorPtrTable.ClearFirst(start, finish);
PageManager.FreePageRange(start, finish);
if (GC.remsetType == RemSetType.Cards) {
OffsetTable.ClearLast(PageTable.PageAddr(start),
PageTable.PageAddr(finish)-1);
}
}
this.skippedPageQueue.Cleanup(true);
// Release the queue standby pages
UnmanagedPageList.ReleaseStandbyPages();
// Update the ownership information for the copied data
PageType destGeneration =
(generation == MAX_GENERATION) ?
MAX_GENERATION :
(PageType) (generation + 1);
UIntPtr limitPage =
PageTable.Page(PageTable.PagePad(newLimitPtr));
for (UIntPtr i = UIntPtr.Zero; i < limitPage; i++) {
if (IsMyZombiePage(i)) {
PageTable.SetType(i, (PageType)destGeneration);
}
}
}
}
}