1 /* 2 * Copyright (c) 2000, 2022, 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.debugger.*; 30 import sun.jvm.hotspot.oops.*; 31 import sun.jvm.hotspot.types.*; 32 import sun.jvm.hotspot.utilities.*; 33 import sun.jvm.hotspot.utilities.Observable; 34 import sun.jvm.hotspot.utilities.Observer; 35 36 /** This is an abstract class because there are certain OS- and 37 CPU-specific operations (like the setting and getting of the last 38 Java frame pointer) which need to be factored out. These 39 operations are implemented by, for example, 40 SolarisSPARCJavaThread, and the concrete subclasses are 41 instantiated by the JavaThreadFactory in the Threads class. */ 42 43 public class JavaThread extends Thread { 44 private static final boolean DEBUG = System.getProperty("sun.jvm.hotspot.runtime.JavaThread.DEBUG") != null; 45 46 private static long threadObjFieldOffset; 47 private static long lockStackCurrentOffset; 48 private static long lockStackBaseOffset; 49 private static AddressField anchorField; 50 private static AddressField lastJavaSPField; 51 private static AddressField lastJavaPCField; 52 private static CIntegerField threadStateField; 53 private static AddressField osThreadField; 54 private static AddressField stackBaseField; 55 private static CIntegerField stackSizeField; 56 private static CIntegerField terminatedField; 57 private static AddressField activeHandlesField; 58 private static long oopPtrSize; 59 60 private static JavaThreadPDAccess access; 61 62 // JavaThreadStates read from underlying process 63 private static int UNINITIALIZED; 64 private static int NEW; 65 private static int NEW_TRANS; 66 private static int IN_NATIVE; 67 private static int IN_NATIVE_TRANS; 68 private static int IN_VM; 69 private static int IN_VM_TRANS; 70 private static int IN_JAVA; 71 private static int IN_JAVA_TRANS; 72 private static int BLOCKED; 73 private static int BLOCKED_TRANS; 74 75 private static int NOT_TERMINATED; 76 private static int EXITING; 77 78 private static final String ADDRESS_FORMAT = VM.getVM().isLP64() ? "0x%016x" : "0x%08x"; 79 80 static { 81 VM.registerVMInitializedObserver(new Observer() { 82 public void update(Observable o, Object data) { 83 initialize(VM.getVM().getTypeDataBase()); 84 } 85 }); 86 } 87 88 private static synchronized void initialize(TypeDataBase db) { 89 Type type = db.lookupType("JavaThread"); 90 Type anchorType = db.lookupType("JavaFrameAnchor"); 91 Type typeLockStack = db.lookupType("LockStack"); 92 93 threadObjFieldOffset = type.getField("_threadObj").getOffset(); 94 95 anchorField = type.getAddressField("_anchor"); 96 lastJavaSPField = anchorType.getAddressField("_last_Java_sp"); 97 lastJavaPCField = anchorType.getAddressField("_last_Java_pc"); 98 threadStateField = type.getCIntegerField("_thread_state"); 99 osThreadField = type.getAddressField("_osthread"); 100 stackBaseField = type.getAddressField("_stack_base"); 101 stackSizeField = type.getCIntegerField("_stack_size"); 102 terminatedField = type.getCIntegerField("_terminated"); 103 activeHandlesField = type.getAddressField("_active_handles"); 104 105 lockStackCurrentOffset = type.getField("_lock_stack").getOffset() + typeLockStack.getField("_current").getOffset(); 106 lockStackBaseOffset = type.getField("_lock_stack").getOffset() + typeLockStack.getField("_base").getOffset(); 107 oopPtrSize = VM.getVM().getAddressSize(); 108 109 UNINITIALIZED = db.lookupIntConstant("_thread_uninitialized").intValue(); 110 NEW = db.lookupIntConstant("_thread_new").intValue(); 111 NEW_TRANS = db.lookupIntConstant("_thread_new_trans").intValue(); 112 IN_NATIVE = db.lookupIntConstant("_thread_in_native").intValue(); 113 IN_NATIVE_TRANS = db.lookupIntConstant("_thread_in_native_trans").intValue(); 114 IN_VM = db.lookupIntConstant("_thread_in_vm").intValue(); 115 IN_VM_TRANS = db.lookupIntConstant("_thread_in_vm_trans").intValue(); 116 IN_JAVA = db.lookupIntConstant("_thread_in_Java").intValue(); 117 IN_JAVA_TRANS = db.lookupIntConstant("_thread_in_Java_trans").intValue(); 118 BLOCKED = db.lookupIntConstant("_thread_blocked").intValue(); 119 BLOCKED_TRANS = db.lookupIntConstant("_thread_blocked_trans").intValue(); 120 121 NOT_TERMINATED = db.lookupIntConstant("JavaThread::_not_terminated").intValue(); 122 EXITING = db.lookupIntConstant("JavaThread::_thread_exiting").intValue(); 123 124 } 125 126 public JavaThread(Address addr) { 127 super(addr); 128 } 129 130 void setThreadPDAccess(JavaThreadPDAccess access) { 131 this.access = access; 132 } 133 134 /** NOTE: for convenience, this differs in definition from the underlying VM. 135 Only "pure" JavaThreads return true; CompilerThreads, 136 JVMDIDebuggerThreads return false. 137 FIXME: 138 consider encapsulating platform-specific functionality in an 139 object instead of using inheritance (which is the primary reason 140 we can't traverse CompilerThreads, etc; didn't want to have, for 141 example, "SolarisSPARCCompilerThread".) */ 142 public boolean isJavaThread() { return true; } 143 144 public boolean isExiting () { 145 return (getTerminated() == EXITING) || isTerminated(); 146 } 147 148 public boolean isTerminated() { 149 return (getTerminated() != NOT_TERMINATED) && (getTerminated() != EXITING); 150 } 151 152 public static AddressField getAnchorField() { return anchorField; } 153 154 /** Get the last Java stack pointer */ 155 public Address getLastJavaSP() { 156 Address sp = lastJavaSPField.getValue(addr.addOffsetTo(anchorField.getOffset())); 157 return sp; 158 } 159 160 public Address getLastJavaPC() { 161 Address pc = lastJavaPCField.getValue(addr.addOffsetTo(anchorField.getOffset())); 162 return pc; 163 } 164 165 /** Abstract accessor to last Java frame pointer, implemented by 166 OS/CPU-specific JavaThread implementation. May return null if 167 there is no frame pointer or if it is not necessary on this 168 platform. */ 169 public Address getLastJavaFP(){ 170 return access.getLastJavaFP(addr); 171 } 172 173 /** Abstract accessor to last Java pc, implemented by 174 OS/CPU-specific JavaThread implementation. May return null if 175 there is no frame pointer or if it is not necessary on this 176 platform. */ 177 178 /* 179 public Address getLastJavaPC(){ 180 return access.getLastJavaPC(addr); 181 } 182 */ 183 184 // FIXME: not yet implementable 185 // public abstract void setLastJavaFP(Address fp); 186 187 /** A stack pointer older than any java frame stack pointer. Only 188 needed on some platforms; for example, see 189 thread_solaris_sparc.hpp. */ 190 public Address getBaseOfStackPointer(){ 191 return access.getBaseOfStackPointer(addr); 192 } 193 // FIXME: not yet implementable 194 // public abstract void setBaseOfStackPointer(Address fp); 195 196 /** Tells whether the last Java frame is set */ 197 public boolean hasLastJavaFrame() { 198 return (getLastJavaSP() != null); 199 } 200 201 /** Accessing frames */ 202 public Frame getLastFrame() { 203 // FIXME: would need to implement runtime routine 204 // "cacheStatePD(boolean)" for reflective system to be able to 205 // flush register windows on SPARC 206 return cookLastFrame(getLastFramePD()); 207 } 208 209 /** Internal routine implemented by platform-dependent subclasses */ 210 protected Frame getLastFramePD(){ 211 return access.getLastFramePD(this, addr); 212 } 213 214 /** Accessing frames. Returns the last Java VFrame or null if none 215 was present. (NOTE that this is mostly unusable in a debugging 216 system; see getLastJavaVFrameDbg, below, which provides very 217 different functionality.) */ 218 public JavaVFrame getLastJavaVFrame(RegisterMap regMap) { 219 if (Assert.ASSERTS_ENABLED) { 220 Assert.that(regMap != null, "a map must be given"); 221 } 222 Frame f = getLastFrame(); 223 if (f == null) { 224 return null; 225 } 226 for (VFrame vf = VFrame.newVFrame(f, regMap, this); vf != null; vf = vf.sender()) { 227 if (vf.isJavaFrame()) { 228 return (JavaVFrame) vf; 229 } 230 } 231 return null; 232 } 233 234 /** This should only be used by a debugger. Uses the current frame 235 guess to attempt to get the topmost JavaVFrame. 236 (getLastJavaVFrame, as a port of the VM's routine, assumes the 237 VM is at a safepoint.) */ 238 public JavaVFrame getLastJavaVFrameDbg() { 239 RegisterMap regMap = newRegisterMap(true); 240 sun.jvm.hotspot.runtime.Frame f = getCurrentFrameGuess(); 241 if (f == null) return null; 242 boolean imprecise = true; 243 if (f.isInterpretedFrame() && !f.isInterpretedFrameValid()) { 244 if (DEBUG) { 245 System.out.println("Correcting for invalid interpreter frame"); 246 } 247 f = f.sender(regMap); 248 imprecise = false; 249 } 250 VFrame vf = VFrame.newVFrame(f, regMap, this, true, imprecise); 251 if (vf == null) { 252 if (DEBUG) { 253 System.out.println(" (Unable to create vframe for topmost frame guess)"); 254 } 255 return null; 256 } 257 return vf.isJavaFrame() ? (JavaVFrame)vf : vf.javaSender(); 258 } 259 260 /** In this system, a JavaThread is the top-level factory for a 261 RegisterMap, since the JavaThread implementation is already 262 platform-specific and RegisterMap is also necessarily 263 platform-specific. The updateMap argument indicates whether the 264 register map needs to be updated, for example during stack 265 traversal -- see frame.hpp. */ 266 public RegisterMap newRegisterMap(boolean updateMap){ 267 return access.newRegisterMap(this, updateMap); 268 } 269 270 /** This is only designed to be used by the debugging system. 271 Returns a "best guess" of the topmost frame on the stack. This 272 guess should be as "raw" as possible. For example, if the 273 topmost frame is an interpreter frame (the return PC is in the 274 interpreter) but is not a valid frame (i.e., the BCI has not yet 275 been set up) this should still return the topmost frame and not 276 the sender. Validity checks are done at higher levels. */ 277 public Frame getCurrentFrameGuess(){ 278 return access.getCurrentFrameGuess(this, addr); 279 } 280 281 /** Also only intended for use by the debugging system. Provides the 282 same effect of OSThread::print(); that is, prints a value which 283 allows the user to intuitively understand which native OS thread 284 maps to this Java thread. Does not print a newline or leading or 285 trailing spaces. */ 286 public void printThreadIDOn(PrintStream tty) { 287 access.printThreadIDOn(addr,tty); 288 } 289 290 public void printThreadID() { 291 printThreadIDOn(System.out); 292 } 293 294 public ThreadProxy getThreadProxy() { 295 return access.getThreadProxy(addr); 296 } 297 298 // 299 // Safepoint support 300 // 301 302 public JavaThreadState getThreadState() { 303 int val = (int) threadStateField.getValue(addr); 304 if (val == UNINITIALIZED) { 305 return JavaThreadState.UNINITIALIZED; 306 } else if (val == NEW) { 307 return JavaThreadState.NEW; 308 } else if (val == NEW_TRANS) { 309 return JavaThreadState.NEW_TRANS; 310 } else if (val == IN_NATIVE) { 311 return JavaThreadState.IN_NATIVE; 312 } else if (val == IN_NATIVE_TRANS) { 313 return JavaThreadState.IN_NATIVE_TRANS; 314 } else if (val == IN_VM) { 315 return JavaThreadState.IN_VM; 316 } else if (val == IN_VM_TRANS) { 317 return JavaThreadState.IN_VM_TRANS; 318 } else if (val == IN_JAVA) { 319 return JavaThreadState.IN_JAVA; 320 } else if (val == IN_JAVA_TRANS) { 321 return JavaThreadState.IN_JAVA_TRANS; 322 } else if (val == BLOCKED) { 323 return JavaThreadState.BLOCKED; 324 } else if (val == BLOCKED_TRANS) { 325 return JavaThreadState.BLOCKED_TRANS; 326 } else { 327 throw new RuntimeException("Illegal thread state " + val); 328 } 329 } 330 // FIXME: not yet implementable 331 // public void setThreadState(JavaThreadState s); 332 333 // 334 // Miscellaneous operations 335 // 336 337 public OSThread getOSThread() { 338 return VMObjectFactory.newObject(OSThread.class, osThreadField.getValue(addr)); 339 } 340 341 public Address getStackBase() { 342 return stackBaseField.getValue(addr); 343 } 344 345 public long getStackBaseValue() { 346 return VM.getVM().getAddressValue(getStackBase()); 347 } 348 349 public long getStackSize() { 350 return stackSizeField.getValue(addr); 351 } 352 353 public int getTerminated() { 354 return (int) terminatedField.getValue(addr); 355 } 356 357 /** Gets the Java-side thread object for this JavaThread */ 358 public Oop getThreadObj() { 359 Oop obj = null; 360 try { 361 Address addr = getAddress().addOffsetTo(threadObjFieldOffset); 362 VMOopHandle vmOopHandle = VMObjectFactory.newObject(VMOopHandle.class, addr); 363 obj = vmOopHandle.resolve(); 364 } catch (Exception e) { 365 System.out.println("WARNING: could not get Thread object: " + e); 366 } 367 return obj; 368 } 369 370 /** Get the Java-side name of this thread */ 371 public String getThreadName() { 372 Oop threadObj = getThreadObj(); 373 if (threadObj == null) { 374 return "<null>"; 375 } 376 return OopUtilities.threadOopGetName(threadObj); 377 } 378 379 // 380 // Oop traversal 381 // 382 383 public void oopsDo(AddressVisitor oopVisitor) { 384 super.oopsDo(oopVisitor); 385 386 // FIXME: add in the rest of the routine from the VM 387 388 // Traverse the execution stack 389 for(StackFrameStream fst = new StackFrameStream(this); !fst.isDone(); fst.next()) { 390 fst.getCurrent().oopsDo(oopVisitor, fst.getRegisterMap()); 391 } 392 } 393 394 public boolean isInStack(Address a) { 395 if (Assert.ASSERTS_ENABLED) { 396 Assert.that(VM.getVM().isDebugging(), "Not yet implemented for non-debugging system"); 397 } 398 Address sp = lastSPDbg(); 399 Address stackBase = getStackBase(); 400 // Be robust 401 if (sp == null) return false; 402 return stackBase.greaterThan(a) && sp.lessThanOrEqual(a); 403 } 404 405 public boolean isLockOwned(OopHandle obj) { 406 Address current = addr.getAddressAt(lockStackCurrentOffset); 407 Address base = addr.getAddressAt(lockStackBaseOffset); 408 while (base.lessThan(current)) { 409 Address oop = base.getAddressAt(0); 410 if (oop.equals(obj)) { 411 return true; 412 } 413 base = base.addOffsetTo(oopPtrSize); 414 } 415 return false; 416 } 417 418 public boolean isLockOwned(Address a) { 419 Address stackBase = getStackBase(); 420 Address stackLimit = stackBase.addOffsetTo(-getStackSize()); 421 422 return stackBase.greaterThan(a) && stackLimit.lessThanOrEqual(a); 423 424 // FIXME: should traverse MonitorArray/MonitorChunks as in VM 425 } 426 427 public Oop getCurrentParkBlocker() { 428 Oop threadObj = getThreadObj(); 429 if (threadObj != null) { 430 try { 431 return OopUtilities.threadOopGetParkBlocker(threadObj); 432 } catch (Exception e) { 433 System.out.println("Could not get current park blocker: " + e); 434 } 435 } 436 return null; 437 } 438 439 public JNIHandleBlock activeHandles() { 440 Address a = activeHandlesField.getAddress(addr); 441 if (a == null) { 442 return null; 443 } 444 return new JNIHandleBlock(a); 445 } 446 447 public void printInfoOn(PrintStream tty) { 448 449 tty.println("State: " + getThreadState().toString()); 450 // Attempt to figure out the addresses covered by Java frames. 451 // NOTE: we should make this a method and let the Stackwalk panel use the result too. 452 // 453 sun.jvm.hotspot.runtime.Frame tmpFrame = getCurrentFrameGuess(); 454 if (tmpFrame != null ) { 455 Address sp = tmpFrame.getSP(); 456 Address maxSP = sp; 457 Address minSP = sp; 458 RegisterMap tmpMap = newRegisterMap(false); 459 while ((tmpFrame != null) && (!tmpFrame.isFirstFrame())) { 460 tmpFrame = tmpFrame.sender(tmpMap); 461 if (tmpFrame != null) { 462 sp = tmpFrame.getSP(); 463 maxSP = AddressOps.max(maxSP, sp); 464 minSP = AddressOps.min(minSP, sp); 465 } 466 } 467 tty.println("Stack in use by Java: " + minSP + " .. " + maxSP); 468 } else { 469 tty.println("No Java frames present"); 470 } 471 tty.println("Base of Stack: " + getStackBase()); 472 tty.println("Last_Java_SP: " + getLastJavaSP()); 473 tty.println("Last_Java_FP: " + getLastJavaFP()); 474 tty.println("Last_Java_PC: " + getLastJavaPC()); 475 // More stuff like saved_execption_pc, safepoint_state, ... 476 access.printInfoOn(addr, tty); 477 478 } 479 480 /////////////////////////////// 481 // // 482 // FIXME: add more accessors // 483 // // 484 /////////////////////////////// 485 486 //-------------------------------------------------------------------------------- 487 // Internals only below this point 488 // 489 490 private Frame cookLastFrame(Frame fr) { 491 if (fr == null) { 492 return null; 493 } 494 495 Address pc = fr.getPC(); 496 497 if (Assert.ASSERTS_ENABLED) { 498 if (pc == null) { 499 Assert.that(VM.getVM().isDebugging(), "must have PC"); 500 } 501 } 502 return fr; 503 } 504 505 public Address lastSPDbg() { 506 return access.getLastSP(addr); 507 } 508 509 // Print the contents of all registers in the thread's context 510 public void printThreadContextOn(PrintStream out, boolean verbose){ 511 ThreadContext tc = getThreadProxy().getContext(); 512 for (int r = 0; r < tc.getNumRegisters(); r++) { 513 Address regAddr = tc.getRegisterAsAddress(r); 514 System.out.format("%s: %s", tc.getRegisterName(r), regAddr); 515 if (regAddr == null) { 516 System.out.println(); 517 } else { 518 PointerLocation l = PointerFinder.find(regAddr); 519 if (l.isUnknown()) { 520 System.out.println(); 521 } else { 522 System.out.print(": "); 523 l.printOn(System.out, false, verbose); 524 } 525 } 526 } 527 } 528 529 public void printThreadInfoOn(PrintStream out){ 530 String threadName = "<unknown>"; 531 boolean daemon = false; 532 int priority = java.lang.Thread.MIN_PRIORITY - 1; 533 String statusName = "<unknown>"; 534 535 Oop threadOop = this.getThreadObj(); 536 if (threadOop == null) { 537 System.out.println("Could not get the java Thread object. Thread info will be limited."); 538 } else { 539 // Some of these accesses can throw an Exception if we are in the 540 // middle of a GC, so be cautious. 541 try { 542 threadName = this.getThreadName(); 543 } catch (Exception e) {} 544 try { 545 // These all rely on the FieldHolder object, so if one fails, they all fail. 546 daemon = OopUtilities.threadOopGetDaemon(threadOop); 547 priority = OopUtilities.threadOopGetPriority(threadOop); 548 statusName = OopUtilities.threadOopGetThreadStatusName(threadOop); 549 } catch (Exception e) {} 550 out.print("\""); 551 out.print(threadName); 552 out.print("\" #"); 553 out.print(OopUtilities.threadOopGetTID(threadOop)); 554 if (daemon) { 555 out.print(" daemon"); 556 } 557 out.print(" prio="); 558 if (priority == java.lang.Thread.MIN_PRIORITY - 1) { 559 out.print("<unknown>"); 560 } else { 561 out.print(priority); 562 } 563 } 564 out.print(" tid="); 565 out.print(this.getAddress()); 566 out.print(" nid="); 567 out.print(String.format("%d ", this.getOSThread().threadId())); 568 out.print(getOSThread().getThreadState().getPrintVal()); 569 out.print(" ["); 570 if (this.getLastJavaSP() == null) { 571 out.print(String.format(ADDRESS_FORMAT, 0L)); 572 } else { 573 out.print(this.getLastJavaSP().andWithMask(~0xFFF)); 574 } 575 out.println("]"); 576 if (threadOop != null) { 577 out.print(" java.lang.Thread.State: "); 578 out.println(statusName); 579 } 580 out.print(" JavaThread state: _thread_"); 581 out.println(this.getThreadState().toString().toLowerCase()); 582 } 583 }