2008-11-17 18:29:00 -05:00
|
|
|
//
|
|
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
//
|
|
|
|
|
2008-03-05 09:52:00 -05:00
|
|
|
/*******************************************************************/
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
internal delegate
|
|
|
|
void ProfileRootsDelegate(NonNullReferenceVisitor visitor);
|
|
|
|
|
|
|
|
internal delegate
|
|
|
|
void ProfileObjectsDelegate(SegregatedFreeList.ObjectVisitor visitor);
|
|
|
|
|
|
|
|
// Receive notifications from the GC and deliver them to a profiler. This class
|
|
|
|
// should be subtyped and then an instance associated with the GC via
|
|
|
|
// System.GC.SetProfiler().
|
2008-11-17 18:29:00 -05:00
|
|
|
#if SINGULARITY
|
2008-03-05 09:52:00 -05:00
|
|
|
[CLSCompliant(false)]
|
2008-11-17 18:29:00 -05:00
|
|
|
#endif
|
2008-03-05 09:52:00 -05:00
|
|
|
public abstract class GCProfiler
|
|
|
|
{
|
|
|
|
public GCProfiler()
|
|
|
|
{
|
|
|
|
rootVisitor = new RootVisitor(this);
|
|
|
|
objectVisitor = new ObjectVisitor(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
// To limit the size of the TCB, we make a strict separation between two APIs.
|
|
|
|
// The trusted API is the one between the GC and this base GCProfiler. The
|
|
|
|
// untrusted API is the one between this base GCProfiler and any subtypes of
|
|
|
|
// this profiler that actually generate useful profiles.
|
|
|
|
|
|
|
|
// Trusted API between this base and the GC
|
|
|
|
internal void NotifyShutdown()
|
|
|
|
{
|
|
|
|
Shutdown();
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void NotifyPreGC(int generation)
|
|
|
|
{
|
|
|
|
PreGC(generation);
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void NotifyPostGC(ProfileRootsDelegate profileRoots,
|
|
|
|
ProfileObjectsDelegate profileObjects)
|
|
|
|
{
|
|
|
|
this.profileRoots = profileRoots;
|
|
|
|
this.profileObjects = profileObjects;
|
|
|
|
PostGC();
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void NotifyAllocation(UIntPtr objAddr, Type type, UIntPtr size)
|
|
|
|
{
|
|
|
|
Allocation(objAddr, type, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Untrusted API between this base and the concrete profiler subtype. The
|
|
|
|
// concrete subtype implements this.
|
|
|
|
protected abstract void Shutdown();
|
|
|
|
protected abstract void PreGC(int generation);
|
|
|
|
protected abstract void PostGC();
|
|
|
|
protected abstract void Allocation(UIntPtr objAddr, Type type, UIntPtr size);
|
|
|
|
|
|
|
|
protected abstract void ScanOneRoot(UIntPtr objectAddress);
|
|
|
|
|
|
|
|
protected abstract void StartScanOneObject(UIntPtr objectAddress, Type type, UIntPtr size);
|
|
|
|
protected abstract void ScanOneObjectField(UIntPtr objectAddress);
|
|
|
|
protected abstract void EndScanOneObject();
|
|
|
|
|
|
|
|
// API for the concrete subtype to call back on the abstract base. We must
|
|
|
|
// not accept UIntPtrs, etc. from the untrusted subtype and operate on them
|
|
|
|
// here!
|
|
|
|
|
|
|
|
protected void ScanRoots()
|
|
|
|
{
|
|
|
|
profileRoots(rootVisitor);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected void ScanObjects()
|
|
|
|
{
|
|
|
|
profileObjects(objectVisitor);
|
|
|
|
}
|
|
|
|
|
|
|
|
// And the rest is implementation detail.
|
|
|
|
|
|
|
|
private RootVisitor rootVisitor;
|
|
|
|
private ObjectVisitor objectVisitor;
|
|
|
|
|
|
|
|
private ProfileRootsDelegate profileRoots;
|
|
|
|
private ProfileObjectsDelegate profileObjects;
|
|
|
|
|
|
|
|
// For one object, visit all the references it contains
|
|
|
|
internal class OneObjectVisitor : NonNullReferenceVisitor
|
|
|
|
{
|
|
|
|
private GCProfiler profiler;
|
|
|
|
|
|
|
|
public OneObjectVisitor(GCProfiler profiler)
|
|
|
|
{
|
|
|
|
this.profiler = profiler;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The NonNullReferenceVisitor contract:
|
|
|
|
internal unsafe override void Visit(UIntPtr *location)
|
|
|
|
{
|
|
|
|
profiler.ScanOneObjectField(*location);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Visit all the roots
|
|
|
|
internal class RootVisitor : NonNullReferenceVisitor
|
|
|
|
{
|
|
|
|
private GCProfiler profiler;
|
|
|
|
|
|
|
|
public RootVisitor(GCProfiler profiler)
|
|
|
|
{
|
|
|
|
this.profiler = profiler;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The NonNullReferenceVisitor contract:
|
|
|
|
internal unsafe override void Visit(UIntPtr *location)
|
|
|
|
{
|
|
|
|
profiler.ScanOneRoot(*location);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Visit all the objects in the heap
|
|
|
|
internal class ObjectVisitor : SegregatedFreeList.ObjectVisitor
|
|
|
|
{
|
|
|
|
private GCProfiler profiler;
|
|
|
|
private OneObjectVisitor oneObjectVisitor;
|
|
|
|
|
|
|
|
public ObjectVisitor(GCProfiler profiler)
|
|
|
|
{
|
|
|
|
this.profiler = profiler;
|
|
|
|
oneObjectVisitor = new OneObjectVisitor(profiler);
|
|
|
|
}
|
|
|
|
|
|
|
|
// The ObjectVisitor contract:
|
|
|
|
// Must return the size of the visited object.
|
|
|
|
internal override UIntPtr Visit(Object obj)
|
|
|
|
{
|
|
|
|
UIntPtr size = ObjectLayout.Sizeof(obj);
|
|
|
|
UIntPtr objectAddress = Magic.addressOf(obj);
|
|
|
|
profiler.StartScanOneObject(objectAddress, obj.GetType(), size);
|
|
|
|
oneObjectVisitor.VisitReferenceFields(obj);
|
|
|
|
profiler.EndScanOneObject();
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|