/* * 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.tele.object; import java.io.*; import java.lang.management.*; import java.lang.ref.*; import java.text.*; import java.util.*; import com.sun.max.lang.*; import com.sun.max.tele.*; import com.sun.max.tele.reference.*; import com.sun.max.tele.util.*; import com.sun.max.unsafe.*; import com.sun.max.vm.heap.*; /** * A manager for remote references to objects allocated in a single region of VM memory where: * <ul> * <li>The region is assumed not to move during its lifetime; and</li> * <li>Objects, once created never move and are never collected/evicted.</li> * </ul> */ public final class FixedObjectRemoteReferenceManager extends AbstractVmHolder implements RemoteObjectReferenceManager { private static final int TRACE_VALUE = 1; private final VmObjectHoldingRegion objectRegion; /** * Map: address in VM --> a {@link RemoteReference} that refers to the object whose origin is at that location. */ private Map<Long, WeakReference<RemoteReference>> originToReference = new HashMap<Long, WeakReference<RemoteReference>>(); /** * Creates a manager for remote references to objects in a single region * of memory in the VM, presumed to be an unmanaged region in which object * never move and are never collected. */ public FixedObjectRemoteReferenceManager(TeleVM vm, VmObjectHoldingRegion objectRegion) { super(vm); this.objectRegion = objectRegion; } /** * {@inheritDoc} * <p> * There is no GC cycle for an unmanaged code cache; object * are neither relocated nor collected. */ public HeapPhase phase() { return HeapPhase.MUTATING; } public ObjectStatus objectStatusAt(Address origin) throws TeleError { TeleError.check(objectRegion.memoryRegion().contains(origin), "Location is outside region"); final WeakReference<RemoteReference> weakRef = originToReference.get(origin.toLong()); if (weakRef != null) { final RemoteReference knownReference = weakRef.get(); if (knownReference != null) { return knownReference.status(); } } // The only way we can tell in general is with the heuristic. return objects().isPlausibleOriginUnsafe(origin) ? ObjectStatus.LIVE : ObjectStatus.DEAD; } public boolean isForwardingAddress(Address forwardingAddress) { return false; } public RemoteReference makeReference(Address origin) { assert vm().lockHeldByCurrentThread(); TeleError.check(objectRegion.memoryRegion().contains(origin), "Attempt to make reference at location outside region"); RemoteReference remoteReference = null; final WeakReference<RemoteReference> weakRef = originToReference.get(origin.toLong()); if (weakRef != null) { remoteReference = weakRef.get(); } if (remoteReference == null && objects().isPlausibleOriginUnsafe(origin)) { remoteReference = new UnmanagedCanonicalTeleReference(vm(), origin); originToReference.put(origin.toLong(), new WeakReference<RemoteReference>(remoteReference)); } return remoteReference; } /** * {@inheritDoc} * <p> * There are no quasi objects in this kind of region. */ public RemoteReference makeQuasiReference(Address origin) { return null; } private int activeReferenceCount() { int count = 0; for (WeakReference<RemoteReference> weakRef : originToReference.values()) { if (weakRef.get() != null) { count++; } } return count; } private int totalReferenceCount() { return originToReference.size(); } public void printObjectSessionStats(PrintStream printStream, int indent, boolean verbose) { final NumberFormat formatter = NumberFormat.getInstance(); // Line 0 String indentation = Strings.times(' ', indent); final StringBuilder sb0 = new StringBuilder(); sb0.append(objectRegion.entityName()); printStream.println(indentation + sb0.toString()); // increase indentation indentation += Strings.times(' ', 4); // Line 1 final StringBuilder sb1 = new StringBuilder(); sb1.append("memory: "); final MaxEntityMemoryRegion memoryRegion = objectRegion.memoryRegion(); final MemoryUsage usage = memoryRegion.getUsage(); final long size = usage.getCommitted(); if (size > 0) { sb1.append("size=" + formatter.format(size)); final long used = usage.getUsed(); sb1.append(", usage=" + (Long.toString(100 * used / size)) + "%"); } else { sb1.append(" <unallocated>"); } sb1.append(", unmanaged"); printStream.println(indentation + sb1.toString()); // Line 2, indented final StringBuilder sb2 = new StringBuilder(); final int activeReferenceCount = activeReferenceCount(); final int totalReferenceCount = totalReferenceCount(); sb2.append("mapped object refs: active=" + formatter.format(activeReferenceCount)); sb2.append(", inactive=" + formatter.format(totalReferenceCount - activeReferenceCount)); if (verbose) { sb2.append(", ref. mgr=" + getClass().getSimpleName()); } printStream.println(indentation + sb2.toString()); } /** * A canonical remote object reference pointing into a region of VM memory that is unmanaged: * objects, once allocated, never move and are never collected/evicted. */ private class UnmanagedCanonicalTeleReference extends ConstantRemoteReference { UnmanagedCanonicalTeleReference(TeleVM vm, Address origin) { super(vm, origin); } @Override public ObjectStatus status() { return ObjectStatus.LIVE; } @Override public ObjectStatus priorStatus() { return null; } } }