Mon, 18 Nov 2019 23:41:06 -0500
8215355: Object monitor deadlock with no threads holding the monitor (using jemalloc 5.1)
Reviewed-by: rehn, stuefe, dcubed, sspitsyn
duke@435 | 1 | /* |
minqi@4750 | 2 | * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. |
duke@435 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
duke@435 | 4 | * |
duke@435 | 5 | * This code is free software; you can redistribute it and/or modify it |
duke@435 | 6 | * under the terms of the GNU General Public License version 2 only, as |
duke@435 | 7 | * published by the Free Software Foundation. |
duke@435 | 8 | * |
duke@435 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
duke@435 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
duke@435 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
duke@435 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
duke@435 | 13 | * accompanied this code). |
duke@435 | 14 | * |
duke@435 | 15 | * You should have received a copy of the GNU General Public License version |
duke@435 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
duke@435 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
duke@435 | 18 | * |
trims@1907 | 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
trims@1907 | 20 | * or visit www.oracle.com if you need additional information or have any |
trims@1907 | 21 | * questions. |
duke@435 | 22 | * |
duke@435 | 23 | */ |
duke@435 | 24 | |
duke@435 | 25 | package sun.jvm.hotspot.runtime; |
duke@435 | 26 | |
duke@435 | 27 | import java.io.*; |
duke@435 | 28 | import java.util.*; |
duke@435 | 29 | import sun.jvm.hotspot.debugger.*; |
duke@435 | 30 | import sun.jvm.hotspot.oops.*; |
duke@435 | 31 | import sun.jvm.hotspot.types.*; |
duke@435 | 32 | import sun.jvm.hotspot.utilities.*; |
duke@435 | 33 | |
duke@435 | 34 | /** This is an abstract class because there are certain OS- and |
duke@435 | 35 | CPU-specific operations (like the setting and getting of the last |
duke@435 | 36 | Java frame pointer) which need to be factored out. These |
duke@435 | 37 | operations are implemented by, for example, |
duke@435 | 38 | SolarisSPARCJavaThread, and the concrete subclasses are |
duke@435 | 39 | instantiated by the JavaThreadFactory in the Threads class. */ |
duke@435 | 40 | |
duke@435 | 41 | public class JavaThread extends Thread { |
duke@435 | 42 | private static final boolean DEBUG = System.getProperty("sun.jvm.hotspot.runtime.JavaThread.DEBUG") != null; |
duke@435 | 43 | |
duke@435 | 44 | private static AddressField nextField; |
duke@435 | 45 | private static sun.jvm.hotspot.types.OopField threadObjField; |
duke@435 | 46 | private static AddressField anchorField; |
duke@435 | 47 | private static AddressField lastJavaSPField; |
duke@435 | 48 | private static AddressField lastJavaPCField; |
duke@435 | 49 | private static CIntegerField threadStateField; |
duke@435 | 50 | private static AddressField osThreadField; |
xlu@1137 | 51 | private static AddressField stackBaseField; |
xlu@1137 | 52 | private static CIntegerField stackSizeField; |
duke@435 | 53 | |
duke@435 | 54 | private static JavaThreadPDAccess access; |
duke@435 | 55 | |
duke@435 | 56 | // JavaThreadStates read from underlying process |
duke@435 | 57 | private static int UNINITIALIZED; |
duke@435 | 58 | private static int NEW; |
duke@435 | 59 | private static int NEW_TRANS; |
duke@435 | 60 | private static int IN_NATIVE; |
duke@435 | 61 | private static int IN_NATIVE_TRANS; |
duke@435 | 62 | private static int IN_VM; |
duke@435 | 63 | private static int IN_VM_TRANS; |
duke@435 | 64 | private static int IN_JAVA; |
duke@435 | 65 | private static int IN_JAVA_TRANS; |
duke@435 | 66 | private static int BLOCKED; |
duke@435 | 67 | private static int BLOCKED_TRANS; |
duke@435 | 68 | |
duke@435 | 69 | static { |
duke@435 | 70 | VM.registerVMInitializedObserver(new Observer() { |
duke@435 | 71 | public void update(Observable o, Object data) { |
duke@435 | 72 | initialize(VM.getVM().getTypeDataBase()); |
duke@435 | 73 | } |
duke@435 | 74 | }); |
duke@435 | 75 | } |
duke@435 | 76 | |
duke@435 | 77 | private static synchronized void initialize(TypeDataBase db) { |
duke@435 | 78 | Type type = db.lookupType("JavaThread"); |
duke@435 | 79 | Type anchorType = db.lookupType("JavaFrameAnchor"); |
duke@435 | 80 | |
duke@435 | 81 | nextField = type.getAddressField("_next"); |
duke@435 | 82 | threadObjField = type.getOopField("_threadObj"); |
duke@435 | 83 | anchorField = type.getAddressField("_anchor"); |
duke@435 | 84 | lastJavaSPField = anchorType.getAddressField("_last_Java_sp"); |
duke@435 | 85 | lastJavaPCField = anchorType.getAddressField("_last_Java_pc"); |
duke@435 | 86 | threadStateField = type.getCIntegerField("_thread_state"); |
duke@435 | 87 | osThreadField = type.getAddressField("_osthread"); |
xlu@1137 | 88 | stackBaseField = type.getAddressField("_stack_base"); |
xlu@1137 | 89 | stackSizeField = type.getCIntegerField("_stack_size"); |
duke@435 | 90 | |
duke@435 | 91 | UNINITIALIZED = db.lookupIntConstant("_thread_uninitialized").intValue(); |
duke@435 | 92 | NEW = db.lookupIntConstant("_thread_new").intValue(); |
duke@435 | 93 | NEW_TRANS = db.lookupIntConstant("_thread_new_trans").intValue(); |
duke@435 | 94 | IN_NATIVE = db.lookupIntConstant("_thread_in_native").intValue(); |
duke@435 | 95 | IN_NATIVE_TRANS = db.lookupIntConstant("_thread_in_native_trans").intValue(); |
duke@435 | 96 | IN_VM = db.lookupIntConstant("_thread_in_vm").intValue(); |
duke@435 | 97 | IN_VM_TRANS = db.lookupIntConstant("_thread_in_vm_trans").intValue(); |
duke@435 | 98 | IN_JAVA = db.lookupIntConstant("_thread_in_Java").intValue(); |
duke@435 | 99 | IN_JAVA_TRANS = db.lookupIntConstant("_thread_in_Java_trans").intValue(); |
duke@435 | 100 | BLOCKED = db.lookupIntConstant("_thread_blocked").intValue(); |
duke@435 | 101 | BLOCKED_TRANS = db.lookupIntConstant("_thread_blocked_trans").intValue(); |
duke@435 | 102 | } |
duke@435 | 103 | |
duke@435 | 104 | public JavaThread(Address addr) { |
duke@435 | 105 | super(addr); |
duke@435 | 106 | } |
duke@435 | 107 | |
duke@435 | 108 | void setThreadPDAccess(JavaThreadPDAccess access) { |
duke@435 | 109 | this.access = access; |
duke@435 | 110 | } |
duke@435 | 111 | |
duke@435 | 112 | public JavaThread next() { |
duke@435 | 113 | Address threadAddr = nextField.getValue(addr); |
duke@435 | 114 | if (threadAddr == null) { |
duke@435 | 115 | return null; |
duke@435 | 116 | } |
duke@435 | 117 | |
duke@435 | 118 | return VM.getVM().getThreads().createJavaThreadWrapper(threadAddr); |
duke@435 | 119 | } |
duke@435 | 120 | |
duke@435 | 121 | /** NOTE: for convenience, this differs in definition from the |
duke@435 | 122 | underlying VM. Only "pure" JavaThreads return true; |
duke@435 | 123 | CompilerThreads and JVMDIDebuggerThreads return false. FIXME: |
duke@435 | 124 | consider encapsulating platform-specific functionality in an |
duke@435 | 125 | object instead of using inheritance (which is the primary reason |
duke@435 | 126 | we can't traverse CompilerThreads, etc; didn't want to have, for |
duke@435 | 127 | example, "SolarisSPARCCompilerThread".) */ |
duke@435 | 128 | public boolean isJavaThread() { return true; } |
duke@435 | 129 | |
duke@435 | 130 | public static AddressField getAnchorField() { return anchorField; } |
duke@435 | 131 | |
duke@435 | 132 | /** Get the last Java stack pointer */ |
duke@435 | 133 | public Address getLastJavaSP() { |
duke@435 | 134 | Address sp = lastJavaSPField.getValue(addr.addOffsetTo(anchorField.getOffset())); |
duke@435 | 135 | return sp; |
duke@435 | 136 | } |
duke@435 | 137 | |
duke@435 | 138 | public Address getLastJavaPC() { |
duke@435 | 139 | Address pc = lastJavaPCField.getValue(addr.addOffsetTo(anchorField.getOffset())); |
duke@435 | 140 | return pc; |
duke@435 | 141 | } |
duke@435 | 142 | |
duke@435 | 143 | /** Abstract accessor to last Java frame pointer, implemented by |
duke@435 | 144 | OS/CPU-specific JavaThread implementation. May return null if |
duke@435 | 145 | there is no frame pointer or if it is not necessary on this |
duke@435 | 146 | platform. */ |
duke@435 | 147 | public Address getLastJavaFP(){ |
duke@435 | 148 | return access.getLastJavaFP(addr); |
duke@435 | 149 | } |
duke@435 | 150 | |
duke@435 | 151 | /** Abstract accessor to last Java pc, implemented by |
duke@435 | 152 | OS/CPU-specific JavaThread implementation. May return null if |
duke@435 | 153 | there is no frame pointer or if it is not necessary on this |
duke@435 | 154 | platform. */ |
duke@435 | 155 | |
duke@435 | 156 | /* |
duke@435 | 157 | public Address getLastJavaPC(){ |
duke@435 | 158 | return access.getLastJavaPC(addr); |
duke@435 | 159 | } |
duke@435 | 160 | */ |
duke@435 | 161 | |
duke@435 | 162 | // FIXME: not yet implementable |
duke@435 | 163 | // public abstract void setLastJavaFP(Address fp); |
duke@435 | 164 | |
duke@435 | 165 | /** A stack pointer older than any java frame stack pointer. Only |
duke@435 | 166 | needed on some platforms; for example, see |
duke@435 | 167 | thread_solaris_sparc.hpp. */ |
duke@435 | 168 | public Address getBaseOfStackPointer(){ |
duke@435 | 169 | return access.getBaseOfStackPointer(addr); |
duke@435 | 170 | } |
duke@435 | 171 | // FIXME: not yet implementable |
duke@435 | 172 | // public abstract void setBaseOfStackPointer(Address fp); |
duke@435 | 173 | |
duke@435 | 174 | /** Tells whether the last Java frame is set */ |
duke@435 | 175 | public boolean hasLastJavaFrame() { |
duke@435 | 176 | return (getLastJavaSP() != null); |
duke@435 | 177 | } |
duke@435 | 178 | |
duke@435 | 179 | /** Accessing frames */ |
duke@435 | 180 | public Frame getLastFrame() { |
duke@435 | 181 | // FIXME: would need to implement runtime routine |
duke@435 | 182 | // "cacheStatePD(boolean)" for reflective system to be able to |
duke@435 | 183 | // flush register windows on SPARC |
duke@435 | 184 | return cookLastFrame(getLastFramePD()); |
duke@435 | 185 | } |
duke@435 | 186 | |
duke@435 | 187 | /** Internal routine implemented by platform-dependent subclasses */ |
duke@435 | 188 | protected Frame getLastFramePD(){ |
duke@435 | 189 | return access.getLastFramePD(this, addr); |
duke@435 | 190 | } |
duke@435 | 191 | |
duke@435 | 192 | /** Accessing frames. Returns the last Java VFrame or null if none |
duke@435 | 193 | was present. (NOTE that this is mostly unusable in a debugging |
duke@435 | 194 | system; see getLastJavaVFrameDbg, below, which provides very |
duke@435 | 195 | different functionality.) */ |
duke@435 | 196 | public JavaVFrame getLastJavaVFrame(RegisterMap regMap) { |
duke@435 | 197 | if (Assert.ASSERTS_ENABLED) { |
duke@435 | 198 | Assert.that(regMap != null, "a map must be given"); |
duke@435 | 199 | } |
duke@435 | 200 | Frame f = getLastFrame(); |
duke@435 | 201 | if (f == null) { |
duke@435 | 202 | return null; |
duke@435 | 203 | } |
duke@435 | 204 | for (VFrame vf = VFrame.newVFrame(f, regMap, this); vf != null; vf = vf.sender()) { |
duke@435 | 205 | if (vf.isJavaFrame()) { |
duke@435 | 206 | return (JavaVFrame) vf; |
duke@435 | 207 | } |
duke@435 | 208 | } |
duke@435 | 209 | return null; |
duke@435 | 210 | } |
duke@435 | 211 | |
duke@435 | 212 | /** This should only be used by a debugger. Uses the current frame |
duke@435 | 213 | guess to attempt to get the topmost JavaVFrame. |
duke@435 | 214 | (getLastJavaVFrame, as a port of the VM's routine, assumes the |
duke@435 | 215 | VM is at a safepoint.) */ |
duke@435 | 216 | public JavaVFrame getLastJavaVFrameDbg() { |
duke@435 | 217 | RegisterMap regMap = newRegisterMap(true); |
duke@435 | 218 | sun.jvm.hotspot.runtime.Frame f = getCurrentFrameGuess(); |
duke@435 | 219 | if (f == null) return null; |
duke@435 | 220 | boolean imprecise = true; |
duke@435 | 221 | if (f.isInterpretedFrame() && !f.isInterpretedFrameValid()) { |
swamyv@653 | 222 | if (DEBUG) { |
swamyv@653 | 223 | System.out.println("Correcting for invalid interpreter frame"); |
swamyv@653 | 224 | } |
swamyv@653 | 225 | f = f.sender(regMap); |
swamyv@653 | 226 | imprecise = false; |
duke@435 | 227 | } |
duke@435 | 228 | VFrame vf = VFrame.newVFrame(f, regMap, this, true, imprecise); |
duke@435 | 229 | if (vf == null) { |
duke@435 | 230 | if (DEBUG) { |
duke@435 | 231 | System.out.println(" (Unable to create vframe for topmost frame guess)"); |
duke@435 | 232 | } |
duke@435 | 233 | return null; |
duke@435 | 234 | } |
swamyv@653 | 235 | return vf.isJavaFrame() ? (JavaVFrame)vf : vf.javaSender(); |
duke@435 | 236 | } |
duke@435 | 237 | |
duke@435 | 238 | /** In this system, a JavaThread is the top-level factory for a |
duke@435 | 239 | RegisterMap, since the JavaThread implementation is already |
duke@435 | 240 | platform-specific and RegisterMap is also necessarily |
duke@435 | 241 | platform-specific. The updateMap argument indicates whether the |
duke@435 | 242 | register map needs to be updated, for example during stack |
duke@435 | 243 | traversal -- see frame.hpp. */ |
duke@435 | 244 | public RegisterMap newRegisterMap(boolean updateMap){ |
duke@435 | 245 | return access.newRegisterMap(this, updateMap); |
duke@435 | 246 | } |
duke@435 | 247 | |
duke@435 | 248 | /** This is only designed to be used by the debugging system. |
duke@435 | 249 | Returns a "best guess" of the topmost frame on the stack. This |
duke@435 | 250 | guess should be as "raw" as possible. For example, if the |
duke@435 | 251 | topmost frame is an interpreter frame (the return PC is in the |
duke@435 | 252 | interpreter) but is not a valid frame (i.e., the BCI has not yet |
duke@435 | 253 | been set up) this should still return the topmost frame and not |
duke@435 | 254 | the sender. Validity checks are done at higher levels. */ |
duke@435 | 255 | public Frame getCurrentFrameGuess(){ |
duke@435 | 256 | return access.getCurrentFrameGuess(this, addr); |
duke@435 | 257 | } |
duke@435 | 258 | |
duke@435 | 259 | /** Also only intended for use by the debugging system. Provides the |
duke@435 | 260 | same effect of OSThread::print(); that is, prints a value which |
duke@435 | 261 | allows the user to intuitively understand which native OS thread |
duke@435 | 262 | maps to this Java thread. Does not print a newline or leading or |
duke@435 | 263 | trailing spaces. */ |
duke@435 | 264 | public void printThreadIDOn(PrintStream tty) { |
duke@435 | 265 | access.printThreadIDOn(addr,tty); |
duke@435 | 266 | } |
duke@435 | 267 | |
duke@435 | 268 | public void printThreadID() { |
duke@435 | 269 | printThreadIDOn(System.out); |
duke@435 | 270 | } |
duke@435 | 271 | |
duke@435 | 272 | public ThreadProxy getThreadProxy() { |
duke@435 | 273 | return access.getThreadProxy(addr); |
duke@435 | 274 | } |
duke@435 | 275 | |
duke@435 | 276 | // |
duke@435 | 277 | // Safepoint support |
duke@435 | 278 | // |
duke@435 | 279 | |
duke@435 | 280 | public JavaThreadState getThreadState() { |
duke@435 | 281 | int val = (int) threadStateField.getValue(addr); |
duke@435 | 282 | if (val == UNINITIALIZED) { |
duke@435 | 283 | return JavaThreadState.UNINITIALIZED; |
duke@435 | 284 | } else if (val == NEW) { |
duke@435 | 285 | return JavaThreadState.NEW; |
duke@435 | 286 | } else if (val == NEW_TRANS) { |
duke@435 | 287 | return JavaThreadState.NEW_TRANS; |
duke@435 | 288 | } else if (val == IN_NATIVE) { |
duke@435 | 289 | return JavaThreadState.IN_NATIVE; |
duke@435 | 290 | } else if (val == IN_NATIVE_TRANS) { |
duke@435 | 291 | return JavaThreadState.IN_NATIVE_TRANS; |
duke@435 | 292 | } else if (val == IN_VM) { |
duke@435 | 293 | return JavaThreadState.IN_VM; |
duke@435 | 294 | } else if (val == IN_VM_TRANS) { |
duke@435 | 295 | return JavaThreadState.IN_VM_TRANS; |
duke@435 | 296 | } else if (val == IN_JAVA) { |
duke@435 | 297 | return JavaThreadState.IN_JAVA; |
duke@435 | 298 | } else if (val == IN_JAVA_TRANS) { |
duke@435 | 299 | return JavaThreadState.IN_JAVA_TRANS; |
duke@435 | 300 | } else if (val == BLOCKED) { |
duke@435 | 301 | return JavaThreadState.BLOCKED; |
duke@435 | 302 | } else if (val == BLOCKED_TRANS) { |
duke@435 | 303 | return JavaThreadState.BLOCKED_TRANS; |
duke@435 | 304 | } else { |
duke@435 | 305 | throw new RuntimeException("Illegal thread state " + val); |
duke@435 | 306 | } |
duke@435 | 307 | } |
duke@435 | 308 | // FIXME: not yet implementable |
duke@435 | 309 | // public void setThreadState(JavaThreadState s); |
duke@435 | 310 | |
duke@435 | 311 | // |
duke@435 | 312 | // Miscellaneous operations |
duke@435 | 313 | // |
duke@435 | 314 | |
duke@435 | 315 | public OSThread getOSThread() { |
duke@435 | 316 | return (OSThread) VMObjectFactory.newObject(OSThread.class, osThreadField.getValue(addr)); |
duke@435 | 317 | } |
duke@435 | 318 | |
xlu@1137 | 319 | public Address getStackBase() { |
xlu@1209 | 320 | return stackBaseField.getValue(addr); |
xlu@1137 | 321 | } |
xlu@1137 | 322 | |
minqi@4750 | 323 | public long getStackBaseValue() { |
minqi@4750 | 324 | return VM.getVM().getAddressValue(getStackBase()); |
minqi@4750 | 325 | } |
minqi@4750 | 326 | |
xlu@1137 | 327 | public long getStackSize() { |
xlu@1209 | 328 | return stackSizeField.getValue(addr); |
xlu@1137 | 329 | } |
xlu@1137 | 330 | |
duke@435 | 331 | /** Gets the Java-side thread object for this JavaThread */ |
duke@435 | 332 | public Oop getThreadObj() { |
poonam@1888 | 333 | Oop obj = null; |
poonam@1888 | 334 | try { |
poonam@1888 | 335 | obj = VM.getVM().getObjectHeap().newOop(threadObjField.getValue(addr)); |
poonam@1888 | 336 | } catch (Exception e) { |
poonam@1888 | 337 | e.printStackTrace(); |
poonam@1888 | 338 | } |
poonam@1888 | 339 | return obj; |
duke@435 | 340 | } |
duke@435 | 341 | |
duke@435 | 342 | /** Get the Java-side name of this thread */ |
duke@435 | 343 | public String getThreadName() { |
duke@435 | 344 | Oop threadObj = getThreadObj(); |
duke@435 | 345 | if (threadObj == null) { |
duke@435 | 346 | return "<null>"; |
duke@435 | 347 | } |
duke@435 | 348 | return OopUtilities.threadOopGetName(threadObj); |
duke@435 | 349 | } |
duke@435 | 350 | |
duke@435 | 351 | // |
duke@435 | 352 | // Oop traversal |
duke@435 | 353 | // |
duke@435 | 354 | |
duke@435 | 355 | public void oopsDo(AddressVisitor oopVisitor) { |
duke@435 | 356 | super.oopsDo(oopVisitor); |
duke@435 | 357 | |
duke@435 | 358 | // FIXME: add in the rest of the routine from the VM |
duke@435 | 359 | |
duke@435 | 360 | // Traverse the execution stack |
duke@435 | 361 | for(StackFrameStream fst = new StackFrameStream(this); !fst.isDone(); fst.next()) { |
duke@435 | 362 | fst.getCurrent().oopsDo(oopVisitor, fst.getRegisterMap()); |
duke@435 | 363 | } |
duke@435 | 364 | } |
duke@435 | 365 | |
duke@435 | 366 | public boolean isInStack(Address a) { |
duke@435 | 367 | if (Assert.ASSERTS_ENABLED) { |
duke@435 | 368 | Assert.that(VM.getVM().isDebugging(), "Not yet implemented for non-debugging system"); |
duke@435 | 369 | } |
duke@435 | 370 | Address sp = lastSPDbg(); |
xlu@1137 | 371 | Address stackBase = getStackBase(); |
duke@435 | 372 | // Be robust |
xlu@1137 | 373 | if (sp == null) return false; |
dholmes@9903 | 374 | return stackBase.greaterThan(a) && sp.lessThanOrEqual(a); |
xlu@1137 | 375 | } |
xlu@1137 | 376 | |
xlu@1137 | 377 | public boolean isLockOwned(Address a) { |
xlu@1137 | 378 | Address stackBase = getStackBase(); |
xlu@1137 | 379 | Address stackLimit = stackBase.addOffsetTo(-getStackSize()); |
xlu@1137 | 380 | |
dholmes@9903 | 381 | return stackBase.greaterThan(a) && stackLimit.lessThanOrEqual(a); |
duke@435 | 382 | |
duke@435 | 383 | // FIXME: should traverse MonitorArray/MonitorChunks as in VM |
duke@435 | 384 | } |
duke@435 | 385 | |
duke@435 | 386 | public Oop getCurrentParkBlocker() { |
duke@435 | 387 | Oop threadObj = getThreadObj(); |
duke@435 | 388 | if (threadObj != null) { |
duke@435 | 389 | return OopUtilities.threadOopGetParkBlocker(threadObj); |
duke@435 | 390 | } |
duke@435 | 391 | return null; |
duke@435 | 392 | } |
duke@435 | 393 | |
duke@435 | 394 | public void printInfoOn(PrintStream tty) { |
duke@435 | 395 | |
duke@435 | 396 | tty.println("State: " + getThreadState().toString()); |
duke@435 | 397 | // Attempt to figure out the addresses covered by Java frames. |
duke@435 | 398 | // NOTE: we should make this a method and let the Stackwalk panel use the result too. |
duke@435 | 399 | // |
duke@435 | 400 | sun.jvm.hotspot.runtime.Frame tmpFrame = getCurrentFrameGuess(); |
duke@435 | 401 | if (tmpFrame != null ) { |
duke@435 | 402 | Address sp = tmpFrame.getSP(); |
duke@435 | 403 | Address maxSP = sp; |
duke@435 | 404 | Address minSP = sp; |
duke@435 | 405 | RegisterMap tmpMap = newRegisterMap(false); |
duke@435 | 406 | while ((tmpFrame != null) && (!tmpFrame.isFirstFrame())) { |
duke@435 | 407 | tmpFrame = tmpFrame.sender(tmpMap); |
duke@435 | 408 | if (tmpFrame != null) { |
duke@435 | 409 | sp = tmpFrame.getSP(); |
duke@435 | 410 | maxSP = AddressOps.max(maxSP, sp); |
duke@435 | 411 | minSP = AddressOps.min(minSP, sp); |
duke@435 | 412 | } |
duke@435 | 413 | } |
duke@435 | 414 | tty.println("Stack in use by Java: " + minSP + " .. " + maxSP); |
duke@435 | 415 | } else { |
duke@435 | 416 | tty.println("No Java frames present"); |
duke@435 | 417 | } |
poonam@8191 | 418 | tty.println("Base of Stack: " + getStackBase()); |
duke@435 | 419 | tty.println("Last_Java_SP: " + getLastJavaSP()); |
duke@435 | 420 | tty.println("Last_Java_FP: " + getLastJavaFP()); |
duke@435 | 421 | tty.println("Last_Java_PC: " + getLastJavaPC()); |
duke@435 | 422 | // More stuff like saved_execption_pc, safepoint_state, ... |
duke@435 | 423 | access.printInfoOn(addr, tty); |
duke@435 | 424 | |
duke@435 | 425 | } |
duke@435 | 426 | |
duke@435 | 427 | /////////////////////////////// |
duke@435 | 428 | // // |
duke@435 | 429 | // FIXME: add more accessors // |
duke@435 | 430 | // // |
duke@435 | 431 | /////////////////////////////// |
duke@435 | 432 | |
duke@435 | 433 | //-------------------------------------------------------------------------------- |
duke@435 | 434 | // Internals only below this point |
duke@435 | 435 | // |
duke@435 | 436 | |
duke@435 | 437 | private Frame cookLastFrame(Frame fr) { |
duke@435 | 438 | if (fr == null) { |
duke@435 | 439 | return null; |
duke@435 | 440 | } |
duke@435 | 441 | |
duke@435 | 442 | Address pc = fr.getPC(); |
duke@435 | 443 | |
duke@435 | 444 | if (Assert.ASSERTS_ENABLED) { |
duke@435 | 445 | if (pc == null) { |
duke@435 | 446 | Assert.that(VM.getVM().isDebugging(), "must have PC"); |
duke@435 | 447 | } |
duke@435 | 448 | } |
duke@435 | 449 | return fr; |
duke@435 | 450 | } |
duke@435 | 451 | |
duke@435 | 452 | private Address lastSPDbg() { |
duke@435 | 453 | return access.getLastSP(addr); |
duke@435 | 454 | } |
duke@435 | 455 | |
duke@435 | 456 | } |