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