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

380 lines
13 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. */
/*******************************************************************/
// #define DEBUG
namespace System.GCs {
using Microsoft.Bartok.Options;
using Microsoft.Bartok.Runtime;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Collections;
[NoCCtor]
[RequiredByBartok]
internal abstract class RCCollector : Collector {
[PreInitRefCounts]
public static void Initialize() {
SegregatedFreeList.Initialize();
}
// This is a compiler intrinsic whose value is controlled by
// /StageControl.RCCollectorVerifyRefCounts.
internal static extern bool VerificationMode {
[Intrinsic]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
get;
}
// This is a compiler intrinsic whose value is controlled by
// /StageControl.RCCollectorVerifyLeakedCycles.
internal static extern bool VerifyLeakedCycles {
[Intrinsic]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
get;
}
// This is a compiler intrinsic whose value is controlled by
// /StageControl.RCCollectorGenerateProfile.
internal static extern bool ProfilingMode {
[Intrinsic]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
get;
}
[MixinConditional("RCGC")]
[Mixin(typeof(PostHeader))]
[StructLayout(LayoutKind.Sequential)]
[RequiredByBartok]
internal struct PostHeaderRCGC {
[CompilerInitField(2)]
internal uint refState;
#if !SINGULARITY
[RequiredByBartok]
#endif
internal VTable vtableObject;
}
[MixinConditional("RCGC")]
[Mixin(typeof(Object))]
internal class RCGCObject : System.Object {
internal new PostHeaderRCGC postHeader;
internal new uint REF_STATE {
[Inline]
[ManualRefCounts]
[MixinOverride]
get {
return this.postHeader.refState;
}
[Inline]
[ManualRefCounts]
[MixinOverride]
set {
this.postHeader.refState = value;
}
}
}
[MixinConditional("RCGCVerification")]
[Mixin(typeof(PreHeader))]
[RequiredByBartok]
internal struct PreHeaderRCGCVerification {
internal UIntPtr backupRefcount;
internal UIntPtr dfsDiscoveryTime;
internal UIntPtr dfsFinishingTime;
}
[MixinConditional("RCGCVerification")]
[Mixin(typeof(Object))]
internal class RCGCVerificationObject : System.Object {
internal new PreHeaderRCGCVerification preHeader;
}
/*
* Every object maintains a 32-bit "reference state" (RS).
* The RS consists of a 29-bit reference count, with the
* remaining bits available for flagging purposes.
*
* In a 32-bit architecture, 4GB of memory is addressable.
* Of this, the upper 2GB is usually reserved for use by
* the system. So given an object size of at least
* 12 bytes (sync block index, RS field and the vtable),
* there can't be more than 2^28 objects. The reference
* count can be more, due to multiple references from an
* object to the same target (think of one large array of
* references), but will be less than 2^29.
*
* Of the remaining three bits, one is reserved to ignore
* reference-counting (RC) operations on objects.
*/
internal struct RSMasks {
internal const uint refCount = 0x1fffffff;
internal const uint countingFlag = 0x80000000;
}
// Used only in profiling mode.
internal struct UpdatePairs {
public int Increments;
public int Decrements;
public static UpdatePairs operator+(UpdatePairs a,
UpdatePairs b) {
a.Increments += b.Increments;
a.Decrements += b.Decrements;
return a;
}
public int Total {
get {
return Increments+Decrements;
}
}
} // Increment and decrement counts of one kind of RC update.
internal struct AcctRecord {
// General RC update, on a "maybe-null" reference.
public UpdatePairs MaybeNull;
// General RC update, but on a non-null reference.
public UpdatePairs NonNull;
public UpdatePairs VtableOperand;
public UpdatePairs RuntimeTypeOperand;
public String MethodName;
public static AcctRecord operator+(AcctRecord a,
AcctRecord b) {
VTable.Assert(Magic.addressOf(a.MethodName) ==
Magic.addressOf(b.MethodName),
@"Magic.addressOf(a.MethodName) ==
Magic.addressOf(b.MethodName)");
a.MaybeNull += b.MaybeNull;
a.NonNull += b.NonNull;
a.VtableOperand += b.VtableOperand;
a.RuntimeTypeOperand += b.RuntimeTypeOperand;
return a;
}
public int CompareTo(AcctRecord rhs) {
int lhsTotal = MaybeNull.Total+NonNull.Total;
int rhsTotal = rhs.MaybeNull.Total+rhs.NonNull.Total;
return lhsTotal < rhsTotal;
}
public void DispCountsHeader() {
VTable.DebugPrint("GIncs\t\tGDecs");
VTable.DebugPrint("\t\tNIncs\t\tNDecs");
VTable.DebugPrint("\t\tV+\t\tV-");
VTable.DebugPrint("\t\tR+\t\tR-");
}
public void DispMethodNameHeader() {
VTable.DebugPrint("\t\tMethod");
}
public void DispCounts() {
VTable.DebugPrint(MaybeNull.Increments);
if (MaybeNull.Increments < 10000000) {
VTable.DebugPrint("\t\t");
} else {
VTable.DebugPrint("\t");
}
VTable.DebugPrint(MaybeNull.Decrements);
if (MaybeNull.Decrements < 10000000) {
VTable.DebugPrint("\t\t");
} else {
VTable.DebugPrint("\t");
}
VTable.DebugPrint(NonNull.Increments);
if (NonNull.Increments < 10000000) {
VTable.DebugPrint("\t\t");
} else {
VTable.DebugPrint("\t");
}
VTable.DebugPrint(NonNull.Decrements);
if (NonNull.Decrements < 10000000) {
VTable.DebugPrint("\t\t");
} else {
VTable.DebugPrint("\t");
}
}
public void DispMethodName() {
VTable.DebugPrint(MethodName);
}
public void Disp() {
DispCounts();
DispMethodName();
}
}
internal override long TotalMemory {
get {
UIntPtr pageCount = UIntPtr.Zero;
for (UIntPtr i = UIntPtr.Zero;
i < PageTable.pageTableCount; i++) {
if (PageTable.IsMyGcPage(i) &&
PageTable.Type(i) !=
SegregatedFreeList.INIT_PAGE) {
pageCount++;
}
}
return (long)PageTable.RegionSize(pageCount);
}
}
internal override UIntPtr FindObjectAddr(UIntPtr interiorPtr) {
return SegregatedFreeList.Find(interiorPtr);
}
internal override void VisitObjects
(ObjectLayout.ObjectVisitor objVisitor,
UIntPtr lowAddr,
UIntPtr highAddr) {
UIntPtr lowPage = PageTable.Page(lowAddr);
UIntPtr highPage = PageTable.Page(highAddr);
SegregatedFreeList.VisitObjects(lowPage,
highPage,
objVisitor);
}
[NoInline]
[ManualRefCounts]
[RequiredByBartok]
internal static unsafe bool AccumulateRCUpdates(String methodName,
int methodIndex,
uint maxIndex,
AcctRecord rec) {
VTable.Assert(RCCollector.ProfilingMode,
@"RCCollector.ProfilingMode");
// Return if the page table hasn't been set up yet.
if (PageTable.pageTableCount == UIntPtr.Zero) {
return false;
}
if (methods == null) {
// Allocate up front storage for the accounting records.
//
// This is requisitioned directly from the memory
// manager. Care should be taken to ensure that
// AccumulateRCUpdates does not indirectly call
// methods that may have compiler-inserted RC updates.
VTable vtable =
((RuntimeType)typeof(AcctRecord[])).classVtable;
UIntPtr size =
ObjectLayout.ArraySize(vtable, maxIndex+1);
BumpAllocator profileData =
new BumpAllocator(PageType.NonGC);
UIntPtr profileDataStart =
MemoryManager.AllocateMemory(size);
profileData.SetRange(profileDataStart, size);
PageManager.SetStaticDataPages(profileDataStart, size);
methods =
(AcctRecord[])Allocate(ref profileData, vtable, size);
VTable.Assert(methods != null,
@"methods != null");
*(uint*)(Magic.addressOf(methods)+
PostHeader.Size) = maxIndex+1;
}
VTable.Assert(methods.Length == maxIndex+1,
@"methods.Length == maxIndex+1");
if (methods[methodIndex].methodName == null) {
methodNames[methodIndex].methodName = methodName;
}
// Not "methodNames[methodIndex].methodName == methodName"
// because the Equality operator carries compiler-inserted
// RC updates!
VTable.Assert(Magic.addressOf(methodNames[methodIndex].
methodName) ==
Magic.addressOf(methodName),
@"Magic.addressOf(methodNames[methodIndex].
methodName) ==
Magic.addressOf(methodName)");
methods[methodIndex] += rec;
return true;
}
[NoInline]
[ManualRefCounts]
internal static void EmitRefCountsProfile() {
VTable.Assert(RCCollector.ProfilingMode,
@"RCCollector.ProfilingMode");
if (methods == null) { // No RC updates present.
return;
}
// Bubble sort in decreasing order of sums.
for (int i = 0; i < methods.Length; i++) {
for (int j = methods.Length-1; j > i; j--) {
if (methods[j].CompareTo(methods[j-1])) {
// Swap contents.
AcctRecord temp = methods[j];
methods[j] = methods[j-1];
methods[j-1] = temp;
}
}
}
VTable.DebugPrint("\n");
AcctRecord.DispCountsHeader();
AcctRecord.DispMethodNameHeader();
VTable.DebugPrint("\n");
for (int i = 0; i < methods.Length; i++) {
if (methods[i].increments.Total == 0 &&
methods[i].decrements.Total == 0) {
continue;
}
methods[i].DispCounts();
methods[i].DispMethodName();
VTable.DebugPrint("\n");
}
}
private static Object Allocate(ref BumpAllocator profileData,
VTable vtable,
UIntPtr numBytes) {
UIntPtr resultAddr =
profileData.AllocateFast(numBytes, vtable.baseAlignment);
Object result = Magic.fromAddress(resultAddr);
result.REF_STATE = 1 ;
result.vtable = vtable;
return result;
}
private static AcctRecord[] methods;
}
}