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