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 long          lockStackCurrentOffset;
 48   private static long          lockStackBaseOffset;
 49   private static AddressField  anchorField;
 50   private static AddressField  lastJavaSPField;
 51   private static AddressField  lastJavaPCField;
 52   private static CIntegerField threadStateField;
 53   private static AddressField  osThreadField;
 54   private static AddressField  stackBaseField;
 55   private static CIntegerField stackSizeField;
 56   private static CIntegerField terminatedField;
 57   private static long oopPtrSize;
 58 
 59   private static JavaThreadPDAccess access;
 60 
 61   // JavaThreadStates read from underlying process
 62   private static int           UNINITIALIZED;
 63   private static int           NEW;
 64   private static int           NEW_TRANS;
 65   private static int           IN_NATIVE;
 66   private static int           IN_NATIVE_TRANS;
 67   private static int           IN_VM;
 68   private static int           IN_VM_TRANS;
 69   private static int           IN_JAVA;
 70   private static int           IN_JAVA_TRANS;
 71   private static int           BLOCKED;
 72   private static int           BLOCKED_TRANS;
 73 
 74   private static int           NOT_TERMINATED;
 75   private static int           EXITING;
 76 
 77   private static final String  ADDRESS_FORMAT = VM.getVM().isLP64() ? "0x%016x" : "0x%08x";
 78 
 79   static {
 80     VM.registerVMInitializedObserver(new Observer() {
 81         public void update(Observable o, Object data) {
 82           initialize(VM.getVM().getTypeDataBase());
 83         }
 84       });
 85   }
 86 
 87   private static synchronized void initialize(TypeDataBase db) {
 88     Type type = db.lookupType("JavaThread");
 89     Type anchorType = db.lookupType("JavaFrameAnchor");
 90     Type typeLockStack = db.lookupType("LockStack");
 91 
 92     threadObjFieldOffset = type.getField("_threadObj").getOffset();
 93 
 94     anchorField       = type.getAddressField("_anchor");
 95     lastJavaSPField   = anchorType.getAddressField("_last_Java_sp");
 96     lastJavaPCField   = anchorType.getAddressField("_last_Java_pc");
 97     threadStateField  = type.getCIntegerField("_thread_state");
 98     osThreadField     = type.getAddressField("_osthread");
 99     stackBaseField    = type.getAddressField("_stack_base");
100     stackSizeField    = type.getCIntegerField("_stack_size");
101     terminatedField   = type.getCIntegerField("_terminated");
102 
103     lockStackCurrentOffset = type.getField("_lock_stack").getOffset() + typeLockStack.getField("_current").getOffset();
104     lockStackBaseOffset = type.getField("_lock_stack").getOffset() + typeLockStack.getField("_base").getOffset();
105     oopPtrSize = VM.getVM().getAddressSize();
106 
107     UNINITIALIZED     = db.lookupIntConstant("_thread_uninitialized").intValue();
108     NEW               = db.lookupIntConstant("_thread_new").intValue();
109     NEW_TRANS         = db.lookupIntConstant("_thread_new_trans").intValue();
110     IN_NATIVE         = db.lookupIntConstant("_thread_in_native").intValue();
111     IN_NATIVE_TRANS   = db.lookupIntConstant("_thread_in_native_trans").intValue();
112     IN_VM             = db.lookupIntConstant("_thread_in_vm").intValue();
113     IN_VM_TRANS       = db.lookupIntConstant("_thread_in_vm_trans").intValue();
114     IN_JAVA           = db.lookupIntConstant("_thread_in_Java").intValue();
115     IN_JAVA_TRANS     = db.lookupIntConstant("_thread_in_Java_trans").intValue();
116     BLOCKED           = db.lookupIntConstant("_thread_blocked").intValue();
117     BLOCKED_TRANS     = db.lookupIntConstant("_thread_blocked_trans").intValue();
118 
119     NOT_TERMINATED    = db.lookupIntConstant("JavaThread::_not_terminated").intValue();
120     EXITING           = db.lookupIntConstant("JavaThread::_thread_exiting").intValue();
121 
122   }
123 
124   public JavaThread(Address addr) {
125     super(addr);
126   }
127 
128   void setThreadPDAccess(JavaThreadPDAccess access) {
129     this.access = access;
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       Address addr = getAddress().addOffsetTo(threadObjFieldOffset);
360       VMOopHandle vmOopHandle = VMObjectFactory.newObject(VMOopHandle.class, addr);
361       obj = vmOopHandle.resolve();
362     } catch (Exception e) {
363       e.printStackTrace();
364     }
365     return obj;
366   }
367 
368   /** Get the Java-side name of this thread */
369   public String getThreadName() {
370     Oop threadObj = getThreadObj();
371     if (threadObj == null) {
372         return "<null>";
373     }
374     return OopUtilities.threadOopGetName(threadObj);
375   }
376 
377   //
378   // Oop traversal
379   //
380 
381   public void oopsDo(AddressVisitor oopVisitor) {
382     super.oopsDo(oopVisitor);
383 
384     // FIXME: add in the rest of the routine from the VM
385 
386     // Traverse the execution stack
387     for(StackFrameStream fst = new StackFrameStream(this); !fst.isDone(); fst.next()) {
388       fst.getCurrent().oopsDo(oopVisitor, fst.getRegisterMap());
389     }
390   }
391 
392   public boolean isInStack(Address a) {
393     if (Assert.ASSERTS_ENABLED) {
394       Assert.that(VM.getVM().isDebugging(), "Not yet implemented for non-debugging system");
395     }
396     Address sp      = lastSPDbg();
397     Address stackBase = getStackBase();
398     // Be robust
399     if (sp == null) return false;
400     return stackBase.greaterThan(a) && sp.lessThanOrEqual(a);
401   }
402 
403   public boolean isLockOwned(OopHandle obj) {
404     Address current = addr.getAddressAt(lockStackCurrentOffset);
405     Address base = addr.getAddressAt(lockStackBaseOffset);
406     while (base.lessThan(current)) {
407       Address oop = base.getAddressAt(0);
408       if (oop.equals(obj)) {
409         return true;
410       }
411       base = base.addOffsetTo(oopPtrSize);
412     }
413     return false;
414   }
415 
416   public boolean isLockOwned(Address a) {
417     Address stackBase = getStackBase();
418     Address stackLimit = stackBase.addOffsetTo(-getStackSize());
419 
420     return stackBase.greaterThan(a) && stackLimit.lessThanOrEqual(a);
421 
422     // FIXME: should traverse MonitorArray/MonitorChunks as in VM
423   }
424 
425   public Oop getCurrentParkBlocker() {
426     Oop threadObj = getThreadObj();
427     if (threadObj != null) {
428       return OopUtilities.threadOopGetParkBlocker(threadObj);
429     }
430     return null;
431   }
432 
433   public void printInfoOn(PrintStream tty) {
434 
435     tty.println("State: " + getThreadState().toString());
436     // Attempt to figure out the addresses covered by Java frames.
437     // NOTE: we should make this a method and let the Stackwalk panel use the result too.
438     //
439     sun.jvm.hotspot.runtime.Frame tmpFrame = getCurrentFrameGuess();
440     if (tmpFrame != null ) {
441       Address sp = tmpFrame.getSP();
442       Address maxSP = sp;
443       Address minSP = sp;
444       RegisterMap tmpMap = newRegisterMap(false);
445       while ((tmpFrame != null) && (!tmpFrame.isFirstFrame())) {
446           tmpFrame = tmpFrame.sender(tmpMap);
447           if (tmpFrame != null) {
448             sp = tmpFrame.getSP();
449             maxSP = AddressOps.max(maxSP, sp);
450             minSP = AddressOps.min(minSP, sp);
451           }
452       }
453       tty.println("Stack in use by Java: " + minSP + " .. " + maxSP);
454     } else {
455       tty.println("No Java frames present");
456     }
457     tty.println("Base of Stack: " + getStackBase());
458     tty.println("Last_Java_SP: " + getLastJavaSP());
459     tty.println("Last_Java_FP: " + getLastJavaFP());
460     tty.println("Last_Java_PC: " + getLastJavaPC());
461     // More stuff like saved_execption_pc, safepoint_state, ...
462     access.printInfoOn(addr, tty);
463 
464   }
465 
466   ///////////////////////////////
467   //                           //
468   // FIXME: add more accessors //
469   //                           //
470   ///////////////////////////////
471 
472   //--------------------------------------------------------------------------------
473   // Internals only below this point
474   //
475 
476   private Frame cookLastFrame(Frame fr) {
477     if (fr == null) {
478       return null;
479     }
480 
481     Address pc        = fr.getPC();
482 
483     if (Assert.ASSERTS_ENABLED) {
484       if (pc == null) {
485         Assert.that(VM.getVM().isDebugging(), "must have PC");
486       }
487     }
488     return fr;
489   }
490 
491   public Address lastSPDbg() {
492     return access.getLastSP(addr);
493   }
494 
495 
496   public void printThreadInfoOn(PrintStream out){
497     Oop threadOop = this.getThreadObj();
498 
499     out.print("\"");
500     out.print(this.getThreadName());
501     out.print("\" #");
502     out.print(OopUtilities.threadOopGetTID(threadOop));
503     if(OopUtilities.threadOopGetDaemon(threadOop)){
504       out.print(" daemon");
505     }
506     out.print(" prio=");
507     out.print(OopUtilities.threadOopGetPriority(threadOop));
508     out.print(" tid=");
509     out.print(this.getAddress());
510     out.print(" nid=");
511     out.print(String.format("0x%x ",this.getOSThread().threadId()));
512     out.print(getOSThread().getThreadState().getPrintVal());
513     out.print(" [");
514     if(this.getLastJavaSP() == null){
515       out.print(String.format(ADDRESS_FORMAT,0L));
516     } else {
517       out.print(this.getLastJavaSP().andWithMask(~0xFFF));
518     }
519     out.println("]");
520     out.print("   java.lang.Thread.State: ");
521     out.println(OopUtilities.threadOopGetThreadStatusName(threadOop));
522     out.print("   JavaThread state: _thread_");
523     out.println(this.getThreadState().toString().toLowerCase());
524   }
525 }