0
|
1 /*
|
|
2 * Copyright 2000-2005 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
|
20 * CA 95054 USA or visit www.sun.com if you need additional information or
|
|
21 * have any 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
|
|
52 private static JavaThreadPDAccess access;
|
|
53
|
|
54 // JavaThreadStates read from underlying process
|
|
55 private static int UNINITIALIZED;
|
|
56 private static int NEW;
|
|
57 private static int NEW_TRANS;
|
|
58 private static int IN_NATIVE;
|
|
59 private static int IN_NATIVE_TRANS;
|
|
60 private static int IN_VM;
|
|
61 private static int IN_VM_TRANS;
|
|
62 private static int IN_JAVA;
|
|
63 private static int IN_JAVA_TRANS;
|
|
64 private static int BLOCKED;
|
|
65 private static int BLOCKED_TRANS;
|
|
66
|
|
67 static {
|
|
68 VM.registerVMInitializedObserver(new Observer() {
|
|
69 public void update(Observable o, Object data) {
|
|
70 initialize(VM.getVM().getTypeDataBase());
|
|
71 }
|
|
72 });
|
|
73 }
|
|
74
|
|
75 private static synchronized void initialize(TypeDataBase db) {
|
|
76 Type type = db.lookupType("JavaThread");
|
|
77 Type anchorType = db.lookupType("JavaFrameAnchor");
|
|
78
|
|
79 nextField = type.getAddressField("_next");
|
|
80 threadObjField = type.getOopField("_threadObj");
|
|
81 anchorField = type.getAddressField("_anchor");
|
|
82 lastJavaSPField = anchorType.getAddressField("_last_Java_sp");
|
|
83 lastJavaPCField = anchorType.getAddressField("_last_Java_pc");
|
|
84 threadStateField = type.getCIntegerField("_thread_state");
|
|
85 osThreadField = type.getAddressField("_osthread");
|
|
86
|
|
87 UNINITIALIZED = db.lookupIntConstant("_thread_uninitialized").intValue();
|
|
88 NEW = db.lookupIntConstant("_thread_new").intValue();
|
|
89 NEW_TRANS = db.lookupIntConstant("_thread_new_trans").intValue();
|
|
90 IN_NATIVE = db.lookupIntConstant("_thread_in_native").intValue();
|
|
91 IN_NATIVE_TRANS = db.lookupIntConstant("_thread_in_native_trans").intValue();
|
|
92 IN_VM = db.lookupIntConstant("_thread_in_vm").intValue();
|
|
93 IN_VM_TRANS = db.lookupIntConstant("_thread_in_vm_trans").intValue();
|
|
94 IN_JAVA = db.lookupIntConstant("_thread_in_Java").intValue();
|
|
95 IN_JAVA_TRANS = db.lookupIntConstant("_thread_in_Java_trans").intValue();
|
|
96 BLOCKED = db.lookupIntConstant("_thread_blocked").intValue();
|
|
97 BLOCKED_TRANS = db.lookupIntConstant("_thread_blocked_trans").intValue();
|
|
98 }
|
|
99
|
|
100 public JavaThread(Address addr) {
|
|
101 super(addr);
|
|
102 }
|
|
103
|
|
104 void setThreadPDAccess(JavaThreadPDAccess access) {
|
|
105 this.access = access;
|
|
106 }
|
|
107
|
|
108 public JavaThread next() {
|
|
109 Address threadAddr = nextField.getValue(addr);
|
|
110 if (threadAddr == null) {
|
|
111 return null;
|
|
112 }
|
|
113
|
|
114 return VM.getVM().getThreads().createJavaThreadWrapper(threadAddr);
|
|
115 }
|
|
116
|
|
117 /** NOTE: for convenience, this differs in definition from the
|
|
118 underlying VM. Only "pure" JavaThreads return true;
|
|
119 CompilerThreads and JVMDIDebuggerThreads return false. FIXME:
|
|
120 consider encapsulating platform-specific functionality in an
|
|
121 object instead of using inheritance (which is the primary reason
|
|
122 we can't traverse CompilerThreads, etc; didn't want to have, for
|
|
123 example, "SolarisSPARCCompilerThread".) */
|
|
124 public boolean isJavaThread() { return true; }
|
|
125
|
|
126 public static AddressField getAnchorField() { return anchorField; }
|
|
127
|
|
128 /** Get the last Java stack pointer */
|
|
129 public Address getLastJavaSP() {
|
|
130 Address sp = lastJavaSPField.getValue(addr.addOffsetTo(anchorField.getOffset()));
|
|
131 return sp;
|
|
132 }
|
|
133
|
|
134 public Address getLastJavaPC() {
|
|
135 Address pc = lastJavaPCField.getValue(addr.addOffsetTo(anchorField.getOffset()));
|
|
136 return pc;
|
|
137 }
|
|
138
|
|
139 /** Abstract accessor to last Java frame pointer, implemented by
|
|
140 OS/CPU-specific JavaThread implementation. May return null if
|
|
141 there is no frame pointer or if it is not necessary on this
|
|
142 platform. */
|
|
143 public Address getLastJavaFP(){
|
|
144 return access.getLastJavaFP(addr);
|
|
145 }
|
|
146
|
|
147 /** Abstract accessor to last Java pc, implemented by
|
|
148 OS/CPU-specific JavaThread implementation. May return null if
|
|
149 there is no frame pointer or if it is not necessary on this
|
|
150 platform. */
|
|
151
|
|
152 /*
|
|
153 public Address getLastJavaPC(){
|
|
154 return access.getLastJavaPC(addr);
|
|
155 }
|
|
156 */
|
|
157
|
|
158 // FIXME: not yet implementable
|
|
159 // public abstract void setLastJavaFP(Address fp);
|
|
160
|
|
161 /** A stack pointer older than any java frame stack pointer. Only
|
|
162 needed on some platforms; for example, see
|
|
163 thread_solaris_sparc.hpp. */
|
|
164 public Address getBaseOfStackPointer(){
|
|
165 return access.getBaseOfStackPointer(addr);
|
|
166 }
|
|
167 // FIXME: not yet implementable
|
|
168 // public abstract void setBaseOfStackPointer(Address fp);
|
|
169
|
|
170 /** Tells whether the last Java frame is set */
|
|
171 public boolean hasLastJavaFrame() {
|
|
172 return (getLastJavaSP() != null);
|
|
173 }
|
|
174
|
|
175 /** Accessing frames */
|
|
176 public Frame getLastFrame() {
|
|
177 // FIXME: would need to implement runtime routine
|
|
178 // "cacheStatePD(boolean)" for reflective system to be able to
|
|
179 // flush register windows on SPARC
|
|
180 return cookLastFrame(getLastFramePD());
|
|
181 }
|
|
182
|
|
183 /** Internal routine implemented by platform-dependent subclasses */
|
|
184 protected Frame getLastFramePD(){
|
|
185 return access.getLastFramePD(this, addr);
|
|
186 }
|
|
187
|
|
188 /** Accessing frames. Returns the last Java VFrame or null if none
|
|
189 was present. (NOTE that this is mostly unusable in a debugging
|
|
190 system; see getLastJavaVFrameDbg, below, which provides very
|
|
191 different functionality.) */
|
|
192 public JavaVFrame getLastJavaVFrame(RegisterMap regMap) {
|
|
193 if (Assert.ASSERTS_ENABLED) {
|
|
194 Assert.that(regMap != null, "a map must be given");
|
|
195 }
|
|
196 Frame f = getLastFrame();
|
|
197 if (f == null) {
|
|
198 return null;
|
|
199 }
|
|
200 for (VFrame vf = VFrame.newVFrame(f, regMap, this); vf != null; vf = vf.sender()) {
|
|
201 if (vf.isJavaFrame()) {
|
|
202 return (JavaVFrame) vf;
|
|
203 }
|
|
204 }
|
|
205 return null;
|
|
206 }
|
|
207
|
|
208 /** This should only be used by a debugger. Uses the current frame
|
|
209 guess to attempt to get the topmost JavaVFrame.
|
|
210 (getLastJavaVFrame, as a port of the VM's routine, assumes the
|
|
211 VM is at a safepoint.) */
|
|
212 public JavaVFrame getLastJavaVFrameDbg() {
|
|
213 RegisterMap regMap = newRegisterMap(true);
|
|
214 sun.jvm.hotspot.runtime.Frame f = getCurrentFrameGuess();
|
|
215 if (f == null) return null;
|
|
216 boolean imprecise = true;
|
|
217 if (f.isInterpretedFrame() && !f.isInterpretedFrameValid()) {
|
|
218 if (DEBUG) {
|
|
219 System.out.println("Correcting for invalid interpreter frame");
|
|
220 }
|
|
221 f = f.sender(regMap);
|
|
222 imprecise = false;
|
|
223 }
|
|
224 VFrame vf = VFrame.newVFrame(f, regMap, this, true, imprecise);
|
|
225 if (vf == null) {
|
|
226 if (DEBUG) {
|
|
227 System.out.println(" (Unable to create vframe for topmost frame guess)");
|
|
228 }
|
|
229 return null;
|
|
230 }
|
|
231 if (vf.isJavaFrame()) {
|
|
232 return (JavaVFrame) vf;
|
|
233 }
|
|
234 return (JavaVFrame) vf.javaSender();
|
|
235 }
|
|
236
|
|
237 /** In this system, a JavaThread is the top-level factory for a
|
|
238 RegisterMap, since the JavaThread implementation is already
|
|
239 platform-specific and RegisterMap is also necessarily
|
|
240 platform-specific. The updateMap argument indicates whether the
|
|
241 register map needs to be updated, for example during stack
|
|
242 traversal -- see frame.hpp. */
|
|
243 public RegisterMap newRegisterMap(boolean updateMap){
|
|
244 return access.newRegisterMap(this, updateMap);
|
|
245 }
|
|
246
|
|
247 /** This is only designed to be used by the debugging system.
|
|
248 Returns a "best guess" of the topmost frame on the stack. This
|
|
249 guess should be as "raw" as possible. For example, if the
|
|
250 topmost frame is an interpreter frame (the return PC is in the
|
|
251 interpreter) but is not a valid frame (i.e., the BCI has not yet
|
|
252 been set up) this should still return the topmost frame and not
|
|
253 the sender. Validity checks are done at higher levels. */
|
|
254 public Frame getCurrentFrameGuess(){
|
|
255 return access.getCurrentFrameGuess(this, addr);
|
|
256 }
|
|
257
|
|
258 /** Also only intended for use by the debugging system. Provides the
|
|
259 same effect of OSThread::print(); that is, prints a value which
|
|
260 allows the user to intuitively understand which native OS thread
|
|
261 maps to this Java thread. Does not print a newline or leading or
|
|
262 trailing spaces. */
|
|
263 public void printThreadIDOn(PrintStream tty) {
|
|
264 access.printThreadIDOn(addr,tty);
|
|
265 }
|
|
266
|
|
267 public void printThreadID() {
|
|
268 printThreadIDOn(System.out);
|
|
269 }
|
|
270
|
|
271 public ThreadProxy getThreadProxy() {
|
|
272 return access.getThreadProxy(addr);
|
|
273 }
|
|
274
|
|
275 //
|
|
276 // Safepoint support
|
|
277 //
|
|
278
|
|
279 public JavaThreadState getThreadState() {
|
|
280 int val = (int) threadStateField.getValue(addr);
|
|
281 if (val == UNINITIALIZED) {
|
|
282 return JavaThreadState.UNINITIALIZED;
|
|
283 } else if (val == NEW) {
|
|
284 return JavaThreadState.NEW;
|
|
285 } else if (val == NEW_TRANS) {
|
|
286 return JavaThreadState.NEW_TRANS;
|
|
287 } else if (val == IN_NATIVE) {
|
|
288 return JavaThreadState.IN_NATIVE;
|
|
289 } else if (val == IN_NATIVE_TRANS) {
|
|
290 return JavaThreadState.IN_NATIVE_TRANS;
|
|
291 } else if (val == IN_VM) {
|
|
292 return JavaThreadState.IN_VM;
|
|
293 } else if (val == IN_VM_TRANS) {
|
|
294 return JavaThreadState.IN_VM_TRANS;
|
|
295 } else if (val == IN_JAVA) {
|
|
296 return JavaThreadState.IN_JAVA;
|
|
297 } else if (val == IN_JAVA_TRANS) {
|
|
298 return JavaThreadState.IN_JAVA_TRANS;
|
|
299 } else if (val == BLOCKED) {
|
|
300 return JavaThreadState.BLOCKED;
|
|
301 } else if (val == BLOCKED_TRANS) {
|
|
302 return JavaThreadState.BLOCKED_TRANS;
|
|
303 } else {
|
|
304 throw new RuntimeException("Illegal thread state " + val);
|
|
305 }
|
|
306 }
|
|
307 // FIXME: not yet implementable
|
|
308 // public void setThreadState(JavaThreadState s);
|
|
309
|
|
310 //
|
|
311 // Miscellaneous operations
|
|
312 //
|
|
313
|
|
314 public OSThread getOSThread() {
|
|
315 return (OSThread) VMObjectFactory.newObject(OSThread.class, osThreadField.getValue(addr));
|
|
316 }
|
|
317
|
|
318 /** Gets the Java-side thread object for this JavaThread */
|
|
319 public Oop getThreadObj() {
|
|
320 return VM.getVM().getObjectHeap().newOop(threadObjField.getValue(addr));
|
|
321 }
|
|
322
|
|
323 /** Get the Java-side name of this thread */
|
|
324 public String getThreadName() {
|
|
325 Oop threadObj = getThreadObj();
|
|
326 if (threadObj == null) {
|
|
327 return "<null>";
|
|
328 }
|
|
329 return OopUtilities.threadOopGetName(threadObj);
|
|
330 }
|
|
331
|
|
332 //
|
|
333 // Oop traversal
|
|
334 //
|
|
335
|
|
336 public void oopsDo(AddressVisitor oopVisitor) {
|
|
337 super.oopsDo(oopVisitor);
|
|
338
|
|
339 // FIXME: add in the rest of the routine from the VM
|
|
340
|
|
341 // Traverse the execution stack
|
|
342 for(StackFrameStream fst = new StackFrameStream(this); !fst.isDone(); fst.next()) {
|
|
343 fst.getCurrent().oopsDo(oopVisitor, fst.getRegisterMap());
|
|
344 }
|
|
345 }
|
|
346
|
|
347 public boolean isInStack(Address a) {
|
|
348 if (Assert.ASSERTS_ENABLED) {
|
|
349 Assert.that(VM.getVM().isDebugging(), "Not yet implemented for non-debugging system");
|
|
350 }
|
|
351 Address highest = highestLock();
|
|
352 Address sp = lastSPDbg();
|
|
353 // Be robust
|
|
354 if ((highest == null) || (sp == null)) return false;
|
|
355 return (highest.greaterThanOrEqual(a) && sp.lessThanOrEqual(a));
|
|
356
|
|
357 // FIXME: should traverse MonitorArray/MonitorChunks as in VM
|
|
358 }
|
|
359
|
|
360 public Oop getCurrentParkBlocker() {
|
|
361 Oop threadObj = getThreadObj();
|
|
362 if (threadObj != null) {
|
|
363 return OopUtilities.threadOopGetParkBlocker(threadObj);
|
|
364 }
|
|
365 return null;
|
|
366 }
|
|
367
|
|
368 public void printInfoOn(PrintStream tty) {
|
|
369
|
|
370 tty.println("State: " + getThreadState().toString());
|
|
371 // Attempt to figure out the addresses covered by Java frames.
|
|
372 // NOTE: we should make this a method and let the Stackwalk panel use the result too.
|
|
373 //
|
|
374 sun.jvm.hotspot.runtime.Frame tmpFrame = getCurrentFrameGuess();
|
|
375 if (tmpFrame != null ) {
|
|
376 Address sp = tmpFrame.getSP();
|
|
377 Address maxSP = sp;
|
|
378 Address minSP = sp;
|
|
379 RegisterMap tmpMap = newRegisterMap(false);
|
|
380 while ((tmpFrame != null) && (!tmpFrame.isFirstFrame())) {
|
|
381 tmpFrame = tmpFrame.sender(tmpMap);
|
|
382 if (tmpFrame != null) {
|
|
383 sp = tmpFrame.getSP();
|
|
384 maxSP = AddressOps.max(maxSP, sp);
|
|
385 minSP = AddressOps.min(minSP, sp);
|
|
386 }
|
|
387 }
|
|
388 tty.println("Stack in use by Java: " + minSP + " .. " + maxSP);
|
|
389 } else {
|
|
390 tty.println("No Java frames present");
|
|
391 }
|
|
392 tty.println("Base of Stack: " + getBaseOfStackPointer());
|
|
393 tty.println("Last_Java_SP: " + getLastJavaSP());
|
|
394 tty.println("Last_Java_FP: " + getLastJavaFP());
|
|
395 tty.println("Last_Java_PC: " + getLastJavaPC());
|
|
396 // More stuff like saved_execption_pc, safepoint_state, ...
|
|
397 access.printInfoOn(addr, tty);
|
|
398
|
|
399 }
|
|
400
|
|
401 ///////////////////////////////
|
|
402 // //
|
|
403 // FIXME: add more accessors //
|
|
404 // //
|
|
405 ///////////////////////////////
|
|
406
|
|
407 //--------------------------------------------------------------------------------
|
|
408 // Internals only below this point
|
|
409 //
|
|
410
|
|
411 private Frame cookLastFrame(Frame fr) {
|
|
412 if (fr == null) {
|
|
413 return null;
|
|
414 }
|
|
415
|
|
416 Address pc = fr.getPC();
|
|
417
|
|
418 if (Assert.ASSERTS_ENABLED) {
|
|
419 if (pc == null) {
|
|
420 Assert.that(VM.getVM().isDebugging(), "must have PC");
|
|
421 }
|
|
422 }
|
|
423 return fr;
|
|
424 }
|
|
425
|
|
426 private Address lastSPDbg() {
|
|
427 return access.getLastSP(addr);
|
|
428 }
|
|
429
|
|
430 }
|