Path: blob/master/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/JavaThread.java
41161 views
/*1* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324package sun.jvm.hotspot.runtime;2526import java.io.*;27import java.util.*;28import sun.jvm.hotspot.debugger.*;29import sun.jvm.hotspot.oops.*;30import sun.jvm.hotspot.types.*;31import sun.jvm.hotspot.utilities.*;32import sun.jvm.hotspot.utilities.Observable;33import sun.jvm.hotspot.utilities.Observer;3435/** This is an abstract class because there are certain OS- and36CPU-specific operations (like the setting and getting of the last37Java frame pointer) which need to be factored out. These38operations are implemented by, for example,39SolarisSPARCJavaThread, and the concrete subclasses are40instantiated by the JavaThreadFactory in the Threads class. */4142public class JavaThread extends Thread {43private static final boolean DEBUG = System.getProperty("sun.jvm.hotspot.runtime.JavaThread.DEBUG") != null;4445private static long threadObjFieldOffset;46private static AddressField anchorField;47private static AddressField lastJavaSPField;48private static AddressField lastJavaPCField;49private static CIntegerField threadStateField;50private static AddressField osThreadField;51private static AddressField stackBaseField;52private static CIntegerField stackSizeField;53private static CIntegerField terminatedField;5455private static JavaThreadPDAccess access;5657// JavaThreadStates read from underlying process58private static int UNINITIALIZED;59private static int NEW;60private static int NEW_TRANS;61private static int IN_NATIVE;62private static int IN_NATIVE_TRANS;63private static int IN_VM;64private static int IN_VM_TRANS;65private static int IN_JAVA;66private static int IN_JAVA_TRANS;67private static int BLOCKED;68private static int BLOCKED_TRANS;6970private static int NOT_TERMINATED;71private static int EXITING;7273private static final String ADDRESS_FORMAT = VM.getVM().isLP64() ? "0x%016x" : "0x%08x";7475static {76VM.registerVMInitializedObserver(new Observer() {77public void update(Observable o, Object data) {78initialize(VM.getVM().getTypeDataBase());79}80});81}8283private static synchronized void initialize(TypeDataBase db) {84Type type = db.lookupType("JavaThread");85Type anchorType = db.lookupType("JavaFrameAnchor");8687threadObjFieldOffset = type.getField("_threadObj").getOffset();8889anchorField = type.getAddressField("_anchor");90lastJavaSPField = anchorType.getAddressField("_last_Java_sp");91lastJavaPCField = anchorType.getAddressField("_last_Java_pc");92threadStateField = type.getCIntegerField("_thread_state");93osThreadField = type.getAddressField("_osthread");94stackBaseField = type.getAddressField("_stack_base");95stackSizeField = type.getCIntegerField("_stack_size");96terminatedField = type.getCIntegerField("_terminated");9798UNINITIALIZED = db.lookupIntConstant("_thread_uninitialized").intValue();99NEW = db.lookupIntConstant("_thread_new").intValue();100NEW_TRANS = db.lookupIntConstant("_thread_new_trans").intValue();101IN_NATIVE = db.lookupIntConstant("_thread_in_native").intValue();102IN_NATIVE_TRANS = db.lookupIntConstant("_thread_in_native_trans").intValue();103IN_VM = db.lookupIntConstant("_thread_in_vm").intValue();104IN_VM_TRANS = db.lookupIntConstant("_thread_in_vm_trans").intValue();105IN_JAVA = db.lookupIntConstant("_thread_in_Java").intValue();106IN_JAVA_TRANS = db.lookupIntConstant("_thread_in_Java_trans").intValue();107BLOCKED = db.lookupIntConstant("_thread_blocked").intValue();108BLOCKED_TRANS = db.lookupIntConstant("_thread_blocked_trans").intValue();109110NOT_TERMINATED = db.lookupIntConstant("JavaThread::_not_terminated").intValue();111EXITING = db.lookupIntConstant("JavaThread::_thread_exiting").intValue();112113}114115public JavaThread(Address addr) {116super(addr);117}118119void setThreadPDAccess(JavaThreadPDAccess access) {120this.access = access;121}122123/** NOTE: for convenience, this differs in definition from the underlying VM.124Only "pure" JavaThreads return true; CompilerThreads, the CodeCacheSweeperThread,125JVMDIDebuggerThreads return false.126FIXME:127consider encapsulating platform-specific functionality in an128object instead of using inheritance (which is the primary reason129we can't traverse CompilerThreads, etc; didn't want to have, for130example, "SolarisSPARCCompilerThread".) */131public boolean isJavaThread() { return true; }132133public boolean isExiting () {134return (getTerminated() == EXITING) || isTerminated();135}136137public boolean isTerminated() {138return (getTerminated() != NOT_TERMINATED) && (getTerminated() != EXITING);139}140141public static AddressField getAnchorField() { return anchorField; }142143/** Get the last Java stack pointer */144public Address getLastJavaSP() {145Address sp = lastJavaSPField.getValue(addr.addOffsetTo(anchorField.getOffset()));146return sp;147}148149public Address getLastJavaPC() {150Address pc = lastJavaPCField.getValue(addr.addOffsetTo(anchorField.getOffset()));151return pc;152}153154/** Abstract accessor to last Java frame pointer, implemented by155OS/CPU-specific JavaThread implementation. May return null if156there is no frame pointer or if it is not necessary on this157platform. */158public Address getLastJavaFP(){159return access.getLastJavaFP(addr);160}161162/** Abstract accessor to last Java pc, implemented by163OS/CPU-specific JavaThread implementation. May return null if164there is no frame pointer or if it is not necessary on this165platform. */166167/*168public Address getLastJavaPC(){169return access.getLastJavaPC(addr);170}171*/172173// FIXME: not yet implementable174// public abstract void setLastJavaFP(Address fp);175176/** A stack pointer older than any java frame stack pointer. Only177needed on some platforms; for example, see178thread_solaris_sparc.hpp. */179public Address getBaseOfStackPointer(){180return access.getBaseOfStackPointer(addr);181}182// FIXME: not yet implementable183// public abstract void setBaseOfStackPointer(Address fp);184185/** Tells whether the last Java frame is set */186public boolean hasLastJavaFrame() {187return (getLastJavaSP() != null);188}189190/** Accessing frames */191public Frame getLastFrame() {192// FIXME: would need to implement runtime routine193// "cacheStatePD(boolean)" for reflective system to be able to194// flush register windows on SPARC195return cookLastFrame(getLastFramePD());196}197198/** Internal routine implemented by platform-dependent subclasses */199protected Frame getLastFramePD(){200return access.getLastFramePD(this, addr);201}202203/** Accessing frames. Returns the last Java VFrame or null if none204was present. (NOTE that this is mostly unusable in a debugging205system; see getLastJavaVFrameDbg, below, which provides very206different functionality.) */207public JavaVFrame getLastJavaVFrame(RegisterMap regMap) {208if (Assert.ASSERTS_ENABLED) {209Assert.that(regMap != null, "a map must be given");210}211Frame f = getLastFrame();212if (f == null) {213return null;214}215for (VFrame vf = VFrame.newVFrame(f, regMap, this); vf != null; vf = vf.sender()) {216if (vf.isJavaFrame()) {217return (JavaVFrame) vf;218}219}220return null;221}222223/** This should only be used by a debugger. Uses the current frame224guess to attempt to get the topmost JavaVFrame.225(getLastJavaVFrame, as a port of the VM's routine, assumes the226VM is at a safepoint.) */227public JavaVFrame getLastJavaVFrameDbg() {228RegisterMap regMap = newRegisterMap(true);229sun.jvm.hotspot.runtime.Frame f = getCurrentFrameGuess();230if (f == null) return null;231boolean imprecise = true;232if (f.isInterpretedFrame() && !f.isInterpretedFrameValid()) {233if (DEBUG) {234System.out.println("Correcting for invalid interpreter frame");235}236f = f.sender(regMap);237imprecise = false;238}239VFrame vf = VFrame.newVFrame(f, regMap, this, true, imprecise);240if (vf == null) {241if (DEBUG) {242System.out.println(" (Unable to create vframe for topmost frame guess)");243}244return null;245}246return vf.isJavaFrame() ? (JavaVFrame)vf : vf.javaSender();247}248249/** In this system, a JavaThread is the top-level factory for a250RegisterMap, since the JavaThread implementation is already251platform-specific and RegisterMap is also necessarily252platform-specific. The updateMap argument indicates whether the253register map needs to be updated, for example during stack254traversal -- see frame.hpp. */255public RegisterMap newRegisterMap(boolean updateMap){256return access.newRegisterMap(this, updateMap);257}258259/** This is only designed to be used by the debugging system.260Returns a "best guess" of the topmost frame on the stack. This261guess should be as "raw" as possible. For example, if the262topmost frame is an interpreter frame (the return PC is in the263interpreter) but is not a valid frame (i.e., the BCI has not yet264been set up) this should still return the topmost frame and not265the sender. Validity checks are done at higher levels. */266public Frame getCurrentFrameGuess(){267return access.getCurrentFrameGuess(this, addr);268}269270/** Also only intended for use by the debugging system. Provides the271same effect of OSThread::print(); that is, prints a value which272allows the user to intuitively understand which native OS thread273maps to this Java thread. Does not print a newline or leading or274trailing spaces. */275public void printThreadIDOn(PrintStream tty) {276access.printThreadIDOn(addr,tty);277}278279public void printThreadID() {280printThreadIDOn(System.out);281}282283public ThreadProxy getThreadProxy() {284return access.getThreadProxy(addr);285}286287//288// Safepoint support289//290291public JavaThreadState getThreadState() {292int val = (int) threadStateField.getValue(addr);293if (val == UNINITIALIZED) {294return JavaThreadState.UNINITIALIZED;295} else if (val == NEW) {296return JavaThreadState.NEW;297} else if (val == NEW_TRANS) {298return JavaThreadState.NEW_TRANS;299} else if (val == IN_NATIVE) {300return JavaThreadState.IN_NATIVE;301} else if (val == IN_NATIVE_TRANS) {302return JavaThreadState.IN_NATIVE_TRANS;303} else if (val == IN_VM) {304return JavaThreadState.IN_VM;305} else if (val == IN_VM_TRANS) {306return JavaThreadState.IN_VM_TRANS;307} else if (val == IN_JAVA) {308return JavaThreadState.IN_JAVA;309} else if (val == IN_JAVA_TRANS) {310return JavaThreadState.IN_JAVA_TRANS;311} else if (val == BLOCKED) {312return JavaThreadState.BLOCKED;313} else if (val == BLOCKED_TRANS) {314return JavaThreadState.BLOCKED_TRANS;315} else {316throw new RuntimeException("Illegal thread state " + val);317}318}319// FIXME: not yet implementable320// public void setThreadState(JavaThreadState s);321322//323// Miscellaneous operations324//325326public OSThread getOSThread() {327return (OSThread) VMObjectFactory.newObject(OSThread.class, osThreadField.getValue(addr));328}329330public Address getStackBase() {331return stackBaseField.getValue(addr);332}333334public long getStackBaseValue() {335return VM.getVM().getAddressValue(getStackBase());336}337338public long getStackSize() {339return stackSizeField.getValue(addr);340}341342public int getTerminated() {343return (int) terminatedField.getValue(addr);344}345346/** Gets the Java-side thread object for this JavaThread */347public Oop getThreadObj() {348Oop obj = null;349try {350Address addr = getAddress().addOffsetTo(threadObjFieldOffset);351VMOopHandle vmOopHandle = VMObjectFactory.newObject(VMOopHandle.class, addr);352obj = vmOopHandle.resolve();353} catch (Exception e) {354e.printStackTrace();355}356return obj;357}358359/** Get the Java-side name of this thread */360public String getThreadName() {361Oop threadObj = getThreadObj();362if (threadObj == null) {363return "<null>";364}365return OopUtilities.threadOopGetName(threadObj);366}367368//369// Oop traversal370//371372public void oopsDo(AddressVisitor oopVisitor) {373super.oopsDo(oopVisitor);374375// FIXME: add in the rest of the routine from the VM376377// Traverse the execution stack378for(StackFrameStream fst = new StackFrameStream(this); !fst.isDone(); fst.next()) {379fst.getCurrent().oopsDo(oopVisitor, fst.getRegisterMap());380}381}382383public boolean isInStack(Address a) {384if (Assert.ASSERTS_ENABLED) {385Assert.that(VM.getVM().isDebugging(), "Not yet implemented for non-debugging system");386}387Address sp = lastSPDbg();388Address stackBase = getStackBase();389// Be robust390if (sp == null) return false;391return stackBase.greaterThan(a) && sp.lessThanOrEqual(a);392}393394public boolean isLockOwned(Address a) {395Address stackBase = getStackBase();396Address stackLimit = stackBase.addOffsetTo(-getStackSize());397398return stackBase.greaterThan(a) && stackLimit.lessThanOrEqual(a);399400// FIXME: should traverse MonitorArray/MonitorChunks as in VM401}402403public Oop getCurrentParkBlocker() {404Oop threadObj = getThreadObj();405if (threadObj != null) {406return OopUtilities.threadOopGetParkBlocker(threadObj);407}408return null;409}410411public void printInfoOn(PrintStream tty) {412413tty.println("State: " + getThreadState().toString());414// Attempt to figure out the addresses covered by Java frames.415// NOTE: we should make this a method and let the Stackwalk panel use the result too.416//417sun.jvm.hotspot.runtime.Frame tmpFrame = getCurrentFrameGuess();418if (tmpFrame != null ) {419Address sp = tmpFrame.getSP();420Address maxSP = sp;421Address minSP = sp;422RegisterMap tmpMap = newRegisterMap(false);423while ((tmpFrame != null) && (!tmpFrame.isFirstFrame())) {424tmpFrame = tmpFrame.sender(tmpMap);425if (tmpFrame != null) {426sp = tmpFrame.getSP();427maxSP = AddressOps.max(maxSP, sp);428minSP = AddressOps.min(minSP, sp);429}430}431tty.println("Stack in use by Java: " + minSP + " .. " + maxSP);432} else {433tty.println("No Java frames present");434}435tty.println("Base of Stack: " + getStackBase());436tty.println("Last_Java_SP: " + getLastJavaSP());437tty.println("Last_Java_FP: " + getLastJavaFP());438tty.println("Last_Java_PC: " + getLastJavaPC());439// More stuff like saved_execption_pc, safepoint_state, ...440access.printInfoOn(addr, tty);441442}443444///////////////////////////////445// //446// FIXME: add more accessors //447// //448///////////////////////////////449450//--------------------------------------------------------------------------------451// Internals only below this point452//453454private Frame cookLastFrame(Frame fr) {455if (fr == null) {456return null;457}458459Address pc = fr.getPC();460461if (Assert.ASSERTS_ENABLED) {462if (pc == null) {463Assert.that(VM.getVM().isDebugging(), "must have PC");464}465}466return fr;467}468469public Address lastSPDbg() {470return access.getLastSP(addr);471}472473474public void printThreadInfoOn(PrintStream out){475Oop threadOop = this.getThreadObj();476477out.print("\"");478out.print(this.getThreadName());479out.print("\" #");480out.print(OopUtilities.threadOopGetTID(threadOop));481if(OopUtilities.threadOopGetDaemon(threadOop)){482out.print(" daemon");483}484out.print(" prio=");485out.print(OopUtilities.threadOopGetPriority(threadOop));486out.print(" tid=");487out.print(this.getAddress());488out.print(" nid=");489out.print(String.format("0x%x ",this.getOSThread().threadId()));490out.print(getOSThread().getThreadState().getPrintVal());491out.print(" [");492if(this.getLastJavaSP() == null){493out.print(String.format(ADDRESS_FORMAT,0L));494} else {495out.print(this.getLastJavaSP().andWithMask(~0xFFF));496}497out.println("]");498out.print(" java.lang.Thread.State: ");499out.println(OopUtilities.threadOopGetThreadStatusName(threadOop));500out.print(" JavaThread state: _thread_");501out.println(this.getThreadState().toString().toLowerCase());502}503}504505506