View Javadoc
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 }