1 /*
   2  * Copyright (c) 2000, 2013, 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 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 getStackBaseValue() {
 324     return VM.getVM().getAddressValue(getStackBase());
 325   }
 326 
 327   public long getStackSize() {
 328     return stackSizeField.getValue(addr);
 329   }
 330 
 331   /** Gets the Java-side thread object for this JavaThread */
 332   public Oop getThreadObj() {
 333     Oop obj = null;
 334     try {
 335       obj = VM.getVM().getObjectHeap().newOop(threadObjField.getValue(addr));
 336     } catch (Exception e) {
 337       e.printStackTrace();
 338     }
 339     return obj;
 340   }
 341 
 342   /** Get the Java-side name of this thread */
 343   public String getThreadName() {
 344     Oop threadObj = getThreadObj();
 345     if (threadObj == null) {
 346         return "<null>";
 347     }
 348     return OopUtilities.threadOopGetName(threadObj);
 349   }
 350 
 351   //
 352   // Oop traversal
 353   //
 354 
 355   public void oopsDo(AddressVisitor oopVisitor) {
 356     super.oopsDo(oopVisitor);
 357 
 358     // FIXME: add in the rest of the routine from the VM
 359 
 360     // Traverse the execution stack
 361     for(StackFrameStream fst = new StackFrameStream(this); !fst.isDone(); fst.next()) {
 362       fst.getCurrent().oopsDo(oopVisitor, fst.getRegisterMap());
 363     }
 364   }
 365 
 366   public boolean isInStack(Address a) {
 367     if (Assert.ASSERTS_ENABLED) {
 368       Assert.that(VM.getVM().isDebugging(), "Not yet implemented for non-debugging system");
 369     }
 370     Address sp      = lastSPDbg();
 371     Address stackBase = getStackBase();
 372     // Be robust
 373     if (sp == null) return false;
 374     return stackBase.greaterThanOrEqual(a) && sp.lessThanOrEqual(a);
 375   }
 376 
 377   public boolean isLockOwned(Address a) {
 378     Address stackBase = getStackBase();
 379     Address stackLimit = stackBase.addOffsetTo(-getStackSize());
 380 
 381     return stackBase.greaterThanOrEqual(a) && stackLimit.lessThanOrEqual(a);
 382 
 383     // FIXME: should traverse MonitorArray/MonitorChunks as in VM
 384   }
 385 
 386   public Oop getCurrentParkBlocker() {
 387     Oop threadObj = getThreadObj();
 388     if (threadObj != null) {
 389       return OopUtilities.threadOopGetParkBlocker(threadObj);
 390     }
 391     return null;
 392   }
 393 
 394   public void printInfoOn(PrintStream tty) {
 395 
 396     tty.println("State: " + getThreadState().toString());
 397     // Attempt to figure out the addresses covered by Java frames.
 398     // NOTE: we should make this a method and let the Stackwalk panel use the result too.
 399     //
 400     sun.jvm.hotspot.runtime.Frame tmpFrame = getCurrentFrameGuess();
 401     if (tmpFrame != null ) {
 402       Address sp = tmpFrame.getSP();
 403       Address maxSP = sp;
 404       Address minSP = sp;
 405       RegisterMap tmpMap = newRegisterMap(false);
 406       while ((tmpFrame != null) && (!tmpFrame.isFirstFrame())) {
 407           tmpFrame = tmpFrame.sender(tmpMap);
 408           if (tmpFrame != null) {
 409             sp = tmpFrame.getSP();
 410             maxSP = AddressOps.max(maxSP, sp);
 411             minSP = AddressOps.min(minSP, sp);
 412           }
 413       }
 414       tty.println("Stack in use by Java: " + minSP + " .. " + maxSP);
 415     } else {
 416       tty.println("No Java frames present");
 417     }
 418     tty.println("Base of Stack: " + getBaseOfStackPointer());
 419     tty.println("Last_Java_SP: " + getLastJavaSP());
 420     tty.println("Last_Java_FP: " + getLastJavaFP());
 421     tty.println("Last_Java_PC: " + getLastJavaPC());
 422     // More stuff like saved_execption_pc, safepoint_state, ...
 423     access.printInfoOn(addr, tty);
 424 
 425   }
 426 
 427   ///////////////////////////////
 428   //                           //
 429   // FIXME: add more accessors //
 430   //                           //
 431   ///////////////////////////////
 432 
 433   //--------------------------------------------------------------------------------
 434   // Internals only below this point
 435   //
 436 
 437   private Frame cookLastFrame(Frame fr) {
 438     if (fr == null) {
 439       return null;
 440     }
 441 
 442     Address pc        = fr.getPC();
 443 
 444     if (Assert.ASSERTS_ENABLED) {
 445       if (pc == null) {
 446         Assert.that(VM.getVM().isDebugging(), "must have PC");
 447       }
 448     }
 449     return fr;
 450   }
 451 
 452   private Address lastSPDbg() {
 453     return access.getLastSP(addr);
 454   }
 455 
 456 }