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