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