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); } } } } }
private static void VisitIfNotContext(Thread thread, NonNullReferenceVisitor threadReferenceVisitor, UIntPtr *p) { if (*p != (UIntPtr) thread.context && (int *) *p != &thread.context->gcStates) { threadReferenceVisitor.Visit(p); } }
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 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 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; } } }
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 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; } } }
void VisitIfNotContext(Thread thread, NonNullReferenceVisitor threadReferenceVisitor, UIntPtr *p) { threadReferenceVisitor.Visit(p); }
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 }