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