Mercurial > hg > truffle
comparison agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java @ 0:a61af66fc99e jdk7-b24
Initial load
author | duke |
---|---|
date | Sat, 01 Dec 2007 00:00:00 +0000 |
parents | |
children | a5838065ab24 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:a61af66fc99e |
---|---|
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 } |