public static new void Initialize() { ConcurrentMSCollector.InitializeAllButVisitors(); // instance = new CoCoMSCollector(); ConcurrentMSCollector.instance = CoCoMSCollector.instance = (CoCoMSCollector) BootstrapMemory.Allocate(typeof(CoCoMSCollector)); ConcurrentMSCollector.markReferenceVisitor = (MarkReferenceVisitor) BootstrapMemory.Allocate(typeof(MarkAndForwardReferenceVisitor)); CoCoMSCollector.normalStackMarker = (NonNullReferenceVisitor) BootstrapMemory.Allocate(typeof(StackForwardReferenceVisitor)); CoCoMSCollector.pinStackMarker = (NonNullReferenceVisitor) BootstrapMemory.Allocate(typeof(StackMarkPinnedReferenceVisitor)); CoCoMSCollector.nopStackMarker = (NonNullReferenceVisitor) BootstrapMemory.Allocate(typeof(StackNopReferenceVisitor)); ConcurrentMSCollector.stackMarkReferenceVisitor = CoCoMSCollector.normalStackMarker; ConcurrentMSCollector.stackMarkPinnedReferenceVisitor = CoCoMSCollector.normalStackMarker; ConcurrentMSCollector.updateReferenceVisitor = (UpdateReferenceVisitor) BootstrapMemory.Allocate(typeof(UpdateAndForwardReferenceVisitor)); ConcurrentMSCollector.partialFreePageVisitor = (SegregatedFreeList.PartialFreePageVisitor) BootstrapMemory.Allocate(typeof(TaggingPartialFreePageVisitor)); // sweepVisitor = new SweepVisitor(); sweepVisitor = (SweepVisitor) BootstrapMemory.Allocate(typeof(SweepVisitor)); }
protected static void UpdateReferentRefCounts (UIntPtr objAddr, VTable vtable, NonNullReferenceVisitor updater) { updater.VisitReferenceFields(objAddr, vtable); }
GenericObjectVisitor(NonNullReferenceVisitor referenceVisitor) { this.referenceVisitor = referenceVisitor; #if DEBUG_OFFSETTABLE lastObjPtr = UIntPtr.Zero; #endif }
internal void ScanLiveRegs(UIntPtr mask, NonNullReferenceVisitor referenceVisitor) { EDI.ScanLiveReg((mask >> 2) & 0x3, referenceVisitor); ESI.ScanLiveReg((mask >> 4) & 0x3, referenceVisitor); EBX.ScanLiveReg((mask >> 0) & 0x3, referenceVisitor); EBP.ScanLiveReg((mask >> 6) & 0x3, referenceVisitor); }
protected static void purgeDeallocationList (NonNullReferenceVisitor decrementer) { while (beingDeallocatedBlock != null || delayedDeallocationList != null) { deallocateObjects(decrementer); } }
private static void VisitIfNotContext(Thread thread, NonNullReferenceVisitor threadReferenceVisitor, UIntPtr *p) { if (*p != (UIntPtr) thread.context && (int *) *p != &thread.context->gcStates) { threadReferenceVisitor.Visit(p); } }
internal Verifier(NonNullReferenceVisitor referenceVisitor, NonNullReferenceVisitor threadReferenceVisitor, ObjectLayout.ObjectVisitor objectVisitor, StackVerifier stackVerifier) { this.referenceVisitor = referenceVisitor;; this.threadReferenceVisitor = threadReferenceVisitor; this.objectVisitor = objectVisitor; this.stackVerifier = stackVerifier; }
// A profiler can request a scan of all Roots, passing in a // visitor for callback. private void ProfileScanRoots(NonNullReferenceVisitor visitor) { CallStack.ScanStacks(visitor, visitor); Thread.VisitBootstrapData(visitor); #if SINGULARITY_KERNEL Kernel.VisitSpecialData(visitor); #endif MultiUseWord.VisitStrongRefs(visitor, false /* Don't use shadows */); StaticData.ScanStaticData(visitor); }
internal void ScanLiveRegs(UIntPtr mask, NonNullReferenceVisitor referenceVisitor) { r4.ScanLiveReg((mask >> 0) & 0x3, referenceVisitor); r5.ScanLiveReg((mask >> 2) & 0x3, referenceVisitor); r6.ScanLiveReg((mask >> 4) & 0x3, referenceVisitor); r7.ScanLiveReg((mask >> 6) & 0x3, referenceVisitor); r8.ScanLiveReg((mask >> 8) & 0x3, referenceVisitor); r9.ScanLiveReg((mask >> 10) & 0x3, referenceVisitor); r10.ScanLiveReg((mask >> 12) & 0x3, referenceVisitor); r11.ScanLiveReg((mask >> 14) & 0x3, referenceVisitor); }
internal override void Scan(NonNullReferenceVisitor ptrVisitor, PageType genToCollect) { for (int i = 0; i < writeBufferIndex; i++) { UIntPtr tag = *(writeBuffer + i); if (tag != UIntPtr.Zero) { if ((tag & 0x1) == 0) { UIntPtr *fieldLoc = (UIntPtr *)tag; if (*fieldLoc != UIntPtr.Zero) { ptrVisitor.Visit(fieldLoc); } } else { UIntPtr objectPtr = (UIntPtr)(tag - 1); Object obj = Magic.fromAddress(objectPtr); ptrVisitor.VisitReferenceFields(obj); } } } // Handle the overflow in the thread objects for (int i = 0; i < Thread.threadTable.Length; i++) { Thread t = Thread.threadTable[i]; if (t != null) { UIntPtr tag = MixinThread(t).ssb.overflowValue; if (tag != UIntPtr.Zero) { if ((tag & 0x1) == 0) { UIntPtr *fieldLoc = (UIntPtr *)tag; if (*fieldLoc != UIntPtr.Zero) { ptrVisitor.Visit(fieldLoc); } } else { UIntPtr objectPtr = (UIntPtr)(tag - 1); Object obj = Magic.fromAddress(objectPtr); ptrVisitor.VisitReferenceFields(obj); } } } } }
internal static int ScanStacks(NonNullReferenceVisitor VisitThreadReference, NonNullReferenceVisitor VisitPinnedReference) { int limit = Thread.threadTable.Length; int countThreads = 0; for (int i = 0; i < limit; i++) { Thread t = Thread.threadTable[i]; if (t != null) { CollectorStatistics.Event(GCEvent.StackScanStart, i); ScanStack(t, VisitThreadReference, VisitPinnedReference); CollectorStatistics.Event(GCEvent.StackScanComplete, i); countThreads++; } } return countThreads; }
private static unsafe uint PurgeZCT(NonNullReferenceVisitor entryVisitor) { uint purgedSlots = 0; for (uint i = 1; i < maxEntries; i++) { UIntPtr content = zeroCountTable[i]; if (((uint)content & 0x01) != 0) { continue; // Node in free list, skip } purgedSlots++; entryVisitor.Visit(&content); } return(purgedSlots); }
uint ScanStack(Thread thread, NonNullReferenceVisitor VisitThreadReference, NonNullReferenceVisitor VisitPinnedReference) { Trace.Log(Trace.Area.Stack, "Scanning stack for thread {0:x}", __arglist(thread.threadIndex)); uint numStackFrames = 0; threadBeingProcessed = thread; CalleeSaveLocations calleeSaves = new CalleeSaveLocations(); #if SINGULARITY_KERNEL TransitionRecord *marker = (TransitionRecord *)thread.context.stackMarkers; #elif SINGULARITY_PROCESS TransitionRecord *marker = null; if (thread.context != null) { marker = (TransitionRecord *)thread.context->stackMarkers; } #else TransitionRecord *marker = (TransitionRecord *) MixinThread(thread).asmStackMarker; #endif while (marker != null) { Trace.Log(Trace.Area.Stack, "Transition record: old={0:x}, callAddr={1:x}, stackBottom={2:x}", __arglist(marker->oldTransitionRecord, marker->callAddr, marker->stackBottom)); marker->calleeSaveRegisters.DebugTrace(); TransitionRecord *stopMarker = marker->oldTransitionRecord; UIntPtr returnAddr = marker->callAddr; UIntPtr * fp = (UIntPtr *) marker->calleeSaveRegisters.GetFramePointer(); UIntPtr *sp = (UIntPtr *)marker->stackBottom; calleeSaves.SetCalleeSaves(&marker->calleeSaveRegisters); numStackFrames += ScanStackSegment(ref calleeSaves, returnAddr, fp, sp, stopMarker, VisitThreadReference, VisitPinnedReference, thread); marker = marker->oldTransitionRecord; } threadBeingProcessed = null; return(numStackFrames); }
static Verifier() { genericReferenceVisitor = new GenericReferenceVisitor(); genericThreadReferenceVisitor = new GenericThreadReferenceVisitor(); genericObjectVisitor = new GenericObjectVisitor(genericReferenceVisitor); genericStackVerifier = new GenericStackVerifier(); bumpAllocatorVerifier = new Verifier(genericReferenceVisitor, genericThreadReferenceVisitor, genericObjectVisitor, genericStackVerifier); segregatedFreeListVerifier = new Verifier(genericReferenceVisitor, genericThreadReferenceVisitor, new SegregatedFreeList.ObjectVisitorWrapper(genericObjectVisitor), genericStackVerifier); }
internal override bool Scan(NonNullReferenceVisitor visitor) { bool globalRepeat = false; while (true) { UIntPtr lowAddr, highAddr; if (this.destinationLow != this.allocator.AllocPtr) { lowAddr = this.destinationLow; highAddr = this.allocator.AllocPtr; this.destinationLow = highAddr; } else if (!this.HaveWork) { // No more work to do break; } else { lowAddr = this.GetWork(out highAddr); } globalRepeat = true; this.sourceHigh = highAddr; lowAddr += PreHeader.Size; lowAddr = BumpAllocator.SkipNonObjectData(lowAddr, highAddr); while (lowAddr < this.sourceHigh) { Object obj = Magic.fromAddress(lowAddr); lowAddr += visitor.VisitReferenceFields(obj); lowAddr = BumpAllocator.SkipNonObjectData(lowAddr, highAddr); } if (lowAddr < highAddr) { // The scanning must have been aborted early due to // overflow into a new page. Put the rest of the // range on the work list. this.AddWork(lowAddr - PreHeader.Size, highAddr); } } return(globalRepeat); }
uint ScanStaticPointerData(NonNullReferenceVisitor referenceVisitor) { uint totalSize = 0; for (int section = 0; section < sectionCount; section++) { uint size = (uint)(*(dataSectionEnd + section) - *(dataSectionBase + section)); totalSize += size; UIntPtr *ptr = *(dataSectionBase + section); uint * pointerBitmap = *(staticDataPointerBitMap + section); uint iters = (size + 31) / 32; for (uint i = 0; i < iters; i++) { uint mask = *pointerBitmap++; if (mask != 0) { for (int j = 0; j < 32; j++) { if ((mask & 1) != 0) { referenceVisitor.Visit(ptr); } ptr++; mask >>= 1; } } else { ptr += 32; } } } for (int section = 0; section < sectionCount; section++) { uint size = (uint)(*(roDataSectionEnd + section) - *(roDataSectionBase + section)); totalSize += size; } return(totalSize * (uint)UIntPtr.Size); }
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 }
internal override bool Scan(NonNullReferenceVisitor visitor) { bool localRepeat = false; bool globalRepeat = false; while (true) { while (this.HaveWork) { localRepeat = true; UIntPtr lowAddr, highAddr; lowAddr = this.GetWork(out highAddr); lowAddr += PreHeader.Size; lowAddr = BumpAllocator.SkipNonObjectData(lowAddr, highAddr); while (lowAddr < highAddr) { Object obj = Magic.fromAddress(lowAddr); lowAddr += visitor.VisitReferenceFields(obj); lowAddr = BumpAllocator.SkipNonObjectData(lowAddr, highAddr); } } if (this.destinationLow != this.allocator.AllocPtr) { localRepeat = true; UIntPtr lowAddr = this.destinationLow; UIntPtr highAddr = this.allocator.AllocPtr; this.destinationLow = highAddr; this.AddWork(lowAddr, highAddr); } if (!localRepeat) { // Exit the loop if we have done nothing this time around break; } globalRepeat = true; localRepeat = false; } return(globalRepeat); }
internal void ScanLiveReg(uint kind, NonNullReferenceVisitor visitor) { switch (kind) { case 0: { // Value is not a traceable heap pointer break; } case 1: { // Value is a pointer variable VTable.Deny(this.head == null); if (value != UIntPtr.Zero) { fixed(UIntPtr *valueField = &this.value) { visitor.Visit(valueField); } } ClearCalleeReg(); break; } case 2: { // Value is unchanged since function entry VTable.Deny(this.pending); this.pending = true; break; } case 3: default: { VTable.NotReached("ScanLiveReg 3 or default"); break; } } }
private static void VisitObjectsInCards(NonNullReferenceVisitor ptrVisitor, UIntPtr first, UIntPtr last) { UIntPtr objectPtr = OffsetTable.FirstObjPtrWithFieldInCard(first); VTable.Assert(objectPtr != UIntPtr.Zero, "No first obj ptr"); // TODO: in semispace.Visit, update cards in visiting promoted objects. // So far, since we have only two generations, and after scanning, all nursery // objects are promoted to mature generation, thus there is no inter-generational // pointers anymore, and we do not need to update cards during visit. But we // need to do that once we have more than two generations. UIntPtr limit = NextCardAddr(last); while (objectPtr != UIntPtr.Zero && objectPtr < limit) { #if DEBUG_CARDS VTable.DebugPrint(" visiting obj ptr {0:x8}\n", __arglist(objectPtr)); #endif Object obj = Magic.fromAddress(objectPtr); UIntPtr objSize = ptrVisitor.VisitReferenceFields(obj); UIntPtr nextObjectPtr = OffsetTable.PtrToNextObject(objectPtr, objSize, limit); VTable.Assert(CardNo(objectPtr) <= CardNo(nextObjectPtr), "Next object should be below the current one"); if (CardNo(objectPtr) < CardNo(nextObjectPtr)) { UIntPtr c = CardNo(objectPtr); UIntPtr offset = objectPtr - CardAddr(c); if (offset > OffsetTable.GetOffset(c)) { OffsetTable.SetOffset(c, offset); } } objectPtr = nextObjectPtr; } }
internal override bool Scan(NonNullReferenceVisitor visitor) { // BUGBUG: return(false); }
internal void Initialize(NonNullReferenceVisitor v) { this.visitor = v; }
protected static unsafe uint incrementalDecrement (UIntPtr objAddr, VTable vtable, NonNullReferenceVisitor decrementer) { uint pointerTracking = (uint)vtable.pointerTrackingMask; uint objTag = pointerTracking & 0xf; uint workDone = 0; switch (objTag) { case ObjectLayout.SPARSE_TAG: { UIntPtr *sparseObject = (UIntPtr *)objAddr; uint lastPointerTracking = getLastTracked(objAddr); for (pointerTracking = lastPointerTracking; pointerTracking != 0 && workDone < decrementSpan; workDone++) { uint index = pointerTracking & 0xf; pointerTracking >>= 4; UIntPtr *loc = sparseObject + (int)index; UIntPtr addr = *loc; if (addr != UIntPtr.Zero) { decrementer.Visit(addr); } } setLastTracked(objAddr, pointerTracking); break; } case ObjectLayout.DENSE_TAG: { UIntPtr *denseObject = (UIntPtr *) (objAddr + PostHeader.Size); int lastIndex = unchecked ((int)getLastTracked(objAddr)); pointerTracking >>= lastIndex + 4; for (denseObject += lastIndex; pointerTracking != 0 && workDone < decrementSpan; workDone++, lastIndex++, denseObject++) { if ((pointerTracking & 0x1) != 0 && *denseObject != UIntPtr.Zero) { decrementer.Visit(denseObject); } pointerTracking >>= 1; } setLastTracked(objAddr, unchecked ((uint)lastIndex)); break; } case ObjectLayout.PTR_VECTOR_TAG: { uint length = *(uint *)(objAddr + PostHeader.Size); UIntPtr *elemAddress = (UIntPtr *) (objAddr + vtable.baseLength - PreHeader.Size); uint lastIndex = getLastTracked(objAddr); for (elemAddress += lastIndex; lastIndex < length && workDone < decrementSpan; workDone++, lastIndex++, elemAddress++) { if (*elemAddress != UIntPtr.Zero) { decrementer.Visit(elemAddress); } } setLastTracked(objAddr, lastIndex); break; } case ObjectLayout.OTHER_VECTOR_TAG: { if (vtable.arrayOf == StructuralType.Struct) { uint length = *(uint *)(objAddr + PostHeader.Size); UIntPtr elemAddress = objAddr + vtable.baseLength - PreHeader.Size - PostHeader.Size; VTable elemVTable = vtable.arrayElementClass; int elemSize = vtable.arrayElementSize; uint lastIndex = getLastTracked(objAddr); for (elemAddress += (UIntPtr)(elemSize * lastIndex); lastIndex < length && workDone < decrementSpan; workDone++, lastIndex++, elemAddress += elemSize) { decrementer.VisitReferenceFields(elemAddress, elemVTable); } setLastTracked(objAddr, lastIndex); } break; } case ObjectLayout.PTR_ARRAY_TAG: { uint length = *(uint *)(objAddr + PostHeader.Size + sizeof(uint)); UIntPtr *elemAddress = (UIntPtr *) (objAddr + vtable.baseLength - PreHeader.Size); uint lastIndex = getLastTracked(objAddr); for (elemAddress += lastIndex; lastIndex < length && workDone < decrementSpan; workDone++, lastIndex++, elemAddress++) { if (*elemAddress != UIntPtr.Zero) { decrementer.Visit(elemAddress); } } setLastTracked(objAddr, lastIndex); break; } case ObjectLayout.OTHER_ARRAY_TAG: { if (vtable.arrayOf == StructuralType.Struct) { uint length = *(uint *)(objAddr + PostHeader.Size + sizeof(uint)); UIntPtr elemAddress = objAddr + vtable.baseLength - PreHeader.Size - PostHeader.Size; VTable elemVTable = vtable.arrayElementClass; int elemSize = vtable.arrayElementSize; uint lastIndex = getLastTracked(objAddr); for (elemAddress += (UIntPtr)(elemSize * lastIndex); lastIndex < length && workDone < decrementSpan; workDone++, lastIndex++, elemAddress += elemSize) { decrementer.VisitReferenceFields(elemAddress, elemVTable); } setLastTracked(objAddr, lastIndex); } break; } case ObjectLayout.STRING_TAG: { break; } default: { VTable.Assert((objTag & 0x1) == 0, @"(objTag & 0x1) == 0"); UIntPtr *largeObject = (UIntPtr *)objAddr; int * pointerDescription = (int *)vtable.pointerTrackingMask; int lastCount = unchecked ((int)getLastTracked(objAddr)); for (int count = *pointerDescription; lastCount <= count && workDone < decrementSpan; workDone++, lastCount++) { UIntPtr *loc = largeObject + *(pointerDescription + lastCount); if (*loc != UIntPtr.Zero) { decrementer.Visit(loc); } } setLastTracked(objAddr, unchecked ((uint)lastCount)); break; } } return(workDone); }
protected static void deallocateObjects (NonNullReferenceVisitor decrementer) { int startTicks = 0; bool enableGCTiming = VTable.enableGCTiming; if (enableGCTiming) { VTable.enableGCTiming = false; startTicks = Environment.TickCount; } if (VTable.enableGCWatermarks) { MemoryAccounting.RecordHeapWatermarks(); } // Set up a block to deallocate, if one doesn't exist. if (beingDeallocatedBlock == null && delayedDeallocationList != null) { beingDeallocatedBlock = delayedDeallocationList; delayedDeallocationList = getNextLink(delayedDeallocationList); delayedDeallocationLength--; UIntPtr objAddr = Magic.addressOf(beingDeallocatedBlock); VTable vtable = beingDeallocatedBlock.vtable; initIncrementalDecrement(objAddr, vtable); } // Perform up to a constant number of work chunks on the // block being deallocated. A "work chunk" is either // decrementing up to a fixed number of references held in // an object, decrementing up to a fixed number of slots // if the object is an array, or reclaiming the object // after all decrements on its internal contents are done. for (uint workDone = 0; beingDeallocatedBlock != null && workDone < deallocationSpan; workDone++) { // Continue work on block. UIntPtr objAddr = Magic.addressOf(beingDeallocatedBlock); #if DEBUG UIntPtr page = PageTable.Page(objAddr); VTable.Assert(PageTable.IsGcPage(page), @"PageTable.IsGcPage(page)"); #endif // DEBUG VTable vtable = beingDeallocatedBlock.vtable; if (incrementalDecrement(objAddr, vtable, decrementer) != 0) { continue; } // All decrements on contained references are over. Object obj = beingDeallocatedBlock; VTable.Assert((obj.REF_STATE & RSMasks.refCount) == 0, @"(obj.REF_STATE & RSMasks.refCount) == 0"); #if DEBUG PLCLink *plcLinkAddr = GetPLCLink(obj); VTable.Assert(plcLinkAddr == null, @"plcLinkAddr == null"); #endif // DEBUG SegregatedFreeList.Free(obj); // Set up block to work on next. beingDeallocatedBlock = delayedDeallocationList; if (delayedDeallocationList != null) { delayedDeallocationList = getNextLink(delayedDeallocationList); delayedDeallocationLength--; objAddr = Magic.addressOf(beingDeallocatedBlock); vtable = beingDeallocatedBlock.vtable; initIncrementalDecrement(objAddr, vtable); } } SegregatedFreeList.RecycleGlobalPages(); SegregatedFreeList.CommitFreedData(); GC.newBytesSinceGC = UIntPtr.Zero; if (enableGCTiming) { int elapsedTicks = Environment.TickCount - startTicks; System.GC.gcTotalTime += elapsedTicks; if (System.GC.maxPauseTime < elapsedTicks) { System.GC.maxPauseTime = elapsedTicks; } System.GC.pauseCount++; VTable.enableGCTiming = true; } }
void Verify(NonNullReferenceVisitor threadReferenceVisitor, Thread thread) { CallStack.ScanStack(thread, threadReferenceVisitor, threadReferenceVisitor); }
protected static unsafe void UpdateReferentRefCounts (UIntPtr objAddr, VTable vtable, int start, int span, NonNullReferenceVisitor updater) { uint pointerTracking = (uint)vtable.pointerTrackingMask; uint objTag = pointerTracking & 0xf; switch (objTag) { case ObjectLayout.PTR_VECTOR_TAG: { uint length = *(uint *)(objAddr + PostHeader.Size); VTable.Assert(span <= length, @"span <= length"); UIntPtr *elemAddress = (UIntPtr *)(objAddr + vtable.baseLength - PreHeader.Size) + start; for (int i = 0; i < span; i++, elemAddress++) { updater.Visit(elemAddress); } break; } case ObjectLayout.OTHER_VECTOR_TAG: { uint length = *(uint *)(objAddr + PostHeader.Size); VTable.Assert(span <= length, @"span <= length"); if (vtable.arrayOf == StructuralType.Struct) { int elemSize = vtable.arrayElementSize; UIntPtr elemAddress = objAddr + vtable.baseLength - PreHeader.Size - PostHeader.Size + elemSize * start; VTable elemVTable = vtable.arrayElementClass; for (int i = 0; i < span; i++, elemAddress += elemSize) { updater.VisitReferenceFields(elemAddress, elemVTable); } } break; } case ObjectLayout.PTR_ARRAY_TAG: { uint length = *(uint *)(objAddr + PostHeader.Size + sizeof(uint)); VTable.Assert(span <= length, @"span <= length"); UIntPtr *elemAddress = (UIntPtr *) (objAddr + vtable.baseLength - PreHeader.Size) + start; for (int i = 0; i < span; i++, elemAddress++) { updater.Visit(elemAddress); } break; } case ObjectLayout.OTHER_ARRAY_TAG: { uint length = *(uint *)(objAddr + PostHeader.Size + sizeof(uint)); VTable.Assert(span <= length, @"span <= length"); if (vtable.arrayOf == StructuralType.Struct) { int elemSize = vtable.arrayElementSize; UIntPtr elemAddress = objAddr + vtable.baseLength - PreHeader.Size - PostHeader.Size + elemSize * start; VTable elemVTable = vtable.arrayElementClass; for (int i = 0; i < span; i++, elemAddress += elemSize) { updater.VisitReferenceFields(elemAddress, elemVTable); } } break; } case ObjectLayout.STRING_TAG: { break; } default: { VTable.NotReached("An unsupported tag found!"); break; } } }
internal abstract bool Scan(NonNullReferenceVisitor visitor);
bool WalkStackFrame(ref UIntPtr *framePointer, ref UIntPtr *stackPointer, ref CalleeSaveLocations calleeSaves, ref UIntPtr returnAddr, NonNullReferenceVisitor threadReferenceVisitor, NonNullReferenceVisitor pinnedReferenceVisitor, CompressedFrameDescriptor smallFrameDescriptor, TransitionRecord *stopMarker, Thread thread) // BUGBUG: Remove thread argument when ThreadContext is on stack! { FrameDescriptor frameDescriptor = new FrameDescriptor(smallFrameDescriptor); if (frameDescriptor.isFramePointerOmitted) { framePointer = stackPointer + frameDescriptor.frameSize; } if (FrameContainsTransitionRecord(framePointer, stackPointer, stopMarker)) { return(true); // true: done } switch (frameDescriptor.argumentTag) { case FrameDescriptor.ESCAPE32_TAG: { int *table = (int *)frameDescriptor.argumentMaskOrTable; int count = table[0]; int pinnedCount = table[1]; int *offsets = &table[2]; if (threadReferenceVisitor != null) { for (int i = 0; i < count; i++) { UIntPtr *loc = framePointer + offsets[i]; if (*loc != UIntPtr.Zero) { // BUGBUG: threadReferenceVisitor.Visit(loc); VisitIfNotContext(thread, threadReferenceVisitor, loc); } } } if (frameDescriptor.hasPinnedVariables && pinnedReferenceVisitor != null) { offsets = &offsets[count]; for (int i = 0; i < pinnedCount; i++) { UIntPtr *loc = framePointer + offsets[i]; if (*loc != UIntPtr.Zero) { pinnedReferenceVisitor.Visit(loc); } } } break; } case FrameDescriptor.ESCAPE16_TAG: { short *table = (short *)frameDescriptor.argumentMaskOrTable; int count = table[0]; int pinnedCount = table[1]; short *offsets = &table[2]; if (threadReferenceVisitor != null) { for (int i = 0; i < count; i++) { UIntPtr *loc = framePointer + offsets[i]; if (*loc != UIntPtr.Zero) { // BUGBUG: threadReferenceVisitor.Visit(loc); VisitIfNotContext(thread, threadReferenceVisitor, loc); } } } if (frameDescriptor.hasPinnedVariables && pinnedReferenceVisitor != null) { offsets = &offsets[count]; for (int i = 0; i < pinnedCount; i++) { UIntPtr *loc = framePointer + offsets[i]; if (*loc != UIntPtr.Zero) { pinnedReferenceVisitor.Visit(loc); } } } break; } case FrameDescriptor.ESCAPE8_TAG: { sbyte *table = (sbyte *)frameDescriptor.argumentMaskOrTable; int count = table[0]; int pinnedCount = table[1]; sbyte *offsets = &table[2]; if (threadReferenceVisitor != null) { for (int i = 0; i < count; i++) { UIntPtr *loc = framePointer + offsets[i]; if (*loc != UIntPtr.Zero) { // BUGBUG: threadReferenceVisitor.Visit(loc); VisitIfNotContext(thread, threadReferenceVisitor, loc); } } } if (frameDescriptor.hasPinnedVariables && pinnedReferenceVisitor != null) { offsets = &offsets[count]; for (int i = 0; i < pinnedCount; i++) { UIntPtr *loc = framePointer + offsets[i]; if (*loc != UIntPtr.Zero) { pinnedReferenceVisitor.Visit(loc); } } } break; } case FrameDescriptor.COMPRESSED_MASK_TAG: { // Process the arguments int inBetweenSlotsAbove = frameDescriptor.inBetweenSlotsAbove; uint stackArgSize = frameDescriptor.argumentCount; UIntPtr mask = frameDescriptor.argumentMaskOrTable; if (threadReferenceVisitor != null && stackArgSize > 0) { UIntPtr *argumentPointer = framePointer + stackArgSize - 1 + inBetweenSlotsAbove; for (int i = 0; mask != 0 && i < stackArgSize; i++) { if ((mask & 0x1) != 0 && *argumentPointer != UIntPtr.Zero) { // BUGBUG: threadReferenceVisitor.Visit(p); VisitIfNotContext(thread, threadReferenceVisitor, argumentPointer); } mask >>= 1; argumentPointer--; } } else { for (int i = 0; mask != 0 && i < stackArgSize; i++) { mask >>= 1; } } // Process the local variables if (threadReferenceVisitor != null) { int transitionRecordSize = frameDescriptor.hasTransitionRecord ? sizeof(TransitionRecord) / sizeof(UIntPtr) : 0; int registerCount = CountBits(frameDescriptor.calleeSaveMask); int inBetweenSlotsBelow = frameDescriptor.inBetweenSlotsBelow; UIntPtr *variablePtr = framePointer - inBetweenSlotsBelow - registerCount - transitionRecordSize - 1; // -1 because FP is pointing in "above" region. while (mask != UIntPtr.Zero) { if ((mask & 0x1) != 0 && *variablePtr != UIntPtr.Zero) { // BUGBUG: threadReferenceVisitor.Visit(p); VisitIfNotContext(thread, threadReferenceVisitor, variablePtr); } mask >>= 1; variablePtr--; } } break; } default: { VTable.NotReached("FrameDescriptor mask switch failed"); break; } } if (frameDescriptor.calleeSaveValueMask != 0 && threadReferenceVisitor != null) { calleeSaves.ScanLiveRegs(frameDescriptor.calleeSaveValueMask, threadReferenceVisitor); } #if X86 || AMD64 || ISA_IX86 || ISA_IX64 UIntPtr nextReturnAddr; if (frameDescriptor.isFramePointerOmitted) { nextReturnAddr = *framePointer; stackPointer = framePointer + 1; } else { nextReturnAddr = *(framePointer + 1); stackPointer = framePointer + 2; } #elif ARM || ISA_ARM // CompressedFrameDescriptor is the target specific portion. // This will be refactored to FrameDescriptor via partial classes. UIntPtr nextReturnAddr = CompressedFrameDescriptor.NextCallSite(frameDescriptor.isFramePointerOmitted, framePointer, out stackPointer); #else #error Unknown Architecture #endif // In Singularity, the final return address of a thread is zero if (nextReturnAddr != UIntPtr.Zero) { calleeSaves.PopFrame(framePointer, frameDescriptor.calleeSaveMask, frameDescriptor.isFramePointerOmitted, frameDescriptor.hasTransitionRecord); } else { calleeSaves.ClearFrame(frameDescriptor.calleeSaveMask, frameDescriptor.isFramePointerOmitted); } UIntPtr *calcedfp = (UIntPtr *)calleeSaves.GetFramePointer(); if (calcedfp != null) { framePointer = calcedfp; } returnAddr = nextReturnAddr; return(false); // false: not done scanning: proceed to next frame }
uint ScanStackSegment(ref CalleeSaveLocations calleeSaves, UIntPtr returnAddr, UIntPtr *fp, UIntPtr *sp, TransitionRecord *stopMarker, NonNullReferenceVisitor VisitThreadReference, NonNullReferenceVisitor VisitPinnedReference, Thread thread) // BUGBUG: Remove thread argument when ThreadContext is on stack! { uint numStackFrames = 0; while (true) { #if SINGULARITY if (returnAddr >= LinkStackFunctionsBegin && returnAddr <= LinkStackFunctionsLimit) { if (returnAddr >= LinkStackBegin && returnAddr <= LinkStackLimit) { returnAddr = SkipLinkStackFrame(ref fp, ref sp); } else if (returnAddr >= UnlinkStackBegin && returnAddr <= UnlinkStackLimit) { returnAddr = SkipUnlinkStackFrame(ref fp, ref sp); } else if (returnAddr >= LinkStackStubsBegin && returnAddr <= LinkStackStubsLimit) { returnAddr = SkipLinkStackStubFrame(ref fp, ref sp); } else { VTable.NotReached("Unexpected link stack function"); } } #endif // Exit loop if we have reached the of the stack segment if (fp >= stopMarker && sp < stopMarker) { break; } int tableIndex = CallSiteTableNumber(returnAddr); if (tableIndex < 0) { break; } int callSiteSet = CallSiteSetNumber(returnAddr, tableIndex); if (callSiteSet < 0) { break; } ushort *callSiteToIndexTable = callSetSiteNumberToIndex[tableIndex]; int activationIndex = (int)callSiteToIndexTable[callSiteSet]; VTable.Assert(activationIndex >= 0); CompressedFrameDescriptor *descriptorTable = activationDescriptorTable[tableIndex]; CompressedFrameDescriptor frameDescriptor = descriptorTable[activationIndex]; bool done = WalkStackFrame(ref fp, ref sp, ref calleeSaves, ref returnAddr, VisitThreadReference, VisitPinnedReference, frameDescriptor, stopMarker, thread); if (done) { break; } numStackFrames++; } calleeSaves.ClearCalleeSaves(); return(numStackFrames); }
void VisitIfNotContext(Thread thread, NonNullReferenceVisitor threadReferenceVisitor, UIntPtr *p) { threadReferenceVisitor.Visit(p); }