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 }