singrdk/base/Imported/Bartok/runtime/shared/System/GC.cs

702 lines
25 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 the Bartok Depot and propagated to the Singularity Depot. */
/*******************************************************************/
namespace System
{
using Microsoft.Bartok.Runtime;
using System.GCs;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
#if SINGULARITY
using Microsoft.Singularity;
#endif
// The GC has only static members and doesn't require the serializable
// keyword.
[CCtorIsRunDuringStartup]
[RequiredByBartok]
[AccessedByRuntime("referenced in {hal,brt}{asm,forgc}.asm")]
#if SINGULARITY
[CLSCompliant(false)]
#endif
public sealed class GC
{
// This is a compiler intrinsic whose value is controlled by
// /StageControl.HeapSizeConfigurable.
internal static extern bool HeapSizeConfigurable {
[Intrinsic]
get;
}
// The *initial* maximum heap size, used if
// HeapSizeConfigurable is true.
internal static int MaxHeapPages = 96;
// Bartok runtime "magic" function
// It saves the callee-save registers in a transition record and
// calls System.GC.CollectBody(thread, generation)
[ManualRefCounts]
[MethodImpl(MethodImplOptions.InternalCall)]
[GCAnnotation(GCOption.GCFRIEND)]
[StackBound(128)]
private static extern void CollectBodyTransition(Thread thread,
int generation);
#if SINGULARITY_KERNEL
internal static uint perfCounter = 6;
#else
internal static uint perfCounter = 5;
#endif
[TrustedNonNull]
internal static Collector installedGC;
private static bool isProfiling;
// Flag to indicate to the collector that it should perform a
// retrace in a stop-the-world mode after finishing a mostly
// normal trace. This allows us to measure the cost of various
// barriers by disabling them. Currently only recognized by CONCMS.
internal static bool enableSTWRetrace;
[RequiredByBartok]
private static Object dummyGlobal; // Used by KeepAlive
[AccessedByRuntime("referenced in halasm.asm/brtasm.asm")]
internal static int allocationGCInhibitCount = 0;
[Intrinsic]
internal static GCType gcType;
[Intrinsic]
internal static WBType wbType;
[Intrinsic]
internal static RemSetType remsetType;
[Intrinsic]
internal static CopyScanType copyscanType;
#if !SINGULARITY // Needed before Bartok runtime is initialized
[NoStackLinkCheck]
#endif
[PreInitRefCounts]
internal static void ConstructHeap() {
PageTable.Initialize();
MemoryManager.Initialize();
#if OS_WINCE
UIntPtr heap_commit_size = new UIntPtr(1 << 16);
#elif SINGULARITY
UIntPtr heap_commit_size = new UIntPtr(1 << 16);
#else
UIntPtr heap_commit_size = new UIntPtr(1 << 20);
#endif
UIntPtr os_commit_size = MemoryManager.OperatingSystemCommitSize;
VTable.Assert(os_commit_size > UIntPtr.Zero);
VTable.Assert(heap_commit_size >= os_commit_size);
UIntPtr bootstrapSize;
if (UIntPtr.Size == 8) {
if (gcType == GCType.ConcurrentMSCollector) {
// increase bootstrap size so that
// the concurrent mark sweep collector will run on
// 64-bit Windows
bootstrapSize = (UIntPtr) 1<<16;
} else {
bootstrapSize = (UIntPtr) 1<<15;
}
} else {
bootstrapSize = (UIntPtr) 1<<14;
}
if (bootstrapSize < os_commit_size) {
bootstrapSize = os_commit_size;
}
BootstrapMemory.Initialize(bootstrapSize);
StaticData.Initialize();
PageManager.Initialize(os_commit_size, heap_commit_size);
CallStack.Initialize();
}
// Called after the GC is up, but before multi-threading is enabled.
internal static void FinishInitializeThread()
{
PageManager.FinishInitializeThread();
}
// NB: This is called from VTable.Initialize()
[PreInitRefCounts]
static GC() // Class Constructor (cctor)
{
GC.Initialize();
switch(gcType) {
#if !SINGULARITY || ADAPTIVE_COPYING_COLLECTOR
case GCType.AdaptiveCopyingCollector: {
AdaptiveCopyingCollector.Initialize();
GC.installedGC = AdaptiveCopyingCollector.instance;
break;
}
#endif
#if !SINGULARITY || MARK_SWEEP_COLLECTOR
case GCType.MarkSweepCollector: {
MarkSweepCollector.Initialize();
GC.installedGC = MarkSweepCollector.instance;
break;
}
#endif
#if !SINGULARITY || TABLE_MARK_SWEEP_COLLECTOR
case GCType.TableMarkSweepCollector: {
SimpleMarkSweepCollector.Initialize();
GC.installedGC = SimpleMarkSweepCollector.instance;
break;
}
#endif
#if !SINGULARITY || SEMISPACE_COLLECTOR
case GCType.SemispaceCollector: {
SemispaceCollector.Initialize();
GC.installedGC = SemispaceCollector.instance;
break;
}
#endif
#if !SINGULARITY || SLIDING_COLLECTOR
case GCType.SlidingCollector: {
SlidingCollector.Initialize();
GC.installedGC = SlidingCollector.instance;
break;
}
#endif
#if !SINGULARITY || CONCURRENT_MS_COLLECTOR
case GCType.ConcurrentMSCollector: {
ConcurrentMSCollector.Initialize();
GC.installedGC = ConcurrentMSCollector.instance;
break;
}
#endif
#if !SINGULARITY || ATOMIC_RC_COLLECTOR
case GCType.AtomicRCCollector: {
AtomicRCCollector.Initialize();
GC.installedGC = AtomicRCCollector.instance;
break;
}
#endif
#if !SINGULARITY
case GCType.ReferenceCountingCollector: {
ReferenceCountingCollector.Initialize();
GC.installedGC = ReferenceCountingCollector.instance;
break;
}
#endif
#if !SINGULARITY
case GCType.DeferredReferenceCountingCollector: {
DeferredReferenceCountingCollector.Initialize();
GC.installedGC = DeferredReferenceCountingCollector.instance;
break;
}
#endif
#if !SINGULARITY || NULL_COLLECTOR
case GCType.NullCollector: {
VTable.Assert(wbType == 0, "No need for a write barrier");
GC.installedGC =
(NullCollector)
BootstrapMemory.Allocate(typeof(NullCollector));
break;
}
#endif
#if !SINGULARITY
case GCType.CoCoMSCollector: {
CoCoMSCollector.Initialize();
GC.installedGC = CoCoMSCollector.instance;
break;
}
#endif
default: {
VTable.NotReached("Unknown GC type: "+gcType);
break;
}
}
GC.installedGC.NewThreadNotification(Thread.initialThread, true);
GC.installedGC.ThreadStartNotification(Thread.initialThread.threadIndex);
}
[NoBarriers]
[PreInitRefCounts]
private static void Initialize()
{
VTable.Assert(GC.allocationGCInhibitCount == 0);
GC.allocationGCInhibitCount = 1;
Transitions.Initialize();
Barrier.Initialize();
}
#if !SINGULARITY
private static DateTime LogMessage(String message)
{
DateTime currentTime = System.DateTime.Now;
System.Text.StringBuilder sb = new System.Text.StringBuilder();
String hourString = currentTime.Hour.ToString();
if (hourString.Length == 1) {
sb.Append('0');
}
sb.Append(hourString);
sb.Append(':');
String minuteString = currentTime.Minute.ToString();
if (minuteString.Length == 1) {
sb.Append('0');
}
sb.Append(minuteString);
sb.Append(':');
String secondString = currentTime.Second.ToString();
if (secondString.Length == 1) {
sb.Append('0');
}
sb.Append(secondString);
sb.Append('.');
String milliString = currentTime.Millisecond.ToString();
if (milliString.Length < 3) {
sb.Append('0');
}
if (milliString.Length < 2) {
sb.Append('0');
}
sb.Append(milliString);
sb.Append(": ");
sb.Append(message);
Console.Out.WriteLine(sb.ToString());
return currentTime;
}
#endif
// This empty class allows us to easily spot the HeapCritialSection
// mutex when debugging.
private class HeapMonitor
{
}
internal static void CheckForNeededGCWork(Thread currentThread) {
installedGC.CheckForNeededGCWork(currentThread);
}
#if SINGULARITY
// This is a Singularity special not in the CLR
public static void Verify()
{
DebugStub.WriteLine("Calling VerifyHeap()");
bool oldGCVerify = VTable.enableGCVerify;
VTable.enableGCVerify = true;
Collect();
VTable.enableGCVerify = oldGCVerify;
DebugStub.WriteLine("Verification finished.");
}
public static void PerformanceCounters(out int collectorCount,
out long collectorMillis,
out long collectorBytes)
{
collectorCount = BaseCollector.gcTotalCount;
collectorMillis = BaseCollector.gcTotalTime;
collectorBytes = BaseCollector.gcTotalBytes;
}
#endif
// Garbage Collect all generations.
[ManualRefCounts]
public static void Collect()
{
installedGC.Collect(Thread.CurrentThread, MaxGeneration);
}
public static void Collect(int generation)
{
if (generation < 0) {
throw new ArgumentOutOfRangeException(
"generation",
"Argument should be positive!");
}
installedGC.Collect(Thread.CurrentThread, generation);
}
// This method is to be used by various runtime routines that
// need to trigger a collection. If there are different kinds
// of collection, most likely a minor collection will be
// performed.
internal static void InvokeCollection(Thread currentThread)
{
installedGC.Collect(currentThread,
(int)SpecialGeneration.InvokeCollection);
}
// This method is to be used by various runtime routines that
// need to trigger a collection. If there are different kinds
// of collections, most likely a major collection will be
// performed.
internal static void InvokeMajorCollection(Thread currentThread)
{
installedGC.Collect(currentThread,
(int)SpecialGeneration.InvokeMajorCollection);
}
// This method is to be used by various garbage collector routines
// that need to trigger a scanning for roots of the call stacks
// of the program threads. Calling this method is not meant
// to trigger a new garbage collection cycle.
internal static void InvokeStackScanOnly(Thread currentThread)
{
installedGC.Collect(currentThread,
(int)SpecialGeneration.InvokeStackScanOnly);
}
// This method is to be used by various garbage collector routines
// that need to trigger an update of all references on the call
// stacks of the program threads. Calling this method is not meant
// to trigger a new garbage collection cycle.
internal static void InvokeStackFixupOnly(Thread currentThread)
{
installedGC.Collect(currentThread,
(int)SpecialGeneration.InvokeStackFixupOnly);
}
internal static void CollectTransition(Thread currentThread,
int generation)
{
CollectBodyTransition(currentThread, generation);
}
// DO NOT REMOVE THE StackLinkCheck ATTRIBUTE FROM THIS
// FUNCTION!
//
// It is called from native code System.GC.CollectBodyTransition
// that only has an attribute for the amount of stack space that
// the native code requires.
[StackLinkCheck]
[ManualRefCounts]
[AccessedByRuntime("called from halforgc.asm/brtforgc.asm")]
private static unsafe Thread CollectBody(Thread currentThread,
int generation)
{
// NOTE: Refrain from creating any GC safe points in this
// method. That includes allocation and system calls,
// which in turn includes print statements. Putting a GC
// safe point before the call to the collector may cause
// infinite recursion. Putting a GC safe point after the
// call to the collector may cause recursion when other
// threads are triggering collections before the current
// thread exits this method. (Bjarne)
int currentThreadIndex = currentThread.threadIndex;
installedGC.CollectStoppable(currentThreadIndex, generation);
return Thread.threadTable[currentThreadIndex];
}
[RequiredByBartok]
[AccessedByRuntime("called from brtasm.asm")]
[Inline]
[ManualRefCounts]
internal static Object AllocateObject(VTable vtable)
{
return AllocateObject(vtable, Thread.CurrentThread);
}
[RequiredByBartok]
[NoInline]
[CalledRarely]
[ManualRefCounts]
internal static Object AllocateObjectNoInline(VTable vtable)
{
return AllocateObject(vtable);
}
[RequiredByBartok]
[Inline]
[ManualRefCounts]
internal static Object AllocateObject(VTable vtable,
Thread currentThread)
{
VTable.Deny(Transitions.UnderGCControl(currentThread.threadIndex));
return installedGC.AllocateObject(vtable, currentThread);
}
[RequiredByBartok]
[NoInline]
[CalledRarely]
[ManualRefCounts]
internal static Object AllocateObjectNoInline(VTable vtable,
Thread currentThread)
{
return AllocateObject(vtable, currentThread);
}
[RequiredByBartok]
[Inline]
[ManualRefCounts]
internal static Object AllocateObject(VTable vtable,
UIntPtr numBytes,
uint baseAlignment,
Thread currentThread)
{
VTable.Deny(Transitions.UnderGCControl(currentThread.threadIndex));
return installedGC.AllocateObject(vtable,
numBytes,
baseAlignment,
currentThread);
}
// Currently only used by MDIL as the compiler explicitly adds the
// RegisterCandidate call in normal builds. In the future, however, we
// would probably like to have this detail expressed in C# rather than
// in the compiler sources.
[RequiredByBartok]
[NoInline]
[ManualRefCounts]
internal static Object AllocateFinalizableObject(VTable vtable) {
Object obj = AllocateObject(vtable);
Finalizer.RegisterCandidate(obj);
return obj;
}
[RequiredByBartok]
[Inline]
[ManualRefCounts]
internal static Array AllocateVector(VTable vtable, int numElements)
{
return AllocateVector(vtable, numElements, Thread.CurrentThread);
}
[Inline]
[ManualRefCounts]
internal static Array AllocateVector(VTable vtable,
int numElements,
Thread currentThread)
{
VTable.Deny(Transitions.UnderGCControl(currentThread.threadIndex));
return installedGC.AllocateVector(vtable, numElements,
currentThread);
}
[RequiredByBartok]
[Inline]
[ManualRefCounts]
internal static Array AllocateArray(VTable vtable, int rank,
int totalElements)
{
return AllocateArray(vtable, rank, totalElements,
Thread.CurrentThread);
}
[Inline]
[ManualRefCounts]
internal static Array AllocateArray(VTable vtable, int rank,
int totalElements,
Thread currentThread)
{
VTable.Deny(Transitions.UnderGCControl(currentThread.threadIndex));
return installedGC.AllocateArray(vtable, rank, totalElements,
currentThread);
}
[RequiredByBartok]
[Inline]
[ManualRefCounts]
internal static String AllocateString(int stringLength)
{
return AllocateString(stringLength, Thread.CurrentThread);
}
[Inline]
[ManualRefCounts]
internal static String AllocateString(int stringLength,
Thread currentThread)
{
VTable.Deny(Transitions.UnderGCControl(currentThread.threadIndex));
return installedGC.AllocateString(stringLength, currentThread);
}
public static int GetGeneration(Object obj)
{
return installedGC.GetGeneration(obj);
}
public static int MaxGeneration {
get { return installedGC.MaxGeneration; }
}
internal enum SpecialGeneration {
InvokeCollection = -1,
InvokeMajorCollection = -2,
// Not all collectors use these next two values.
InvokeStackScanOnly = -3,
InvokeStackFixupOnly = -4
}
internal static bool IsUserCollectionRequest(int gen)
{
return gen >= 0;
}
internal static bool IsInternalCollectionRequest(int gen)
{
return gen == (int)SpecialGeneration.InvokeCollection
|| gen == (int)SpecialGeneration.InvokeMajorCollection;
}
internal static bool IsRealCollectionRequest(int gen)
{
return gen >= 0
|| gen == (int)SpecialGeneration.InvokeCollection
|| gen == (int)SpecialGeneration.InvokeMajorCollection;
}
[NoInline]
[RequiredByBartok]
public static void KeepAlive(Object obj)
{
dummyGlobal = obj;
dummyGlobal = null;
}
public static void WaitForPendingFinalizers()
{
Finalizer.WaitForPending();
}
public static long GetTotalMemory(bool forceFullCollection)
{
long size = installedGC.TotalMemory;
if (!forceFullCollection) {
return size;
}
// If we force a full collection, we will run the finalizers on all
// existing objects and do a collection until the value stabilizes.
// The value is "stable" when either the value is within 5% of the
// previous call to installedGC.TotalMemory, or if we have been sitting
// here for more than x times (we don't want to loop forever here).
for (int reps = 0; reps < 8; reps++) {
WaitForPendingFinalizers();
Collect();
long newSize = installedGC.TotalMemory;
long bound = size / 20; // 5%
long diff = newSize - size;
size = newSize;
if (diff >= -bound && diff <= bound) {
break;
}
}
return size;
}
public static void SuppressFinalize(Object obj)
{
if (obj == null) {
throw new ArgumentNullException("obj");
}
Finalizer.SuppressCandidate(obj);
}
internal static void nativeSuppressFinalize(Object obj) {
Finalizer.SuppressCandidate(obj);
}
public static void ReRegisterForFinalize(Object obj)
{
if (obj == null) {
throw new ArgumentNullException("obj");
}
Finalizer.RegisterCandidate(obj);
}
public static int GetGeneration(WeakReference wo)
{
Object obj = wo.Target;
if (obj == null) {
throw new ArgumentException("wo", "target already collected");
}
return GetGeneration(obj);
}
public static void SetProfiler(GCProfiler profiler)
{
installedGC.SetProfiler(profiler);
isProfiling = true;
}
public static bool IsProfiling
{
get {
return isProfiling;
}
}
internal static void ProfileAllocation(Object obj)
{
if (isProfiling) {
installedGC.ProfileAllocation(obj);
}
}
private static void SetCleanupCache()
{
// REVIEW: will not ever clean up these caches (such as Assembly
// strong names)
}
internal static void EnableHeap()
{
VTable.Assert(GC.allocationGCInhibitCount == 1);
GC.allocationGCInhibitCount = 0;
CollectorStatistics.Initialize();
CollectorStatistics.Event(GCEvent.CreateHeap);
GC.installedGC.EnableHeap();
Finalizer.StartFinalizerThread();
}
internal static void Shutdown()
{
if(installedGC != null) {
installedGC.Shutdown();
}
}
// Called on VM shutdown.
internal static void DestructHeap()
{
if (installedGC != null) {
installedGC.DestructHeap();
}
}
internal static void NewThreadNotification(Thread newThread,
bool initial)
{
GC.installedGC.NewThreadNotification(newThread, initial);
}
internal static void DeadThreadNotification(Thread deadThread)
{
GC.installedGC.DeadThreadNotification(deadThread);
}
internal static void ThreadStartNotification(int currentThreadIndex)
{
GC.installedGC.ThreadStartNotification(currentThreadIndex);
}
internal static void ThreadEndNotification(Thread dyingThread)
{
GC.installedGC.ThreadEndNotification(dyingThread);
}
internal static void ThreadDormantGCNotification(int threadIndex)
{
GC.installedGC.ThreadDormantGCNotification(threadIndex);
}
}
}