/*
* Copyright (c) 2011, 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.HeapFreeChunk.*;
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.*;
/**
* A simple tool that counts (and print to the log) references that escapes a particular heap account.
* References to the boot image aren't counted as escaping.
* The tools is currently used to verify that no references escape the {@link HeapRegionManager}'s heap account.
*/
class OutgoingReferenceChecker extends PointerIndexVisitor implements CellVisitor {
private final Object accountOwner;
private final RegionTable regionTable;
private long outgoingReferenceCount = 0L;
/**
* @param heapAccount
*/
OutgoingReferenceChecker(HeapAccount<?> heapAccount) {
accountOwner = heapAccount.owner();
regionTable = RegionTable.theRegionTable();
}
void reset() {
outgoingReferenceCount = 0L;
}
private void checkReference(Pointer refHolder, int wordIndex) {
Pointer cell = refHolder.getReference(wordIndex).toOrigin();
if (!cell.isZero()) {
final HeapRegionInfo rinfo = regionTable.regionInfo(cell);
if (rinfo.owner() != accountOwner && !Heap.bootHeapRegion.contains(cell)) {
Log.print("outgoing ref: ");
Log.print(refHolder);
Log.print(" [ ");
Log.print(wordIndex);
Log.print(" ] = ");
Log.println(cell);
outgoingReferenceCount++;
}
}
}
@Override
public Pointer visitCell(Pointer cell) {
final Pointer origin = Layout.cellToOrigin(cell);
final Hub hub = Layout.getHub(origin);
if (hub == heapFreeChunkHub()) {
return cell.plus(toHeapFreeChunk(origin).size);
}
checkReference(origin, Layout.hubIndex());
final SpecificLayout specificLayout = hub.specificLayout;
if (specificLayout.isTupleLayout()) {
TupleReferenceMap.visitReferences(hub, origin, this);
return cell.plus(hub.tupleSize);
} else if (specificLayout.isHybridLayout()) {
TupleReferenceMap.visitReferences(hub, origin, this);
} else if (specificLayout.isReferenceArrayLayout()) {
final int length = Layout.firstElementIndex() + Layout.readArrayLength(origin);
for (int index = Layout.firstElementIndex(); index < length; index++) {
checkReference(origin, index);
}
}
Size size = Layout.size(origin);
return cell.plus(size);
}
@Override
public void visit(Pointer pointer, int wordIndex) {
checkReference(pointer, wordIndex);
}
public long outgoingReferenceCount() {
return outgoingReferenceCount;
}
}