/*
* Copyright (c) 2008, 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.object;
import static com.sun.max.tele.object.ObjectStatus.*;
import java.io.*;
import java.text.*;
import java.util.*;
import com.sun.max.lang.*;
import com.sun.max.memory.*;
import com.sun.max.program.*;
import com.sun.max.tele.*;
import com.sun.max.tele.data.*;
import com.sun.max.tele.field.*;
import com.sun.max.tele.heap.*;
import com.sun.max.tele.method.*;
import com.sun.max.tele.object.TeleObjectFactory.ClassCount;
import com.sun.max.tele.object.TeleObjectFactory.ObjectFactoryMapStats;
import com.sun.max.tele.reference.*;
import com.sun.max.tele.util.*;
import com.sun.max.unsafe.*;
import com.sun.max.vm.actor.holder.*;
import com.sun.max.vm.layout.*;
import com.sun.max.vm.layout.Layout.HeaderField;
import com.sun.max.vm.reference.*;
import com.sun.max.vm.reference.direct.*;
import com.sun.max.vm.type.*;
/**
* Singleton cache of information about objects in the VM, including a factory for creating
* local surrogates (instances of {@link TeleObject}) for objects in the VM, and methods for
* locating objects by various means.
* <p>
* Objects in the VM can appear in memory regions other than the heap proper.
* <p>
* Assumes use of the {@link DirectReferenceScheme} in the VM.
* <p>
* TODO (mlvdv) generalize for uses with other implementations of {@link ReferenceScheme}
*
* @see VmObjectHoldingRegion
* @see VmHeapRegion
* @see VmCodeCacheRegion
*/
public final class VmObjectAccess extends AbstractVmHolder implements TeleVMCache, MaxObjects {
private static final int STATS_NUM_TYPE_COUNTS = 10;
/**
* Name of system property that specifies the address where the heap is located, or where it should be relocated, depending
* on the user of the class.
*/
public static final String HEAP_ADDRESS_PROPERTY = "max.heap";
private static final int TRACE_VALUE = 1;
private static VmObjectAccess vmObjectAccess;
public static VmObjectAccess make(TeleVM vm) {
if (vmObjectAccess == null) {
vmObjectAccess = new VmObjectAccess(vm);
}
return vmObjectAccess;
}
final Address zappedMarker = Address.fromLong(Memory.ZAPPED_MARKER);
/**
* Offset from an object's origin where GC implementations store forwarding pointers.
*/
private final int gcForwardingAddressOffset;
private final TimedTrace updateTracer;
private long lastUpdateEpoch = -1L;
private final String entityName = "Objects";
private final String entityDescription;
private List<MaxCodeLocation> inspectableMethods = null;
/**
* The VM object instances that implement the schemes.
*/
private final List<TeleVMScheme> schemes = new ArrayList<TeleVMScheme>();
private final TeleObjectFactory teleObjectFactory;
private Word cachedDynamicHubHubWord = null;
private Word cachedStaticHubHubWord = null;
private boolean initializingHubHubCaches = false;
private void initializeHubHubCaches() {
if (initializingHubHubCaches) {
return;
}
initializingHubHubCaches = true;
final RemoteReference hubRef = vm().classes().vmBootClassRegistryReference().readHubAsRemoteReference();
RemoteReference cachedDynamicHubHubReference = hubRef.readHubAsRemoteReference();
assert cachedDynamicHubHubReference.equals(cachedDynamicHubHubReference.readHubAsRemoteReference());
cachedDynamicHubHubWord = cachedDynamicHubHubReference.toOrigin();
RemoteReference cachedStaticHubHubReference = TeleInstanceReferenceFieldAccess.readPath(hubRef, vm().fields().Hub_classActor, vm().fields().ClassActor_staticHub).readHubAsRemoteReference();
cachedStaticHubHubWord = cachedStaticHubHubReference.toOrigin();
}
private Word dynamicHubHubWord() {
if (cachedDynamicHubHubWord == null && vm().classes() != null) {
initializeHubHubCaches();
}
return cachedDynamicHubHubWord;
}
private Word staticHubHubWord() {
if (cachedStaticHubHubWord == null && vm().classes() != null) {
initializeHubHubCaches();
}
return cachedStaticHubHubWord;
}
private final Object statsPrinter = new Object() {
@Override
public String toString() {
final StringBuilder msg = new StringBuilder();
return msg.toString();
}
};
private VmObjectAccess(TeleVM vm) {
super(vm);
final TimedTrace tracer = new TimedTrace(TRACE_VALUE, tracePrefix() + " creating");
tracer.begin();
// All Maxine collectors stores forwarding pointers in the Hub field of the header
this.gcForwardingAddressOffset = Layout.generalLayout().getOffsetFromOrigin(HeaderField.HUB).toInt();
this.teleObjectFactory = TeleObjectFactory.make(vm, vm.teleProcess().epoch());
this.entityDescription = "Object creation and management for the " + vm.entityName();
this.updateTracer = new TimedTrace(TRACE_VALUE, tracePrefix() + " updating");
tracer.end(statsPrinter);
}
/** {@inheritDoc}
* <p>
* Updates the representation of every <strong>remote object</strong> surrogate
* (represented as instances of subclasses of {@link TeleObject},
* in case any of the information in the VM object has changed since the previous update. This should not be
* attempted until all information about allocated regions that might contain objects has been updated.
*/
public void updateCache(long epoch) {
teleObjectFactory.updateCache(epoch);
lastUpdateEpoch = epoch;
}
public String entityName() {
return entityName;
}
public String entityDescription() {
return entityDescription;
}
public MaxEntityMemoryRegion<MaxObjects> memoryRegion() {
// The heap has no VM memory allocated, other than the regions allocated directly from the OS.
return null;
}
public boolean contains(Address address) {
// There's no real notion of containing an address here.
return false;
}
public TeleObject representation() {
// No distinguished object in VM runtime represents the heap.
return null;
}
private static final int MAX_VM_LOCK_TRIALS = 100;
public ObjectStatus objectStatusAt(Address origin) {
if (origin.isZero() || origin.equals(zappedMarker)) {
return DEAD;
}
final MaxEntityMemoryRegion<?> maxMemoryRegion = vm().addressSpace().find(origin);
if (maxMemoryRegion != null && maxMemoryRegion.owner() instanceof VmObjectHoldingRegion<?>) {
final VmObjectHoldingRegion<?> objectHoldingRegion = (VmObjectHoldingRegion<?>) maxMemoryRegion.owner();
return objectHoldingRegion.objectReferenceManager().objectStatusAt(origin);
}
Trace.line(TRACE_VALUE + 1, tracePrefix() + "origin in unknown region @" + origin.to0xHexString());
return DEAD;
}
public TeleObject findObject(RemoteReference reference) throws MaxVMBusyException {
if (vm().tryLock(MAX_VM_LOCK_TRIALS)) {
try {
return makeTeleObject(reference);
} finally {
vm().unlock();
}
} else {
throw new MaxVMBusyException();
}
}
public TeleObject findForwardedObjectAt(Address forwardingAddress) {
if (forwardingAddress.isZero() || forwardingAddress.equals(zappedMarker)) {
return null;
}
final MaxEntityMemoryRegion<?> maxMemoryRegion = vm().addressSpace().find(forwardingAddress);
if (maxMemoryRegion != null && maxMemoryRegion.owner() instanceof VmObjectHoldingRegion<?>) {
final VmObjectHoldingRegion<?> objectHoldingRegion = (VmObjectHoldingRegion<?>) maxMemoryRegion.owner();
if (objectHoldingRegion.objectReferenceManager().isForwardingAddress(forwardingAddress)) {
return findObjectAt(forwardingPointerToOriginUnsafe(forwardingAddress));
}
}
//Trace.line(TRACE_VALUE + 1, tracePrefix() + "origin in unknown region @" + origin.to0xHexString());
return null;
}
public TeleObject findObjectByOID(long id) {
return teleObjectFactory.lookupObject(id);
}
public TeleObject findObjectAt(Address origin) {
if (vm().tryLock(MAX_VM_LOCK_TRIALS)) {
try {
return makeTeleObject(vm().referenceManager().makeReference(origin));
} catch (Throwable throwable) {
// Can't resolve the address somehow
} finally {
vm().unlock();
}
}
return null;
}
public TeleObject findQuasiObjectAt(Address origin) {
if (vm().tryLock(MAX_VM_LOCK_TRIALS)) {
try {
return makeTeleObject(vm().referenceManager().makeQuasiReference(origin));
} catch (Throwable throwable) {
// Can't resolve the address somehow
} finally {
vm().unlock();
}
}
return null;
}
public TeleObject findAnyObjectAt(Address origin) {
TeleObject object = findObjectAt(origin);
return object == null ? findQuasiObjectAt(origin) : object;
}
public TeleObject findAnyObjectFollowing(Address cellAddress, long maxSearchExtent) {
// Search limit expressed in words
long wordSearchExtent = Long.MAX_VALUE;
final int wordSize = vm().platform().nBytesInWord();
if (maxSearchExtent > 0) {
wordSearchExtent = maxSearchExtent / wordSize;
}
TeleObject foundObject = null;
Address origin = cellAddress.plus(wordSize);
try {
for (long count = 0; count < wordSearchExtent && foundObject == null; count++, origin = origin.plus(wordSize)) {
foundObject = findAnyObjectAt(origin);
}
} catch (Throwable throwable) {
}
return foundObject;
}
public TeleObject findAnyObjectPreceding(Address cellAddress, long maxSearchExtent) {
// Search limit expressed in words
long wordSearchExtent = Long.MAX_VALUE;
final int wordSize = vm().platform().nBytesInWord();
if (maxSearchExtent > 0) {
wordSearchExtent = maxSearchExtent / wordSize;
}
TeleObject foundObject = null;
Address origin = cellAddress.minus(wordSize);
try {
for (long count = 0; count < wordSearchExtent && foundObject == null; count++, origin = origin.minus(wordSize)) {
foundObject = findAnyObjectAt(origin);
}
} catch (Throwable throwable) {
}
return foundObject;
}
public TeleObject vmBootClassRegistry() throws MaxVMBusyException {
return findObject(classes().vmBootClassRegistryReference());
}
/**
* @return the specific scheme implementations in the VM.
*/
public List<TeleVMScheme> schemes() {
if (schemes.isEmpty()) {
TeleHeapScheme heapScheme = vm().teleVMConfiguration().heapScheme();
if (heapScheme != null) {
schemes.add(heapScheme);
}
TeleLayoutScheme layoutScheme = vm().teleVMConfiguration().layoutScheme();
if (layoutScheme != null) {
schemes.add(layoutScheme);
}
TeleMonitorScheme monitorScheme = vm().teleVMConfiguration().monitorScheme();
if (monitorScheme != null) {
schemes.add(monitorScheme);
}
TeleReferenceScheme referenceScheme = vm().teleVMConfiguration().referenceScheme();
if (referenceScheme != null) {
schemes.add(referenceScheme);
}
TeleRunScheme runScheme = vm().teleVMConfiguration().runScheme();
if (runScheme != null) {
schemes.add(runScheme);
}
}
return schemes;
}
/**
* Checks if a location in VM memory could be the origin of an object representation,
* determined by examining memory contents using only low-level mechanisms that do
* not rely on type information.
* <ul>
* <li>No discrimination is made regarding the location of the proposed origin;</li>
* <li>No discrimination is made relative to the state of any memory management;</li>
* <li>Forwarded objects that overwrite the {@code Hub} field are not recognized;</li>
* <li><strong>May produce false positives</strong>, in particular when the address is a field
* holding a pointer to a {@link Hub};</li>
* <li>Uses only <em>unsafe</em> {@link RemoteReference}s to avoid circularities, since this method
* is needed for the construction of legitimate references.</li>
* </ul>
*
* @param possibleOrigin a legitimate location in VM memory, in the area managed.
* @return whether the location is likely to be an object origin.
*/
public boolean isPlausibleOriginUnsafe(Address possibleOrigin) {
if (dynamicHubHubWord() != null) {
return fastIsPlausibleOriginUnsafe(possibleOrigin);
}
// Assuming we're starting an an object origin. follow hub pointers until the same hub is
// traversed twice or an address outside of heap is encountered.
//
// For all objects other than a {@link StaticTuple}, the maximum chain takes only two hops
// find the distinguished object with self-referential hub pointer: the {@link DynamicHub} for
// class {@link DynamicHub}.
//
// Typical pattern: tuple --> dynamicHub of the tuple's class --> dynamicHub of the DynamicHub class
try {
Word hubWord = referenceManager().makeTemporaryRemoteReference(possibleOrigin).readHubAsWord();
for (int i = 0; i < 3; i++) {
if (hubWord.isZero() || hubWord.asAddress().equals(zappedMarker)) {
return false;
}
final RemoteReference hubRef = referenceManager().makeTemporaryRemoteReference(hubWord.asAddress());
Address hubOrigin = hubRef.toOrigin();
// Check if the presumed hub is in the heap; it couldn't be elsewhere, for example in the code cache.
if (!heap().contains(hubOrigin)) {
return false;
}
// Presume that we have a valid location of a Hub object.
final Word nextHubWord = hubRef.readHubAsWord();
// Does the Hub reference in this object point back to the object itself?
if (nextHubWord.equals(hubWord)) {
// We arrived at a DynamicHub for the class DynamicHub
if (i < 2) {
// All ordinary cases will have stopped by now
return true;
}
// This longer chain can only happen when we started with a {@link StaticTuple}.
// Perform a more precise test to check for this.
return isStaticTuple(possibleOrigin);
}
hubWord = nextHubWord;
}
} catch (DataIOError dataAccessError) {
}
return false;
}
/**
* Fast version of checking if a location in VM memory could be the origin of an object representation.
* This relies on the address of the dynamic hub for dynamic hubs and the address of the dynamic Hub for static hubs,
* both of which are in the boot region and never relocate.
*/
private boolean fastIsPlausibleOriginUnsafe(Address possibleOrigin) {
final Word hubHubWord = dynamicHubHubWord();
try {
Word hubWord = referenceManager().makeTemporaryRemoteReference(possibleOrigin).readHubAsWord();
if (hubWord.equals(hubHubWord)) {
// We already arrived at the DynamicHub for the class DynamicHub. This is a possible origin for a dynamic hub.
return true;
}
if (hubWord.isZero() || hubWord.asAddress().equals(zappedMarker)) {
return false;
}
final RemoteReference hubRef = referenceManager().makeTemporaryRemoteReference(hubWord.asAddress());
Address hubOrigin = hubRef.toOrigin();
// Check if the presumed hub is in the heap; it couldn't be elsewhere, for example in the code cache.
if (!heap().contains(hubOrigin)) {
return false;
}
// Presume that we have a valid location of a Hub object.
Word nextHubWord = hubRef.readHubAsWord();
if (nextHubWord.equals(hubHubWord)) {
// We arrived at the DynamicHub for the class DynamicHub
return true;
}
if (hasForwardingAddressUnsafe(hubOrigin)) {
final Address forwardedHubOrigin = getForwardingAddressUnsafe(hubOrigin);
final RemoteReference forwardedHubRef = referenceManager().makeTemporaryRemoteReference(forwardedHubOrigin);
nextHubWord = forwardedHubRef.readHubAsWord();
if (nextHubWord.equals(hubHubWord)) {
// We arrived at the DynamicHub for the class DynamicHub
return true;
}
}
// If we're still not at the dynamic hub's hub, this can only be the dynamic hub for static hub. If not, it isn't a plausible object.
return nextHubWord.equals(staticHubHubWord());
} catch (DataIOError dataAccessError) {
}
return false;
}
/**
* Registers a type of surrogate object to be created for a specific VM object type.
* The local object must be a concrete subtype of {@link TeleTupleObject} and must have
* a constructor that takes two arguments: {@link TeleVM}, {@link RemoteReference}.
*
* @param vmClass the VM class for which a specialized representation is desired
* @param localClass the local representation to be constructed
*/
public void registerTeleObjectType(Class vmClass, Class localClass) {
teleObjectFactory.register(vmClass, localClass);
}
/**
* Factory method for canonical {@link TeleObject} surrogate for objects in the VM. Specific subclasses are
* created for Maxine implementation objects of special interest, and for other objects for which special treatment
* is desired.
* <p>
* Returns {@code null} for the distinguished zero {@link RemoteReference}.
* <p>
* Must be called with current thread holding the VM lock.
* <p>
* Care is taken to avoid I/O with the VM during synchronized access to the canonicalization map. There is a small
* exception to this for {@link TeleTargetMethod}, which can lead to infinite regress if the constructors for
* mutually referential objects (notably {@link TeleClassMethodActor}) also create {@link TeleObject}s.
*
* @param reference non-null location of a Java object in the VM
* @return canonical local surrogate for the object
*/
public TeleObject makeTeleObject(RemoteReference reference) {
return teleObjectFactory.make(reference);
}
/**
* @return access to information about object layout in the VM.
*/
public LayoutScheme layoutScheme() {
return Layout.layoutScheme();
}
/**
* @return access to general information about array object layout in the VM.
*/
public ArrayLayout arrayLayout() {
return layoutScheme().arrayLayout;
}
/**
* @return access to information about a specific kind of array object layout in the VM.
*/
public ArrayLayout arrayLayout(Kind kind) {
return kind.arrayLayout(layoutScheme());
}
/**
* Low-level read of a VM array length
* <p>
* <strong>Unsafe:</strong> does not check that there is a valid array at the specified location.
*
* @param reference location in the VM presumed (but not checked) to be an array origin of the specified kind
* @return the value in the length field of the array
*/
public int unsafeReadArrayLength(RemoteReference reference) {
return arrayLayout().readLength(reference);
}
/**
* Low-level translation of an index into a specific array to the address of the array element in VM memory.
* <p>
* <strong>Unsafe:</strong> does not check that there is a valid array if the specified kind at the specified origin.
*
* @param kind identifies one of the basic VM value types
* @param origin location in VM memory presumed (but not checked) to be an array origin of the specified kind
* @param index identifies a specific array element
* @return address of the array element in VM memory
*/
public Address unsafeArrayIndexToAddress(Kind kind, Address origin, int index) {
return origin.plus(arrayLayout(kind).getElementOffsetFromOrigin(index));
}
/**
* Low-level translation of an address, presumed to be the location in VM memory of an array element of the specified type,
* to the index of the array element.
* <p>
* <strong>Unsafe:</strong> does not check that there is a valid array if the specified kind at the specified origin.
*
* @param kind identifies one of the basic VM value types
* @param origin location in VM memory presumed (but not checked) to be an array origin of the specified kind
* @param address location of a specific array element
* @return index of the array element in VM memory
*/
public int unsafeArrayElementAddressToIndex(Kind kind, Address origin, Address address) {
return address.minus(origin.plus(arrayLayout(kind).getElementOffsetFromOrigin(0))).dividedBy(kind.width.numberOfBytes).toInt();
}
/**
* Low level copying of array elements from the VM into a local object.
* <p>
* <strong>Unsafe:</strong> does not check that there is a valid array of the specified kind at the specified location.
*
* @param kind the kind of elements held in the array.
* @param src a reference to an array in VM memory described by the layout configured for this kind
* @param srcIndex starting index in the source array
* @param dst the array into which the values are copied
* @param dstIndex the starting index in the destination array
* @param length the number of elements to copy
* @see ArrayLayout#copyElements(Accessor, int, Object, int, int)
*/
public void unsafeCopyElements(Kind kind, RemoteReference src, int srcIndex, Object dst, int dstIndex, int length) {
arrayLayout(kind).copyElements(src, srcIndex, dst, dstIndex, length);
}
/**
* Converts an address, if it is encoded as a forwarding pointer, into the actual
* address. This takes no account of the location or the state of memory management
* for that area of memory.
*
* @param address an address possibly encoded as a forwarding pointer
* @return the decoded address, {@link Address#zero()} if not encoded as a forwarding pointer.
*/
public Address forwardingPointerToOriginUnsafe(Address address) {
if (address.isBitSet(0)) {
final Address newCellAddress = address.bitClear(0);
return Layout.generalLayout().cellToOrigin(newCellAddress.asPointer());
}
return Address.zero();
}
// TODO (mlvdv) Replace with methods derived from Layout, with supporting implementations in RemoteReferenceScheme
/**
* Return the address where a forwarding pointer is stored within the specified tele object.
* @param object
* @return Address of a forwarding pointer.
*/
public Address getForwardingPointerAddress(MaxObject object) {
return object.origin().plus(gcForwardingAddressOffset);
}
// TODO (mlvdv) Replace with methods derived from Layout, with supporting implementations in RemoteReferenceScheme
/**
* Assumes the address is a valid object origin; returns whether the object holds a forwarding pointer.
* <p>
* <strong>Does not</strong> check whether the origin is a plausible object origin or even whether it is a
* legitimate address at all.
*/
public boolean hasForwardingAddressUnsafe(Address origin) {
return forwardingPointerToOriginUnsafe(readForwardWordUnsafe(origin).asAddress()).isNotZero();
}
// TODO (mlvdv) Replace with methods derived from Layout, with supporting implementations in RemoteReferenceScheme
/**
* Returns the actual address pointed at by a forwarding address stored in the object at
* the specified location in VM memory, <em>assuming</em> that the object's origin is
* actually holding a forwarding address.
* <p>
* <string>Does not</strong> check whether the origin is a plausible object origin, whether there
* is actually a forwarding address stored in the object, or even whether the origin is a legitimate
* address at all.
*/
// TODO (mlvdv) Replace with methods derived from Layout, with supporting implementations in RemoteReferenceScheme
public Address getForwardingAddressUnsafe(Address origin) {
return forwardingPointerToOriginUnsafe(readForwardWordUnsafe(origin).asAddress());
}
// TODO (mlvdv) Replace with methods derived from Layout, with supporting implementations in RemoteReferenceScheme
/**
* Assuming that the argument is the origin of an object in VM memory, reads the word that would hold the forwarding
* address.
* <p>
* <strong>Does not</strong> check whether the origin is a plausible object origin or even whether it is a
* legitimate address at all.
*/
private Word readForwardWordUnsafe(Address origin) {
return memory().readWord(origin.plus(gcForwardingAddressOffset));
}
/**
* Low-level predicate for identifying the special case of a {@link StaticTuple} in the VM,
* using only the most primitive operations, since it is needed for building all the higher-level
* services in the Inspector.
* <p>
* Note that this predicate is not precise; it may very rarely return a false positive.
* <p>
* The predicate depends on the following chain in the VM heap layout:
* <ol>
* <li>The hub of a {@link StaticTuple} points at a {@link StaticHub}</li>
* <li>A field in a {@link StaticHub} points at the {@link ClassActor} for the class being implemented.</li>
* <li>A field in a {@link ClassActor} points at the {@link StaticTuple} for the class being implemented,
* which will point back at the original location if it is in fact a {@link StaticTuple}.</li>
* </ol>
* No type checks are performed, however, since this predicate must not depend on such higher-level information.
*
* @param origin a memory location in the VM
* @return whether the object (probably) points at an instance of {@link StaticTuple}
*/
private boolean isStaticTuple(Address origin) {
// If this is a {@link StaticTuple} then a field in the header points at a {@link StaticHub}
Word staticHubWord = referenceManager().makeTemporaryRemoteReference(origin).readHubAsWord();
final RemoteReference staticHubRef = referenceManager().makeTemporaryRemoteReference(staticHubWord.asAddress());
final Pointer staticHubOrigin = staticHubRef.toOrigin();
if (!heap().contains(staticHubOrigin) && !codeCache().contains(staticHubOrigin)) {
return false;
}
// If we really have a {@link StaticHub}, then a known field points at a {@link ClassActor}.
final int hubClassActorOffset = fields().Hub_classActor.fieldActor().offset();
final Word classActorWord = memory().readWord(staticHubOrigin, hubClassActorOffset);
final RemoteReference classActorRef = referenceManager().makeTemporaryRemoteReference(classActorWord.asAddress());
final Pointer classActorOrigin = classActorRef.toOrigin();
if (!heap().contains(classActorOrigin) && !codeCache().contains(classActorOrigin)) {
return false;
}
// If we really have a {@link ClassActor}, then a known field points at the {@link StaticTuple} for the class.
final int classActorStaticTupleOffset = fields().ClassActor_staticTuple.fieldActor().offset();
final Word staticTupleWord = memory().readWord(classActorOrigin, classActorStaticTupleOffset);
final RemoteReference staticTupleRef = referenceManager().makeTemporaryRemoteReference(staticTupleWord.asAddress());
final Pointer staticTupleOrigin = staticTupleRef.toOrigin();
// If we really started with a {@link StaticTuple}, then this field will point at it
return staticTupleOrigin.equals(origin);
}
public void printSessionStats(PrintStream printStream, int indent, boolean verbose) {
final ObjectFactoryMapStats stats = teleObjectFactory.mapStats();
final String indentation = Strings.times(' ', indent);
final NumberFormat formatter = NumberFormat.getInstance();
final StringBuilder sb = new StringBuilder();
sb.append("Currently mapped: ").append(formatter.format(stats.mapSize));
sb.append(" (live=").append(stats.liveCount);
sb.append(", quasi=").append(formatter.format(stats.quasiCount));
sb.append(", dead=").append(formatter.format(stats.deadCount));
sb.append(", collected=").append(formatter.format(stats.collectedCount)).append(")");
printStream.println(indentation + sb.toString());
final TreeSet<ClassCount> sortedObjectsCreatedPerType = new TreeSet<ClassCount>(new Comparator<ClassCount>() {
@Override
public int compare(ClassCount o1, ClassCount o2) {
return o2.value - o1.value;
}
});
sortedObjectsCreatedPerType.addAll(teleObjectFactory.objectsCreatedPerType());
printStream.println(indentation + "TeleObjects created in session (total): " + formatter.format(teleObjectFactory.objectsCreatedCount()));
printStream.println(indentation + "TeleObjects created in session (top " + STATS_NUM_TYPE_COUNTS + " types):");
int countsPrinted = 0;
for (ClassCount count : sortedObjectsCreatedPerType) {
if (countsPrinted++ >= STATS_NUM_TYPE_COUNTS) {
break;
}
if (verbose) {
printStream.println(" " + count.value + "\t" + count.type.getName());
} else {
printStream.println(" " + count.value + "\t" + count.type.getSimpleName());
}
}
}
}