631 lines
26 KiB
C#
631 lines
26 KiB
C#
//
|
|
// 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
|
|
using Microsoft.Singularity;
|
|
#if SINGULARITY_PROCESS
|
|
using Microsoft.Singularity.V1.Services;
|
|
using Microsoft.Singularity.V1.Threads;
|
|
#else
|
|
using Microsoft.Singularity.Memory;
|
|
#endif
|
|
#endif
|
|
|
|
[NoCCtor]
|
|
internal class MarkSweepCollector: StopTheWorldCollector
|
|
{
|
|
#if OS_WINCE // || ISA_ARM
|
|
private const uint InitialTrigger = (uint)(1 << 20);
|
|
private const uint MinTrigger = (uint)(1 << 20);
|
|
private const uint MaxTrigger = (uint)(1 << 22);
|
|
#else
|
|
private const uint InitialTrigger = (uint)(1 << 24);
|
|
private const uint MinTrigger = (uint)(1 << 24);
|
|
private const uint MaxTrigger = (uint)(1 << 26);
|
|
#endif
|
|
|
|
private static UIntPtr collectionTrigger;
|
|
|
|
internal static MarkSweepCollector instance;
|
|
|
|
// Visitor instances used for marking objects
|
|
private static MarkReferenceVisitor markReferenceVisitor;
|
|
private static MarkAndProcessReferenceVisitor markAndProcessReferenceVisitor;
|
|
private static UpdateReferenceVisitor updateReferenceVisitor;
|
|
private static ThreadMarkReferenceVisitor threadMarkReferenceVisitor;
|
|
private static SweepVisitor sweepVisitor;
|
|
|
|
private static int traceTime;
|
|
private static int sweepTime;
|
|
private static int numCollections;
|
|
|
|
private MarkSweepCollector() {
|
|
}
|
|
|
|
public static new void Initialize() {
|
|
StopTheWorldCollector.Initialize();
|
|
SegregatedFreeList.Initialize();
|
|
// instance = new MarkSweepCollector();
|
|
MarkSweepCollector.instance = (MarkSweepCollector)
|
|
BootstrapMemory.Allocate(typeof(MarkSweepCollector));
|
|
// markReferenceVisitor = new MarkReferenceVisitor();
|
|
markReferenceVisitor = (MarkReferenceVisitor)
|
|
BootstrapMemory.Allocate(typeof(MarkReferenceVisitor));
|
|
// markAndProcessReferenceVisitor = new MarkAndProcessReferenceVisitor();
|
|
markAndProcessReferenceVisitor = (MarkAndProcessReferenceVisitor)
|
|
BootstrapMemory.Allocate(typeof(MarkAndProcessReferenceVisitor));
|
|
// updateReferenceVisitor = new UpdateReferenceVisitor();
|
|
updateReferenceVisitor = (UpdateReferenceVisitor)
|
|
BootstrapMemory.Allocate(typeof(UpdateReferenceVisitor));
|
|
// threadMarkReferenceVisitor = new ThreadMarkReferenceVisitor();
|
|
threadMarkReferenceVisitor = (ThreadMarkReferenceVisitor)
|
|
BootstrapMemory.Allocate(typeof(ThreadMarkReferenceVisitor));
|
|
// sweepVisitor = new SweepVisitor();
|
|
sweepVisitor = (SweepVisitor)
|
|
BootstrapMemory.Allocate(typeof(SweepVisitor));
|
|
collectionTrigger = (UIntPtr) InitialTrigger;
|
|
}
|
|
|
|
// GCInterface methods
|
|
internal override bool IsOnTheFlyCollector {
|
|
get {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
internal override void CollectStopped(int currentThreadIndex,
|
|
int generation)
|
|
{
|
|
#if SINGULARITY
|
|
#if DEBUG
|
|
#if THREAD_TIME_ACCOUNTING
|
|
UIntPtr preGcTotalBytes = SegregatedFreeList.TotalBytes;
|
|
#endif
|
|
DebugStub.WriteLine("~~~~~ Start MarkSweep Cleanup [data={0:x8}, pid={1:x3}]",
|
|
__arglist(SegregatedFreeList.TotalBytes,
|
|
PageTable.processTag >> 16));
|
|
#endif
|
|
#if SINGULARITY_KERNEL
|
|
#if THREAD_TIME_ACCOUNTING
|
|
TimeSpan ticks = Thread.CurrentThread.ExecutionTime;
|
|
TimeSpan ticks2 = SystemClock.KernelUpTime;
|
|
#else
|
|
TimeSpan ticks = SystemClock.KernelUpTime;
|
|
#endif
|
|
#elif SINGULARITY_PROCESS
|
|
#if THREAD_TIME_ACCOUNTING
|
|
TimeSpan ticks = ProcessService.GetThreadTime();
|
|
TimeSpan ticks2 = ProcessService.GetUpTime();
|
|
#else
|
|
TimeSpan ticks = ProcessService.GetUpTime();
|
|
#endif
|
|
#endif
|
|
#endif
|
|
int before=0;
|
|
if (VTable.enableGCTiming) {
|
|
before=Environment.TickCount;
|
|
}
|
|
if (GC.IsProfiling) {
|
|
GcProfiler.NotifyPreGC(MinGeneration);
|
|
// non-generational collector, so pretend Gen0
|
|
// Calls like ResurrectCandidates below can cause
|
|
// allocations and thus, potentially, profiler
|
|
// notifications. However, at that time the heap is
|
|
// damaged in the sense that VPtrs have bits OR-ed in
|
|
// for object marking. We do not want to accept
|
|
// profiling during this window.
|
|
//
|
|
// There is no synchronization issue with setting this
|
|
// flag because it will only be consulted by the
|
|
// thread that sets and resets it.
|
|
HeapDamaged = true;
|
|
}
|
|
// 1) Mark the live objects
|
|
CollectorStatistics.Event(GCEvent.TraceStart);
|
|
#if !VC
|
|
TryAllManager.PreGCHookTryAll();
|
|
#endif
|
|
MultiUseWord.PreGCHook(false /* don't use shadows */);
|
|
Finalizer.PrepareCollectFinalizers();
|
|
int countThreads =
|
|
CallStack.ScanStacks(threadMarkReferenceVisitor,
|
|
threadMarkReferenceVisitor);
|
|
Thread.VisitBootstrapData(markAndProcessReferenceVisitor);
|
|
#if SINGULARITY_KERNEL
|
|
Kernel.VisitSpecialData(markAndProcessReferenceVisitor);
|
|
#endif
|
|
MultiUseWord.VisitStrongRefs(markAndProcessReferenceVisitor,
|
|
false /* Don't use shadows */);
|
|
#if !VC
|
|
TryAllManager.VisitStrongRefs(markAndProcessReferenceVisitor);
|
|
#endif
|
|
StaticData.ScanStaticData(markAndProcessReferenceVisitor);
|
|
CollectorStatistics.Event(GCEvent.TraceSpecial);
|
|
WeakReference.Process(updateReferenceVisitor, true, true);
|
|
Finalizer.ResurrectCandidates(updateReferenceVisitor,
|
|
markAndProcessReferenceVisitor, true);
|
|
markReferenceVisitor.Cleanup();
|
|
UnmanagedPageList.ReleaseStandbyPages();
|
|
// 2) Sweep the garbage objects
|
|
int afterTrace=0;
|
|
if (VTable.enableGCTiming) {
|
|
afterTrace=Environment.TickCount;
|
|
}
|
|
CollectorStatistics.Event(GCEvent.SweepStart, TotalMemory);
|
|
WeakReference.Process(updateReferenceVisitor, true, false);
|
|
MultiUseWord.VisitWeakRefs(updateReferenceVisitor,
|
|
false /* Don't use shadows */);
|
|
#if !VC
|
|
TryAllManager.VisitWeakRefs(updateReferenceVisitor);
|
|
#endif
|
|
SegregatedFreeList.VisitAllObjects(sweepVisitor);
|
|
SegregatedFreeList.RecycleGlobalPages();
|
|
SegregatedFreeList.CommitFreedData();
|
|
CollectorStatistics.Event(GCEvent.SweepSpecial);
|
|
MultiUseWord.PostGCHook();
|
|
if (GC.IsProfiling) {
|
|
HeapDamaged = false;
|
|
// Allocations may occur inside the PostGCHook. Hopefully a
|
|
// sufficiently limited quantity that we don't recursively
|
|
// trigger a GC.
|
|
GcProfiler.NotifyPostGC(ProfileRoots, ProfileObjects);
|
|
}
|
|
Finalizer.ReleaseCollectFinalizers();
|
|
#if !VC
|
|
TryAllManager.PostGCHookTryAll();
|
|
#endif
|
|
CollectorStatistics.Event(GCEvent.CollectionComplete,
|
|
TotalMemory);
|
|
if (VTable.enableGCTiming) {
|
|
int after=Environment.TickCount;
|
|
numCollections++;
|
|
traceTime+=(afterTrace-before);
|
|
sweepTime+=(after-afterTrace);
|
|
}
|
|
// 3) Determine a new collection trigger
|
|
UIntPtr testTrigger = (UIntPtr) this.TotalMemory >> 2;
|
|
UIntPtr minTrigger = (UIntPtr) MinTrigger;
|
|
UIntPtr maxTrigger = (UIntPtr) MaxTrigger;
|
|
collectionTrigger =
|
|
(testTrigger > minTrigger) ?
|
|
(testTrigger < maxTrigger ?
|
|
testTrigger : maxTrigger) : minTrigger;
|
|
#if SINGULARITY
|
|
#if SINGULARITY_KERNEL
|
|
#if THREAD_TIME_ACCOUNTING
|
|
int procId = Thread.CurrentProcess.ProcessId;
|
|
ticks = Thread.CurrentThread.ExecutionTime - ticks;
|
|
ticks2 = SystemClock.KernelUpTime - ticks2;
|
|
#else
|
|
ticks = SystemClock.KernelUpTime - ticks;
|
|
#endif
|
|
//Thread.CurrentProcess.SetGcPerformanceCounters(ticks, (long) SegregatedFreeList.TotalBytes);
|
|
#elif SINGULARITY_PROCESS
|
|
#if THREAD_TIME_ACCOUNTING
|
|
ushort procId = ProcessService.GetCurrentProcessId();
|
|
ticks = ProcessService.GetThreadTime() - ticks;
|
|
ticks2 = ProcessService.GetUpTime() - ticks2;
|
|
#else
|
|
ticks = ProcessService.GetUpTime() - ticks;
|
|
#endif
|
|
//ProcessService.SetGcPerformanceCounters(ticks, (long) SegregatedFreeList.TotalBytes);
|
|
#endif
|
|
#if DEBUG
|
|
#if THREAD_TIME_ACCOUNTING
|
|
DebugStub.WriteLine("~~~~~ Finish MarkSweep Cleanup [data={0:x8}, diff={7:x8} pid={1:x3}, ms(Thread)={2:d6}, ms(System)={3:d6}, thds={4}, procId={5}, tid={6}]",
|
|
__arglist(SegregatedFreeList.TotalBytes,
|
|
PageTable.processTag >> 16,
|
|
ticks.Milliseconds,
|
|
ticks2.Milliseconds,
|
|
countThreads,
|
|
procId,
|
|
Thread.GetCurrentThreadIndex(),
|
|
preGcTotalBytes - SegregatedFreeList.TotalBytes
|
|
));
|
|
#else
|
|
DebugStub.WriteLine("~~~~~ Finish MarkSweep Cleanup [data={0:x8}, pid={1:x3}, ms={2:d6}, thds={3}]",
|
|
__arglist(SegregatedFreeList.TotalBytes,
|
|
PageTable.processTag >> 16,
|
|
ticks.Milliseconds,
|
|
countThreads));
|
|
#endif
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
internal override int CollectionGeneration(int genRequest)
|
|
{
|
|
return MinGeneration;
|
|
}
|
|
|
|
[Inline]
|
|
protected override void CreateObject(Object obj,
|
|
VTable vtable,
|
|
Thread currentThread)
|
|
{
|
|
base.CreateObject(obj, vtable, currentThread);
|
|
ProfileAllocation(obj);
|
|
}
|
|
|
|
[Inline]
|
|
internal override UIntPtr AllocateObjectMemory(UIntPtr numBytes,
|
|
uint alignment,
|
|
Thread currentThread)
|
|
{
|
|
UIntPtr resultAddr =
|
|
SegregatedFreeList.AllocateFast(currentThread,
|
|
numBytes, alignment);
|
|
if (resultAddr == UIntPtr.Zero) {
|
|
resultAddr = this.AllocateObjectMemorySlow(numBytes, alignment,
|
|
currentThread);
|
|
}
|
|
return resultAddr;
|
|
}
|
|
|
|
[NoInline]
|
|
private UIntPtr AllocateObjectMemorySlow(UIntPtr numBytes,
|
|
uint alignment,
|
|
Thread currentThread)
|
|
{
|
|
if (NewBytesSinceGCExceeds(collectionTrigger) &&
|
|
GC.allocationGCInhibitCount == 0) {
|
|
//REVIEW: This actually happens after the trigger...
|
|
GC.InvokeCollection(currentThread);
|
|
}
|
|
return SegregatedFreeList.AllocateSlow(currentThread,
|
|
numBytes, alignment);
|
|
}
|
|
|
|
internal override int GetGeneration(Object obj) {
|
|
return MinGeneration;
|
|
}
|
|
|
|
internal override int MaxGeneration {
|
|
get { return (int)PageType.Owner0; }
|
|
}
|
|
|
|
internal override int MinGeneration {
|
|
get { return (int)PageType.Owner0; }
|
|
}
|
|
|
|
internal override long TotalMemory {
|
|
get {
|
|
return (long)SegregatedFreeList.TotalBytes;
|
|
#if false
|
|
UIntPtr pageCount = UIntPtr.Zero;
|
|
for (UIntPtr i=UIntPtr.Zero; i<PageTable.pageTableCount; i++) {
|
|
if (PageTable.IsGcPage(i) && PageTable.IsMyPage(i)) {
|
|
pageCount++;
|
|
}
|
|
}
|
|
return (long) PageTable.RegionSize(pageCount);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
internal override void EnableHeap()
|
|
{
|
|
}
|
|
|
|
internal override void DestructHeap() {
|
|
base.DestructHeap();
|
|
if (VTable.enableFinalGCTiming) {
|
|
VTable.DebugPrint("total trace time = ");
|
|
VTable.DebugPrint((long) traceTime);
|
|
VTable.DebugPrint("\n");
|
|
VTable.DebugPrint("total stw time = ");
|
|
VTable.DebugPrint((long) (traceTime+sweepTime));
|
|
VTable.DebugPrint("\n");
|
|
VTable.DebugPrint("total sweep time = ");
|
|
VTable.DebugPrint((long) sweepTime);
|
|
VTable.DebugPrint("\n");
|
|
VTable.DebugPrint("num traces = ");
|
|
VTable.DebugPrint((long) numCollections);
|
|
VTable.DebugPrint("\n");
|
|
VTable.DebugPrint("num stw = ");
|
|
VTable.DebugPrint((long) numCollections);
|
|
VTable.DebugPrint("\n");
|
|
VTable.DebugPrint("num sweeps = ");
|
|
VTable.DebugPrint((long) numCollections);
|
|
VTable.DebugPrint("\n");
|
|
}
|
|
if (GC.IsProfiling) {
|
|
GcProfiler.NotifyShutdown();
|
|
}
|
|
}
|
|
|
|
internal override void VerifyHeap(bool beforeCollection) {
|
|
Verifier.segregatedFreeListVerifier.VerifyHeap();
|
|
}
|
|
|
|
internal override UIntPtr FindObjectAddr(UIntPtr interiorPtr) {
|
|
return SegregatedFreeList.Find(interiorPtr);
|
|
}
|
|
|
|
internal override
|
|
void VisitObjects(ObjectLayout.ObjectVisitor objectVisitor,
|
|
UIntPtr lowAddr, UIntPtr highAddr)
|
|
{
|
|
VTable.Assert(PageTable.PageAligned(lowAddr));
|
|
VTable.Assert(PageTable.PageAligned(highAddr));
|
|
UIntPtr lowPage = PageTable.Page(lowAddr);
|
|
UIntPtr highPage = PageTable.Page(highAddr);
|
|
SegregatedFreeList.VisitObjects(lowPage, highPage, objectVisitor);
|
|
}
|
|
|
|
internal override void NewThreadNotification(Thread newThread,
|
|
bool initial)
|
|
{
|
|
base.NewThreadNotification(newThread, initial);
|
|
SegregatedFreeList.NewThreadNotification(newThread, initial);
|
|
}
|
|
|
|
internal override void DeadThreadNotification(Thread deadThread)
|
|
{
|
|
SegregatedFreeList.DeadThreadNotification(deadThread);
|
|
base.DeadThreadNotification(deadThread);
|
|
}
|
|
|
|
// This is a quick-and-dirty check of whether something is an object.
|
|
// All objects have a vtable. A VTable is an object that itself has a
|
|
// vtable. All VTable objects have the same vtable, which we rely
|
|
// upon for this fast check. This predicate will gracefully fail in
|
|
// corrupted memory situations where a real type check will cause a
|
|
// catastrophic failure.
|
|
private static bool IsPossiblyObject(Object obj)
|
|
{
|
|
// First, check for a null reference
|
|
if (obj == null) { return false; }
|
|
// Second, check for a null vtable
|
|
VTable vtable = obj.GcUnmarkedVTable;
|
|
if (vtable == null) { return false; }
|
|
// Third, check for a null vtable of the vtable
|
|
VTable vtableVtable = vtable.GcUnmarkedVTable;
|
|
if (vtableVtable == null) { return false; }
|
|
// Finally, rely on the invariant that all vtables have the
|
|
// same vtable.
|
|
return (vtableVtable == vtableVtable.GcUnmarkedVTable);
|
|
}
|
|
|
|
// Routines for updating pointers to new locations of marked objects
|
|
// No objects are resurrected using this mechanism
|
|
// As this is mark sweep the value does not need to be updated.
|
|
private class UpdateReferenceVisitor: NonNullReferenceVisitor
|
|
{
|
|
|
|
internal unsafe override void Visit(UIntPtr *loc) {
|
|
UIntPtr addr = *loc;
|
|
// Ignore pointers out of our memory area
|
|
if (PageTable.IsForeignAddr(addr)) {
|
|
return;
|
|
}
|
|
UIntPtr page = PageTable.Page(addr);
|
|
PageType pageType = PageTable.Type(page);
|
|
if (!PageTable.IsGcPage(pageType)) {
|
|
VTable.Assert((PageTable.IsNonGcPage(pageType) &&
|
|
PageTable.IsMyPage(page)) ||
|
|
PageTable.IsStackPage(pageType));
|
|
return;
|
|
}
|
|
VTable.Assert(PageTable.IsMyPage(page));
|
|
Object obj = Magic.fromAddress(addr);
|
|
VTable.Assert(IsPossiblyObject(obj), "Bad Object/VTable");
|
|
if (obj.GcMark() == UIntPtr.Zero) {
|
|
// The object was not live
|
|
*loc = UIntPtr.Zero;
|
|
}
|
|
}
|
|
}
|
|
|
|
private class MarkReferenceVisitor : NonNullReferenceVisitor
|
|
{
|
|
|
|
private static UIntPtrStack workList;
|
|
|
|
[Inline]
|
|
protected override unsafe
|
|
void Filter(UIntPtr *location, ref ObjectDescriptor objDesc)
|
|
{
|
|
if (*location!=UIntPtr.Zero) {
|
|
this.Visit(location);
|
|
}
|
|
}
|
|
|
|
[Inline]
|
|
internal unsafe override void Visit(UIntPtr *loc) {
|
|
UIntPtr addr = *loc;
|
|
// Ignore pointers out of our memory area
|
|
if (PageTable.IsForeignAddr(addr)) {
|
|
return;
|
|
}
|
|
UIntPtr page = PageTable.Page(addr);
|
|
PageType pageType = PageTable.Type(page);
|
|
if (!PageTable.IsGcPage(pageType)) {
|
|
VTable.Assert((PageTable.IsNonGcPage(pageType) &&
|
|
PageTable.IsMyPage(page)) ||
|
|
PageTable.IsStackPage(pageType));
|
|
return;
|
|
}
|
|
VTable.Assert(PageTable.IsMyPage(page));
|
|
Object obj = Magic.fromAddress(addr);
|
|
VTable.Assert(IsPossiblyObject(obj), "Bad object/vtable");
|
|
if (obj.GcMark((UIntPtr)1)) {
|
|
// We changed the color of the object, so we
|
|
// have to mark the objects reachable from the fields
|
|
workList.Write(addr);
|
|
}
|
|
}
|
|
|
|
internal void ProcessScheduledObjects() {
|
|
while (!workList.IsEmpty) {
|
|
UIntPtr addr = workList.Read();
|
|
Object obj = Magic.fromAddress(addr);
|
|
this.VisitReferenceFields(obj);
|
|
}
|
|
}
|
|
|
|
internal void Cleanup() {
|
|
VTable.Assert(workList.IsEmpty);
|
|
workList.Cleanup(true);
|
|
}
|
|
|
|
[Inline]
|
|
internal override UIntPtr VisitReferenceFields(Object obj)
|
|
{
|
|
return this.VisitReferenceFields(Magic.addressOf(obj),
|
|
obj.GcUnmarkedVTable);
|
|
}
|
|
|
|
[ManualRefCounts]
|
|
[Inline]
|
|
internal override UIntPtr VisitReferenceFields(UIntPtr objectBase,
|
|
VTable vtable)
|
|
{
|
|
ObjectDescriptor objDesc =
|
|
new ObjectDescriptor(vtable, objectBase);
|
|
return VisitReferenceFieldsTemplate(ref objDesc);
|
|
}
|
|
}
|
|
|
|
private class MarkAndProcessReferenceVisitor : NonNullReferenceVisitor
|
|
{
|
|
[Inline]
|
|
internal unsafe override void Visit(UIntPtr *loc) {
|
|
markReferenceVisitor.Visit(loc);
|
|
markReferenceVisitor.ProcessScheduledObjects();
|
|
}
|
|
|
|
[Inline]
|
|
internal override UIntPtr VisitReferenceFields(Object obj)
|
|
{
|
|
return this.VisitReferenceFields(Magic.addressOf(obj),
|
|
obj.GcUnmarkedVTable);
|
|
}
|
|
}
|
|
|
|
private class ThreadMarkReferenceVisitor : NonNullReferenceVisitor
|
|
{
|
|
|
|
internal unsafe override void Visit(UIntPtr *loc) {
|
|
UIntPtr addr = *loc;
|
|
// Ignore pointers out of our memory area
|
|
if (PageTable.IsForeignAddr(addr)) {
|
|
return;
|
|
}
|
|
UIntPtr page = PageTable.Page(addr);
|
|
if (!PageTable.IsMyGcPage(page)) {
|
|
PageType pageType = PageTable.Type(page);
|
|
#if SINGULARITY_PROCESS
|
|
// We have to allow reference pointers to the
|
|
// ThreadContext, which lives in the kernel space.
|
|
VTable.Assert((PageTable.IsNonGcPage(pageType) &&
|
|
PageTable.IsMyPage(page)) ||
|
|
PageTable.IsStackPage(pageType) ||
|
|
PageTable.IsSharedPage(pageType) ||
|
|
(PageTable.IsGcPage(pageType) &&
|
|
PageTable.IsKernelPage(page)));
|
|
#else
|
|
VTable.Assert((PageTable.IsNonGcPage(pageType) &&
|
|
PageTable.IsMyPage(page))||
|
|
PageTable.IsStackPage(pageType) ||
|
|
PageTable.IsSharedPage(pageType));
|
|
#endif
|
|
return;
|
|
}
|
|
UIntPtr objectAddr = SegregatedFreeList.Find(addr);
|
|
markAndProcessReferenceVisitor.Visit(&objectAddr);
|
|
}
|
|
|
|
}
|
|
|
|
private class SweepVisitor : SegregatedFreeList.ObjectVisitor
|
|
{
|
|
|
|
private SegregatedFreeList.TempList tempList;
|
|
|
|
internal override void VisitSmall(Object obj, UIntPtr memAddr)
|
|
{
|
|
if (!obj.GcMark(UIntPtr.Zero)) {
|
|
// We did not change the color of the object back
|
|
// to unmarked, so we are responsible for freeing it.
|
|
tempList.Add(memAddr);
|
|
}
|
|
}
|
|
|
|
internal override void VisitSmallPageEnd() {
|
|
SegregatedFreeList.FreeSmallList(ref tempList);
|
|
}
|
|
|
|
internal override UIntPtr VisitLarge(Object obj)
|
|
{
|
|
UIntPtr objectSize =
|
|
ObjectLayout.ObjectSize(Magic.addressOf(obj),
|
|
obj.GcUnmarkedVTable);
|
|
if (!obj.GcMark(UIntPtr.Zero)) {
|
|
// We did not change the color of the object back
|
|
// to unmarked, so we are responsible for freeing it.
|
|
SegregatedFreeList.FreeLarge(obj);
|
|
}
|
|
// REVIEW: Should we return a real size here?
|
|
return objectSize;
|
|
}
|
|
|
|
}
|
|
|
|
private class VerifyVisitor : ObjectLayout.ObjectVisitor {
|
|
|
|
internal static VerifyVisitor visitor = new VerifyVisitor();
|
|
|
|
internal override UIntPtr Visit(Object obj) {
|
|
UIntPtr size;
|
|
if (obj.GcMark() != UIntPtr.Zero) {
|
|
// The object has the mark color, so it should only
|
|
// reference other objects with the mark color.
|
|
size = VerifyMarkVisitor.visitor.VisitReferenceFields(obj);
|
|
} else {
|
|
size = ObjectLayout.Sizeof(obj);
|
|
}
|
|
return size;
|
|
}
|
|
|
|
}
|
|
|
|
private class VerifyMarkVisitor : NonNullReferenceVisitor {
|
|
|
|
internal static VerifyMarkVisitor visitor =new VerifyMarkVisitor();
|
|
|
|
internal unsafe override void Visit(UIntPtr *loc) {
|
|
UIntPtr addr = *loc;
|
|
// Ignore pointers out of our memory area
|
|
if (PageTable.IsForeignAddr(addr)) {
|
|
return;
|
|
}
|
|
UIntPtr page = PageTable.Page(addr);
|
|
PageType pageType = PageTable.Type(page);
|
|
if (PageTable.IsGcPage(pageType)) {
|
|
Object obj = Magic.fromAddress(addr);
|
|
VTable.Assert(obj.GcMark() != UIntPtr.Zero);
|
|
VTable.Assert(PageTable.IsMyPage(page));
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|