1 /*
   2  * Copyright (c) 2000, 2018, 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             if (OopUtilities.threadOopGetThreadStatus(thread.getThreadObj()) == OopUtilities.THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER) {
 110                 waitState = "waiting to re-lock in wait()";
 111             }
 112             printLockedObjectClassName(tty, o, waitState);
 113           }
 114         } else {
 115           tty.println("\t- " + waitState + " <no object reference available>");
 116         }
 117       } else if (thread.getCurrentParkBlocker() != null) {
 118         Oop obj = thread.getCurrentParkBlocker();
 119         Klass k = obj.getKlass();
 120         tty.format("\t- parking to wait for <" + ADDRESS_FORMAT + "> (a %s)",
 121                    obj.getHandle().asLongValue(), k.getName().asString());
 122         tty.println();
 123       }
 124     }
 125 
 126     // Print out all monitors that we have locked, or are trying to lock,
 127     // including re-locking after being notified or timing out in a wait().
 128     List<MonitorInfo> mons = getMonitors();
 129     if (!mons.isEmpty()) {
 130       boolean foundFirstMonitor = false;
 131       for (int index = mons.size() - 1; index >= 0; index--) {
 132         MonitorInfo monitor = mons.get(index);
 133         if (monitor.eliminated() && isCompiledFrame()) { // Eliminated in compiled code
 134           if (monitor.ownerIsScalarReplaced()) {
 135             Klass k = Oop.getKlassForOopHandle(monitor.ownerKlass());
 136             tty.println("\t- eliminated <owner is scalar replaced> (a " + k.getName().asString() + ")");
 137           } else if (monitor.owner() != null) {
 138             printLockedObjectClassName(tty, monitor.owner(), "eliminated");
 139           }
 140           continue;
 141         }
 142         if (monitor.owner() != null) {
 143           // the monitor is associated with an object, i.e., it is locked
 144           String lockState = "locked";
 145           if (!foundFirstMonitor && frameCount == 0) {
 146             // If this is the first frame and we haven't found an owned
 147             // monitor before, then we need to see if we have completed
 148             // the lock or if we are blocked trying to acquire it. Only
 149             // an inflated monitor that is first on the monitor list in
 150             // the first frame can block us on a monitor enter.
 151             lockState = identifyLockState(monitor, "waiting to lock");
 152           }
 153           printLockedObjectClassName(tty, monitor.owner(), lockState);
 154           foundFirstMonitor = true;
 155         }
 156       }
 157     }
 158   }
 159 
 160   /** Printing operations */
 161 
 162   //
 163   // FIXME: implement visitor pattern for traversing vframe contents?
 164   //
 165 
 166   public void print() {
 167     printOn(System.out);
 168   }
 169 
 170   public void printOn(PrintStream tty) {
 171     super.printOn(tty);
 172 
 173     tty.print("\t");
 174     getMethod().printValueOn(tty);
 175     tty.println();
 176     tty.println("\tbci:\t" + getBCI());
 177 
 178     printStackValuesOn(tty, "locals",      getLocals());
 179     printStackValuesOn(tty, "expressions", getExpressions());
 180   }
 181 
 182   public void printActivation(int index) {
 183     printActivationOn(System.out, index);
 184   }
 185 
 186   public void printActivationOn(PrintStream tty, int index) {
 187     // frame number and method
 188     tty.print(index + " - ");
 189     printValueOn(tty);
 190     tty.println();
 191 
 192     if (VM.getVM().wizardMode()) {
 193       printOn(tty);
 194       tty.println();
 195     }
 196   }
 197 
 198   /** Verification operations */
 199   public void verify() {
 200   }
 201 
 202   public boolean equals(Object o) {
 203       if (o == null || !(o instanceof JavaVFrame)) {
 204           return false;
 205       }
 206 
 207       JavaVFrame other = (JavaVFrame) o;
 208 
 209       // Check static part
 210       if (!getMethod().equals(other.getMethod())) {
 211           return false;
 212       }
 213 
 214       if (getBCI() != other.getBCI()) {
 215           return false;
 216       }
 217 
 218       // dynamic part - we just compare the frame pointer
 219       if (! getFrame().equals(other.getFrame())) {
 220           return false;
 221       }
 222       return true;
 223   }
 224 
 225   public int hashCode() {
 226       return getMethod().hashCode() ^ getBCI() ^ getFrame().hashCode();
 227   }
 228 
 229   /** Structural compare */
 230   public boolean structuralCompare(JavaVFrame other) {
 231     // Check static part
 232     if (!getMethod().equals(other.getMethod())) {
 233       return false;
 234     }
 235 
 236     if (getBCI() != other.getBCI()) {
 237       return false;
 238     }
 239 
 240     // Check locals
 241     StackValueCollection locs      = getLocals();
 242     StackValueCollection otherLocs = other.getLocals();
 243     if (Assert.ASSERTS_ENABLED) {
 244       Assert.that(locs.size() == otherLocs.size(), "sanity check");
 245     }
 246     for (int i = 0; i < locs.size(); i++) {
 247       // it might happen the compiler reports a conflict and
 248       // the interpreter reports a bogus int.
 249       if (      isCompiledFrame() && (locs.get(i)).getType()      == BasicType.getTConflict()) continue;
 250       if (other.isCompiledFrame() && (otherLocs.get(i)).getType() == BasicType.getTConflict()) continue;
 251 
 252       if (!locs.get(i).equals(otherLocs.get(i))) {
 253         return false;
 254       }
 255     }
 256 
 257     // Check expressions
 258     StackValueCollection exprs      = getExpressions();
 259     StackValueCollection otherExprs = other.getExpressions();
 260     if (Assert.ASSERTS_ENABLED) {
 261       Assert.that(exprs.size() == otherExprs.size(), "sanity check");
 262     }
 263     for (int i = 0; i < exprs.size(); i++) {
 264       if (!exprs.get(i).equals(otherExprs.get(i))) {
 265         return false;
 266       }
 267     }
 268 
 269     return true;
 270   }
 271 
 272   //--------------------------------------------------------------------------------
 273   // Internals only below this point
 274   //
 275 
 276   private void printStackValuesOn(PrintStream tty, String title, StackValueCollection values) {
 277     if (values.isEmpty()) {
 278       return;
 279     }
 280     tty.println("\t" + title + ":");
 281     for (int index = 0; index < values.size(); index++) {
 282       tty.print("\t" + index + "\t");
 283       values.get(index).printOn(tty);
 284       tty.println();
 285     }
 286   }
 287 }