internal static void InterlockWithCopier(ref bool condition) { lock (interlock) { if (fVerbose) { VTable.DebugPrint(" ~~ acquired lock, setting condition\n"); } condition = true; if (fVerbose) { VTable.DebugPrint(" ~~ pulsing = "); VTable.DebugPrint((ulong)Magic.addressOf(interlock)); VTable.DebugPrint("\n"); } Monitor.PulseAll(interlock); if (fVerbose) { VTable.DebugPrint(" ~~ waiting\n"); } while (condition) { Monitor.Wait(interlock); } } }
internal override ulong Copy() { if (fDietDebug) { VTable.DebugPrint("Doing Diet CoCo Copy\n"); } ulong numCopied = 0; TagNode tagHead = ProbabilisticCoCoBarrier.tagHead; ProbabilisticCoCoBarrier.tagHead = null; for (TagNode cur = tagHead; cur != null; cur = cur.next) { if (CopyObject(cur.from)) { numCopied++; } } if (fDietDebug) { VTable.DebugPrint("Done With Diet CoCo Copy\n"); } return(numCopied); }
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-"); }
internal override void Cleanup() { base.Cleanup(); if (spaceOverhead > maxSpaceOverhead) { maxSpaceOverhead = spaceOverhead; } if (amMarkingForCoCo) { markingForCoCo = 0; #if !ARM && !ISA_ARM // HACK: MemoryBarrier is unimplemented in ARM // and causes compile-time failures when building // mscorlib in sepcomp mode. This change will break // CoCo if built with ARM. Thread.MemoryBarrier(); #endif } if (fDebug) { VTable.DebugPrint(" $$$ tagged "); VTable.DebugPrint(cnt); VTable.DebugPrint(" objects\n"); } }
internal override void Finish() { lastSmallPagesRecycle = SegregatedFreeList.SmallPages; if (fDebug) { VTable.DebugPrint(" $$$ marked "); VTable.DebugPrint((ulong)cnt); VTable.DebugPrint(", unmarked "); VTable.DebugPrint((ulong)unmarkedCnt); VTable.DebugPrint(", delayed "); VTable.DebugPrint((ulong)delayedCnt); VTable.DebugPrint(", and freed "); VTable.DebugPrint(emptyCnt); VTable.DebugPrint(".\n"); } if (cnt != 0) { delayCnt = cocoDelay; markingForCoCo = 1; #if !ARM && !ISA_ARM // HACK: MemoryBarrier is unimplemented in ARM // and causes compile-time failures when building // mscorlib in sepcomp mode. This change will break // CoCo if built with ARM. Thread.MemoryBarrier(); #endif } }
internal override UIntPtr Visit(Object obj) { #if DEBUG_OFFSETTABLE VTable.DebugPrint("visit obj {0:x8}\n", __arglist(Magic.addressOf(obj))); if (lastObjPtr != UIntPtr.Zero) { UIntPtr lastCard = CardTable.CardNo(lastObjPtr); if (lastCard != CardTable.CardNo(Magic.addressOf(obj))) { if (!OffsetTable.NoObjectPtrToTheCard(lastCard)) { UIntPtr realOffst = lastObjPtr - CardTable.CardAddr(lastCard); UIntPtr currOffst = OffsetTable.GetOffset(lastCard); if (realOffst != currOffst) { VTable.DebugPrint("Verifier: wrong offset. Card {0:x8} Offset {1:x8} Should be {2:x8}\n", __arglist(lastCard, currOffst, realOffst)); VTable.Assert(false); } } } } #endif return(this.referenceVisitor.VisitReferenceFields(obj)); }
protected void postVerifyHeap(bool beforeCollection) { VTable.Assert(RCCollector.VerificationMode, @"RCCollector.VerificationMode"); SegregatedFreeList.RecycleGlobalPages(); SegregatedFreeList.CommitFreedData(); GC.newBytesSinceGC = UIntPtr.Zero; // Initialize the "backup" reference count. SegregatedFreeList.VisitAllObjects(backupInit); // Count all references and managed pointers. rootsScanner.Initialize(backupRefCount); CallStack.ScanStacks(rootsScanner, rootsScanner); Thread.VisitBootstrapData(rootsScanner); StaticData.ScanStaticData(rootsScanner); MultiUseWord.VisitStrongRefs(rootsScanner, false); CallStack.ScanStacks(resetRoots, resetRoots); Thread.VisitBootstrapData(resetRoots); StaticData.ScanStaticData(resetRoots); SegregatedFreeList.VisitAllObjects(resetTraversal); // Actual leaks (refCount > 0 and backup refCount = 0). leakAccumulator.Initialize(); SegregatedFreeList.VisitAllObjects(leakAccumulator); VTable.DebugPrint("Leaked storage: "); VTable.DebugPrint((int)leakAccumulator.Size); VTable.DebugPrint("B"); if (VerifyLeakedCycles) { // Find leaked data that *should* have been reclaimed. // (If L is the set of all leaked nodes, and L' the // transitive closure of leaked cycles, then L-L' is // the set of nodes that should have been captured // by a pure RC collector.) SegregatedFreeList.VisitAllObjects(leakedNodesDFS); SegregatedFreeList.VisitAllObjects(resetTraversal); SegregatedFreeList.VisitAllObjects(leakedCycleClosure); SegregatedFreeList.VisitAllObjects(resetTraversal); leakAccumulator.Initialize(); SegregatedFreeList.VisitAllObjects(leakAccumulator); VTable.DebugPrint(" ("); VTable.DebugPrint((int)leakAccumulator.Size); VTable.DebugPrint("B acyclic)"); } // Find the roots of leaked data. leakedRoots.Initialize(); SegregatedFreeList.VisitAllObjects(leakedRoots); leakedRootsCounter.Initialize(); SegregatedFreeList.VisitAllObjects(leakedRootsCounter); SegregatedFreeList.VisitAllObjects(resetTraversal); VTable.DebugPrint("; leaked heap roots: "); VTable.DebugPrint((int)leakedRootsCounter.Total); VTable.DebugPrint("\n"); }
internal override void PinningEnabledHook() { if (fAbortDebug) { VTable.DebugPrint("Aborter: un-aborting "); VTable.DebugPrint(nTagged); VTable.DebugPrint(" objects.\n"); } for (TagNode n = tagHead; n != null; n = n.next) { if (fAbortVerboseDebug) { VTable.DebugPrint("Aborter: un-aborting "); VTable.DebugPrint((ulong)Magic.addressOf(n.from)); VTable.DebugPrint("\n"); } UIntPtr oldCoCoWord = CAS(ref MixinObject(n.from).preHeader.CoCoWord, WithNoForwardCopying(n.from), WithNoForwardNotCopying(n.from)); VTable.Assert(!IsCopying(oldCoCoWord)); VTable.Assert(!IsForwarded(oldCoCoWord, n.from)); } if (fAbortDebug) { VTable.DebugPrint("Aborter: un-aborted "); VTable.DebugPrint(nTagged); VTable.DebugPrint(" objects.\n"); } }
internal unsafe override void Visit(UIntPtr *loc) { UIntPtr addr = *loc; UIntPtr page = PageTable.Page(addr); PageType pageType = PageTable.Type(page); if (!PageTable.IsZombiePage(pageType)) { VTable.Assert(PageTable.IsGcPage(pageType) || PageTable.IsNonGcPage(pageType) || PageTable.IsStackPage(pageType) || PageTable.IsSharedPage(pageType)); return; } UIntPtr vtableAddr = Allocator.GetObjectVTable(addr); // Mark object if (vtableAddr == UIntPtr.Zero) { VTable.DebugPrint("Found null vtable in MarkReference (loc = 0x{0:x8}, addr = 0x{1:x8})\n", __arglist(((UIntPtr)loc), addr)); VTable.NotReached(); } *loc = vtableAddr; Allocator.SetObjectVTable(addr, (UIntPtr)loc + 1); // If first visit to the object, schedule visit of fields if ((vtableAddr & 0x1) == 0) { MarkVisit(addr, vtableAddr & (UIntPtr) ~2U); } }
protected static void deallocationListChecker() { // Check for nonzero reference counts and for // loops in the delayed deallocation list. for (Object block = delayedDeallocationList; block != null; block = getNextLink(block)) { UIntPtr objAddr = Magic.addressOf(block); UIntPtr page = PageTable.Page(objAddr); if (!PageTable.IsGcPage(page)) { VTable.DebugPrint("Non-GC memory for freeing!\n"); VTable.DebugBreak(); } uint refState = block.REF_STATE; if ((refState & RSMasks.refCount) != 0) { VTable.DebugPrint("Non-zero reference count!\n"); VTable.DebugBreak(); } block.REF_STATE = refState + 1; } // Make another pass to reset reference counts. for (Object block = delayedDeallocationList; block != null; block = getNextLink(block)) { block.REF_STATE--; } }
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 static void PrintStat(string name, ulong n) { VTable.DebugPrint(name); VTable.DebugPrint(" = "); VTable.DebugPrint(n); VTable.DebugPrint("\n"); }
internal override void Shutdown() { base.Shutdown(); lock (interlock) { die = true; Monitor.PulseAll(interlock); } cocoThread.Join(); if (VTable.enableFinalGCTiming) { VTable.DebugPrint("CoCo completed "); VTable.DebugPrint(cycles); VTable.DebugPrint(" cycles, started "); VTable.DebugPrint(cyclesStarted); VTable.DebugPrint(" cycles, and copied "); VTable.DebugPrint(numCopied); VTable.DebugPrint(" objects.\n"); VTable.DebugPrint("CoCo took "); VTable.DebugPrint((ulong)pinTime); VTable.DebugPrint("+"); VTable.DebugPrint((ulong)prepTime); VTable.DebugPrint("+"); VTable.DebugPrint((ulong)copyTime); VTable.DebugPrint("+"); VTable.DebugPrint((ulong)forwardTime); VTable.DebugPrint("="); VTable.DebugPrint((ulong)(pinTime + prepTime + copyTime + forwardTime)); VTable.DebugPrint(" ms.\n"); VTable.DebugPrint("max space overhead = "); VTable.DebugPrint((ulong)maxSpaceOverhead); VTable.DebugPrint("\n"); CoCoBarrier.PrintStats(); } }
internal override void Start() { cnt = UIntPtr.Zero; unmarkedCnt = UIntPtr.Zero; delayedCnt = UIntPtr.Zero; emptyCnt = 0; if (fDebug) { VTable.DebugPrint(" $$$ delayCnt = "); VTable.DebugPrint((ulong)delayCnt); VTable.DebugPrint(", markingForCoCo = "); VTable.DebugPrint((ulong)markingForCoCo); VTable.DebugPrint("\n"); } if (delayCnt == 0) { delay = (markingForCoCo != 0); // delay if there are still pages marked } else { delayCnt--; delay = true; } if (fDebug) { VTable.DebugPrint(" $$$ delayCnt = "); VTable.DebugPrint((ulong)delayCnt); VTable.DebugPrint(", markingForCoCo = "); VTable.DebugPrint((ulong)markingForCoCo); VTable.DebugPrint(", delay = "); VTable.DebugPrint(delay?"yes":"no"); VTable.DebugPrint("\n"); } }
internal static void ReportHeapWatermarks() { VTable.DebugPrint("Max. Heap: {0}KB ", __arglist(MaxHeapWatermark >> 10)); VTable.DebugPrint("Avg. Heap: {0}KB ", __arglist(((ulong)AvgHeapSize) >> 10)); VTable.DebugPrint("\n"); }
internal static Object Pin(Object o, Pinner pinner) { if (fAbortVerboseDebug) { VTable.DebugPrint("Aborter: requested pinning on "); VTable.DebugPrint((ulong)Magic.addressOf(o)); VTable.DebugPrint(" in thread "); VTable.DebugPrint((ulong)Magic.addressOf(Thread.CurrentThread)); VTable.DebugPrint(" with pinner = "); VTable.DebugPrint((int)pinner); VTable.DebugPrint("\n"); } UIntPtr oldCoCoWord = CAS(ref MixinObject(o).preHeader.CoCoWord, WithNoForwardNotCopying(o), WithNoForwardCopying(o)); if (!IsForwarded(oldCoCoWord, o)) { // the object is not forwarded - nothing further to do. // (we know that it must now be aborted, since if it // was, then that couldn't have changed; and if it wasn't, // then our CAS would have succeeded.) if (fAbortVerboseDebug && IsCopying(oldCoCoWord)) { VTable.DebugPrint("Aborter: aborted copying on "); VTable.DebugPrint((ulong)Magic.addressOf(o)); VTable.DebugPrint(" in thread "); VTable.DebugPrint((ulong)Magic.addressOf(Thread.CurrentThread)); VTable.DebugPrint("\n"); } if (fBreakOnAbort && Thread.CurrentThread != mainThread && pinner == Pinner.Barrier) { VTable.DebugBreak(); } return(o); } else { VTable.Assert(pinner == Pinner.Barrier, "Encountered a forwarded object in a pin " + "request that did not originate from the " + "barrier"); if (fAbortVerboseDebug) { VTable.DebugPrint("Aborter: encountered forwarded object " + "at "); VTable.DebugPrint((ulong)Magic.addressOf(o)); VTable.DebugPrint(" in thread "); VTable.DebugPrint((ulong)Magic.addressOf(Thread.CurrentThread)); VTable.DebugPrint("\n"); } return(Magic.fromAddress(ForwardPtr(oldCoCoWord))); } }
internal static unsafe void VerifyFirst(UIntPtr previousObjectAddr, UIntPtr objectAddr) { UIntPtr page = PageTable.Page(objectAddr); if (previousObjectAddr != UIntPtr.Zero) { UIntPtr previousPage = PageTable.Page(previousObjectAddr); UIntPtr pageCursor = previousPage + 1; while (pageCursor < page) { uint cursorOffset = PageTable.Extra(pageCursor); UIntPtr objAddr = (PageTable.PageAddr(pageCursor) + cursorOffset - OFFSET_SKEW); if (!(cursorOffset <= OFFSET_NO_DATA || BumpAllocator.IsUnusedSpace(objAddr) || Allocator.IsAlignment(objAddr) || BumpAllocator.IsRestOfPageZero(objAddr))) { VTable.DebugPrint ("cursorOffset={0:x} OFFSET_NO_DATA={1:x} objAddr={2:x} unused={3} isalign={4} iszero={5}\n", __arglist((cursorOffset), (OFFSET_NO_DATA), ((long)objAddr), (BumpAllocator.IsUnusedSpace(objAddr)), (Allocator.IsAlignment(objAddr)), (BumpAllocator.IsRestOfPageZero(objAddr)))); } VTable.Assert(cursorOffset <= OFFSET_NO_DATA || BumpAllocator.IsUnusedSpace(objAddr) || Allocator.IsAlignment(objAddr) || BumpAllocator.IsRestOfPageZero(objAddr), "VerifyFirst 1"); pageCursor++; } } uint offset = PageTable.Extra(page); if (offset > OFFSET_NO_DATA) { UIntPtr firstAddr = PageTable.PageAddr(page) + offset - OFFSET_SKEW; if (!(firstAddr == objectAddr || (firstAddr + UIntPtr.Size == objectAddr && Allocator.IsAlignment(firstAddr)))) { VTable.DebugPrint ("firstAddr={0:x} objectAddr={1:x} isalign={2}\n", __arglist(((long)firstAddr), ((long)objectAddr), (Allocator.IsAlignment(firstAddr)))); } VTable.Assert(firstAddr == objectAddr || (firstAddr + 4 == objectAddr && Allocator.IsAlignment(firstAddr)), "VerifyFirst 2"); } }
// must have some manner of handshake after this internal static void EnablePinning() { if (fDebug) { VTable.DebugPrint(" --> CoCo enabling pinning "); } pinning = true; SetAllowFastPath(); }
internal override void Collect(Thread currentThread, int generation) { try { GC.CollectTransition(currentThread, generation); } catch (Exception e) { VTable.DebugPrint("Garbage collection failed with exception"); VTable.DebugPrint(e.GetType().Name); VTable.DebugBreak(); } }
internal static void ClearCards(UIntPtr c1, UIntPtr c2) { for (UIntPtr i = c1; i <= c2; i++) { SetNoObjPtrToCard(i); } #if DEBUG_OFFSETTABLE VTable.DebugPrint("ClearLast from {0:x8} to {1:x8}\n", __arglist(c1, c2)); #endif }
internal override void Init() { base.Init(); cnt = 0; amMarkingForCoCo = (markingForCoCo != 0); spaceOverhead = UIntPtr.Zero; if (fDebug && amMarkingForCoCo) { VTable.DebugPrint("+++++ Marking For CoCo\n"); } }
internal override void PostTraceHook() { if (fVerbose) { VTable.DebugPrint(" ~~~~~ PostTraceHook ~ waiting\n"); } InterlockWithCopier(ref didEndTrace); if (fVerbose) { VTable.DebugPrint(" ~~~~~ PostTraceHook ~ awoken\n"); } }
internal void Dump() { #if SINGULARITY Tracing.Log(Tracing.Debug, "[gen={0} {1:x8}..{2:x8}..{3:x8}]", (UIntPtr) unchecked ((uint)this.pageType), this.allocPtr, this.zeroedLimit, this.reserveLimit); #else VTable.DebugPrint(" [gen={0} {1:x8}..{2:x8}..{3:x8}]\n", __arglist(this.pageType, this.allocPtr, this.zeroedLimit, this.reserveLimit)); #endif }
internal static new void Initialize() { if (fDietDebug) { VTable.DebugPrint("Diet DoCo!\n"); } ProbabilisticCoCoBarrier.instance = (ProbabilisticCoCoBarrier) BootstrapMemory.Allocate(typeof(ProbabilisticCoCoBarrier)); ProbabilisticCoCoBarrier.instance.InitEarly(); LowAbortCoCoBarrier.Initialize(); }
private static UIntPtr AllocateBlock(UIntPtr bytes, uint alignment) { UIntPtr startPtr = Allocator.AlignedAllocationPtr(allocPtr, limitPtr, alignment); allocPtr = startPtr + bytes; if (allocPtr > limitPtr) { VTable.DebugPrint("Out of BootstrapMemory"); VTable.DebugBreak(); } return(startPtr + PreHeader.Size); }
internal static void ClientHandshake() { if (inited) { if (fVerbose) { VTable.DebugPrint(" !! ClientHandshake: interlock at "); VTable.DebugPrint((ulong)Magic.addressOf(interlock)); VTable.DebugPrint("\n"); } if (fVerbose) { if (Magic.addressOf(interlock) != interlockAddr) { VTable.DebugPrint(" !! ClientHandshake seeing interlock at new address: "); VTable.DebugPrint((ulong)Magic.addressOf(interlock)); VTable.DebugPrint("\n"); } if (ToSpaceAsPtr(interlock) != forwardedInterlockAddr) { VTable.DebugPrint(" !! ClientHandshake seeing interlock at new FORWARDED address: "); VTable.DebugPrint((ulong)ToSpaceAsPtr(interlock)); VTable.DebugPrint("\n"); } } lock (interlock) { if (fVerbose) { interlockAddr = Magic.addressOf(interlock); forwardedInterlockAddr = ToSpaceAsPtr(interlock); } CoCoThread t = MixinThread(Thread.CurrentThread); if (phase != (Phase)t.acknowledgedPhase || forwarding != t.acknowledgedForwarding || pinning != t.acknowledgedPinning) { if (fDebug) { VTable.DebugPrint(" !! thread "); VTable.DebugPrint((ulong)Magic.addressOf(t)); VTable.DebugPrint(" doing ack\n"); } t.acknowledgedPhase = (int)phase; t.acknowledgedForwarding = forwarding; t.acknowledgedPinning = pinning; t.phaseVersion++; Monitor.PulseAll(interlock); } } } }
// OffsetTable records all objects promoted or directly allocated in mature // generation. internal static void SetLast(UIntPtr objPtr) { VTable.Assert(PageTable.IsGcPage(PageTable.Page(objPtr)), "Not GC page"); UIntPtr card = CardTable.CardNo(objPtr); UIntPtr mask = (UIntPtr)(CardTable.CardSize - 1); UIntPtr offset = objPtr & mask; VTable.Assert(offset < CardTable.CardSize, "Overflow"); SetOffset(card, offset); #if DEBUG_OFFSETTABLE VTable.DebugPrint("SetLast objPtr {0:x8}, card {1:x8}, offset {2:x8}\n", __arglist(objPtr, card, offset)); #endif }
private static void Log(LogEntry le) { #if SINGULARITY Tracing.Log(Tracing.Audit, EventToFormatString(le.Event), unchecked ((UIntPtr)(uint)le.Data)); #endif #if DONT Thread t = Thread.CurrentThread; VTable.DebugPrint("#GCEVENT Thread {0}: {1}, {2}, {3}\n", __arglist(t.threadIndex, EventToString(le.Event), le.TimeStamp, le.Data)); #endif }
internal override void Scan(NonNullReferenceVisitor ptrVisitor, PageType genToCollect) { #if DEBUG_CARDS VTable.DebugPrint("************ Scan to collect generation {0:x8} ******\n", __arglist(genToCollect)); for (UIntPtr i = firstCardNo; i < firstCardNo + totalCards; i++) { if (CardIsDirty(i)) { VTable.DebugPrint("dirty card {0:x8} gen {1:x8}\n", __arglist(i, CardGeneration(i))); } } #endif for (UIntPtr c = firstCardNo; c < firstCardNo + totalCards;) { if (CardIsDirty(c) && IsMyLiveGcCard(c) && CardGeneration(c) > genToCollect) { UIntPtr last = c + 1; while (last < firstCardNo + totalCards && CardIsDirty(last) && IsMyLiveGcCard(last) && CardGeneration(last) > genToCollect) { last++; } #if DEBUG_CARDS VTable.DebugPrint("Scan from {0:x8} to {1:x8} to collect gen {2:x8}\n", __arglist(c, last - 1, genToCollect)); #endif VisitObjectsInCards(ptrVisitor, c, last - 1); c = last; } else { c++; } } #if DEBUG_CARDS VTable.DebugPrint("************ End Scan ******\n"); #endif }
//[NoBarriers] void ProcessObjectsSlow(ref ThreadHeaderQueue.LocalList workList) { while (!ConcurrentMSCollector.killCollectorThreads && !workList.IsEmpty()) { // Pop the next value Object obj = workList.Pop(markedColor); if (fVerbose) { VTable.DebugPrint("cms popped: "); VTable.DebugPrint((ulong)Magic.addressOf(obj)); VTable.DebugPrint("\n"); } // let CoCo do some stuff ScanHook(obj); // Visit Fields this.VisitReferenceFields(obj); } }