1 /*
   2  * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 package sun.jvm.hotspot.runtime;
  26 
  27 import java.io.*;
  28 import java.util.*;
  29 import sun.jvm.hotspot.oops.*;
  30 import sun.jvm.hotspot.utilities.*;
  31 import sun.jvm.hotspot.debugger.*;
  32 
  33 public abstract class JavaVFrame extends VFrame {
  34 
  35   private static final String ADDRESS_FORMAT = VM.getVM().isLP64() ? "0x%016x"
  36                                                                    : "0x%08x";
  37 
  38   /** JVM state */
  39   public abstract Method getMethod();
  40   public abstract int    getBCI();
  41   public abstract StackValueCollection getLocals();
  42   public abstract StackValueCollection getExpressions();
  43   public abstract List<MonitorInfo> getMonitors();
  44 
  45   /** Test operation */
  46   public boolean isJavaFrame() { return true; }
  47 
  48   /** Package-internal constructor */
  49   JavaVFrame(Frame fr, RegisterMap regMap, JavaThread thread) {
  50     super(fr, regMap, thread);
  51   }
  52 
  53   /** Get monitor (if any) that this JavaVFrame is trying to enter */
  54   // FIXME: not yet implemented
  55   //  public Address getPendingMonitor(int frameCount);
  56 
  57   public void printLockedObjectClassName(PrintStream tty,
  58                                          OopHandle hobj, String lockState) {
  59     if (hobj.asLongValue() != 0L) {
  60       tty.format("\t- %s <" + ADDRESS_FORMAT + "> ",
  61                  lockState, hobj.asLongValue());
  62 
  63       Klass klass = Oop.getKlassForOopHandle(hobj);
  64       String klassName = klass.getName().asString();
  65       tty.print("(a ");
  66       if (klassName.equals("java/lang/Class")) {
  67         Oop obj = VM.getVM().getObjectHeap().newOop(hobj);
  68         klassName = java_lang_Class.asExternalName(obj);
  69         tty.print("java.lang.Class for ");
  70       }
  71       tty.println(klassName.replace('/', '.') + ")");
  72     }
  73   }
  74 
  75   private String identifyLockState(MonitorInfo monitor, String waitingState) {
  76     Mark mark = new Mark(monitor.owner());
  77     if (mark.hasMonitor() &&
  78         ( // we have marked ourself as pending on this monitor
  79           mark.monitor().equals(thread.getCurrentPendingMonitor()) ||
  80           // we are not the owner of this monitor
  81           !mark.monitor().isEntered(thread)
  82         )) {
  83       return waitingState;
  84     }
  85     return "locked";
  86   }
  87 
  88   /** Printing used during stack dumps */
  89   public void printLockInfo(PrintStream tty, int frameCount) {
  90     // If this is the first frame and it is java.lang.Object.wait(...)
  91     // then print out the receiver. Locals are not always available,
  92     // e.g., compiled native frames have no scope so there are no locals.
  93     if (frameCount == 0) {
  94       if (getMethod().getName().asString().equals("wait") &&
  95           getMethod().getMethodHolder().getName().asString().equals("java/lang/Object")) {
  96         String waitState = "waiting on"; // assume we are waiting
  97         // If earlier in the output we reported java.lang.Thread.State ==
  98         // "WAITING (on object monitor)" and now we report "waiting on", then
  99         // we are still waiting for notification or timeout. Otherwise if
 100         // we earlier reported java.lang.Thread.State == "BLOCKED (on object
 101         // monitor)", then we are actually waiting to re-lock the monitor.
 102         // At this level we can't distinguish the two cases to report
 103         // "waited on" rather than "waiting on" for the second case.
 104         StackValueCollection locs = getLocals();
 105         if (!locs.isEmpty()) {
 106           StackValue sv = locs.get(0);
 107           if (sv.getType() == BasicType.getTObject()) {
 108             OopHandle o = sv.getObject();
 109             printLockedObjectClassName(tty, o, waitState);
 110           }
 111         } else {
 112           tty.println("\t- " + waitState + " <no object reference available>");
 113         }
 114       } else if (thread.getCurrentParkBlocker() != null) {
 115         Oop obj = thread.getCurrentParkBlocker();
 116         Klass k = obj.getKlass();
 117         tty.format("\t- parking to wait for <" + ADDRESS_FORMAT + "> (a %s)",
 118                    obj.getHandle().asLongValue(), k.getName().asString());
 119         tty.println();
 120       }
 121     }
 122 
 123     // Print out all monitors that we have locked, or are trying to lock,
 124     // including re-locking after being notified or timing out in a wait().
 125     List<MonitorInfo> mons = getMonitors();
 126     if (!mons.isEmpty()) {
 127       boolean foundFirstMonitor = false;
 128       for (int index = mons.size() - 1; index >= 0; index--) {
 129         MonitorInfo monitor = mons.get(index);
 130         if (monitor.eliminated() && isCompiledFrame()) { // Eliminated in compiled code
 131           if (monitor.ownerIsScalarReplaced()) {
 132             Klass k = Oop.getKlassForOopHandle(monitor.ownerKlass());
 133             tty.println("\t- eliminated <owner is scalar replaced> (a " + k.getName().asString() + ")");
 134           } else if (monitor.owner() != null) {
 135             printLockedObjectClassName(tty, monitor.owner(), "eliminated");
 136           }
 137           continue;
 138         }
 139         if (monitor.owner() != null) {
 140           // the monitor is associated with an object, i.e., it is locked
 141           String lockState = "locked";
 142           if (!foundFirstMonitor && frameCount == 0) {
 143             // If this is the first frame and we haven't found an owned
 144             // monitor before, then we need to see if we have completed
 145             // the lock or if we are blocked trying to acquire it. Only
 146             // an inflated monitor that is first on the monitor list in
 147             // the first frame can block us on a monitor enter.
 148             lockState = identifyLockState(monitor, "waiting to lock");
 149           } else if (frameCount != 0) {
 150             // This is not the first frame so we either own this monitor
 151             // or we owned the monitor before and called wait(). Because
 152             // wait() could have been called on any monitor in a lower
 153             // numbered frame on the stack, we have to check all the
 154             // monitors on the list for this frame.
 155             lockState = identifyLockState(monitor, "waiting to re-lock in wait()");
 156           }
 157           printLockedObjectClassName(tty, monitor.owner(), lockState);
 158           foundFirstMonitor = true;
 159         }
 160       }
 161     }
 162   }
 163 
 164   /** Printing operations */
 165 
 166   //
 167   // FIXME: implement visitor pattern for traversing vframe contents?
 168   //
 169 
 170   public void print() {
 171     printOn(System.out);
 172   }
 173 
 174   public void printOn(PrintStream tty) {
 175     super.printOn(tty);
 176 
 177     tty.print("\t");
 178     getMethod().printValueOn(tty);
 179     tty.println();
 180     tty.println("\tbci:\t" + getBCI());
 181 
 182     printStackValuesOn(tty, "locals",      getLocals());
 183     printStackValuesOn(tty, "expressions", getExpressions());
 184   }
 185 
 186   public void printActivation(int index) {
 187     printActivationOn(System.out, index);
 188   }
 189 
 190   public void printActivationOn(PrintStream tty, int index) {
 191     // frame number and method
 192     tty.print(index + " - ");
 193     printValueOn(tty);
 194     tty.println();
 195 
 196     if (VM.getVM().wizardMode()) {
 197       printOn(tty);
 198       tty.println();
 199     }
 200   }
 201 
 202   /** Verification operations */
 203   public void verify() {
 204   }
 205 
 206   public boolean equals(Object o) {
 207       if (o == null || !(o instanceof JavaVFrame)) {
 208           return false;
 209       }
 210 
 211       JavaVFrame other = (JavaVFrame) o;
 212 
 213       // Check static part
 214       if (!getMethod().equals(other.getMethod())) {
 215           return false;
 216       }
 217 
 218       if (getBCI() != other.getBCI()) {
 219           return false;
 220       }
 221 
 222       // dynamic part - we just compare the frame pointer
 223       if (! getFrame().equals(other.getFrame())) {
 224           return false;
 225       }
 226       return true;
 227   }
 228 
 229   public int hashCode() {
 230       return getMethod().hashCode() ^ getBCI() ^ getFrame().hashCode();
 231   }
 232 
 233   /** Structural compare */
 234   public boolean structuralCompare(JavaVFrame other) {
 235     // Check static part
 236     if (!getMethod().equals(other.getMethod())) {
 237       return false;
 238     }
 239 
 240     if (getBCI() != other.getBCI()) {
 241       return false;
 242     }
 243 
 244     // Check locals
 245     StackValueCollection locs      = getLocals();
 246     StackValueCollection otherLocs = other.getLocals();
 247     if (Assert.ASSERTS_ENABLED) {
 248       Assert.that(locs.size() == otherLocs.size(), "sanity check");
 249     }
 250     for (int i = 0; i < locs.size(); i++) {
 251       // it might happen the compiler reports a conflict and
 252       // the interpreter reports a bogus int.
 253       if (      isCompiledFrame() && (locs.get(i)).getType()      == BasicType.getTConflict()) continue;
 254       if (other.isCompiledFrame() && (otherLocs.get(i)).getType() == BasicType.getTConflict()) continue;
 255 
 256       if (!locs.get(i).equals(otherLocs.get(i))) {
 257         return false;
 258       }
 259     }
 260 
 261     // Check expressions
 262     StackValueCollection exprs      = getExpressions();
 263     StackValueCollection otherExprs = other.getExpressions();
 264     if (Assert.ASSERTS_ENABLED) {
 265       Assert.that(exprs.size() == otherExprs.size(), "sanity check");
 266     }
 267     for (int i = 0; i < exprs.size(); i++) {
 268       if (!exprs.get(i).equals(otherExprs.get(i))) {
 269         return false;
 270       }
 271     }
 272 
 273     return true;
 274   }
 275 
 276   //--------------------------------------------------------------------------------
 277   // Internals only below this point
 278   //
 279 
 280   private void printStackValuesOn(PrintStream tty, String title, StackValueCollection values) {
 281     if (values.isEmpty()) {
 282       return;
 283     }
 284     tty.println("\t" + title + ":");
 285     for (int index = 0; index < values.size(); index++) {
 286       tty.print("\t" + index + "\t");
 287       values.get(index).printOn(tty);
 288       tty.println();
 289     }
 290   }
 291 }