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 }