< prev index next >

src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaVFrame.java

Print this page

        

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2017, 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.

@@ -26,18 +26,23 @@
 
 import java.io.*;
 import java.util.*;
 import sun.jvm.hotspot.oops.*;
 import sun.jvm.hotspot.utilities.*;
+import sun.jvm.hotspot.debugger.*;
 
 public abstract class JavaVFrame extends VFrame {
+
+  private static final String ADDRESS_FORMAT = VM.getVM().isLP64() ? "0x%016x"
+                                                                   : "0x%08x";
+
   /** JVM state */
   public abstract Method getMethod();
   public abstract int    getBCI();
   public abstract StackValueCollection getLocals();
   public abstract StackValueCollection getExpressions();
-  public abstract List   getMonitors();    // List<MonitorInfo>
+  public abstract List<MonitorInfo> getMonitors();
 
   /** Test operation */
   public boolean isJavaFrame() { return true; }
 
   /** Package-internal constructor */

@@ -47,13 +52,129 @@
 
   /** Get monitor (if any) that this JavaVFrame is trying to enter */
   // FIXME: not yet implemented
   //  public Address getPendingMonitor(int frameCount);
 
+  public void printLockedObjectClassName(PrintStream tty,
+                                         OopHandle hobj, String lockState) {
+    if (hobj.asLongValue() != 0L) {
+      tty.format("\t- %s <" + ADDRESS_FORMAT + "> ",
+                 lockState, hobj.asLongValue());
+
+      Klass klass = Oop.getKlassForOopHandle(hobj);
+      String klassName = klass.getName().asString();
+      tty.print("(a ");
+      if (klassName.equals("java/lang/Class")) {
+        Oop obj = VM.getVM().getObjectHeap().newOop(hobj);
+        klassName = java_lang_Class.asExternalName(obj);
+        tty.print("java.lang.Class for ");
+      }
+      tty.println(klassName.replace('/', '.') + ")");
+    }
+  }
+
   /** Printing used during stack dumps */
-  // FIXME: not yet implemented
-  //  void print_lock_info(int frame_count);
+  public void printLockInfo(PrintStream tty, int frameCount) {
+    // If this is the first frame and it is java.lang.Object.wait(...)
+    // then print out the receiver. Locals are not always available,
+    // e.g., compiled native frames have no scope so there are no locals.
+    if (frameCount == 0) {
+      if (getMethod().getName().asString().equals("wait") &&
+          getMethod().getMethodHolder().getName().asString().equals("java/lang/Object")) {
+        String waitState = "waiting on"; // assume we are waiting
+        // If earlier in the output we reported java.lang.Thread.State ==
+        // "WAITING (on object monitor)" and now we report "waiting on", then
+        // we are still waiting for notification or timeout. Otherwise if
+        // we earlier reported java.lang.Thread.State == "BLOCKED (on object
+        // monitor)", then we are actually waiting to re-lock the monitor.
+        // At this level we can't distinguish the two cases to report
+        // "waited on" rather than "waiting on" for the second case.
+        StackValueCollection locs = getLocals();
+        if (!locs.isEmpty()) {
+          StackValue sv = locs.get(0);
+          if (sv.getType() == BasicType.getTObject()) {
+            OopHandle o = sv.getObject();
+            printLockedObjectClassName(tty, o, waitState);
+          }
+        } else {
+          tty.println("\t- " + waitState + " <no object reference available>");
+        }
+      } else if (thread.getCurrentParkBlocker() != null) {
+        Oop obj = thread.getCurrentParkBlocker();
+        Klass k = obj.getKlass();
+        tty.format("\t- parking to wait for <" + ADDRESS_FORMAT + "> (a %s)",
+                   obj.getHandle().asLongValue(), k.getName().asString());
+        tty.println();
+      }
+    }
+
+    // Print out all monitors that we have locked, or are trying to lock,
+    // including re-locking after being notified or timing out in a wait().
+    List<MonitorInfo> mons = getMonitors();
+    if (!mons.isEmpty()) {
+      boolean foundFirstMonitor = false;
+      for (int index = mons.size() - 1; index >= 0; index--) {
+        MonitorInfo monitor = mons.get(index);
+        if (monitor.eliminated() && isCompiledFrame()) { // Eliminated in compiled code
+          if (monitor.ownerIsScalarReplaced()) {
+            Klass k = Oop.getKlassForOopHandle(monitor.ownerKlass());
+            tty.println("\t- eliminated <owner is scalar replaced> (a " + k.getName().asString() + ")");
+          } else if (monitor.owner() != null) {
+            printLockedObjectClassName(tty, monitor.owner(), "eliminated");
+          }
+          continue;
+        }
+        if (monitor.owner() != null) {
+          // the monitor is associated with an object, i.e., it is locked
+
+          Mark mark = null;
+          String lockState = "locked";
+          if (!foundFirstMonitor && frameCount == 0) {
+            // If this is the first frame and we haven't found an owned
+            // monitor before, then we need to see if we have completed
+            // the lock or if we are blocked trying to acquire it. Only
+            // an inflated monitor that is first on the monitor list in
+            // the first frame can block us on a monitor enter.
+            mark = new Mark(monitor.owner());
+            if (mark.hasMonitor() &&
+                ( // we have marked ourself as pending on this monitor
+                  mark.monitor().equals(thread.getCurrentPendingMonitor()) ||
+                  // we are not the owner of this monitor
+                  !mark.monitor().isEntered(thread)
+                )) {
+              lockState = "waiting to lock";
+            } else {
+              // We own the monitor which is not as interesting so
+              // disable the extra printing below.
+              mark = null;
+            }
+          } else if (frameCount != 0) {
+            // This is not the first frame so we either own this monitor
+            // or we owned the monitor before and called wait(). Because
+            // wait() could have been called on any monitor in a lower
+            // numbered frame on the stack, we have to check all the
+            // monitors on the list for this frame.
+            mark = new Mark(monitor.owner());
+            if (mark.hasMonitor() &&
+                ( // we have marked ourself as pending on this monitor
+                  mark.monitor().equals(thread.getCurrentPendingMonitor()) ||
+                  // we are not the owner of this monitor
+                  !mark.monitor().isEntered(thread)
+                )) {
+              lockState = "waiting to re-lock in wait()";
+            } else {
+              // We own the monitor which is not as interesting so
+              // disable the extra printing below.
+              mark = null;
+            }
+          }
+          printLockedObjectClassName(tty, monitor.owner(), lockState);
+          foundFirstMonitor = true;
+        }
+      }
+    }
+  }
 
   /** Printing operations */
 
   //
   // FIXME: implement visitor pattern for traversing vframe contents?

@@ -71,26 +192,10 @@
     tty.println();
     tty.println("\tbci:\t" + getBCI());
 
     printStackValuesOn(tty, "locals",      getLocals());
     printStackValuesOn(tty, "expressions", getExpressions());
-
-    // List<MonitorInfo>
-    // FIXME: not yet implemented
-    //    List list = getMonitors();
-    //    if (list.isEmpty()) {
-    //      return;
-    //    }
-    //    for (int index = 0; index < list.size(); index++) {
-    //      MonitorInfo monitor = (MonitorInfo) list.get(index);
-    //      tty.print("\t  obj\t");
-    //      monitor.getOwner().printValueOn(tty);
-    //      tty.println();
-    //      tty.print("\t  ");
-    //      monitor.lock().printOn(tty);
-    //      tty.println();
-    //    }
   }
 
   public void printActivation(int index) {
     printActivationOn(System.out, index);
   }
< prev index next >