void VisitBootstrapData(DirectReferenceVisitor visitor) { #if !(REFERENCE_COUNTING_GC || DEFERRED_REFERENCE_COUNTING_GC) VisitAllRunFinalizer(visitor, true, false); // Trace other GC data. Being careful to NOT trace the Shadow visitor.VisitReferenceFields(CandidateTable); visitor.VisitReferenceFields(RunFinalizerTable); visitor.VisitReferenceFields(RunFinalizerTable[0]); #endif // REFERENCE_COUNTING_GC }
void ResurrectCandidates(DirectReferenceVisitor forwardVisitor, DirectReferenceVisitor resurrectVisitor, bool copyFirst) { #if !(REFERENCE_COUNTING_GC || DEFERRED_REFERENCE_COUNTING_GC) UIntPtr[] runTable = null; int runTableIndex = 0; int runIndex = 0; // For the concurrent collector, ResurrectCandidates could happen // while the application threads are calling SuppressFinalize and // ReRegisterForFinalize. So we need to use the spinLock to prevent // races. But we do not want to hold the spinLock while allocating // (i.e. when we grow the RunFinalizerTable[Shadow]) because our // spinLock is a leaf lock. We don't want to worry about deadlocks // involving the spinLock and any locking that occurs as part of a // GC provoked by an allocation attempt. #if SINGULARITY bool disabled = Processor.DisableLocalPreemption(); #endif spinLock.Acquire(); bool lockHeld = true; try { int logicalIndex = 0; for (int i = 0; i < CandidateTableShadow.Length; i++) { UIntPtr[] table = copyFirst ? CandidateTable[i] : CandidateTableShadow[i]; if (table == null) { VTable.Assert(logicalIndex == lastCandidateIndex); break; } for (int j = 0; j < table.Length; j++, logicalIndex++) { if (table[j] == UIntPtr.Zero) { VTable.Assert(logicalIndex == lastCandidateIndex); break; } fixed(UIntPtr *loc = &table[j]) { if (!IsLink((int)*loc)) { UIntPtr oldVal = *loc; forwardVisitor.Visit(loc); if (*loc == UIntPtr.Zero) { // Put this slot onto the CandidateTable's free list *loc = (UIntPtr)freeCandidateLink; freeCandidateLink = IndexToLink(logicalIndex); // marching forward through the RunFinalizer[Shadow] table, find an // empty slot to install this object. Maintain the cursor across // objects, so we can efficiently transfer an entire batch. for (; runTableIndex < RunFinalizerTableShadow.Length; runTableIndex++) { runTable = copyFirst ? RunFinalizerTable[runTableIndex] : RunFinalizerTableShadow[runTableIndex]; if (runTable == null) { // Create a new table int length = RunFinalizerTableShadow[runTableIndex - 1].Length * 2; lockHeld = false; spinLock.Release(); #if SINGULARITY Processor.RestoreLocalPreemption(disabled); #endif UIntPtr[] newTable = new UIntPtr[length]; #if SINGULARITY disabled = Processor.DisableLocalPreemption(); #endif spinLock.Acquire(); lockHeld = true; // There is no race with the RunFinalizerTable[Shadow]. // The spinLock serializes access to the CandidateTable[Shadow]. runTable = newTable; RunFinalizerTable[runTableIndex] = newTable; RunFinalizerTableShadow[runTableIndex] = newTable; UIntPtr tableAddr = Magic.addressOf(newTable); resurrectVisitor.Visit(&tableAddr); resurrectVisitor.VisitReferenceFields(RunFinalizerTable[runTableIndex]); resurrectVisitor.VisitReferenceFields(RunFinalizerTableShadow[runTableIndex]); } for (; runIndex < runTable.Length; runIndex++) { if (runTable[runIndex] == UIntPtr.Zero) { goto outer; } } runIndex -= runTable.Length; VTable.Assert(runIndex == 0); // ready for next sub-table } outer: // We found an empty slot in the RunFinalizerTable[Shadow], // where we can put our ready Candidate. It's also possible // to reach this label by falling through after exhausting the // entire table. This will result in an exception when we // attempt to over-index the array. It's not clear what more // protections are required... the process has exceeded an // unlikely and hard-wired capacity limit. Interlocked.Increment(ref WaitingToRun); madeRunnable = true; if (copyFirst) { RunFinalizerTable[runTableIndex][runIndex] = oldVal | new UIntPtr(1); } else { RunFinalizerTableShadow[runTableIndex][runIndex] = oldVal | new UIntPtr(1); } } } } } } } finally { if (lockHeld) { spinLock.Release(); #if SINGULARITY Processor.RestoreLocalPreemption(disabled); #endif } } if (madeRunnable) { // Resurrect objects! VisitAllRunFinalizer(resurrectVisitor, copyFirst, true); } #endif // REFERENCE_COUNTING_GC }