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