/*
* 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 static com.sun.max.vm.heap.gcx.HeapRegionConstants.*;
import static com.sun.max.vm.intrinsics.MaxineIntrinsicIDs.*;
import com.sun.max.annotate.*;
import com.sun.max.memory.*;
import com.sun.max.unsafe.*;
import com.sun.max.vm.*;
import com.sun.max.vm.MaxineVM.Phase;
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.*;
/**
* The heap region table centralizes all the descriptors for all regions in the heap space.
* Region descriptors of all the regions are allocated in a single contiguous space in order
* to enable a simple mapping from region address to region descriptor, which in turn, enables
* direct retrieval of a region descriptor from an arbitrary pointer to the heap space.
* The index in the region table forms a unique region identifier that can be simply maps to a region
* descriptor and the region address in the heap space. The region table occupies the first bytes of
* the heap space.
*/
public final class RegionTable {
public static final HeapRegionInfo nullHeapRegionInfo = new HeapRegionInfo();
public static int DebuggedRegion = INVALID_REGION_ID;
static {
VMOptions.addFieldOption("-XX:", "DebuggedRegion", RegionTable.class, "Do specific debug for the specified region only", Phase.PRISTINE);
}
public static boolean inDebuggedRegion(Address address) {
return theRegionTable.regionID(address) == DebuggedRegion;
}
/**
* Inspector support for fast retrieval of region info from region id.
*/
@HOSTED_ONLY
static final int TableOffset = ClassActor.fromJava(RegionTable.class).dynamicTupleSize().toInt();
@FOLD
static int tableOffset() {
return ClassActor.fromJava(RegionTable.class).dynamicTupleSize().toInt();
}
@INSPECTED
@CONSTANT_WHEN_NOT_ZERO
private static RegionTable theRegionTable;
@INLINE
public static RegionTable theRegionTable() {
return theRegionTable;
}
@INTRINSIC(UNSAFE_CAST)
private static native HeapRegionInfo asHeapRegionInfo(Object regionInfo);
@INLINE
private static HeapRegionInfo toHeapRegionInfo(Pointer regionInfoPointer) {
return asHeapRegionInfo(Reference.fromOrigin(Layout.cellToOrigin(regionInfoPointer)).toJava());
}
private Pointer table() {
return Reference.fromJava(this).toOrigin().plus(tableOffset());
}
@INSPECTED
final private Address regionPoolStart;
@INSPECTED
final private Address regionPoolEnd;
@INSPECTED
final private int regionInfoSize;
@INSPECTED
final private int length;
private boolean isInHeapRegion(Address address) {
return address.greaterEqual(regionPoolStart) && address.lessThan(regionPoolEnd);
}
@HOSTED_ONLY
public RegionTable(Address start, Address end, int numRegions, int infoSize) {
regionPoolStart = start;
regionPoolEnd = end;
length = numRegions;
regionInfoSize = infoSize;
}
private RegionTable(Class<HeapRegionInfo> regionInfoClass, MemoryRegion regionPool, int numRegions) {
final HeapScheme heapScheme = VMConfiguration.vmConfig().heapScheme();
final Hub regionInfoHub = ClassActor.fromJava(regionInfoClass).dynamicHub();
regionPoolStart = regionPool.start();
regionPoolEnd = regionPool.end();
regionInfoSize = regionInfoHub.tupleSize.toInt();
for (int i = 0; i < numRegions; i++) {
Object regionInfo = heapScheme.createTuple(regionInfoHub);
if (MaxineVM.isDebug()) {
FatalError.check(regionInfo == regionInfo(i), "Failed to create valid region table");
}
}
// This makes the region table initialized with respect to the inspector.
length = numRegions;
}
static void initialize(Class<HeapRegionInfo> regionInfoClass, MemoryRegion regionPool, int numRegions) {
theRegionTable = new RegionTable(regionInfoClass, regionPool, numRegions);
}
int regionID(HeapRegionInfo regionInfo) {
final int regionID = Reference.fromJava(regionInfo).toOrigin().minus(table()).dividedBy(regionInfoSize).toInt();
return regionID;
}
public Offset offsetInRegionPool(Address address) {
if (!isInHeapRegion(address)) {
return Word.allOnes().asOffset();
}
return address.minus(regionPoolStart).asOffset();
}
private int inHeapAddressRegionID(Address address) {
return address.minus(regionPoolStart).unsignedShiftedRight(log2RegionSizeInBytes).toInt();
}
/**
* Returns the region ID of the heap region an address refers to.
* @param address
* @return an integer identifying a heap region, or {@link HeapRegionConstants#INVALID_REGION_ID} if the address doesn't refer to a location in a heap region.
*/
public int regionID(Address address) {
if (!isInHeapRegion(address)) {
return INVALID_REGION_ID;
}
return inHeapAddressRegionID(address);
}
/**
* Inspector support.
*
* @param regionID a unique region identifier
* @return an offset from the region table's address to the HeapRegionInfo instance for the requested region identifier.
*/
@HOSTED_ONLY
public int regionInfoOffset(int regionID) {
return TableOffset + regionID * regionInfoSize;
}
/**
* Inspector support.
*
* @param offsetFromTableAddress an offset from the region table's address to a HeapRegionInfo instance
* @return a unique region identifier
*/
@HOSTED_ONLY
public int regionIDFromRegionInfoOffset(int offsetFromTableAddress) {
int offsetFromTableBase = offsetFromTableAddress - TableOffset;
assert offsetFromTableBase % regionInfoSize == 0;
int index = (offsetFromTableAddress - TableOffset) / regionInfoSize;
assert index < length;
return index;
}
public boolean isValidRegionID(int regionID) {
return regionID >= 0 && regionID < length;
}
HeapRegionInfo regionInfo(int regionID) {
return toHeapRegionInfo(table().plus(regionID * regionInfoSize));
}
HeapRegionInfo inHeapAddressRegionInfo(Address addr) {
return regionInfo(inHeapAddressRegionID(addr));
}
HeapRegionInfo regionInfo(Address addr) {
if (!isInHeapRegion(addr)) {
return nullHeapRegionInfo;
}
return regionInfo(inHeapAddressRegionID(addr));
}
public Address regionAddress(int regionID) {
return regionPoolStart.plus(Address.fromInt(regionID).shiftedLeft(log2RegionSizeInBytes));
}
Address regionAddress(HeapRegionInfo regionInfo) {
return regionAddress(regionID(regionInfo));
}
/**
* Apply CellVisitor over all references within a region range.
* @param regionRange
* @param cellVisitor
*/
void walk(RegionRange regionRange, CellVisitor cellVisitor) {
Pointer p = regionAddress(regionRange.firstRegion()).asPointer();
final Pointer end = p.plus(Pointer.fromInt(regionRange.numRegions()).shiftedLeft(log2RegionSizeInBytes));
while (p.lessThan(end)) {
p = cellVisitor.visitCell(p);
}
}
void walk(RegionRange regionRange, CellRangeVisitor visitor) {
final Address start = regionAddress(regionRange.firstRegion()).asPointer();
final Address end = start.plus(Pointer.fromInt(regionRange.numRegions()).shiftedLeft(log2RegionSizeInBytes));
visitor.visitCells(start, end);
}
HeapRegionInfo next(HeapRegionInfo regionInfo) {
return toHeapRegionInfo(Reference.fromJava(regionInfo).toOrigin().plus(regionInfoSize));
}
HeapRegionInfo prev(HeapRegionInfo regionInfo) {
return toHeapRegionInfo(Reference.fromJava(regionInfo).toOrigin().minus(regionInfoSize));
}
}