Mercurial > hg > graal-jvmci-8
annotate agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java @ 218:a5838065ab24
6620329: jstack prints double native methods on Solaris/sparc
Summary: Fixed stack walking code in sparc to start frame walk from last_java_sp.
Reviewed-by: sgoldman
author | swamyv |
---|---|
date | Tue, 24 Jun 2008 21:37:10 -0700 |
parents | a61af66fc99e |
children | b9fba36710f2 |
rev | line source |
---|---|
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
a5838065ab24
6620329: jstack prints double native methods on Solaris/sparc
swamyv
parents:
0
diff
changeset
|
218 if (DEBUG) { |
a5838065ab24
6620329: jstack prints double native methods on Solaris/sparc
swamyv
parents:
0
diff
changeset
|
219 System.out.println("Correcting for invalid interpreter frame"); |
a5838065ab24
6620329: jstack prints double native methods on Solaris/sparc
swamyv
parents:
0
diff
changeset
|
220 } |
a5838065ab24
6620329: jstack prints double native methods on Solaris/sparc
swamyv
parents:
0
diff
changeset
|
221 f = f.sender(regMap); |
a5838065ab24
6620329: jstack prints double native methods on Solaris/sparc
swamyv
parents:
0
diff
changeset
|
222 imprecise = false; |
0 | 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 } | |
218
a5838065ab24
6620329: jstack prints double native methods on Solaris/sparc
swamyv
parents:
0
diff
changeset
|
231 return vf.isJavaFrame() ? (JavaVFrame)vf : vf.javaSender(); |
0 | 232 } |
233 | |
234 /** In this system, a JavaThread is the top-level factory for a | |
235 RegisterMap, since the JavaThread implementation is already | |
236 platform-specific and RegisterMap is also necessarily | |
237 platform-specific. The updateMap argument indicates whether the | |
238 register map needs to be updated, for example during stack | |
239 traversal -- see frame.hpp. */ | |
240 public RegisterMap newRegisterMap(boolean updateMap){ | |
241 return access.newRegisterMap(this, updateMap); | |
242 } | |
243 | |
244 /** This is only designed to be used by the debugging system. | |
245 Returns a "best guess" of the topmost frame on the stack. This | |
246 guess should be as "raw" as possible. For example, if the | |
247 topmost frame is an interpreter frame (the return PC is in the | |
248 interpreter) but is not a valid frame (i.e., the BCI has not yet | |
249 been set up) this should still return the topmost frame and not | |
250 the sender. Validity checks are done at higher levels. */ | |
251 public Frame getCurrentFrameGuess(){ | |
252 return access.getCurrentFrameGuess(this, addr); | |
253 } | |
254 | |
255 /** Also only intended for use by the debugging system. Provides the | |
256 same effect of OSThread::print(); that is, prints a value which | |
257 allows the user to intuitively understand which native OS thread | |
258 maps to this Java thread. Does not print a newline or leading or | |
259 trailing spaces. */ | |
260 public void printThreadIDOn(PrintStream tty) { | |
261 access.printThreadIDOn(addr,tty); | |
262 } | |
263 | |
264 public void printThreadID() { | |
265 printThreadIDOn(System.out); | |
266 } | |
267 | |
268 public ThreadProxy getThreadProxy() { | |
269 return access.getThreadProxy(addr); | |
270 } | |
271 | |
272 // | |
273 // Safepoint support | |
274 // | |
275 | |
276 public JavaThreadState getThreadState() { | |
277 int val = (int) threadStateField.getValue(addr); | |
278 if (val == UNINITIALIZED) { | |
279 return JavaThreadState.UNINITIALIZED; | |
280 } else if (val == NEW) { | |
281 return JavaThreadState.NEW; | |
282 } else if (val == NEW_TRANS) { | |
283 return JavaThreadState.NEW_TRANS; | |
284 } else if (val == IN_NATIVE) { | |
285 return JavaThreadState.IN_NATIVE; | |
286 } else if (val == IN_NATIVE_TRANS) { | |
287 return JavaThreadState.IN_NATIVE_TRANS; | |
288 } else if (val == IN_VM) { | |
289 return JavaThreadState.IN_VM; | |
290 } else if (val == IN_VM_TRANS) { | |
291 return JavaThreadState.IN_VM_TRANS; | |
292 } else if (val == IN_JAVA) { | |
293 return JavaThreadState.IN_JAVA; | |
294 } else if (val == IN_JAVA_TRANS) { | |
295 return JavaThreadState.IN_JAVA_TRANS; | |
296 } else if (val == BLOCKED) { | |
297 return JavaThreadState.BLOCKED; | |
298 } else if (val == BLOCKED_TRANS) { | |
299 return JavaThreadState.BLOCKED_TRANS; | |
300 } else { | |
301 throw new RuntimeException("Illegal thread state " + val); | |
302 } | |
303 } | |
304 // FIXME: not yet implementable | |
305 // public void setThreadState(JavaThreadState s); | |
306 | |
307 // | |
308 // Miscellaneous operations | |
309 // | |
310 | |
311 public OSThread getOSThread() { | |
312 return (OSThread) VMObjectFactory.newObject(OSThread.class, osThreadField.getValue(addr)); | |
313 } | |
314 | |
315 /** Gets the Java-side thread object for this JavaThread */ | |
316 public Oop getThreadObj() { | |
317 return VM.getVM().getObjectHeap().newOop(threadObjField.getValue(addr)); | |
318 } | |
319 | |
320 /** Get the Java-side name of this thread */ | |
321 public String getThreadName() { | |
322 Oop threadObj = getThreadObj(); | |
323 if (threadObj == null) { | |
324 return "<null>"; | |
325 } | |
326 return OopUtilities.threadOopGetName(threadObj); | |
327 } | |
328 | |
329 // | |
330 // Oop traversal | |
331 // | |
332 | |
333 public void oopsDo(AddressVisitor oopVisitor) { | |
334 super.oopsDo(oopVisitor); | |
335 | |
336 // FIXME: add in the rest of the routine from the VM | |
337 | |
338 // Traverse the execution stack | |
339 for(StackFrameStream fst = new StackFrameStream(this); !fst.isDone(); fst.next()) { | |
340 fst.getCurrent().oopsDo(oopVisitor, fst.getRegisterMap()); | |
341 } | |
342 } | |
343 | |
344 public boolean isInStack(Address a) { | |
345 if (Assert.ASSERTS_ENABLED) { | |
346 Assert.that(VM.getVM().isDebugging(), "Not yet implemented for non-debugging system"); | |
347 } | |
348 Address highest = highestLock(); | |
349 Address sp = lastSPDbg(); | |
350 // Be robust | |
351 if ((highest == null) || (sp == null)) return false; | |
352 return (highest.greaterThanOrEqual(a) && sp.lessThanOrEqual(a)); | |
353 | |
354 // FIXME: should traverse MonitorArray/MonitorChunks as in VM | |
355 } | |
356 | |
357 public Oop getCurrentParkBlocker() { | |
358 Oop threadObj = getThreadObj(); | |
359 if (threadObj != null) { | |
360 return OopUtilities.threadOopGetParkBlocker(threadObj); | |
361 } | |
362 return null; | |
363 } | |
364 | |
365 public void printInfoOn(PrintStream tty) { | |
366 | |
367 tty.println("State: " + getThreadState().toString()); | |
368 // Attempt to figure out the addresses covered by Java frames. | |
369 // NOTE: we should make this a method and let the Stackwalk panel use the result too. | |
370 // | |
371 sun.jvm.hotspot.runtime.Frame tmpFrame = getCurrentFrameGuess(); | |
372 if (tmpFrame != null ) { | |
373 Address sp = tmpFrame.getSP(); | |
374 Address maxSP = sp; | |
375 Address minSP = sp; | |
376 RegisterMap tmpMap = newRegisterMap(false); | |
377 while ((tmpFrame != null) && (!tmpFrame.isFirstFrame())) { | |
378 tmpFrame = tmpFrame.sender(tmpMap); | |
379 if (tmpFrame != null) { | |
380 sp = tmpFrame.getSP(); | |
381 maxSP = AddressOps.max(maxSP, sp); | |
382 minSP = AddressOps.min(minSP, sp); | |
383 } | |
384 } | |
385 tty.println("Stack in use by Java: " + minSP + " .. " + maxSP); | |
386 } else { | |
387 tty.println("No Java frames present"); | |
388 } | |
389 tty.println("Base of Stack: " + getBaseOfStackPointer()); | |
390 tty.println("Last_Java_SP: " + getLastJavaSP()); | |
391 tty.println("Last_Java_FP: " + getLastJavaFP()); | |
392 tty.println("Last_Java_PC: " + getLastJavaPC()); | |
393 // More stuff like saved_execption_pc, safepoint_state, ... | |
394 access.printInfoOn(addr, tty); | |
395 | |
396 } | |
397 | |
398 /////////////////////////////// | |
399 // // | |
400 // FIXME: add more accessors // | |
401 // // | |
402 /////////////////////////////// | |
403 | |
404 //-------------------------------------------------------------------------------- | |
405 // Internals only below this point | |
406 // | |
407 | |
408 private Frame cookLastFrame(Frame fr) { | |
409 if (fr == null) { | |
410 return null; | |
411 } | |
412 | |
413 Address pc = fr.getPC(); | |
414 | |
415 if (Assert.ASSERTS_ENABLED) { | |
416 if (pc == null) { | |
417 Assert.that(VM.getVM().isDebugging(), "must have PC"); | |
418 } | |
419 } | |
420 return fr; | |
421 } | |
422 | |
423 private Address lastSPDbg() { | |
424 return access.getLastSP(addr); | |
425 } | |
426 | |
427 } |