/* * Copyright (c) 2010, 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 static com.sun.max.vm.heap.gcx.TricolorHeapMarker.*; import com.sun.max.annotate.*; import com.sun.max.unsafe.*; import com.sun.max.vm.*; import com.sun.max.vm.heap.gcx.TricolorHeapMarker.ColorMapScanState; import com.sun.max.vm.heap.gcx.TricolorHeapMarker.MarkingStackFlusher; /** * State of an overflow scan of the tricolor map. A scan of the tricolor map enter this state when the marking stack overflow. * The overflow state remembers the bound of the forward scan to resume it once the overflow is dealt with, in addition to state necessary to * deal with the overflow of the marking stack. This consists in rescanning a part of the tricolor map already scanned to find grey references * dropped from the marking stack. * Sub-class of this class implements various rescan strategies depending on information recorded during forward scan to increase the precision of * overflow scan. */ abstract class OverflowScanState extends ColorMapScanState { /** * Specifies where the end of the overflow scan should end. Typically, this is saving the finger of the forward scan. */ protected Address endOfScan; /** * Specifies how the marking stack is flushed. */ protected MarkingStackFlusher markingStackFlusher; /** * Specifies the discontinuous regions to iterate over. */ protected HeapRegionRangeIterable regionsRanges; OverflowScanState(TricolorHeapMarker heapMarker) { super(heapMarker); } protected final void setMarkingStackFlusher(MarkingStackFlusher flusher) { markingStackFlusher = flusher; } /** * VM startup initialization. */ void initialize() { heapMarker.markingStack.initialize(markingStackFlusher); } void setHeapRegionsRanges(HeapRegionRangeIterable regionsRanges) { this.regionsRanges = regionsRanges; } @Override public int rightmostBitmapWordIndex() { return heapMarker.bitmapWordIndex(endOfScan); } @INLINE final boolean isRecovering() { return heapMarker.currentScanState == this; } final MarkingStackFlusher markingStackFlusher() { return markingStackFlusher; } abstract void recoverFromOverflow(); /** * Visit all grey objects whose mark is within the specified range of words of the color map. * The forward scan finger may be anywhere within the rightmost bitmap word of the range, so * we must test every grey cell against it to stop correctly the recovery scan. * * @param bitmapWordIndex * @param rightmostBitmapWordIndex */ void visitGreyObjectsToEndOfScan(int bitmapWordIndex, int rightmostBitmapWordIndex) { // This is slightly different from the forward scan: // The scan ends when reaching the forward scan finger. This one may be located in word shared with some // object visited during overflow scan. So we must check that precise condition to avoid visiting // objects already visited by the forward scan. // We do that only for the last mark bitmap word, the one the forward scan finger points to. if (bitmapWordIndex < rightmostBitmapWordIndex) { final int beforeRightmostBitmapWordIndex = rightmostBitmapWordIndex - 1; // Avoid systematic testing of marked object against the end of scan for all but the last bitmap word. visitGreyObjects(bitmapWordIndex, beforeRightmostBitmapWordIndex); bitmapWordIndex = beforeRightmostBitmapWordIndex; } final Pointer colorMapBase = heapMarker.colorMapBase(); while (bitmapWordIndex <= rightmostBitmapWordIndex) { long bitmapWord = colorMapBase.getLong(bitmapWordIndex); if (bitmapWord != 0L) { final long greyMarksInWord = bitmapWord & (bitmapWord >>> 1); if (greyMarksInWord != 0L) { // First grey mark is the least set bit. final int bitIndexInWord = Pointer.fromLong(greyMarksInWord).leastSignificantBitSet(); final int bitIndexOfGreyCell = (bitmapWordIndex << Word.widthValue().log2numberOfBits) + bitIndexInWord; Pointer p = heapMarker.addressOf(bitIndexOfGreyCell).asPointer(); if (p.greaterEqual(endOfScan)) { return; } p = markAndVisitCell(p); // Get bitmap word index at the end of the object. This may avoid reading multiple mark bitmap words // when marking objects crossing multiple mark bitmap words. bitmapWordIndex = heapMarker.bitmapWordIndex(p); continue; } else if ((bitmapWord >>> TricolorHeapMarker.LAST_BIT_INDEX_IN_WORD) == 1L) { // Mark span two words. Check first bit of next word to decide if mark is grey. bitmapWord = colorMapBase.getLong(bitmapWordIndex + 1); if ((bitmapWord & 1) != 0) { // it is a grey object. final int bitIndexOfGreyCell = (bitmapWordIndex << Word.widthValue().log2numberOfBits) + TricolorHeapMarker.LAST_BIT_INDEX_IN_WORD; Pointer p = heapMarker.addressOf(bitIndexOfGreyCell).asPointer(); if (p.greaterEqual(endOfScan)) { return; } p = markAndVisitCell(p); bitmapWordIndex = heapMarker.bitmapWordIndex(p); continue; } } } bitmapWordIndex++; } } /** * Visit grey objects between the overflow scan's finger and the forward scan finger. The grey objects are located in the potentially discontinuous * ranges of regions identified by the {@link HeapRegionInfoIterable} arguments. * * @param regionsRanges an iterable over the regions ranges that comprises the grey objects to visit. */ protected void visitGreyObjects(HeapRegionRangeIterable regionsRanges) { final int log2RegionToBitmapWord = HeapRegionConstants.log2RegionSizeInBytes - heapMarker.log2BitmapWord; int rightmostBitmapWordIndex = rightmostBitmapWordIndex(); int fingerBitmapWordIndex = heapMarker.bitmapWordIndex(finger); int fingerRegion = HeapRegionConstants.regionStart(finger).minus(heapMarker.coveredAreaStart).unsignedShiftedRight(HeapRegionConstants.log2RegionSizeInBytes).toInt(); regionsRanges.reset(fingerRegion); while (regionsRanges.hasNext()) { final RegionRange regionRange = regionsRanges.next(); final int rangeLeftmostBitmapWordIndex = regionRange.firstRegion() << log2RegionToBitmapWord; final int rangeRightmostBitmapWordIndex = rangeLeftmostBitmapWordIndex + (regionRange.numRegions() << log2RegionToBitmapWord); if (rangeLeftmostBitmapWordIndex > fingerBitmapWordIndex) { fingerBitmapWordIndex = rangeLeftmostBitmapWordIndex; } if (rangeRightmostBitmapWordIndex > rightmostBitmapWordIndex) { visitGreyObjectsToEndOfScan(fingerBitmapWordIndex, rightmostBitmapWordIndex); break; } visitGreyObjects(fingerBitmapWordIndex, rangeRightmostBitmapWordIndex); } } @INLINE protected void verifyHasNoGreyMarks(Address end) { if (!TricolorHeapMarker.VerifyGreyLessAreas) { return; } if (regionsRanges != null) { regionsRanges.reset(); heapMarker.verifyHasNoGreyMarks(regionsRanges, end); } else { heapMarker.verifyHasNoGreyMarks(heapMarker.coveredAreaStart, end); } } protected void beginRecovery() { final ForwardScanState forwardScanState = heapMarker.forwardScanState; heapMarker.startTimer(heapMarker.recoveryScanTimer); heapMarker.currentScanState = this; // set the upper bound for rescanning to the finger of the forward scan endOfScan = forwardScanState.finger; // cache rightmost locally. rightmost = forwardScanState.rightmost; markingStackFlusher.setScanState(this); if (MaxineVM.isDebug() && TraceMarking) { Log.println("Begin Overflow Scan"); heapMarker.traceMark(endOfScan, " => endOfScan\n"); heapMarker.traceMark(rightmost, " => rightmost\n"); } } protected void endRecovery() { final ForwardScanState forwardScanState = heapMarker.forwardScanState; verifyHasNoGreyMarks(forwardScanState.finger); forwardScanState.rightmost = rightmost; markingStackFlusher.setScanState(forwardScanState); heapMarker.currentScanState = forwardScanState; heapMarker.stopTimer(heapMarker.recoveryScanTimer); if (MaxineVM.isDebug() && TraceMarking) { Log.print("End Overflow Scan (# mark stack overflow = "); Log.print(numMarkinkgStackOverflow); Log.println(")"); heapMarker.traceMark(finger, " => overflow finger\n"); heapMarker.traceMark(rightmost, " => rightmost\n"); } } @Override public String toString() { return "overflow scan"; } }