internal static void Initialize() { switch (ptType) { case PTType.CentralPT: { CentralPT.Initialize(); break; } case PTType.CentralPTHimem: { CentralPTHimem.Initialize(); break; } case PTType.FlatDistributedPT: { FlatDistributedPT.Initialize(); break; } case PTType.FlatDistributedPTTest: { FlatDistributedPTTest.Initialize(); break; } default: { VTable.NotReached("Unknown PT type: " + ptType); break; } } }
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); } }
internal override void CheckForNeededGCWork(Thread currentThread) { if (NewBytesSinceGCExceeds((UIntPtr)1500000000)) { VTable.NotReached ("OutOfMemory: NullCollector: Out of original memory quota"); } }
public static new void Initialize() { GenerationalCollector.Initialize(); // copyScanners = new CopyScan[MAX_GENERATION+1]; copyScanners = (CopyScan[]) BootstrapMemory.Allocate(typeof(CopyScan[]), (uint)MAX_GENERATION + 1); for (int i = (int)MIN_GENERATION; i <= (int)MAX_GENERATION; i++) { switch (GC.copyscanType) { case CopyScanType.CheneyScan: { copyScanners[i] = (CopyScan) BootstrapMemory.Allocate(typeof(CheneyScan)); break; } case CopyScanType.HierarchicalScan: { copyScanners[i] = (CopyScan) BootstrapMemory.Allocate(typeof(HierarchicalScan)); break; } case CopyScanType.NestedHierarchicalScan: { copyScanners[i] = (CopyScan) BootstrapMemory.Allocate(typeof(NestedHierarchicalScan)); break; } default: { VTable.NotReached("Unknown CopyScan type: " + GC.copyscanType); break; } } copyScanners[i].Initialize((PageType)i); } // SemispaceCollector.instance = new SemispaceCollector(); SemispaceCollector.instance = (SemispaceCollector) BootstrapMemory.Allocate(typeof(SemispaceCollector)); // generalReferenceVisitor = new ForwardReferenceVisitor(); SemispaceCollector.generalReferenceVisitor = (ForwardReferenceVisitor) BootstrapMemory.Allocate(typeof(ForwardReferenceVisitor)); // threadReferenceVisitor = new ForwardThreadReference(generalReferenceVisitor); SemispaceCollector.threadReferenceVisitor = (ForwardThreadReference) BootstrapMemory.Allocate(typeof(ForwardThreadReference)); // pinnedReferenceVisitor = new RegisterPinnedReference(); SemispaceCollector.pinnedReferenceVisitor = (RegisterPinnedReference) BootstrapMemory.Allocate(typeof(RegisterPinnedReference)); // forwardOnlyReferenceVisitor = new ForwardOnlyReferenceVisitor(); SemispaceCollector.forwardOnlyReferenceVisitor = (ForwardOnlyReferenceVisitor) BootstrapMemory.Allocate(typeof(ForwardOnlyReferenceVisitor)); }
internal static uint PageTableEntry(UIntPtr page) { switch (ptType) { case PTType.CentralPT: case PTType.CentralPTHimem: return(CentralPT.PageTableEntryImpl(page)); #if !SINGULARITY case PTType.FlatDistributedPT: case PTType.FlatDistributedPTTest: return(FlatDistributedPT.PageTableEntryImpl(page)); #endif default: { VTable.NotReached("Unknown PT type: " + ptType); return(0xffffffff); } } }
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 InstallRemSet() { switch (GC.remsetType) { case RemSetType.SSB: { SequentialStoreBuffer.Initialize(); installedRemSet = SequentialStoreBuffer.instance; break; } case RemSetType.Cards: { CardTable.Initialize(); installedRemSet = CardTable.instance; break; } default: { VTable.NotReached("Unsupported remembered set: " + GC.remsetType); break; } } }
internal static void SetPageTableEntry(UIntPtr page, uint value) { switch (ptType) { case PTType.CentralPT: case PTType.CentralPTHimem: { CentralPT.SetPageTableEntryImpl(page, value); break; } #if !SINGULARITY case PTType.FlatDistributedPT: case PTType.FlatDistributedPTTest: { FlatDistributedPT.SetPageTableEntryImpl(page, value); break; } #endif default: { VTable.NotReached("Unknown PT type: " + ptType); break; } } }
internal override void CollectStoppable(int currentThreadIndex, int generation) { VTable.NotReached("OutOfMemory: NullCollector: Collect called"); }
static bool CopyObject(Object from) { if (fDietVerboseCopyDebug) { VTable.DebugPrint(" Copying "); VTable.DebugPrint((ulong)Magic.addressOf(from)); VTable.DebugPrint(" with CoCoWord = "); VTable.DebugPrint((ulong)MixinObject(from).preHeader.CoCoWord); VTable.DebugPrint("\n"); } for (;;) { UIntPtr CoCoWord = MixinObject(from).preHeader.CoCoWord; if (IsSimple(CoCoWord)) { // got pinned .. ignore return(false); } else if (IsTagged(CoCoWord)) { if (ShouldPin(Magic.addressOf(from))) { if (CASCoCoWord(from, Simple(), CoCoWord)) { // pinned NotifyPin(Magic.addressOf(from)); return(false); } } else { CASCoCoWord(from, Copying(CoCoWord), CoCoWord); } } else if (IsCopying(CoCoWord)) { Object to = Magic.fromAddress(ForwardPtr(CoCoWord)); UIntPtr begin = UIntPtr.Zero - (UIntPtr)PreHeader.Size; UIntPtr end = ((ObjectLayout.Sizeof(from) + sizeof(UIntPtr) - 1) & ~((UIntPtr)sizeof(UIntPtr) - 1)) - PreHeader.Size; if (fDietVerboseCopyDebug) { VTable.DebugPrint(" copying to "); VTable.DebugPrint((ulong)Magic.addressOf(to)); VTable.DebugPrint("; begin = "); VTable.DebugPrint((ulong)begin); VTable.DebugPrint("; end = "); VTable.DebugPrint((ulong)end); VTable.DebugPrint("; PreHeader.Size = "); VTable.DebugPrint((ulong)PreHeader.Size); VTable.DebugPrint("; Sizeof(from) = "); VTable.DebugPrint((ulong)ObjectLayout.Sizeof(from)); VTable.DebugPrint("; Sizeof(to) = "); VTable.DebugPrint((ulong)ObjectLayout.Sizeof(to)); VTable.DebugPrint("\n"); } for (UIntPtr offset = begin; offset != end; offset += sizeof(UIntPtr)) { if (!IgnoreOffset(offset)) { UIntPtr *fptr = (UIntPtr *)(Magic.addressOf(from) + offset); UIntPtr *tptr = (UIntPtr *)(Magic.addressOf(to) + offset); for (;;) { UIntPtr word = *fptr; if (word == Alpha) { // NOTE: this case will only be hit the first time // around the loop. if it's not hit the first time // it'll never get hit. break; } *tptr = word; if (InternalImmutableOffset(from, offset) || CAS(fptr, Alpha, word) == word) { break; } } } } MixinObject(from).preHeader.CoCoWord = Forwarded(CoCoWord); return(true); } else { VTable.NotReached(); } } }
internal static void ChangePhase(Phase phase_, bool forwarding_, bool pinning_) { if (fDebug) { VTable.DebugPrint(" --> CoCo going to "); switch (phase_) { case Phase.Idle: VTable.DebugPrint("Idle"); break; case Phase.Prep: VTable.DebugPrint("Prep"); break; case Phase.Copy: VTable.DebugPrint("Copy"); break; case Phase.Fixup: VTable.DebugPrint("Fixup"); break; default: VTable.NotReached(); break; } VTable.DebugPrint(" (with"); if (!forwarding_) { VTable.DebugPrint("out"); } VTable.DebugPrint(" forwarding, with"); if (!pinning_) { VTable.DebugPrint("out"); } VTable.DebugPrint(" pinning)\n"); } lock (interlock) { phase = phase_; forwarding = forwarding_ || forceForwarding; pinning = pinning_ || forcePinning; SetAllowFastPath(); isNotIdle = phase != Phase.Idle || forceNotIdle; CoCoThread t = MixinThread(Thread.CurrentThread); t.acknowledgedPhase = (int)phase; t.acknowledgedForwarding = forwarding; t.acknowledgedPinning = pinning; t.phaseVersion++; Monitor.PulseAll(interlock); for (;;) { bool needToWait = false; bool doPulseAll = false; for (int i = 0; i < Thread.threadTable.Length; ++i) { Thread t_ = Thread.threadTable[i]; if (t_ == null) { continue; } t = MixinThread(t_); if (Transitions.InDormantState(i) || !t.readyForCoCo || t.pinnedOut) { t.acknowledgedPhase = (int)phase; t.acknowledgedForwarding = forwarding; t.acknowledgedPinning = pinning; } if (t.pinnedOut && phase == Phase.Idle) { t.pinnedOut = false; doPulseAll = true; } if ((Phase)t.acknowledgedPhase != phase || t.acknowledgedForwarding != forwarding || t.acknowledgedPinning != pinning) { if (fDebug) { VTable.DebugPrint(" !! thread "); VTable.DebugPrint((ulong)Magic.addressOf(t)); VTable.DebugPrint(" not ack\n"); } needToWait = true; } } if (doPulseAll) { Monitor.PulseAll(interlock); } if (!needToWait) { break; } // REVIEW: make the timeout less than 500 ms Monitor.Wait(interlock, 500); } } }
internal static void ReportHeapDetails() { VTable.DebugPrint("\nHeap details:\n"); uint pageCount = 0; for (UIntPtr i = UIntPtr.Zero; i < PageTable.pageTableCount; i++) { if (PageTable.IsMyGcPage(i)) { pageCount++; } } VTable.DebugPrint("\tTotal number of heap pages: {0}", __arglist(pageCount)); // The following obtains counts of heap objects against types. UIntPtr lowPage = UIntPtr.Zero; UIntPtr highPage = PageTable.pageTableCount; assertRuntimeTypeHeaders(lowPage, highPage); // First count the RuntimeType instances for heap objects. runtimeTypeReckoner.Initialize(true); visitAllObjects(forGCRuntimeTypeReckoner, lowPage, highPage); // Next, create a table for RuntimeType instance accounting. // NOTE: Storage for the table is marked "non-GC". Since // static data accounting is done before this, it's okay. int numSlots = runtimeTypeReckoner.Count; if (numSlots > TABLE_SIZE) { VTable.DebugPrint("Need {0} slots, have {1}\n", __arglist(numSlots, TABLE_SIZE)); VTable.NotReached("MemoryAccounting table not large enough"); } // Associate a table slot for each RuntimeType instance. runtimeTypeMapper.Initialize(false, MemoryAccounting.table); visitAllObjects(forGCRuntimeTypeMapper, lowPage, highPage); // Map each relevant RuntimeType instance to its table slot. for (uint i = 0; i < numSlots; i++) { RuntimeType rType = MemoryAccounting.table[i].RuntimeTypeObject; VTable.Assert(!MultiUseWord.IsMarked(rType), @"!MultiUseWord.IsMarked(rType)"); MemoryAccounting.table[i].SavedMUW = MultiUseWord.GetForObject(rType); MultiUseWord.SetValForObject(rType, (UIntPtr)i); } // Count heap object instances by RuntimeType using table. instanceReckoner.Initialize(MemoryAccounting.table); visitAllObjects(forGCInstanceReckoner, lowPage, highPage); // Bubble sort the table in decreasing order of total size. for (int i = 0; i < numSlots; i++) { for (int j = numSlots - 1; j > i; j--) { if (MemoryAccounting.table[j].TotalSize > MemoryAccounting.table[j - 1].TotalSize) { // Swap contents. RuntimeTypeAccounting temp = MemoryAccounting.table[j]; MemoryAccounting.table[j] = MemoryAccounting.table[j - 1]; MemoryAccounting.table[j - 1] = temp; } } } // Display table. VTable.DebugPrint("\n\tCounts of objects against types:\n"); for (uint i = 0; i < numSlots; i++) { if ((uint)MemoryAccounting.table[i].TotalSize < 1024) { continue; } VTable.DebugPrint ("\t\t{0,36} instances: {1,6}, bytes: {2,10}\n", __arglist(MemoryAccounting.table[i].RuntimeTypeObject.Name, (uint)MemoryAccounting.table[i].Count, (uint)MemoryAccounting.table[i].TotalSize)); } // Reset book-keeping information maintained in headers and the global // table. for (uint i = 0; i < numSlots; i++) { RuntimeType rType = MemoryAccounting.table[i].RuntimeTypeObject; MultiUseWord.SetForObject (rType, MemoryAccounting.table[i].SavedMUW); VTable.Assert(!MultiUseWord.IsMarked(rType), "@!MultiUseWord.IsMarked(rType)"); MemoryAccounting.table[i].RuntimeTypeObject = null; MemoryAccounting.table[i].SavedMUW = new MultiUseWord(new UIntPtr(0)); MemoryAccounting.table[i].TotalSize = new UIntPtr(0); MemoryAccounting.table[i].Count = 0; } }
internal unsafe static void Report(GCType gcType) { if (!MemoryAccounting.initialized) { VTable.DebugPrint("MemoryAccounting invoked before" + " initialization was completed!\n"); return; } VTable.DebugPrint("\nCollector: "); switch (gcType) { case GCType.AdaptiveCopyingCollector: { VTable.DebugPrint("Adaptive Copying\n"); break; } case GCType.MarkSweepCollector: { VTable.DebugPrint("Mark-Sweep\n"); break; } case GCType.SemispaceCollector: { VTable.DebugPrint("Semispace\n"); break; } case GCType.SlidingCollector: { VTable.DebugPrint("Sliding\n"); break; } case GCType.ConcurrentMSCollector: { VTable.DebugPrint("Concurrent Mark-Sweep\n"); break; } case GCType.ReferenceCountingCollector: { VTable.DebugPrint("Reference Counting\n"); VTable.NotImplemented(); return; // Not supported yet. } #if !SINGULARITY case GCType.DeferredReferenceCountingCollector: { VTable.DebugPrint("Deferred Reference Counting\n"); VTable.NotImplemented(); return; // Not supported yet. } #endif default: { VTable.NotReached("Unknown GC type: " + gcType); break; } } uint pageSize = (uint)(PageTable.PageSize >> 10); VTable.DebugPrint("\nPage size: {0}KB\nVM size: {1} KB\n", __arglist(pageSize, pageSize * (uint)PageTable.pageTableCount)); ReportNonGCDetails(); ReportStackDetails(); ReportHeapDetails(); }
internal override UIntPtr FindObjectAddr(UIntPtr interiorPtr) { VTable.NotReached ("OutOfMemory: NullCollector: FindObjectAddr called"); return(UIntPtr.Zero); }
internal override int CollectionGeneration(int gen) { VTable.NotReached ("OutOfMemory: NullCollector: CollectionGeneration called"); return(MinGeneration); }
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); }
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; } } }