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