internal static unsafe void VerifyFirst(UIntPtr previousObjectAddr, UIntPtr objectAddr) { UIntPtr page = PageTable.Page(objectAddr); if (previousObjectAddr != UIntPtr.Zero) { UIntPtr previousPage = PageTable.Page(previousObjectAddr); UIntPtr pageCursor = previousPage + 1; while (pageCursor < page) { uint cursorOffset = PageTable.Extra(pageCursor); UIntPtr objAddr = (PageTable.PageAddr(pageCursor) + cursorOffset - OFFSET_SKEW); if (!(cursorOffset <= OFFSET_NO_DATA || BumpAllocator.IsUnusedSpace(objAddr) || Allocator.IsAlignment(objAddr) || BumpAllocator.IsRestOfPageZero(objAddr))) { VTable.DebugPrint ("cursorOffset={0:x} OFFSET_NO_DATA={1:x} objAddr={2:x} unused={3} isalign={4} iszero={5}\n", __arglist((cursorOffset), (OFFSET_NO_DATA), ((long)objAddr), (BumpAllocator.IsUnusedSpace(objAddr)), (Allocator.IsAlignment(objAddr)), (BumpAllocator.IsRestOfPageZero(objAddr)))); } VTable.Assert(cursorOffset <= OFFSET_NO_DATA || BumpAllocator.IsUnusedSpace(objAddr) || Allocator.IsAlignment(objAddr) || BumpAllocator.IsRestOfPageZero(objAddr), "VerifyFirst 1"); pageCursor++; } } uint offset = PageTable.Extra(page); if (offset > OFFSET_NO_DATA) { UIntPtr firstAddr = PageTable.PageAddr(page) + offset - OFFSET_SKEW; if (!(firstAddr == objectAddr || (firstAddr + UIntPtr.Size == objectAddr && Allocator.IsAlignment(firstAddr)))) { VTable.DebugPrint ("firstAddr={0:x} objectAddr={1:x} isalign={2}\n", __arglist(((long)firstAddr), ((long)objectAddr), (Allocator.IsAlignment(firstAddr)))); } VTable.Assert(firstAddr == objectAddr || (firstAddr + 4 == objectAddr && Allocator.IsAlignment(firstAddr)), "VerifyFirst 2"); } }
internal void ProcessPinnedPages(ReferenceVisitor ptrVisitor) { if (pinnedPageList == null || pinnedPageList.Count == 0) { return; } pinnedPageList.Sort(comparer); int limit = pinnedPageList.Count; for (int i = 0; i < limit; i++) { UIntPtr page = (UIntPtr)pinnedPageList[i]; PageType fromSpaceType = PageTable.Type(page); VTable.Assert(PageTable.IsZombiePage(fromSpaceType), "Semispace:RegisterPinnedReference:2"); PageType toSpaceType = PageTable.ZombieToLive(fromSpaceType); PageTable.SetType(page, toSpaceType); } int pageIndex = 0; while (pageIndex < limit) { UIntPtr startPage = (UIntPtr)pinnedPageList[pageIndex]; UIntPtr endPage = startPage + 1; pageIndex++; while (pageIndex < limit && (UIntPtr)pinnedPageList[pageIndex] == endPage) { pageIndex++; endPage++; } UIntPtr objectAddr = FirstPinnedObjectAddr(startPage); UIntPtr pastAddr = PostPinnedObjectAddr(endPage); while (objectAddr < pastAddr) { if (Allocator.IsAlignment(objectAddr)) { objectAddr += UIntPtr.Size; } else if (BumpAllocator.IsUnusedSpace(objectAddr)) { objectAddr = (PageTable.PagePad(objectAddr) + PreHeader.Size); } else { Object obj = Magic.fromAddress(objectAddr); objectAddr += ptrVisitor.VisitReferenceFields(obj); } } } }
// Finds the object base for an interior pointer. In the case of a // pointer to the tail of an object and the head of another, it will // return the former object (the one whose tail we point at). To // get the base pointer for a pointer into the pre-header, you should // add PreHeader.Size before calling this. internal static UIntPtr Find(UIntPtr addr) { UIntPtr page = PageTable.Page(addr); UIntPtr currAddr = InteriorPtrTable.First(page); // Look out for the unused space token: this page may not // have been completely allocated: its "first" object might not // be valid. if (BumpAllocator.IsUnusedSpace(currAddr) || currAddr > addr) { // Back up to the previous object. Should be fast // since First updated the InteriorPtrTable entries. currAddr = Before(PageTable.PageAddr(page)); } VTable.Assert(!BumpAllocator.IsUnusedSpace(currAddr), "InteriorPtrTable.Find 0"); VTable.Assert(currAddr <= addr, "InteriorPtrTable.Find 1"); while (true) { // Watch out for alignment padding; advance the pointer if // it points to a syncblock index rather than a vtable // pointer. Note that we must do this before scrolling, // since the page table value was set before we knew the // required alignment. if (Allocator.IsAlignment(currAddr)) { currAddr += UIntPtr.Size; } else if (BumpAllocator.IsUnusedSpace(currAddr)) { UIntPtr postAddr = PageTable.PagePad(currAddr) + PreHeader.Size; VTable.Assert(postAddr <= addr, "InteriorPtrTable.Find 2"); currAddr = postAddr; } else { VTable.Assert(currAddr <= addr, "InteriorPtrTable.Find 3"); UIntPtr size = ObjectSize(currAddr); VTable.Assert(size >= UIntPtr.Zero, "InteriorPtrTable.Find 4"); UIntPtr postAddr = currAddr + size; if (postAddr > addr) { return(currAddr); } else { currAddr = postAddr; } } } }
private static UIntPtr PostPinnedObjectAddr(UIntPtr endPage) { UIntPtr endAddr = PageTable.PageAddr(endPage); UIntPtr postLastObjectAddr = InteriorPtrTable.Last(endPage - 1); if (postLastObjectAddr < endAddr && !BumpAllocator.IsUnusedSpace(postLastObjectAddr)) { // If the next object straddles into the next page, // return the location just past the object Object lastObject = Magic.fromAddress(postLastObjectAddr); UIntPtr lastObjectSize = ObjectLayout.ObjectSize(postLastObjectAddr, lastObject.vtable); postLastObjectAddr += lastObjectSize; } return(postLastObjectAddr - PreHeader.Size); }
/* * Returns a pointer to the first object on the given page. * N.B. If called on a page with no ~allocated~ first object it may * return a pointer to the unused space token. */ internal static UIntPtr First(UIntPtr page) { uint offset = PageTable.Extra(page); UIntPtr pageAddr = PageTable.PageAddr(page); UIntPtr currAddr; if (offset != OFFSET_NO_DATA) { currAddr = pageAddr + (offset - OFFSET_SKEW); } else { currAddr = Before(pageAddr); VTable.Assert(currAddr <= pageAddr); UIntPtr nextPageStart = PageTable.PagePad(currAddr + 1); while (currAddr < pageAddr) { if (Allocator.IsAlignment(currAddr)) { currAddr += UIntPtr.Size; } else if (BumpAllocator.IsUnusedSpace(currAddr)) { currAddr = PageTable.PagePad(currAddr) + PreHeader.Size; } else { if (currAddr >= nextPageStart) { InteriorPtrTable.SetFirst(currAddr); nextPageStart = PageTable.PagePad(currAddr + 1); } currAddr += ObjectSize(currAddr); } } } currAddr = Allocator.SkipAlignment(currAddr); return(currAddr); }
private static UIntPtr FirstPtrFromInteriorTable(UIntPtr c) { UIntPtr cardAddr = CardTable.CardAddr(c); UIntPtr nextCardAddr = CardTable.NextCardAddr(c); UIntPtr page = PageTable.Page(cardAddr); UIntPtr pageAddr = PageTable.PageAddr(page); UIntPtr currAddr; if (page == 0) { currAddr = PtrToNextObject(pageAddr, (UIntPtr)PreHeader.Size, nextCardAddr); } else { short offset = PageTable.Extra(page); currAddr = UIntPtr.Zero; if (offset != InteriorPtrTable.OFFSET_NO_DATA) { currAddr = pageAddr + (offset - InteriorPtrTable.OFFSET_SKEW); } // In general, we expect currAddr <= cardAddr. Or in the extreme // case, when the object starts from the page boundary, // currAddr - Object.HEADER_BYTES <= cardAddr. The contrary // cases has to be handled by searching previous pages. if (currAddr == UIntPtr.Zero || (currAddr > cardAddr && currAddr - PreHeader.Size > cardAddr)) { // look from previous pages, in case that an object on // them spans to the current page. In that case, we should // should use that object's ptr. currAddr = InteriorPtrTable.Last(page - 1); // Usually, Last() returns a pointer before or at the page // boundary. However, there is one exception: when an object // exactly fits to the last byte of the previous page, and the next // object starts right from the page boundary (the first byte of // the next page), then the pointer to this next object is returned. // Example found: objPtr =3d09fa8, size=60, pageboundary= // 3d0a000, next objPtr=3d0a008. Then returned pointer is // 3d0a008, which is beyond the page boundary. VTable.Assert(currAddr <= pageAddr || currAddr - PreHeader.Size <= pageAddr, "object is expected before page or right at the beginning of it"); } } VTable.Assert(currAddr < nextCardAddr, "object is expected before next card"); while (currAddr < nextCardAddr) { if (Allocator.IsAlignment(currAddr)) { currAddr += UIntPtr.Size; } else if (BumpAllocator.IsUnusedSpace(currAddr)) { currAddr = PageTable.PagePad(currAddr) + PreHeader.Size; } else { UIntPtr size = InteriorPtrTable.ObjectSize(currAddr); if (currAddr + size - PreHeader.Size > cardAddr) { return(currAddr); } currAddr += size; } } VTable.Assert(false, "No obj ptr found by looking at interior table"); return(UIntPtr.Zero); }
private static void CleanPageTail(UIntPtr postPinnedAddr) { if (!PageTable.PageAligned(postPinnedAddr)) { // If postPinnedAddr points to the first object on its page, // then we are removing all objects (specifically the part // of the object that the InteriorPtrTable tracks, the // vtables) from the page, so we should clear the page's // entry in the InteriorPtrTable. UIntPtr page = PageTable.Page(postPinnedAddr); UIntPtr firstObjPtr = InteriorPtrTable.First(page); if (firstObjPtr > postPinnedAddr) { VTable.Assert (firstObjPtr - PreHeader.Size >= postPinnedAddr, "postPinnedAddr should not point to the " + "interior of an object (1)"); InteriorPtrTable.ClearFirst(page); } else if (!BumpAllocator.IsUnusedSpace(firstObjPtr)) { UIntPtr firstObjSize = InteriorPtrTable.ObjectSize(firstObjPtr); VTable.Assert (firstObjPtr + firstObjSize - PreHeader.Size <= postPinnedAddr, "postPinnedAddr should not point to the " + "interior of an object (2)"); } UIntPtr byteCount = PageTable.PagePad(postPinnedAddr) - postPinnedAddr; Util.MemClear(postPinnedAddr, byteCount); BumpAllocator.WriteUnusedMarker(postPinnedAddr); if (GC.remsetType == RemSetType.Cards && byteCount > 0) { UIntPtr firstCard = CardTable.CardNo(postPinnedAddr); UIntPtr lastCard = CardTable.CardNo(postPinnedAddr + byteCount - 1); if (!OffsetTable.NoObjectPtrToTheCard(firstCard)) { UIntPtr offset = OffsetTable.GetOffset(firstCard); UIntPtr objPtr = CardTable.CardAddr(firstCard) + offset; UIntPtr size = OffsetTable.ObjectSize(objPtr); VTable.Assert ((objPtr + size - PreHeader.Size <= postPinnedAddr) || (objPtr >= postPinnedAddr), "Object should be totally " + "above or below postPinnedAddr"); if (objPtr >= postPinnedAddr) { OffsetTable.ClearCards(firstCard, firstCard); } } OffsetTable.ClearCards(firstCard + 1, lastCard); } } }
/* * Returns a pointer past the last object _that_fits_completely_ on * the given page. Note that the "last" object on a page may * actually start on a previous page. */ internal static UIntPtr Last(UIntPtr page) { UIntPtr currAddr = InteriorPtrTable.First(page); UIntPtr endAddr = PageTable.PageAddr(page + 1); // Look out for the unused space token: this page may not // have been completely allocated: its "first" object might not // be valid. if (BumpAllocator.IsUnusedSpace(currAddr) || currAddr >= endAddr) { // Back up to the previous object. Should be fast // since First updated the InteriorPtrTable entries. currAddr = Before(PageTable.PageAddr(page)); } // REVIEW this is very similar to Find(addr) below. VTable.Assert(currAddr <= endAddr); while (true) { // Watch out for alignment padding; advance the pointer if // it points to a syncblock index rather than a vtable // pointer. Note that we must do this before scrolling, // since the page table value was set before we knew the // required alignment. if (Allocator.IsAlignment(currAddr)) { currAddr += UIntPtr.Size; } else if (BumpAllocator.IsUnusedSpace(currAddr)) { UIntPtr nextAddr = PageTable.PagePad(currAddr) + PreHeader.Size; if (nextAddr >= endAddr) { return(currAddr); } else { currAddr = nextAddr; } } else { VTable.Assert(currAddr <= endAddr); UIntPtr size = ObjectSize(currAddr); UIntPtr postAddr = currAddr + size; if (postAddr > endAddr) { if (postAddr - PreHeader.Size > endAddr) { // The object spills over onto the next page return(currAddr); } else { // The object ended at or before the page boundary return(postAddr); } } else { currAddr = postAddr; } } } }