/* * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.max.vm.heap.gcx; import com.sun.max.annotate.*; import com.sun.max.unsafe.*; import com.sun.max.vm.*; import com.sun.max.vm.actor.holder.*; import com.sun.max.vm.heap.*; import com.sun.max.vm.layout.*; import com.sun.max.vm.reference.*; import com.sun.max.vm.runtime.*; /** * After mark-sweep verifier for a free space manager with tracing based on TricolorHeapMarker. */ public class AfterMarkSweepVerifier extends PointerIndexVisitor implements CellRangeVisitor, CellVisitor { final TricolorHeapMarker heapMarker; final Sweeper sweeper; long darkMatterByteCount; long freeChunksByteCount; long liveDataByteCount; Pointer visitedCellOrigin; int visitedIndex; final AfterMarkSweepBootHeapVerifier bootHeapVerifier; public AfterMarkSweepVerifier(TricolorHeapMarker heapMarker, Sweeper msVerification, AfterMarkSweepBootHeapVerifier bootHeapVerifier) { this.heapMarker = heapMarker; this.sweeper = msVerification; this.bootHeapVerifier = bootHeapVerifier; } private void printMark(Pointer origin) { final int bitIndex = heapMarker.bitIndexOf(origin); Log.print("bit index = "); Log.print(bitIndex); Log.print(" at bitmap word # "); Log.print(heapMarker.bitmapWordIndex(origin)); Log.print(", marked "); Log.print(heapMarker.colorName(bitIndex)); } @INLINE private void visit(Pointer origin) { if (!origin.isZero()) { final boolean inDeadSpace = HeapFreeChunk.isInDeadSpace(origin); if (inDeadSpace) { Log.print("\n\nvisited Cell @"); Log.print(visitedCellOrigin); printMark(visitedCellOrigin); Log.print(" pointing to dead space @"); Log.println(origin); printMark(origin); Log.println(); FatalError.check(!HeapFreeChunk.isInDeadSpace(origin), "must not points to dead space"); } // Check that the reference points to a valid object, and that if it is in the covered area, it is marked black. Reference hubRef = Layout.readHubReference(origin); FatalError.check(!hubRef.isZero() && hubRef.toJava() instanceof Hub, "Invalid reference detected"); if (heapMarker.isCovered(origin)) { FatalError.check(heapMarker.isBlackWhenNoGreys(origin), "pointer to live object in covered area must be black after GC"); } } } @Override public void visit(Pointer pointer, int wordIndex) { visit(pointer.getReference(wordIndex).toOrigin()); } public Pointer visitCell(Pointer cell) { return verifyCell(cell); } private Pointer verifyCell(Pointer cell) { final Pointer origin = Layout.cellToOrigin(cell); visitedCellOrigin = origin; final Reference hubRef = Layout.readHubReference(origin); final Hub hub = UnsafeCast.asHub(hubRef.toJava()); if (hub == HeapFreeChunk.heapFreeChunkHub()) { FatalError.check(heapMarker.isWhite(cell), "free chunk must not be marked"); Size chunkSize = HeapFreeChunk.getFreechunkSize(cell); freeChunksByteCount += chunkSize.toLong(); return cell.plus(chunkSize); } Size size = Layout.size(origin); if (heapMarker.isWhite(cell)) { darkMatterByteCount += size.toLong(); } else { FatalError.check(heapMarker.isBlackWhenNoGreys(cell), "cell must be marked live"); final Pointer hubOrigin = hubRef.toOrigin(); if (heapMarker.isCovered(hubOrigin)) { FatalError.check(heapMarker.isBlackWhenNoGreys(hubOrigin), "hub must be marked live"); } final SpecificLayout specificLayout = hub.specificLayout; if (specificLayout.isTupleLayout()) { TupleReferenceMap.visitReferences(hub, origin, this); } else if (specificLayout.isHybridLayout()) { TupleReferenceMap.visitReferences(hub, origin, this); } else if (specificLayout.isReferenceArrayLayout()) { final int length = Layout.readArrayLength(origin); for (visitedIndex = 0; visitedIndex < length; visitedIndex++) { visit(Layout.getReference(origin, visitedIndex).toOrigin()); } } liveDataByteCount += size.toLong(); } return cell.plus(size); } public void run() { darkMatterByteCount = 0L; freeChunksByteCount = 0L; liveDataByteCount = 0L; sweeper.verify(this); bootHeapVerifier.run(); } @Override public void visitCells(Address start, Address end) { Pointer p = start.asPointer(); while (p.lessThan(end)) { p = verifyCell(p); } } }