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