/* * Copyright (c) 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.tele.heap.region; import static com.sun.max.tele.MaxMarkBitmap.MarkColor.*; import java.io.*; import java.util.*; import com.sun.max.tele.*; import com.sun.max.tele.data.*; import com.sun.max.tele.memory.*; import com.sun.max.tele.object.*; import com.sun.max.tele.reference.*; import com.sun.max.tele.util.*; import com.sun.max.unsafe.*; import com.sun.max.vm.heap.*; import com.sun.max.vm.heap.gcx.*; /** * A specialized subclass of the Mark Bitmap used by some GC implementations. The singleton instance, corresponding to * the one used in the VM, is not created until the VM heap scheme has allocated the bit map data and initialized * everything, so no refreshing is needed. * <p> * The Mark Bitmap's data is stored in a region separate from the heap, allocated from the OS. The region is filled with * a single array (in standard Maxine format) of longs. */ public final class VmMarkBitmap extends TricolorHeapMarker implements MaxMarkBitmap, VmObjectHoldingRegion<MaxMarkBitmap> { private static final String ENTITY_NAME = "Heap-Mark Bitmap data"; /** * Representation of a VM memory region used to hold a MarkBitmap. The MarkBitmap is implemented as a single long array that * occupied the entire region. * <p> * This region has no parent; it is allocated dynamically from the OS * <p> * This region has no children. */ private static final class MarkBitmapMemoryRegion extends TeleFixedMemoryRegion implements MaxEntityMemoryRegion<MaxMarkBitmap> { private static final List<MaxEntityMemoryRegion< ? extends MaxEntity>> EMPTY = Collections.emptyList(); private final MaxMarkBitmap owner; protected MarkBitmapMemoryRegion(MaxVM vm, MaxMarkBitmap owner, String regionName, Address start, long nBytes) { super(vm, regionName, start, nBytes); this.owner = owner; } @Override public MaxEntityMemoryRegion< ? extends MaxEntity> parent() { // The MarkBitmap fully occupies a region allocated from the OS, not part of any other region. return null; } @Override public List<MaxEntityMemoryRegion< ? extends MaxEntity>> children() { return EMPTY; } @Override public MaxMarkBitmap owner() { return owner; } } private final TeleVM vm; private final TeleTricolorHeapMarker remoteHeapMarker; private final TeleFixedMemoryRegion coveredMemoryRegion; private final MarkBitmapMemoryRegion markBitmapMemoryRegion; private final TeleArrayObject markBitmapArray; private final MarkBitmapObjectReferenceManager objectReferenceManager; public VmMarkBitmap(TeleVM vm, TeleTricolorHeapMarker remoteHeapMarker) { super(remoteHeapMarker.wordsCoveredPerBit(), remoteHeapMarker.coveredAreaStart(), remoteHeapMarker.coveredAreaEnd(), remoteHeapMarker.bitmapStorage(), Size.fromLong(remoteHeapMarker.bitmapSize())); this.vm = vm; this.remoteHeapMarker = remoteHeapMarker; final long coveredSize = remoteHeapMarker.coveredAreaEnd().minus(remoteHeapMarker.coveredAreaStart()).toLong(); this.coveredMemoryRegion = new TeleFixedMemoryRegion(vm, ENTITY_NAME, remoteHeapMarker.coveredAreaStart(), coveredSize); final Address dataRegionStart = remoteHeapMarker.colorMapDataRegion().getRegionStart(); final long dataRegionSize = remoteHeapMarker.colorMapDataRegion().getRegionNBytes(); this.markBitmapMemoryRegion = new MarkBitmapMemoryRegion(vm, this, ENTITY_NAME, dataRegionStart, dataRegionSize); this.objectReferenceManager = new MarkBitmapObjectReferenceManager(vm, dataRegionStart); this.markBitmapArray = (TeleArrayObject) vm.objects().makeTeleObject(objectReferenceManager.longArrayRef); this.markBitmapArray.setMaxineRole(ENTITY_NAME); } public TeleVM vm() { return vm; } public String entityName() { return markBitmapMemoryRegion.regionName(); } public String entityDescription() { return "The region of OS-allocated memory in which a Mark Bitmap is stored, formatted as a single long array"; } public MaxEntityMemoryRegion<MaxMarkBitmap> memoryRegion() { return markBitmapMemoryRegion; } /** * {@inheritDoc} * <p> * This the allocation holding the mark bitmap. */ public boolean contains(Address address) { return markBitmapMemoryRegion.contains(address); } public MaxObject representation() { return markBitmapArray; } @Override public MaxMemoryRegion coveredMemoryRegion() { return coveredMemoryRegion; } public int getBitIndexOf(Address heapAddress) { return coveredMemoryRegion.contains(heapAddress) ? bitIndexOf(heapAddress) : -1; } public Address heapAddress(int bitIndex) { return addressOf(bitIndex); } public Address bitmapWordAddress(int bitIndex) { return bitmapWordPointerAt(bitIndex); } public long readBitmapWord(int bitIndex) { return hostedBitmapWordAt(bitIndex); } public int getBitIndexInWord(int bitIndex) { return bitIndexInWord(bitIndex); } public boolean isBitSet(int bitIndex) { return isSet(bitIndex); } public void setBit(int bitIndex) { TeleError.unimplemented(); } /** * {@inheritDoc} * <p> * Override the standard method in {@link TricolorHeapMarker} for reading a word out of the bitmap table with one * that reads the memory remotely from the VM. */ @Override protected long hostedBitmapWordAt(int bitIndex) { return vm().memoryIO().getLong(base, 0, bitmapWordIndex(bitIndex)); } public MarkColor getMarkColor(Address heapAddress) { if (vm().objects().objectStatusAt(heapAddress).isLive() && isCovered(heapAddress)) { return getMarkColorUnsafe(heapAddress); } return null; } public MarkColor getMarkColor(int bitIndex) { final Address heapAddress = addressOf(bitIndex); if (vm().objects().objectStatusAt(heapAddress).isLive()) { return getMarkColorUnsafe(heapAddress); } return null; } /** * Gets the marking at a particular index of the bitmap. Does <em>not check</em> that there is an object at that * location, or even whether the address is covered by the bitmap, so the mark could be at an invalid location. */ public MarkColor getMarkColorUnsafe(Address address) { final int bitIndex = bitIndexOf(address); try { if (isWhite(bitIndex)) { if (isClear(bitIndex + 1)) { return MARK_WHITE; } TeleWarning.message("Invalid mark in mark bitmap @" + bitIndex); return MARK_INVALID; } else if (isGreyWhenNotWhite(bitIndex)) { return MARK_GRAY; } if (isClear(bitIndex + 1)) { return MARK_BLACK; } TeleWarning.message("Invalid mark in mark bitmap @" + bitIndex); return MARK_INVALID; } catch (DataIOError e) { return MARK_UNAVAILABLE; } } /** * @return bitmap index one past the last covered heap address */ private int endBitIndex() { return bitIndexOf(coveredMemoryRegion.end()); } public int nextSetBitAfter(int startBitIndex) { for (int bitIndex = startBitIndex + 1; bitIndex < endBitIndex(); bitIndex++) { if (isSet(bitIndex)) { return bitIndex; } } return -1; } public int previousSetBitBefore(int startBitIndex) { for (int bitIndex = startBitIndex - 1; bitIndex >= 0; bitIndex--) { if (isSet(bitIndex)) { return bitIndex; } } return -1; } public int nextMarkAfter(int startBitIndex, MarkColor color) { switch(color) { case MARK_BLACK: case MARK_GRAY: for (int bitIndex = startBitIndex + 1; bitIndex < endBitIndex(); bitIndex++) { // For BLACK and GRAY marks, we only have to check at locations where the first bit is set if (isSet(bitIndex) && getMarkColor(bitIndex) == color) { return bitIndex; } } return -1; case MARK_WHITE: case MARK_INVALID: for (int bitIndex = startBitIndex + 1; bitIndex < endBitIndex(); bitIndex++) { if (getMarkColor(bitIndex) == color) { return bitIndex; } } return -1; case MARK_UNAVAILABLE: return -1; } return -1; } public int previousMarkBefore(int startBitIndex, MarkColor color) { switch(color) { case MARK_BLACK: case MARK_GRAY: for (int bitIndex = startBitIndex - 1; bitIndex >= 0; bitIndex--) { // For BLACK and GRAY marks, we only have to check at locations where the first bit is set if (isSet(bitIndex) && getMarkColor(bitIndex) == color) { return bitIndex; } } return -1; case MARK_WHITE: case MARK_INVALID: for (int bitIndex = startBitIndex - 1; bitIndex >= 0; bitIndex--) { if (getMarkColor(bitIndex) == color) { return bitIndex; } } return -1; case MARK_UNAVAILABLE: return -1; } return -1; } public RemoteObjectReferenceManager objectReferenceManager() { return objectReferenceManager; } public void printObjectSessionStats(PrintStream printStream, int indent, boolean verbose) { TeleWarning.unimplemented(); } /** * Manager for object references for the unmanaged mark bitmap region, which contains, * once initialized, a singleton long array. */ private class MarkBitmapObjectReferenceManager extends AbstractVmHolder implements RemoteObjectReferenceManager { private final Address longArrayOrigin; private final ConstantRemoteReference longArrayRef; protected MarkBitmapObjectReferenceManager(TeleVM vm, Address start) { super(vm); longArrayOrigin = objects().layoutScheme().generalLayout.cellToOrigin(start.asPointer()); longArrayRef = new ConstantRemoteReference(vm(), longArrayOrigin) { @Override public ObjectStatus status() { return ObjectStatus.LIVE; } @Override public ObjectStatus priorStatus() { return null; } }; } /** * {@inheritDoc} * <p> * There is no GC cycle; the singleton long array is neither relocated nor collected. */ public HeapPhase phase() { return HeapPhase.MUTATING; } public ObjectStatus objectStatusAt(Address origin) { TeleError.check(memoryRegion().contains(origin), "Location is outside region"); return origin.equals(longArrayOrigin) ? ObjectStatus.LIVE : ObjectStatus.DEAD; } public boolean isForwardingAddress(Address forwardingAddress) { return false; } /** * {@inheritDoc} * <p> * The only reference possible is to the header of the array that holds the whole map in the region. */ public RemoteReference makeReference(Address origin) throws TeleError { return objectStatusAt(origin).isLive() ? longArrayRef : null; } public RemoteReference makeQuasiReference(Address origin) { return null; } public void printObjectSessionStats(PrintStream printStream, int indent, boolean verbose) { TeleWarning.unimplemented(); } } }