// // 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; 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(). #if SINGULARITY [CLSCompliant(false)] #endif 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; } } } }