/* * Copyright (c) 2009, 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.lang.ref.*; import java.lang.reflect.*; import java.util.*; import java.util.concurrent.*; import com.sun.cri.ci.*; 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.reference.*; import com.sun.max.tele.util.*; import com.sun.max.vm.*; import com.sun.max.vm.actor.holder.*; import com.sun.max.vm.actor.member.*; import com.sun.max.vm.classfile.*; import com.sun.max.vm.classfile.constant.*; import com.sun.max.vm.code.*; import com.sun.max.vm.compiler.target.*; import com.sun.max.vm.heap.*; import com.sun.max.vm.heap.gcx.*; import com.sun.max.vm.heap.gcx.rset.ctbl.*; import com.sun.max.vm.layout.hom.*; import com.sun.max.vm.layout.ohm.*; import com.sun.max.vm.log.*; import com.sun.max.vm.log.java.*; import com.sun.max.vm.log.nat.*; import com.sun.max.vm.monitor.*; import com.sun.max.vm.reference.direct.*; import com.sun.max.vm.run.java.*; import com.sun.max.vm.thread.*; import com.sun.max.vm.type.*; import com.sun.max.vm.value.*; /** * A singleton factory that manages the creation and maintenance of instances of {@link TeleObject}, each of which is a * canonical surrogate for an object in the VM. * <p> * Instances are created reflectively, based on a table in which constructors for various subtypes of {@link TeleObject} * are registered. This allows the factory to create a {@link TeleObject} instance of the most specific subtype of the * VM object for which a constructor is registered. * <p> * A {@link TeleObject} is intended to be cannonical, so the unique instance for each object can be retrieved either by * location or by OID. Exceptions to this can occur because of GC: * <ul> * <li>An object in the VM can be released by the running application and "collected" by the GC. As soon as this is * discovered, the {@TeleObject} that refers to it is marked "dead". * <li>During some phases of copying GC, there may be two instances that refer to what is semantically the same object: * one referring to the old copy and one referring to the new.</li> * <li>As soon as a duplication due to copying is discovered, the {@link TeleObject} that refers to the old copy is * marked "obsolete". It is possible to discover the {@link TeleObject} that refers to the newer copy of the object.</li> * <li>A {@link TeleObject} that is either "dead" or "obsolete" is removed from the maps and cannot be discovered, * either by location or OID.</li> * </ul> * @see TeleObject */ public final class TeleObjectFactory extends AbstractVmHolder implements TeleVMCache { private static final int TRACE_VALUE = 1; /** * Map: Class -> counters. * <br> * Class-indexed statistics. * 0: number of objects in class updated * 1: total system time of updates for objects in class * */ private static class TimerPerType extends HashMap<Class, long[]> { @Override public long[] get(Object key) { long[] time = super.get(key); if (time == null) { time = new long[2]; super.put((Class) key, time); } return time; } } /** * A count associated with an instance of {@link Class}. */ public static final class ClassCount { public final Class type; public int value = 0; private ClassCount(Class type) { this.type = type; } } public final class ObjectFactoryMapStats { public int mapSize; public int liveCount = 0; public int quasiCount = 0; public int deadCount = 0; public int collectedCount = 0; public ObjectFactoryMapStats() { int live = 0; int quasi = 0; int dead = 0; int collected = 0; for (WeakReference<TeleObject> weakRef : referenceToTeleObject.values()) { final TeleObject teleObject = weakRef.get(); if (teleObject == null) { collected++; } else { switch(teleObject.reference().status()) { case LIVE: live++; break; case DEAD: dead++; break; default: quasi++; break; } } } this.mapSize = referenceToTeleObject.size(); this.liveCount = live; this.quasiCount = quasi; this.deadCount = dead; this.collectedCount = collected; } public ObjectFactoryMapStats(int mapSize, int liveCount, int quasiCount, int deadCount, int collectedCount) { this.mapSize = mapSize; this.liveCount = liveCount; this.quasiCount = quasiCount; this.deadCount = deadCount; this.collectedCount = collectedCount; } } private static TeleObjectFactory teleObjectFactory; /** * @return the singleton manager for instances of {@link TeleObject}. */ public static TeleObjectFactory make(TeleVM vm, long processEpoch) { if (teleObjectFactory == null) { teleObjectFactory = new TeleObjectFactory(vm, processEpoch); } return teleObjectFactory; } /** * Map: Reference to {@link Object}s in the VM --> canonical local {@link TeleObject} that represents the * object in the VM. Relies on References being canonical and GC-safe. */ private final Map<RemoteReference, WeakReference<TeleObject>> referenceToTeleObject = new ConcurrentHashMap<RemoteReference, WeakReference<TeleObject>>(); private final Map<RemoteReference, WeakReference<TeleObject>> referenceToTeleHeapFreeChunk = new HashMap<RemoteReference, WeakReference<TeleObject>>(); private int heapFreeChunksCount = 0; /** * Map: OID --> {@link TeleObject}. * <br> * Synchronized so that it can be read outside the VM lock if needed. */ private final Map<Long, WeakReference<TeleObject>> oidToTeleObject = Collections.synchronizedMap(new HashMap<Long, WeakReference<TeleObject>>()); /** * Constructors for specific classes of tuple objects in the heap in the VM. * The most specific class that matches a particular {@link TeleObject} will * be used, in an emulation of virtual method dispatch. */ private final Map<Class, Constructor> classToTeleTupleObjectConstructor = new HashMap<Class, Constructor>(); private final TimedTrace updateTracer; /** * A printer for statistics concerning a cache update. */ private final Object statsPrinter = new Object() { @Override public String toString() { final ObjectFactoryMapStats stats = lastUpdateMapStats; final StringBuilder msg = new StringBuilder(); msg.append("#mapped=(live=").append(stats.liveCount).append(", quasi=").append(stats.quasiCount).append("), "); msg.append("#removed=(dead=").append(stats.deadCount).append(", collected=").append(stats.collectedCount).append(")"); return msg.toString(); } }; /** * Total number of instances of {@link TeleObject} created during session. */ private int objectsCreatedCount = 0; /** * Map: {@link Class} of a {@link TeleObject} --> counter for number of instances created during session. */ private final HashMap<Class, ClassCount> objectsCreatedPerType = new HashMap<Class, ClassCount>() { @Override public ClassCount get(Object key) { ClassCount count = super.get(key); if (count == null) { count = new ClassCount((Class) key); put((Class) key, count); } return count; } }; /** * The census of the map's content, as determined by the most recent refresh. */ private ObjectFactoryMapStats lastUpdateMapStats = new ObjectFactoryMapStats(0, 0, 0, 0, 0); private long lastUpdateEpoch = -1L; private TeleObjectFactory(TeleVM vm, long processEpoch) { super(vm); assert vm().lockHeldByCurrentThread(); final TimedTrace tracer = new TimedTrace(TRACE_VALUE, tracePrefix() + " creating"); tracer.begin(); this.updateTracer = new TimedTrace(TRACE_VALUE, tracePrefix() + " updating"); // Representation for all tuple objects not otherwise mentioned classToTeleTupleObjectConstructor.put(Object.class, getConstructor(TeleTupleObject.class)); // Some common Java classes classToTeleTupleObjectConstructor.put(String.class, getConstructor(TeleString.class)); classToTeleTupleObjectConstructor.put(Enum.class, getConstructor(TeleEnum.class)); classToTeleTupleObjectConstructor.put(ClassLoader.class, getConstructor(TeleClassLoader.class)); // Default representation of scheme implementations; should be specialized for implementation-specific support classToTeleTupleObjectConstructor.put(AbstractMonitorScheme.class, getConstructor(TeleMonitorScheme.class)); classToTeleTupleObjectConstructor.put(DirectReferenceScheme.class, getConstructor(TeleReferenceScheme.class)); classToTeleTupleObjectConstructor.put(HeapSchemeAdaptor.class, getConstructor(TeleHeapScheme.class)); classToTeleTupleObjectConstructor.put(HomLayoutScheme.class, getConstructor(TeleLayoutScheme.class)); classToTeleTupleObjectConstructor.put(JavaRunScheme.class, getConstructor(TeleRunScheme.class)); classToTeleTupleObjectConstructor.put(MonitorScheme.class, getConstructor(TeleMonitorScheme.class)); classToTeleTupleObjectConstructor.put(OhmLayoutScheme.class, getConstructor(TeleLayoutScheme.class)); // Maxine Actors classToTeleTupleObjectConstructor.put(FieldActor.class, getConstructor(TeleFieldActor.class)); classToTeleTupleObjectConstructor.put(VirtualMethodActor.class, getConstructor(TeleVirtualMethodActor.class)); classToTeleTupleObjectConstructor.put(StaticMethodActor.class, getConstructor(TeleStaticMethodActor.class)); classToTeleTupleObjectConstructor.put(InterfaceMethodActor.class, getConstructor(TeleInterfaceMethodActor.class)); classToTeleTupleObjectConstructor.put(InterfaceActor.class, getConstructor(TeleInterfaceActor.class)); classToTeleTupleObjectConstructor.put(VmThread.class, getConstructor(TeleVmThread.class)); classToTeleTupleObjectConstructor.put(PrimitiveClassActor.class, getConstructor(TelePrimitiveClassActor.class)); classToTeleTupleObjectConstructor.put(ArrayClassActor.class, getConstructor(TeleArrayClassActor.class)); classToTeleTupleObjectConstructor.put(ReferenceClassActor.class, getConstructor(TeleReferenceClassActor.class)); // Memory management classToTeleTupleObjectConstructor.put(MemoryRegion.class, getConstructor(TeleMemoryRegion.class)); classToTeleTupleObjectConstructor.put(LinearAllocationMemoryRegion.class, getConstructor(TeleLinearAllocationMemoryRegion.class)); classToTeleTupleObjectConstructor.put(BootHeapRegion.class, getConstructor(TeleBootHeapRegion.class)); // Maxine code management classToTeleTupleObjectConstructor.put(TargetMethod.class, getConstructor(TeleTargetMethod.class)); classToTeleTupleObjectConstructor.put(CodeRegion.class, getConstructor(TeleCodeRegion.class)); classToTeleTupleObjectConstructor.put(SemiSpaceCodeRegion.class, getConstructor(TeleSemiSpaceCodeRegion.class)); classToTeleTupleObjectConstructor.put(CodeManager.class, getConstructor(TeleCodeManager.class)); // Maxine heap management classToTeleTupleObjectConstructor.put(BaseAtomicBumpPointerAllocator.class, getConstructor(TeleBaseAtomicBumpPointerAllocator.class)); classToTeleTupleObjectConstructor.put(CardTableRSet.class, getConstructor(TeleCardTableRSet.class)); classToTeleTupleObjectConstructor.put(ContiguousHeapSpace.class, getConstructor(TeleContiguousHeapSpace.class)); classToTeleTupleObjectConstructor.put(FirstFitMarkSweepSpace.class, getConstructor(TeleFirstFitMarkSweepSpace.class)); classToTeleTupleObjectConstructor.put(FreeHeapSpaceManager.class, getConstructor(TeleFreeHeapSpaceManager.class)); classToTeleTupleObjectConstructor.put(HeapFreeChunk.class, getConstructor(TeleHeapFreeChunk.class)); classToTeleTupleObjectConstructor.put(NoAgingRegionalizedNursery.class, getConstructor(TeleNoAgingRegionalizedNursery.class)); classToTeleTupleObjectConstructor.put(TricolorHeapMarker.class, getConstructor(TeleTricolorHeapMarker.class)); // Other Maxine support classToTeleTupleObjectConstructor.put(MaxineVM.class, getConstructor(TeleMaxineVM.class)); classToTeleTupleObjectConstructor.put(VMConfiguration.class, getConstructor(TeleVMConfiguration.class)); classToTeleTupleObjectConstructor.put(ClassRegistry.class, getConstructor(TeleClassRegistry.class)); classToTeleTupleObjectConstructor.put(Kind.class, getConstructor(TeleKind.class)); classToTeleTupleObjectConstructor.put(ObjectReferenceValue.class, getConstructor(TeleObjectReferenceValue.class)); classToTeleTupleObjectConstructor.put(CiConstant.class, getConstructor(TeleCiConstant.class)); classToTeleTupleObjectConstructor.put(HeapRegionInfo.class, getConstructor(TeleHeapRegionInfo.class)); classToTeleTupleObjectConstructor.put(VMLog.class, getConstructor(TeleVMLog.class)); classToTeleTupleObjectConstructor.put(VMLogArray.class, getConstructor(TeleVMLogArray.class)); classToTeleTupleObjectConstructor.put(VMLogNative.class, getConstructor(TeleVMLogNative.class)); // ConstantPool and PoolConstants classToTeleTupleObjectConstructor.put(ConstantPool.class, getConstructor(TeleConstantPool.class)); classToTeleTupleObjectConstructor.put(CodeAttribute.class, getConstructor(TeleCodeAttribute.class)); classToTeleTupleObjectConstructor.put(PoolConstant.class, getConstructor(TelePoolConstant.class)); classToTeleTupleObjectConstructor.put(Utf8Constant.class, getConstructor(TeleUtf8Constant.class)); classToTeleTupleObjectConstructor.put(StringConstant.class, getConstructor(TeleStringConstant.class)); classToTeleTupleObjectConstructor.put(ClassConstant.Resolved.class, getConstructor(TeleClassConstant.Resolved.class)); classToTeleTupleObjectConstructor.put(ClassConstant.Unresolved.class, getConstructor(TeleClassConstant.Unresolved.class)); classToTeleTupleObjectConstructor.put(FieldRefConstant.Resolved.class, getConstructor(TeleFieldRefConstant.Resolved.class)); classToTeleTupleObjectConstructor.put(FieldRefConstant.Unresolved.class, getConstructor(TeleFieldRefConstant.Unresolved.class)); classToTeleTupleObjectConstructor.put(FieldRefConstant.UnresolvedIndices.class, getConstructor(TeleFieldRefConstant.UnresolvedIndices.class)); classToTeleTupleObjectConstructor.put(ClassMethodRefConstant.Resolved.class, getConstructor(TeleClassMethodRefConstant.Resolved.class)); classToTeleTupleObjectConstructor.put(ClassMethodRefConstant.Unresolved.class, getConstructor(TeleClassMethodRefConstant.Unresolved.class)); classToTeleTupleObjectConstructor.put(ClassMethodRefConstant.UnresolvedIndices.class, getConstructor(TeleClassMethodRefConstant.UnresolvedIndices.class)); classToTeleTupleObjectConstructor.put(InterfaceMethodRefConstant.Resolved.class, getConstructor(TeleInterfaceMethodRefConstant.Resolved.class)); classToTeleTupleObjectConstructor.put(InterfaceMethodRefConstant.Unresolved.class, getConstructor(TeleInterfaceMethodRefConstant.Unresolved.class)); classToTeleTupleObjectConstructor.put(InterfaceMethodRefConstant.UnresolvedIndices.class, getConstructor(TeleInterfaceMethodRefConstant.UnresolvedIndices.class)); // Java language objects classToTeleTupleObjectConstructor.put(Class.class, getConstructor(TeleClass.class)); classToTeleTupleObjectConstructor.put(Constructor.class, getConstructor(TeleConstructor.class)); classToTeleTupleObjectConstructor.put(Field.class, getConstructor(TeleField.class)); classToTeleTupleObjectConstructor.put(Method.class, getConstructor(TeleMethod.class)); classToTeleTupleObjectConstructor.put(TypeDescriptor.class, getConstructor(TeleTypeDescriptor.class)); classToTeleTupleObjectConstructor.put(SignatureDescriptor.class, getConstructor(TeleSignatureDescriptor.class)); classToTeleTupleObjectConstructor.put(StackTraceElement.class, getConstructor(TeleStackTraceElement.class)); tracer.end(statsPrinter); } public void updateCache(long epoch) { updateTracer.begin(); assert vm().lockHeldByCurrentThread(); TimerPerType timePerType = new TimerPerType(); int liveCount = 0; int quasiCount = 0; int deadCount = 0; int collectedCount = 0; final Iterator<RemoteReference> iterator = referenceToTeleObject.keySet().iterator(); while (iterator.hasNext()) { final RemoteReference remoteRef = iterator.next(); final WeakReference<TeleObject> weakRef = referenceToTeleObject.get(remoteRef); TeleObject teleObject = weakRef.get(); if (teleObject == null) { collectedCount++; iterator.remove(); } else { switch(teleObject.reference().status()) { case LIVE: liveCount++; break; case DEAD: deadCount++; iterator.remove(); Trace.line(TRACE_VALUE + 1, tracePrefix() + ": DEAD reference removed from map " + teleObject.reference().toString() + " gc=\"" + remoteRef.gcDescription() + "\""); break; default: quasiCount++; break; } Class type = teleObject.getClass(); long[] stats = timePerType.get(type); long s = System.currentTimeMillis(); teleObject.updateCache(epoch); stats[1] += System.currentTimeMillis() - s; stats[0]++; } } lastUpdateMapStats = new ObjectFactoryMapStats(referenceToTeleObject.size(), liveCount, quasiCount, deadCount, collectedCount); lastUpdateEpoch = epoch; updateTracer.end(statsPrinter); // Check that we haven't stumbled into a very bad update situation with an object. for (Map.Entry<Class, long[]> entry : timePerType.entrySet()) { long[] stats = entry.getValue(); long time = stats[1]; if (time > 100) { long count = stats[0]; Class key = entry.getKey(); Trace.line(TRACE_VALUE, tracePrefix() + "Excessive refresh time for type " + key + ": " + count + " updated, total time=" + time + "ms"); } } } /** * 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 class of local surrogates for the VM type objects. */ public void register(Class vmClass, Class localClass) { classToTeleTupleObjectConstructor.put(vmClass, getConstructor(localClass)); } /** * Factory method for canonical {@link TeleObject} surrogate for heap 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 * @throws TeleError if the reference is not live or otherwise illegitimate */ public TeleObject make(RemoteReference reference) throws TeleError { assert reference != null; if (reference.isZero()) { return null; } if (reference.isTemporary()) { // TODO (mlvdv) this should become an error TeleWarning.message("Creating a TeleObject with a temporary Reference" + reference.toString() + " @" + reference.toOrigin().to0xHexString()); } if (reference.status().isDead()) { // TODO (mlvdv) This should probably be an error when it all shakes out TeleWarning.message("Attempt to create TeleObject with a DEAD Reference" + reference.toString() + " @" + reference.toOrigin().to0xHexString()); } //assert vm().lockHeldByCurrentThread(); TeleObject teleObject = getTeleObject(reference); if (teleObject != null) { return teleObject; } if (reference.status().isForwarder()) { final TeleObject newCopyObject = objects().makeTeleObject(reference.followIfForwarded()); switch (newCopyObject.kind()) { case TUPLE: teleObject = new TeleTupleForwarderQuasi(vm(), reference); break; case ARRAY: final ClassActor classActor = newCopyObject.classActorForObjectType(); if (classActor == null) { return null; } teleObject = new TeleArrayForwarderQuasi(vm(), reference, classActor.componentClassActor().kind, classActor.dynamicHub().specificLayout); break; case HYBRID: if (newCopyObject instanceof TeleDynamicHub) { teleObject = new TeleDynamicHubForwarderQuasi(vm(), reference); } else if (newCopyObject instanceof TeleStaticHub) { teleObject = new TeleStaticHubForwarderQuasi(vm(), reference); } else { TeleError.unexpected(tracePrefix() + "unknown hub type"); } break; } } else { // not a Forwarder // Most important of the roles played by a {@link TeleObject} is to capture // the type of the object at the specified location. This gets done empirically, // by examining the meta-information stored with the presumed object. // Because of the meta-circular design, this relies on analysis of meta-information // in the VM that is also stored as objects (notably hubs and class actors). This // must be done carefully in order to avoid circularities, which is why the initial // investigation must be done using the lowest level memory reading primitives. // Location of the {@link Hub} in the VM that describes the layout of the presumed object. RemoteReference hubReference = vm().referenceManager().zeroReference(); // Location of the {@link ClassActor} in the VM that describes the type of the presumed object. RemoteReference classActorReference = vm().referenceManager().zeroReference(); // Local copy of the {@link ClassActor} in the VM that describes the type of the presumed object. // We presume to have loaded exactly the same classes as in the VM, so we can use this local // copy for a kind of reflective access to the structure of the presumed object. ClassActor classActor = null; try { hubReference = reference.readHubAsRemoteReference(); classActorReference = fields().Hub_classActor.readRemoteReference(hubReference); classActor = classes().makeClassActor(classActorReference); } catch (InvalidReferenceException invalidReferenceException) { Log.println("InvalidReferenceException reference: " + reference + "/" + reference.toOrigin() + " hubReference: " + hubReference + "/" + hubReference.toOrigin() + " classActorReference: " + classActorReference + "/" + classActorReference.toOrigin() + " classActor: " + classActor); return null; } // Must check for the static tuple case first; it doesn't follow the usual rules final RemoteReference hubhubReference = hubReference.readHubAsRemoteReference(); final RemoteReference hubClassActorReference = fields().Hub_classActor.readRemoteReference(hubhubReference); final ClassActor hubClassActor = classes().makeClassActor(hubClassActorReference); final Class hubJavaClass = hubClassActor.toJava(); // the class of this object's hub if (StaticHub.class.isAssignableFrom(hubJavaClass)) { teleObject = getTeleObject(reference); if (teleObject == null) { teleObject = new TeleStaticTuple(vm(), reference); } } else if (classActor.isArrayClass()) { // Check map again, just in case there's a race teleObject = getTeleObject(reference); if (teleObject == null) { teleObject = new TeleArrayObject(vm(), reference, classActor.componentClassActor().kind, classActor.dynamicHub().specificLayout); } } else if (classActor.isHybridClass()) { final Class javaClass = classActor.toJava(); // Check map again, just in case there's a race teleObject = getTeleObject(reference); if (teleObject == null) { if (DynamicHub.class.isAssignableFrom(javaClass)) { teleObject = new TeleDynamicHub(vm(), reference); } else if (StaticHub.class.isAssignableFrom(javaClass)) { teleObject = new TeleStaticHub(vm(), reference); } else { throw TeleError.unexpected(tracePrefix() + "invalid hybrid implementation type"); } } } else if (classActor.isTupleClass()) { // Check map again, just in case there's a race teleObject = getTeleObject(reference); if (teleObject == null) { // Walk up the type hierarchy for the class, locating the most specific type // for which a constructor is defined. Constructor constructor = null; for (Class javaClass = classActor.toJava(); javaClass != null; javaClass = javaClass.getSuperclass()) { constructor = classToTeleTupleObjectConstructor.get(javaClass); if (constructor != null) { break; } } if (constructor == null) { TeleError.unexpected(tracePrefix() + "failed to find constructor for class" + classActor.toJava()); } try { teleObject = (TeleObject) constructor.newInstance(vm(), reference); } catch (InstantiationException e) { TeleError.unexpected(); } catch (IllegalAccessException e) { TeleError.unexpected(); } catch (InvocationTargetException e) { TeleError.unexpected(e); } } } else { //throw TeleError.unexpected("invalid object implementation type"); Trace.line(TRACE_VALUE, tracePrefix() + "failed to create object at apparently valid origin=0x" + reference.toOrigin().toHexString()); return null; } } final WeakReference<TeleObject> teleObjectWeakReference = new WeakReference<TeleObject>(teleObject); if (reference.status().isDead()) { if (teleObject.classActorForObjectType().toJava() == HeapFreeChunk.class) { referenceToTeleHeapFreeChunk.put(reference, teleObjectWeakReference); heapFreeChunksCount++; teleObject.updateCache(vm().teleProcess().epoch()); } } else { oidToTeleObject.put(teleObject.getOID(), teleObjectWeakReference); //Log.println("OID: " + teleObject.getOID() + " ref: " + teleObject.getCurrentOrigin()); //assert oidToTeleObject.containsKey(teleObject.getOID()); referenceToTeleObject.put(reference, teleObjectWeakReference); teleObject.updateCache(vm().teleProcess().epoch()); objectsCreatedCount++; objectsCreatedPerType.get(teleObject.getClass()).value++; } return teleObject; } /** * Gets a VM object with a specified OID, if it exists. * <br> * Thread-safe; synchronized lookup does not require the VM lock. * * @return the {@link TeleObject} with specified OID, null if none exists. */ public TeleObject lookupObject(long id) { WeakReference<TeleObject> teleObject = oidToTeleObject.get(id); return teleObject == null ? null : teleObject.get(); } /** * @return the total number of {@link TeleObject} instances created during the session. */ public int objectsCreatedCount() { return objectsCreatedCount; } /** * @return counters for each type of {@link TeleObject}, counting the number created during the session. */ public Collection<ClassCount> objectsCreatedPerType() { return objectsCreatedPerType.values(); } /** * @return census of the map's current contents, not necessarily the same as the census during the refresh. */ public ObjectFactoryMapStats mapStats() { return new ObjectFactoryMapStats(); } private Constructor getConstructor(Class clazz) { return Classes.getDeclaredConstructor(clazz, TeleVM.class, RemoteReference.class); } /** * @param reference location of an object in the VM * @return the (preferably) canonical instance of {@link TeleObject} corresponding to the VM object */ private TeleObject getTeleObject(RemoteReference reference) { TeleObject teleObject = null; synchronized (referenceToTeleObject) { final WeakReference<TeleObject> teleObjectRef = referenceToTeleObject.get(reference); if (teleObjectRef != null) { teleObject = teleObjectRef.get(); } } return teleObject; } }