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 25package sun.jvm.hotspot.runtime; 26 27import java.io.*; 28import java.util.*; 29import sun.jvm.hotspot.debugger.*; 30import sun.jvm.hotspot.oops.*; 31import sun.jvm.hotspot.types.*; 32import 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 41public class JavaThread extends Thread { 42 private static final boolean DEBUG = System.getProperty("sun.jvm.hotspot.runtime.JavaThread.DEBUG") != null; 43 44 private static AddressField nextField; 45 private static sun.jvm.hotspot.types.OopField threadObjField; 46 private static AddressField anchorField; 47 private static AddressField lastJavaSPField; 48 private static AddressField lastJavaPCField; 49 private static CIntegerField threadStateField; 50 private static AddressField osThreadField; 51 private static AddressField stackBaseField; 52 private static CIntegerField stackSizeField; 53 private static CIntegerField terminatedField; 54 55 private static JavaThreadPDAccess access; 56 57 // JavaThreadStates read from underlying process 58 private static int UNINITIALIZED; 59 private static int NEW; 60 private static int NEW_TRANS; 61 private static int IN_NATIVE; 62 private static int IN_NATIVE_TRANS; 63 private static int IN_VM; 64 private static int IN_VM_TRANS; 65 private static int IN_JAVA; 66 private static int IN_JAVA_TRANS; 67 private static int BLOCKED; 68 private static int BLOCKED_TRANS; 69 70 private static int NOT_TERMINATED; 71 private static int EXITING; 72 73 private static final String ADDRESS_FORMAT = VM.getVM().isLP64() ? "0x%016x" : "0x%08x"; 74 75 static { 76 VM.registerVMInitializedObserver(new Observer() { 77 public void update(Observable o, Object data) { 78 initialize(VM.getVM().getTypeDataBase()); 79 } 80 }); 81 } 82 83 private static synchronized void initialize(TypeDataBase db) { 84 Type type = db.lookupType("JavaThread"); 85 Type anchorType = db.lookupType("JavaFrameAnchor"); 86 87 nextField = type.getAddressField("_next"); 88 threadObjField = type.getOopField("_threadObj"); 89 anchorField = type.getAddressField("_anchor"); 90 lastJavaSPField = anchorType.getAddressField("_last_Java_sp"); 91 lastJavaPCField = anchorType.getAddressField("_last_Java_pc"); 92 threadStateField = type.getCIntegerField("_thread_state"); 93 osThreadField = type.getAddressField("_osthread"); 94 stackBaseField = type.getAddressField("_stack_base"); 95 stackSizeField = type.getCIntegerField("_stack_size"); 96 terminatedField = type.getCIntegerField("_terminated"); 97 98 UNINITIALIZED = db.lookupIntConstant("_thread_uninitialized").intValue(); 99 NEW = db.lookupIntConstant("_thread_new").intValue(); 100 NEW_TRANS = db.lookupIntConstant("_thread_new_trans").intValue(); 101 IN_NATIVE = db.lookupIntConstant("_thread_in_native").intValue(); 102 IN_NATIVE_TRANS = db.lookupIntConstant("_thread_in_native_trans").intValue(); 103 IN_VM = db.lookupIntConstant("_thread_in_vm").intValue(); 104 IN_VM_TRANS = db.lookupIntConstant("_thread_in_vm_trans").intValue(); 105 IN_JAVA = db.lookupIntConstant("_thread_in_Java").intValue(); 106 IN_JAVA_TRANS = db.lookupIntConstant("_thread_in_Java_trans").intValue(); 107 BLOCKED = db.lookupIntConstant("_thread_blocked").intValue(); 108 BLOCKED_TRANS = db.lookupIntConstant("_thread_blocked_trans").intValue(); 109 110 NOT_TERMINATED = db.lookupIntConstant("JavaThread::_not_terminated").intValue(); 111 EXITING = db.lookupIntConstant("JavaThread::_thread_exiting").intValue(); 112 113 } 114 115 public JavaThread(Address addr) { 116 super(addr); 117 } 118 119 void setThreadPDAccess(JavaThreadPDAccess access) { 120 this.access = access; 121 } 122 123 public JavaThread next() { 124 Address threadAddr = nextField.getValue(addr); 125 if (threadAddr == null) { 126 return null; 127 } 128 129 return VM.getVM().getThreads().createJavaThreadWrapper(threadAddr); 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 obj = VM.getVM().getObjectHeap().newOop(threadObjField.getValue(addr)); 360 } catch (Exception e) { 361 e.printStackTrace(); 362 } 363 return obj; 364 } 365 366 /** Get the Java-side name of this thread */ 367 public String getThreadName() { 368 Oop threadObj = getThreadObj(); 369 if (threadObj == null) { 370 return "<null>"; 371 } 372 return OopUtilities.threadOopGetName(threadObj); 373 } 374 375 // 376 // Oop traversal 377 // 378 379 public void oopsDo(AddressVisitor oopVisitor) { 380 super.oopsDo(oopVisitor); 381 382 // FIXME: add in the rest of the routine from the VM 383 384 // Traverse the execution stack 385 for(StackFrameStream fst = new StackFrameStream(this); !fst.isDone(); fst.next()) { 386 fst.getCurrent().oopsDo(oopVisitor, fst.getRegisterMap()); 387 } 388 } 389 390 public boolean isInStack(Address a) { 391 if (Assert.ASSERTS_ENABLED) { 392 Assert.that(VM.getVM().isDebugging(), "Not yet implemented for non-debugging system"); 393 } 394 Address sp = lastSPDbg(); 395 Address stackBase = getStackBase(); 396 // Be robust 397 if (sp == null) return false; 398 return stackBase.greaterThanOrEqual(a) && sp.lessThanOrEqual(a); 399 } 400 401 public boolean isLockOwned(Address a) { 402 Address stackBase = getStackBase(); 403 Address stackLimit = stackBase.addOffsetTo(-getStackSize()); 404 405 return stackBase.greaterThanOrEqual(a) && stackLimit.lessThanOrEqual(a); 406 407 // FIXME: should traverse MonitorArray/MonitorChunks as in VM 408 } 409 410 public Oop getCurrentParkBlocker() { 411 Oop threadObj = getThreadObj(); 412 if (threadObj != null) { 413 return OopUtilities.threadOopGetParkBlocker(threadObj); 414 } 415 return null; 416 } 417 418 public void printInfoOn(PrintStream tty) { 419 420 tty.println("State: " + getThreadState().toString()); 421 // Attempt to figure out the addresses covered by Java frames. 422 // NOTE: we should make this a method and let the Stackwalk panel use the result too. 423 // 424 sun.jvm.hotspot.runtime.Frame tmpFrame = getCurrentFrameGuess(); 425 if (tmpFrame != null ) { 426 Address sp = tmpFrame.getSP(); 427 Address maxSP = sp; 428 Address minSP = sp; 429 RegisterMap tmpMap = newRegisterMap(false); 430 while ((tmpFrame != null) && (!tmpFrame.isFirstFrame())) { 431 tmpFrame = tmpFrame.sender(tmpMap); 432 if (tmpFrame != null) { 433 sp = tmpFrame.getSP(); 434 maxSP = AddressOps.max(maxSP, sp); 435 minSP = AddressOps.min(minSP, sp); 436 } 437 } 438 tty.println("Stack in use by Java: " + minSP + " .. " + maxSP); 439 } else { 440 tty.println("No Java frames present"); 441 } 442 tty.println("Base of Stack: " + getStackBase()); 443 tty.println("Last_Java_SP: " + getLastJavaSP()); 444 tty.println("Last_Java_FP: " + getLastJavaFP()); 445 tty.println("Last_Java_PC: " + getLastJavaPC()); 446 // More stuff like saved_execption_pc, safepoint_state, ... 447 access.printInfoOn(addr, tty); 448 449 } 450 451 /////////////////////////////// 452 // // 453 // FIXME: add more accessors // 454 // // 455 /////////////////////////////// 456 457 //-------------------------------------------------------------------------------- 458 // Internals only below this point 459 // 460 461 private Frame cookLastFrame(Frame fr) { 462 if (fr == null) { 463 return null; 464 } 465 466 Address pc = fr.getPC(); 467 468 if (Assert.ASSERTS_ENABLED) { 469 if (pc == null) { 470 Assert.that(VM.getVM().isDebugging(), "must have PC"); 471 } 472 } 473 return fr; 474 } 475 476 private Address lastSPDbg() { 477 return access.getLastSP(addr); 478 } 479 480 481 public void printThreadInfoOn(PrintStream out){ 482 Oop threadOop = this.getThreadObj(); 483 484 out.print("\""); 485 out.print(this.getThreadName()); 486 out.print("\" #"); 487 out.print(OopUtilities.threadOopGetTID(threadOop)); 488 if(OopUtilities.threadOopGetDaemon(threadOop)){ 489 out.print(" daemon"); 490 } 491 out.print(" prio="); 492 out.print(OopUtilities.threadOopGetPriority(threadOop)); 493 out.print(" tid="); 494 out.print(this.getAddress()); 495 out.print(" nid="); 496 out.print(String.format("0x%x ",this.getOSThread().threadId())); 497 out.print(getOSThread().getThreadState().getPrintVal()); 498 out.print(" ["); 499 if(this.getLastJavaSP() == null){ 500 out.print(String.format(ADDRESS_FORMAT,0L)); 501 } else { 502 out.print(this.getLastJavaSP().andWithMask(~0xFFF)); 503 } 504 out.println("]"); 505 out.print(" java.lang.Thread.State: "); 506 out.println(OopUtilities.threadOopGetThreadStatusName(threadOop)); 507 out.print(" JavaThread state: _thread_"); 508 out.println(this.getThreadState().toString().toLowerCase()); 509 } 510} 511