/* * 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.method; import java.io.*; 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.object.*; import com.sun.max.tele.object.TeleTargetMethod.CodeCacheReferenceKind; import com.sun.max.tele.reference.*; import com.sun.max.tele.util.*; import com.sun.max.unsafe.*; import com.sun.max.vm.compiler.target.*; import com.sun.max.vm.heap.*; /** * A manager for remote references to objects allocated in an <em>unmanaged</em> {@linkplain VmCodeCacheRegion code cache region}. * <ul> * <li>This manager assumes that objects in this region, once created, neither move nor are collected.</li> * <li>This manager assumes that there can only * be objects in the region of the kinds enumerated by {@link CodeCacheReferenceKind}, which * are pointed to by corresponding fields in a (heap) instance of {@link TeleMethodActor}.</li> * <li>This manager creates <em>canonical references</em>.</li> * </ul> * <p> * This implementation depends on knowledge of the internal workings of {@link TargetMethod}. * * @see TargetMethod * @see VmCodeCacheRegion * @see TeleTargetMethod */ final class UnmanagedCodeCacheRemoteReferenceManager extends AbstractVmHolder implements RemoteObjectReferenceManager { /** * The code cache region whose objects are being managed. */ private final VmCodeCacheRegion codeCacheRegion; /** * A two level map. For each of the possible kinds of references that can be created, * it records the ones we've created so far, indexed by TeleTargetMethod * <pre> * CodeCacheReferenceKind --> [ TeleTargetMethod --> WeakReference<TeleReference>] * </pre> */ private final Map<CodeCacheReferenceKind, Map<TeleTargetMethod, WeakReference<UnmanagedCodeCacheRemoteReference> > > refMaps = new HashMap<CodeCacheReferenceKind, Map<TeleTargetMethod, WeakReference<UnmanagedCodeCacheRemoteReference> > >(); /** * Create a manager for objects allocated in an <em>unmanaged</em> {@linkplain VmCodeCacheRegion code cache region}. * * @param codeCacheRegion the code cache region whose objects are to be managed. */ public UnmanagedCodeCacheRemoteReferenceManager(TeleVM vm, VmCodeCacheRegion codeCacheRegion) { super(vm); this.codeCacheRegion = codeCacheRegion; // Create a separate map for references of each kind for (CodeCacheReferenceKind kind : CodeCacheReferenceKind.values()) { refMaps.put(kind, new HashMap<TeleTargetMethod, WeakReference<UnmanagedCodeCacheRemoteReference> >()); } } /** * {@inheritDoc} * <p> * There is no GC cycle for an unmanaged code cache; object * are neither relocated nor collected. */ public HeapPhase phase() { return HeapPhase.MUTATING; } /** * {@inheritDoc} * <p> * We don't need a heuristic for objects in a code cache region; if they are present, then they are * pointed at by one of the fields in a {@link TargetMethod}. */ public ObjectStatus objectStatusAt(Address origin) throws TeleError { TeleError.check(codeCacheRegion.memoryRegion().contains(origin), "Location is outside region"); final TeleCompilation compilation = codeCacheRegion.findCompilation(origin); if (compilation != null) { final TeleTargetMethod teleTargetMethod = compilation.teleTargetMethod(); if (teleTargetMethod != null) { // The address is contained in the code cache allocation for this target method. // Does one of the target method's references point at this location?? for (CodeCacheReferenceKind kind : CodeCacheReferenceKind.values()) { final Address objectOrigin = teleTargetMethod.codeCacheObjectOrigin(kind); if (objectOrigin != null && objectOrigin.equals(origin)) { // The specified location matches one of the target method's pointers. // There should be an object there, but check just in case. assert objects().isPlausibleOriginUnsafe(objectOrigin); return ObjectStatus.LIVE; } } } } return ObjectStatus.DEAD; } public boolean isForwardingAddress(Address forwardingAddress) { return false; } /** * {@inheritDoc} * <p> * The only objects in the code cache region must be pointed to by a field in * some (heap) instance of {@link TargetMethod}. This is a precise check. * <p> * If the location is an origin of such an object, return an object reference * that indirects through the {@link TargetMethod} that points at the object. */ public RemoteReference makeReference(Address origin) throws TeleError { assert vm().lockHeldByCurrentThread(); TeleError.check(codeCacheRegion.contains(origin)); // Locate the compilation, if any, whose code cache allocation in VM memory includes the address final TeleCompilation compilation = codeCacheRegion.findCompilation(origin); if (compilation != null) { final TeleTargetMethod teleTargetMethod = compilation.teleTargetMethod(); if (teleTargetMethod != null) { // The address is contained in the code cache allocation for this target method. for (CodeCacheReferenceKind kind : CodeCacheReferenceKind.values()) { // Does one of the target method's references point at this location?? final Address objectOrigin = teleTargetMethod.codeCacheObjectOrigin(kind); if (objectOrigin != null && origin.equals(objectOrigin)) { // Return a canonical reference to this location return makeCanonicalReference(teleTargetMethod, kind); } } } } return null; } /** * {@inheritDoc} * <p> * There are no <em>quasi</em> objects in this kind of region. */ public RemoteReference makeQuasiReference(Address origin) throws TeleError { return null; } private int activeReferenceCount() { int count = 0; for (CodeCacheReferenceKind kind : CodeCacheReferenceKind.values()) { final Map<TeleTargetMethod, WeakReference<UnmanagedCodeCacheRemoteReference> > kindRefMap = refMaps.get(kind); for (WeakReference<UnmanagedCodeCacheRemoteReference> weakRef : kindRefMap.values()) { if (weakRef != null) { final UnmanagedCodeCacheRemoteReference teleRef = weakRef.get(); if (teleRef != null) { count++; } } } } return count; } private int totalReferenceCount() { int count = 0; for (CodeCacheReferenceKind kind : CodeCacheReferenceKind.values()) { count += refMaps.get(kind).size(); } return count; } public void printObjectSessionStats(PrintStream printStream, int indent, boolean verbose) { final String indentation = Strings.times(' ', indent); printStream.println(indentation + "Object holding region: " + codeCacheRegion.entityName()); final NumberFormat formatter = NumberFormat.getInstance(); final StringBuilder sb2 = new StringBuilder(); final int activeReferenceCount = activeReferenceCount(); final int totalReferenceCount = totalReferenceCount(); sb2.append("object refs: active=" + formatter.format(activeReferenceCount)); sb2.append(", inactive=" + formatter.format(totalReferenceCount - activeReferenceCount)); sb2.append(", mgr=" + getClass().getSimpleName()); printStream.println(indentation + sb2.toString()); } /** * @return a canonical reference of the specified kind for the specified target method */ private RemoteReference makeCanonicalReference(TeleTargetMethod teleTargetMethod, CodeCacheReferenceKind kind) { UnmanagedCodeCacheRemoteReference remoteRef = null; final Map<TeleTargetMethod, WeakReference<UnmanagedCodeCacheRemoteReference> > kindMap = refMaps.get(kind); WeakReference<UnmanagedCodeCacheRemoteReference> weakRef = kindMap.get(teleTargetMethod); if (weakRef != null) { remoteRef = weakRef.get(); } if (remoteRef == null) { // By construction, there should be an object at the location; let's just check. assert objects().isPlausibleOriginUnsafe(teleTargetMethod.codeCacheObjectOrigin(kind)); remoteRef = new UnmanagedCodeCacheRemoteReference(vm(), teleTargetMethod, kind); kindMap.put(teleTargetMethod, new WeakReference<UnmanagedCodeCacheRemoteReference>(remoteRef)); } return remoteRef; } /** * A remote object reference constrained to point only at data stored in object format in an unmanaged region of * code cache. In particular, it may refer only to one of the three possible data arrays pointed at by an instance * of {@link TeleTargetMethod} in the VM. * <p> * Such data, by definition, never moves and is always {@linkplain ObjectStatus#LIVE LIVE}, even if/when the * {@link TeleTargetMethod} responsible for it has been collected. * * @see TeleTargetMethod */ private final class UnmanagedCodeCacheRemoteReference extends AbstractCodeCacheRemoteReference { private final CodeCacheReferenceKind kind; private Address origin = Address.zero(); public UnmanagedCodeCacheRemoteReference(TeleVM vm, TeleTargetMethod teleTargetMethod, CodeCacheReferenceKind kind) { super(vm, teleTargetMethod); this.origin = teleTargetMethod.codeCacheObjectOrigin(kind); this.kind = kind; } /** * {@inheritDoc} * <p> * Objects in an unmanaged code cache region are immortal; even if the * {@link TeleTargetMethod} that points at them has been collected. */ @Override public ObjectStatus status() { return ObjectStatus.LIVE; } @Override public ObjectStatus priorStatus() { return null; } @Override public Address origin() { if (origin.isZero() && teleTargetMethod().status().isLive()) { origin = teleTargetMethod().codeCacheObjectOrigin(kind); } return origin; } /** * {@inheritDoc} * <p> * Unmanaged objects never move, and so are never <em>forwarded</em>. */ @Override public Address forwardedFrom() { return Address.zero(); } /** * {@inheritDoc} * <p> * Unmanaged objects never move, and so are never <em>forwarded</em>. */ @Override public Address forwardedTo() { return Address.zero(); } @Override public String gcDescription() { return "object in an unmanaged code cache region: " + kind.label(); } } }