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 }