Mercurial > hg > truffle
view agent/src/share/classes/sun/jvm/hotspot/jdi/ObjectReferenceImpl.java @ 18665:96861e3f8cc5
made CFGPrinterObserver reset (upon close) properly
author | Doug Simon <doug.simon@oracle.com> |
---|---|
date | Thu, 11 Dec 2014 22:14:30 +0100 |
parents | c18cbe5936b8 |
children |
line wrap: on
line source
/* * Copyright (c) 2002, 2009, 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 sun.jvm.hotspot.jdi; import java.io.*; import com.sun.jdi.*; import sun.jvm.hotspot.debugger.Address; import sun.jvm.hotspot.debugger.OopHandle; import sun.jvm.hotspot.oops.Oop; import sun.jvm.hotspot.oops.Mark; import sun.jvm.hotspot.oops.Instance; import sun.jvm.hotspot.oops.Array; import sun.jvm.hotspot.oops.OopUtilities; import sun.jvm.hotspot.oops.Klass; import sun.jvm.hotspot.oops.DefaultHeapVisitor; import sun.jvm.hotspot.runtime.JavaThread; import sun.jvm.hotspot.runtime.JavaVFrame; import sun.jvm.hotspot.runtime.MonitorInfo; import sun.jvm.hotspot.runtime.ObjectMonitor; import sun.jvm.hotspot.runtime.Threads; import sun.jvm.hotspot.utilities.Assert; import java.util.*; public class ObjectReferenceImpl extends ValueImpl implements ObjectReference { private Oop saObject; private long myID; private boolean monitorInfoCached = false; private ThreadReferenceImpl owningThread = null; private List waitingThreads = null; // List<ThreadReferenceImpl> private int entryCount = 0; private static long nextID = 0L; private static synchronized long nextID() { return nextID++; } ObjectReferenceImpl(VirtualMachine aVm, sun.jvm.hotspot.oops.Oop oRef) { super(aVm); saObject = oRef; myID = nextID(); } protected Oop ref() { return saObject; } public Type type() { return referenceType(); } public ReferenceType referenceType() { Klass myKlass = ref().getKlass(); return vm.referenceType(myKlass); } public Value getValue(Field sig) { List list = new ArrayList(1); list.add(sig); Map map = getValues(list); return(Value)map.get(sig); } public Map getValues(List theFields) { //validateMirrors(theFields); List staticFields = new ArrayList(0); int size = theFields.size(); List instanceFields = new ArrayList(size); for (int i=0; i<size; i++) { sun.jvm.hotspot.jdi.FieldImpl field = (sun.jvm.hotspot.jdi.FieldImpl)theFields.get(i); // Make sure the field is valid ((ReferenceTypeImpl)referenceType()).validateFieldAccess(field); // FIX ME! We need to do some sanity checking // here; make sure the field belongs to this // object. if (field.isStatic()) { staticFields.add(field); } else { instanceFields.add(field); } } // Look up static field(s) first to mimic the JDI implementation Map map; if (staticFields.size() > 0) { map = referenceType().getValues(staticFields); } else { map = new HashMap(size); } // Then get instance field(s) size = instanceFields.size(); for (int ii=0; ii<size; ii++){ FieldImpl fieldImpl = (FieldImpl)instanceFields.get(ii); map.put(fieldImpl, fieldImpl.getValue(saObject)); } return map; } public void setValue(Field field, Value value) throws InvalidTypeException, ClassNotLoadedException { vm.throwNotReadOnlyException("ObjectReference.setValue(...)"); } public Value invokeMethod(ThreadReference threadIntf, Method methodIntf, List arguments, int options) throws InvalidTypeException, IncompatibleThreadStateException, InvocationException, ClassNotLoadedException { vm.throwNotReadOnlyException("ObjectReference.invokeMethod(...)"); return null; } public void disableCollection() { vm.throwNotReadOnlyException("ObjectReference.disableCollection()"); } public void enableCollection() { vm.throwNotReadOnlyException("ObjectReference.enableCollection()"); } public boolean isCollected() { vm.throwNotReadOnlyException("ObjectReference.isCollected()"); return false; } public long uniqueID() { return myID; } public List waitingThreads() throws IncompatibleThreadStateException { if (vm.canGetMonitorInfo() == false) { throw new UnsupportedOperationException(); } if (! monitorInfoCached) { computeMonitorInfo(); } return waitingThreads; } public ThreadReference owningThread() throws IncompatibleThreadStateException { if (vm.canGetMonitorInfo() == false) { throw new UnsupportedOperationException(); } if (! monitorInfoCached) { computeMonitorInfo(); } return owningThread; } public int entryCount() throws IncompatibleThreadStateException { if (vm.canGetMonitorInfo() == false) { throw new UnsupportedOperationException(); } if (! monitorInfoCached) { computeMonitorInfo(); } return entryCount; } // new method since 1.6. // Real body will be supplied later. public List referringObjects(long maxReferrers) { if (!vm.canGetInstanceInfo()) { throw new UnsupportedOperationException( "target does not support getting instances"); } if (maxReferrers < 0) { throw new IllegalArgumentException("maxReferrers is less than zero: " + maxReferrers); } final ObjectReference obj = this; final List objects = new ArrayList(0); final long max = maxReferrers; vm.saObjectHeap().iterate(new DefaultHeapVisitor() { private long refCount = 0; public boolean doObj(Oop oop) { try { ObjectReference objref = vm.objectMirror(oop); List fields = objref.referenceType().allFields(); for (int i=0; i < fields.size(); i++) { Field fld = (Field)fields.get(i); if (objref.getValue(fld).equals(obj) && !objects.contains(objref)) { objects.add(objref); refCount++; } } if (max > 0 && refCount >= max) { return true; } } catch (RuntimeException x) { // Ignore RuntimeException thrown from vm.objectMirror(oop) // for bad oop. It is possible to see some bad oop // because heap might be iterating at no safepoint. } return false; } }); return objects; } // refer to JvmtiEnvBase::count_locked_objects. // Count the number of objects for a lightweight monitor. The obj // parameter is object that owns the monitor so this routine will // count the number of times the same object was locked by frames // in JavaThread. i.e., we count total number of times the same // object is (lightweight) locked by given thread. private int countLockedObjects(JavaThread jt, Oop obj) { int res = 0; JavaVFrame frame = jt.getLastJavaVFrameDbg(); while (frame != null) { List monitors = frame.getMonitors(); OopHandle givenHandle = obj.getHandle(); for (Iterator itr = monitors.iterator(); itr.hasNext();) { MonitorInfo mi = (MonitorInfo) itr.next(); if (mi.eliminated() && frame.isCompiledFrame()) continue; // skip eliminated monitor if (givenHandle.equals(mi.owner())) { res++; } } frame = (JavaVFrame) frame.javaSender(); } return res; } // wrappers on same named method of Threads class // returns List<JavaThread> private List getPendingThreads(ObjectMonitor mon) { return vm.saVM().getThreads().getPendingThreads(mon); } // returns List<JavaThread> private List getWaitingThreads(ObjectMonitor mon) { return vm.saVM().getThreads().getWaitingThreads(mon); } private JavaThread owningThreadFromMonitor(Address addr) { return vm.saVM().getThreads().owningThreadFromMonitor(addr); } // refer to JvmtiEnv::GetObjectMonitorUsage private void computeMonitorInfo() { monitorInfoCached = true; Mark mark = saObject.getMark(); ObjectMonitor mon = null; Address owner = null; // check for heavyweight monitor if (! mark.hasMonitor()) { // check for lightweight monitor if (mark.hasLocker()) { owner = mark.locker().getAddress(); // save the address of the Lock word } // implied else: no owner } else { // this object has a heavyweight monitor mon = mark.monitor(); // The owner field of a heavyweight monitor may be NULL for no // owner, a JavaThread * or it may still be the address of the // Lock word in a JavaThread's stack. A monitor can be inflated // by a non-owning JavaThread, but only the owning JavaThread // can change the owner field from the Lock word to the // JavaThread * and it may not have done that yet. owner = mon.owner(); } // find the owning thread if (owner != null) { owningThread = vm.threadMirror(owningThreadFromMonitor(owner)); } // compute entryCount if (owningThread != null) { if (owningThread.getJavaThread().getAddress().equals(owner)) { // the owner field is the JavaThread * if (Assert.ASSERTS_ENABLED) { Assert.that(false, "must have heavyweight monitor with JavaThread * owner"); } entryCount = (int) mark.monitor().recursions() + 1; } else { // The owner field is the Lock word on the JavaThread's stack // so the recursions field is not valid. We have to count the // number of recursive monitor entries the hard way. entryCount = countLockedObjects(owningThread.getJavaThread(), saObject); } } // find the contenders & waiters waitingThreads = new ArrayList(); if (mon != null) { // this object has a heavyweight monitor. threads could // be contenders or waiters // add all contenders List pendingThreads = getPendingThreads(mon); // convert the JavaThreads to ThreadReferenceImpls for (Iterator itrPend = pendingThreads.iterator(); itrPend.hasNext();) { waitingThreads.add(vm.threadMirror((JavaThread) itrPend.next())); } // add all waiters (threads in Object.wait()) // note that we don't do this JVMTI way. To do it JVMTI way, // we would need to access ObjectWaiter list maintained in // ObjectMonitor::_queue. But we don't have this struct exposed // in vmStructs. We do waiters list in a way similar to getting // pending threads list List objWaitingThreads = getWaitingThreads(mon); // convert the JavaThreads to ThreadReferenceImpls for (Iterator itrWait = objWaitingThreads.iterator(); itrWait.hasNext();) { waitingThreads.add(vm.threadMirror((JavaThread) itrWait.next())); } } } public boolean equals(Object obj) { if ((obj != null) && (obj instanceof ObjectReferenceImpl)) { ObjectReferenceImpl other = (ObjectReferenceImpl)obj; return (ref().equals(other.ref())) && super.equals(obj); } else { return false; } } public int hashCode() { return saObject.hashCode(); } public String toString() { return "instance of " + referenceType().name() + "(id=" + uniqueID() + ")"; } }