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 EnableHeap() { interlock = new Object(); MultiUseWord.GetMonitor(interlock); CoCoBarrier.InitLate(); // REVIEW: add some bartok args instead sizeFracLim = EnvInt(10, "COCO_SIZE_FRAC_LIM"); sizeLim = EnvInt(-1, "COCO_SIZE_LIM"); pageFragThres = EnvInt(2, "COCO_PAGE_FRAG_THRES"); pinPenalty = EnvInt(10, "COCO_PIN_PENALTY"); cocoDelay = EnvInt(8, "COCO_COPY_DELAY"); if (EnvInt(0, "COCO_FORCE_SLOW") != 0) { CoCoBarrier.ForceSlow(); } if (EnvInt(0, "COCO_FORCE_NOT_IDLE") != 0) { CoCoBarrier.ForceNotIdle(); } if (EnvInt(0, "COCO_FORCE_FORWARDING") != 0) { CoCoBarrier.ForceForwarding(); } if (EnvInt(0, "COCO_FORCE_PINNING") != 0) { CoCoBarrier.ForcePinning(); } base.EnableHeap(); cocoThread = new Thread(new ThreadStart(CoCoLoop)); cocoThread.Start(); }
internal override void PostRootScanHook() { if (inFixUp) { timingAfterCopy = Environment.TickCount; CoCoBarrier.ChangePhase(CoCoBarrier.Phase.Idle, true, true); } }
internal override UIntPtr AllocateObjectMemorySlow(UIntPtr numBytes, uint alignment, Thread currentThread) { CoCoBarrier.ClientHandshake(); return(base.AllocateObjectMemorySlow(numBytes, alignment, currentThread)); }
internal override unsafe void ProcessObjectPtr(UIntPtr realPtr, UIntPtr *loc, UIntPtr addr) { UIntPtr forward = CoCoBarrier.ToSpaceAsPtr(realPtr); if (forward != realPtr) { *loc = addr - realPtr + forward; } markReferenceVisitor.VisitValueAnyThreadMaybeNull(forward); }
internal unsafe void ForwardAndVisit(UIntPtr *loc) { UIntPtr addr = *loc; if (addr == UIntPtr.Zero) { return; } UIntPtr forward = CoCoBarrier.instance.ToSpaceImplNonNull(Magic.fromAddress(addr)); if (forward != addr) { CoCoBarrier.CAS(loc, forward, addr); // if this CAS fails it means that someone stored // a different pointer into the field, but in that // case the pointer stored would have already been // forwarded thanks to the CoCo write barrier. } VisitValueNonNull(forward); }
internal override UIntPtr ForwardIfNecessary(UIntPtr addr) { return(CoCoBarrier.ToSpaceAsPtr(addr)); }
internal unsafe void ScanHook(Object obj) { UIntPtr page = PageTable.Page(Magic.addressOf(obj)); if (PageTable.Type(page) != SegregatedFreeList.SMALL_OBJ_PAGE) { //VTable.DebugPrint(" not tagging because this isn't a small object page"); return; } SegregatedFreeList.PageHeader *ph = (SegregatedFreeList.PageHeader *)PageTable.PageAddr(page); if (!new CoCoPageUserValue(ph->userValue).Marked) { //VTable.DebugPrint(" not tagging because the page isn't marked\n"); return; } if (obj is EMU || obj is Monitor || obj is Thread || obj is ThreadHeaderQueue) { CoCoBarrier.NotifyPin(Magic.addressOf(obj)); if (fVerbose) { VTable.DebugPrint(" $$ not tagging object because it's a monitor or EMU\n"); } return; } if (doingCoCo) { //VTable.DebugPrint(" not tagging object because doingCoCo\n"); return; } if (!CoCoBarrier.instance.ObjectIsNotCopied(obj)) { if (fVerbose) { VTable.DebugPrint(" not tagging object because object is already in the process of being copied.\n"); } return; } if (fVerbose && obj.GetType() != typeof(Object)) { VTable.DebugPrint(" $$ tagging a non-System.Object; type is "); VTable.DebugPrint(obj.GetType().Name); VTable.DebugPrint("\n"); } // REVIEW: I wish that there was an easier way of // doing this. Object copy; if (obj is Array) { Array a = (Array)obj; if (a.IsVector) { copy = GC.AllocateVector(a.vtable, a.Length); } else { copy = GC.AllocateArray(a.vtable, a.Rank, a.Length); } } else if (obj is String) { String s = (String)obj; // REVIEW: this is not nice. copy = GC.AllocateString(s.ArrayLength - 1); } else { copy = GC.AllocateObject(obj.vtable); } VTable.Assert(ObjectLayout.Sizeof(copy) == ObjectLayout.Sizeof(obj), "Copy is not same size as original"); spaceOverhead += ObjectLayout.Sizeof(copy); bool first = !CoCoBarrier.instance.AnyTaggedForCopying; UIntPtr thisSpaceOverhead; if (CoCoBarrier.instance.TagObjectForCopy(obj, copy, out thisSpaceOverhead)) { cnt++; if (first) { lock (interlock) { if (!wantCoCo && !doingCoCo) { wantCoCo = true; } } } } spaceOverhead += thisSpaceOverhead; }
internal static void CoCoLoop() { if (fDebug) { VTable.DebugPrint("coco thread = "); VTable.DebugPrint((ulong)Win32Native.GetCurrentThreadId()); VTable.DebugPrint("\n"); VTable.DebugPrint("CoCo at "); VTable.DebugPrint((ulong)Magic.addressOf(Thread.CurrentThread)); VTable.DebugPrint("\n"); } for (;;) { lock (interlock) { doingCoCo = false; for (;;) { if (die) { return; } else if (didStartTrace) { didStartTrace = false; Monitor.PulseAll(interlock); } else if (didEndTrace) { didEndTrace = false; Monitor.PulseAll(interlock); if (wantCoCo) { break; } } Monitor.Wait(interlock); } wantCoCo = false; } // now further tracing is BLOCKED cyclesStarted++; timingBefore = Environment.TickCount; if (fDebug) { VTable.DebugPrint("+++++ Start Concurrent Copying\n"); } CoCoBarrier.EnablePinning(); doingCoCo = true; ConcurrentMSCollector.stackMarkReferenceVisitor = CoCoMSCollector.nopStackMarker; ConcurrentMSCollector.stackMarkPinnedReferenceVisitor = CoCoMSCollector.pinStackMarker; // Perform a scan of all call stacks, including the call // stack of the CoCo thread. ConcurrentMSCollector.TrivialHandshake = false; ConcurrentMSCollector.IncludeMUWInHandshake = false; ConcurrentMSCollector.CollectorHandshake(cocoThread); // In order to scan the call stack of the current thread, // we need a TransitionRecord for the thread. At this // point we don't have one, so we have to go through // CollectBodyTransition to get one. Transitions.MakeGCRequest(cocoThread.threadIndex); GC.InvokeCollection(cocoThread); ConcurrentMSCollector.TrivialHandshake = true; ConcurrentMSCollector.IncludeMUWInHandshake = true; ConcurrentMSCollector.stackMarkReferenceVisitor = CoCoMSCollector.normalStackMarker; ConcurrentMSCollector.stackMarkPinnedReferenceVisitor = CoCoMSCollector.normalStackMarker; timingAfterPin = Environment.TickCount; if (fDebug) { VTable.DebugPrint("+++++ Copying\n"); } if (CoCoBarrier.instance.NeedsPrepPhase) { CoCoBarrier.ChangePhase(CoCoBarrier.Phase.Prep, false, true); } timingAfterPrep = Environment.TickCount; CoCoBarrier.ChangePhase(CoCoBarrier.Phase.Copy, true, true); numCopied += CoCoBarrier.instance.Copy(); CoCoBarrier.ChangePhase(CoCoBarrier.Phase.Fixup, true, true); AddCollectionRequest(); // wait for a complete collector cycle. This is for fixup. if (fDebug) { VTable.DebugPrint("+++++ Fixup: Waiting to start tracing\n"); } lock (interlock) { while (!didStartTrace && !die) { Monitor.Wait(interlock); } if (die) { return; } didStartTrace = false; inFixUp = true; Monitor.PulseAll(interlock); } if (fDebug) { VTable.DebugPrint("+++++ Fixup: Waiting to end tracing\n"); } lock (interlock) { while (!didEndTrace && !die) { Monitor.Wait(interlock); } if (die) { return; } didEndTrace = false; doingCoCo = false; inFixUp = false; Monitor.PulseAll(interlock); } timingAfter = Environment.TickCount; CoCoBarrier.ChangePhase(CoCoBarrier.Phase.Idle, false, false); if (fDebug) { VTable.DebugPrint("+++++ Finish Concurrent Copying\n"); } pinTime += (timingAfterPin - timingBefore); prepTime += (timingAfterPrep - timingAfterPin); copyTime += (timingAfterCopy - timingAfterPrep); forwardTime += (timingAfter - timingAfterCopy); cycles++; } }
internal override void PostSweepHook() { CoCoBarrier.ExchangeReadyForCoCo(true); }
internal override void PreSweepHook() { CoCoBarrier.ExchangeReadyForCoCo(false); }
internal override void ThreadStartNotification(int currentThreadIndex) { base.ThreadStartNotification(currentThreadIndex); CoCoBarrier.ThreadStart(Thread.threadTable[currentThreadIndex]); }