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 }
--- EOF ---