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