diff agent/src/share/classes/sun/jvm/hotspot/jdi/ObjectReferenceImpl.java @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children b109e761e927
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/jdi/ObjectReferenceImpl.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,366 @@
+/*
+ * Copyright 2002-2007 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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 (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() + ")";
+    }
+}