/* * Copyright (c) 2011, 2011, 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.unsafe.*; import com.sun.max.vm.*; import com.sun.max.vm.heap.*; import com.sun.max.vm.heap.gcx.TricolorHeapMarker.*; import com.sun.max.vm.layout.*; import com.sun.max.vm.reference.*; import com.sun.max.vm.runtime.*; /** * State of the forward scan of the tricolor mark-bitmap. * The forward scan linearly iterates over the mark bitmap, starting from the leftmost object marked grey by the root scan, up to the rightmost * object. The forward scan advances a cursor, called the finger, which is set on the currently visited grey object. * References to the left of the cursor (i.e., backward references) are pushed on a marking stack while reference forward are marked grey. * To avoid duplicates on the marking stack, the backward references are marked grey as well. */ final class ForwardScanState extends ColorMapScanState implements SpecialReferenceManager.GC { ForwardScanState(TricolorHeapMarker heapMarker) { super(heapMarker); } Address endOfRightmostVisitedObject() { return rightmost.plus(Layout.size(Layout.cellToOrigin(rightmost.asPointer()))); } @Override public int rightmostBitmapWordIndex() { return heapMarker.bitmapWordIndex(endOfRightmostVisitedObject()); } /* * Helper instance variables for debugging purposes only. * Easier to track than local variables when under the inspector. */ private int debugRightmostBitmapWordIndex; private int debugBitmapWordIndex; private long debugBitmapWord; /** * Visit grey objects located between the finger and a rightmost position identified by a word index in the color map. * Iteration stops when the index of the word holding the mark of the finger goes beyond the rightmost position specified. * This code is shared between marking for region-based heaps and marking for single-contiguous space heaps. * * @param rightmostBitmapWordIndex */ void visitGreyObjects(int rightmostBitmapWordIndex) { final Pointer colorMapBase = heapMarker.base.asPointer(); int bitmapWordIndex = heapMarker.bitmapWordIndex(finger); if (MaxineVM.isDebug()) { debugRightmostBitmapWordIndex = rightmostBitmapWordIndex; debugBitmapWordIndex = bitmapWordIndex; } visitGreyObjects(bitmapWordIndex, rightmostBitmapWordIndex); // There might be some objects left in the marking stack. Drain it. // Before draining, advance the finger to the next mark bitmap word boundary to force all white references from drained cells that point to objects // with mark in the current mark word to be pushed up on the marking stack and processed during the drainage. Address fingerBeforeDraining = finger; if (MaxineVM.isDebug() && TricolorHeapMarker.TraceMarking) { heapMarker.traceMark(fingerBeforeDraining, " => finger before draining marking stack\n"); } finger = heapMarker.nextMarkWordBoundary(finger); heapMarker.markingStack.drain(); // Reset the finger to the rightmost black object in the finger's mark word. int fingerBitmapWordIndex = heapMarker.bitmapWordIndex(fingerBeforeDraining); int fingerBitIndex = fingerBitmapWordIndex << Word.widthValue().log2numberOfBits; fingerBitIndex += Address.fromLong(colorMapBase.getLong(fingerBitmapWordIndex)).mostSignificantBitSet(); finger = heapMarker.addressOf(fingerBitIndex); // Adjust the rightmost pointer too. This one may have been before the next mark word boundary, in which case it wouldn't be updated by // the draining of the marking stack if the rightmost visited object remain before that boundary. if (rightmost.lessThan(finger)) { rightmost = finger; } if (MaxineVM.isDebug() && TricolorHeapMarker.TraceMarking) { heapMarker.traceMark(rightmost, " => rightmost after draining marking stack\n"); } } /** * Forward scan over the mark bitmap, from the finger to the rightmost marked position. * @param regionsRanges */ public void visitGreyObjects(HeapRegionRangeIterable regionsRanges) { final int log2RegionToBitmapWord = HeapRegionConstants.log2RegionSizeInBytes - heapMarker.log2BitmapWord; if (MaxineVM.isDebug() && TricolorHeapMarker.TraceMarking) { Log.println("Begin Forward Scan"); } while (regionsRanges.hasNext()) { final int fingerBitmapWordIndex = heapMarker.bitmapWordIndex(finger); final RegionRange regionRange = regionsRanges.next(); final int firstRegion = regionRange.firstRegion(); if (MaxineVM.isDebug() && TricolorHeapMarker.TraceMarking) { Log.print("Begin scan of regions range ["); Log.print(firstRegion); Log.print(", "); Log.print(firstRegion + regionRange.numRegions()); Log.println("["); } final int rangeRightmostBitmapWordIndex = ((firstRegion + regionRange.numRegions()) << log2RegionToBitmapWord) - 1; if (fingerBitmapWordIndex > rangeRightmostBitmapWordIndex) { // skip this range, finger is past it already. This may happen after initial root marking. when the leftmost marked // position is beyond the first ranges, or when starting a new pass on the mark bitmap, e.g., to trace live objects from untraced special references. continue; } FatalError.check((firstRegion << log2RegionToBitmapWord) <= fingerBitmapWordIndex, "finger must be within the region range"); int rightmostBitmapWordIndex = rightmostBitmapWordIndex(); if (rightmostBitmapWordIndex > rangeRightmostBitmapWordIndex) { rightmostBitmapWordIndex = rangeRightmostBitmapWordIndex; } do { visitGreyObjects(rightmostBitmapWordIndex); if (finger == rightmost) { // We reached the right most mark. No need to continue iterating over regions. FatalError.check(heapMarker.markingStack.isEmpty(), "marking stack must be empty"); if (!heapMarker.isBlackWhenNotWhite(rightmost)) { int rbi = heapMarker.bitIndexOf(rightmost); heapMarker.traceMark(rightmost, heapMarker.color(rbi), rbi, " *** rightmost object must be marked black\n"); printState(); heapMarker.overflowScanState.printState(); MarkingError.rightmostNotBlackError.report(heapMarker.markPhase); } if (MaxineVM.isDebug() && TricolorHeapMarker.TraceMarking) { Log.println("End Forward Scan"); } return; } if (MaxineVM.isDebug() && finger.greaterThan(rightmost)) { MarkingError.fingerGreaterThanRightmostError.report(heapMarker.markPhase); } // finger is less than rightmost. This may be because: // - the rightmost was not in this region range but in one further up the address space // - we may have drained an object that contained a reference past the finger's mark word boundary. final int b = rightmostBitmapWordIndex(); if (rightmostBitmapWordIndex == rangeRightmostBitmapWordIndex) { if (MaxineVM.isDebug() && b > rangeRightmostBitmapWordIndex) { MarkingError.rightmostNotAboveCurrentRegionRangeError.report(heapMarker.markPhase); } if (MaxineVM.isDebug() && TricolorHeapMarker.TraceMarking) { Log.print("End scan of regions range ["); Log.print(firstRegion); Log.print(", "); Log.print(firstRegion + regionRange.numRegions()); Log.println("["); } // We're done with the current regions range. Break // to the outer loop to iterate over subsequent region ranges. break; } // Update rightmost for the next iterate over the current range. rightmostBitmapWordIndex = b > rangeRightmostBitmapWordIndex ? rangeRightmostBitmapWordIndex : b; } while(true); } } public void visitGreyObjects() { int rightmostBitmapWordIndex = rightmostBitmapWordIndex(); do { visitGreyObjects(rightmostBitmapWordIndex); // Rightmost may have been updated (e.g., when the marking stack was drained). Check for this, and loop back if it has. final int b = rightmostBitmapWordIndex(); if (b <= rightmostBitmapWordIndex) { // We're done. return; } rightmostBitmapWordIndex = b; } while(true); } public boolean isReachable(Reference ref) { Pointer origin = ref.toOrigin(); if (heapMarker.isCovered(origin)) { // If either back or grey, the object is reachable. return !heapMarker.isWhite(origin); } // If not in the covered area, it must be in one of the regions treated as permanent roots. // We cannot easily check that here because of NativeMutex which store the address of a NativeMutex // in there reference field (nasty piece of work...). return true; } public Reference preserve(Reference ref) { visit(ref); return ref; } public boolean mayRelocateLiveObjects() { return false; } @Override public String toString() { return "forward scan"; } }