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.oops;
|
|
26
|
|
27 import java.util.*;
|
|
28
|
|
29 import sun.jvm.hotspot.debugger.*;
|
|
30 import sun.jvm.hotspot.memory.*;
|
|
31 import sun.jvm.hotspot.runtime.*;
|
|
32 import sun.jvm.hotspot.types.TypeDataBase;
|
|
33 import sun.jvm.hotspot.utilities.*;
|
|
34 import sun.jvm.hotspot.jdi.JVMTIThreadState;
|
|
35
|
|
36 /** A utility class encapsulating useful oop operations */
|
|
37
|
|
38 public class OopUtilities implements /* imports */ JVMTIThreadState {
|
|
39
|
|
40 // FIXME: access should be synchronized and cleared when VM is
|
|
41 // resumed
|
|
42 // String fields
|
|
43 private static IntField offsetField;
|
|
44 private static IntField countField;
|
|
45 private static OopField valueField;
|
|
46 // ThreadGroup fields
|
|
47 private static OopField threadGroupParentField;
|
|
48 private static OopField threadGroupNameField;
|
|
49 private static IntField threadGroupNThreadsField;
|
|
50 private static OopField threadGroupThreadsField;
|
|
51 private static IntField threadGroupNGroupsField;
|
|
52 private static OopField threadGroupGroupsField;
|
|
53 // Thread fields
|
|
54 private static OopField threadNameField;
|
|
55 private static OopField threadGroupField;
|
|
56 private static LongField threadEETopField;
|
|
57 // threadStatus field is new since 1.5
|
|
58 private static IntField threadStatusField;
|
|
59 // parkBlocker field is new since 1.6
|
|
60 private static OopField threadParkBlockerField;
|
|
61
|
|
62 // possible values of java_lang_Thread::ThreadStatus
|
|
63 private static int THREAD_STATUS_NEW;
|
|
64 /*
|
|
65 Other enum constants are not needed as of now. Uncomment these as and when needed.
|
|
66
|
|
67 private static int THREAD_STATUS_RUNNABLE;
|
|
68 private static int THREAD_STATUS_SLEEPING;
|
|
69 private static int THREAD_STATUS_IN_OBJECT_WAIT;
|
|
70 private static int THREAD_STATUS_IN_OBJECT_WAIT_TIMED;
|
|
71 private static int THREAD_STATUS_PARKED;
|
|
72 private static int THREAD_STATUS_PARKED_TIMED;
|
|
73 private static int THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER;
|
|
74 private static int THREAD_STATUS_TERMINATED;
|
|
75 */
|
|
76
|
|
77 // java.lang.Class fields
|
|
78 private static OopField hcKlassField;
|
|
79
|
|
80 // java.util.concurrent.locks.AbstractOwnableSynchronizer fields
|
|
81 private static OopField absOwnSyncOwnerThreadField;
|
|
82
|
|
83 static {
|
|
84 VM.registerVMInitializedObserver(new Observer() {
|
|
85 public void update(Observable o, Object data) {
|
|
86 initialize(VM.getVM().getTypeDataBase());
|
|
87 }
|
|
88 });
|
|
89 }
|
|
90
|
|
91 private static synchronized void initialize(TypeDataBase db) {
|
|
92 // FIXME: don't need this observer; however, do need a VM resumed
|
|
93 // and suspended observer to refetch fields
|
|
94 }
|
|
95
|
|
96 public static String charArrayToString(TypeArray charArray) {
|
|
97 if (charArray == null) {
|
|
98 return null;
|
|
99 }
|
|
100 return charArrayToString(charArray, 0, (int) charArray.getLength());
|
|
101 }
|
|
102
|
|
103 public static String charArrayToString(TypeArray charArray, int offset, int length) {
|
|
104 if (charArray == null) {
|
|
105 return null;
|
|
106 }
|
|
107 final int limit = offset + length;
|
|
108 if (Assert.ASSERTS_ENABLED) {
|
|
109 Assert.that(offset >= 0 && limit <= charArray.getLength(), "out of bounds");
|
|
110 }
|
|
111 StringBuffer buf = new StringBuffer(length);
|
|
112 for (int i = offset; i < limit; i++) {
|
|
113 buf.append(charArray.getCharAt(i));
|
|
114 }
|
|
115 return buf.toString();
|
|
116 }
|
|
117
|
|
118 public static String stringOopToString(Oop stringOop) {
|
|
119 if (offsetField == null) {
|
|
120 InstanceKlass k = (InstanceKlass) stringOop.getKlass();
|
|
121 offsetField = (IntField) k.findField("offset", "I");
|
|
122 countField = (IntField) k.findField("count", "I");
|
|
123 valueField = (OopField) k.findField("value", "[C");
|
|
124 if (Assert.ASSERTS_ENABLED) {
|
|
125 Assert.that(offsetField != null &&
|
|
126 countField != null &&
|
|
127 valueField != null, "must find all java.lang.String fields");
|
|
128 }
|
|
129 }
|
|
130 return charArrayToString((TypeArray) valueField.getValue(stringOop),
|
|
131 offsetField.getValue(stringOop),
|
|
132 countField.getValue(stringOop));
|
|
133 }
|
|
134
|
|
135 private static void initThreadGroupFields() {
|
|
136 if (threadGroupParentField == null) {
|
|
137 SystemDictionary sysDict = VM.getVM().getSystemDictionary();
|
|
138 InstanceKlass k = sysDict.getThreadGroupKlass();
|
|
139 threadGroupParentField = (OopField) k.findField("parent", "Ljava/lang/ThreadGroup;");
|
|
140 threadGroupNameField = (OopField) k.findField("name", "Ljava/lang/String;");
|
|
141 threadGroupNThreadsField = (IntField) k.findField("nthreads", "I");
|
|
142 threadGroupThreadsField = (OopField) k.findField("threads", "[Ljava/lang/Thread;");
|
|
143 threadGroupNGroupsField = (IntField) k.findField("ngroups", "I");
|
|
144 threadGroupGroupsField = (OopField) k.findField("groups", "[Ljava/lang/ThreadGroup;");
|
|
145 if (Assert.ASSERTS_ENABLED) {
|
|
146 Assert.that(threadGroupParentField != null &&
|
|
147 threadGroupNameField != null &&
|
|
148 threadGroupNThreadsField != null &&
|
|
149 threadGroupThreadsField != null &&
|
|
150 threadGroupNGroupsField != null &&
|
|
151 threadGroupGroupsField != null, "must find all java.lang.ThreadGroup fields");
|
|
152 }
|
|
153 }
|
|
154 }
|
|
155
|
|
156 public static Oop threadGroupOopGetParent(Oop threadGroupOop) {
|
|
157 initThreadGroupFields();
|
|
158 return threadGroupParentField.getValue(threadGroupOop);
|
|
159 }
|
|
160
|
|
161 public static String threadGroupOopGetName(Oop threadGroupOop) {
|
|
162 initThreadGroupFields();
|
|
163 return stringOopToString(threadGroupNameField.getValue(threadGroupOop));
|
|
164 }
|
|
165
|
|
166 public static Oop[] threadGroupOopGetThreads(Oop threadGroupOop) {
|
|
167 initThreadGroupFields();
|
|
168 int nthreads = threadGroupNThreadsField.getValue(threadGroupOop);
|
|
169 Oop[] result = new Oop[nthreads];
|
|
170 ObjArray threads = (ObjArray) threadGroupThreadsField.getValue(threadGroupOop);
|
|
171 for (int i = 0; i < nthreads; i++) {
|
|
172 result[i] = threads.getObjAt(i);
|
|
173 }
|
|
174 return result;
|
|
175 }
|
|
176
|
|
177 public static Oop[] threadGroupOopGetGroups(Oop threadGroupOop) {
|
|
178 initThreadGroupFields();
|
|
179 int ngroups = threadGroupNGroupsField.getValue(threadGroupOop);
|
|
180 Oop[] result = new Oop[ngroups];
|
|
181 ObjArray groups = (ObjArray) threadGroupGroupsField.getValue(threadGroupOop);
|
|
182 for (int i = 0; i < ngroups; i++) {
|
|
183 result[i] = groups.getObjAt(i);
|
|
184 }
|
|
185 return result;
|
|
186 }
|
|
187
|
|
188 private static void initThreadFields() {
|
|
189 if (threadNameField == null) {
|
|
190 SystemDictionary sysDict = VM.getVM().getSystemDictionary();
|
|
191 InstanceKlass k = sysDict.getThreadKlass();
|
|
192 threadNameField = (OopField) k.findField("name", "[C");
|
|
193 threadGroupField = (OopField) k.findField("group", "Ljava/lang/ThreadGroup;");
|
|
194 threadEETopField = (LongField) k.findField("eetop", "J");
|
|
195 threadStatusField = (IntField) k.findField("threadStatus", "I");
|
|
196 threadParkBlockerField = (OopField) k.findField("parkBlocker",
|
|
197 "Ljava/lang/Object;");
|
|
198 TypeDataBase db = VM.getVM().getTypeDataBase();
|
|
199 THREAD_STATUS_NEW = db.lookupIntConstant("java_lang_Thread::NEW").intValue();
|
|
200 /*
|
|
201 Other enum constants are not needed as of now. Uncomment these as and when needed.
|
|
202
|
|
203 THREAD_STATUS_RUNNABLE = db.lookupIntConstant("java_lang_Thread::RUNNABLE").intValue();
|
|
204 THREAD_STATUS_SLEEPING = db.lookupIntConstant("java_lang_Thread::SLEEPING").intValue();
|
|
205 THREAD_STATUS_IN_OBJECT_WAIT = db.lookupIntConstant("java_lang_Thread::IN_OBJECT_WAIT").intValue();
|
|
206 THREAD_STATUS_IN_OBJECT_WAIT_TIMED = db.lookupIntConstant("java_lang_Thread::IN_OBJECT_WAIT_TIMED").intValue();
|
|
207 THREAD_STATUS_PARKED = db.lookupIntConstant("java_lang_Thread::PARKED").intValue();
|
|
208 THREAD_STATUS_PARKED_TIMED = db.lookupIntConstant("java_lang_Thread::PARKED_TIMED").intValue();
|
|
209 THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER = db.lookupIntConstant("java_lang_Thread::BLOCKED_ON_MONITOR_ENTER").intValue();
|
|
210 THREAD_STATUS_TERMINATED = db.lookupIntConstant("java_lang_Thread::TERMINATED").intValue();
|
|
211 */
|
|
212
|
|
213 if (Assert.ASSERTS_ENABLED) {
|
|
214 // it is okay to miss threadStatusField, because this was
|
|
215 // introduced only in 1.5 JDK.
|
|
216 Assert.that(threadNameField != null &&
|
|
217 threadGroupField != null &&
|
|
218 threadEETopField != null, "must find all java.lang.Thread fields");
|
|
219 }
|
|
220 }
|
|
221 }
|
|
222
|
|
223 public static Oop threadOopGetThreadGroup(Oop threadOop) {
|
|
224 initThreadFields();
|
|
225 return threadGroupField.getValue(threadOop);
|
|
226 }
|
|
227
|
|
228 public static String threadOopGetName(Oop threadOop) {
|
|
229 initThreadFields();
|
|
230 return charArrayToString((TypeArray) threadNameField.getValue(threadOop));
|
|
231 }
|
|
232
|
|
233 /** May return null if, e.g., thread was not started */
|
|
234 public static JavaThread threadOopGetJavaThread(Oop threadOop) {
|
|
235 initThreadFields();
|
|
236 Address addr = threadOop.getHandle().getAddressAt(threadEETopField.getOffset());
|
|
237 if (addr == null) {
|
|
238 return null;
|
|
239 }
|
|
240 return VM.getVM().getThreads().createJavaThreadWrapper(addr);
|
|
241 }
|
|
242
|
|
243 /** returns value of java.lang.Thread.threadStatus field */
|
|
244 public static int threadOopGetThreadStatus(Oop threadOop) {
|
|
245 initThreadFields();
|
|
246 // The threadStatus is only present starting in 1.5
|
|
247 if (threadStatusField != null) {
|
|
248 return (int) threadStatusField.getValue(threadOop);
|
|
249 } else {
|
|
250 // All we can easily figure out is if it is alive, but that is
|
|
251 // enough info for a valid unknown status.
|
|
252 JavaThread thr = threadOopGetJavaThread(threadOop);
|
|
253 if (thr == null) {
|
|
254 // the thread hasn't run yet or is in the process of exiting
|
|
255 return THREAD_STATUS_NEW;
|
|
256 } else {
|
|
257 return JVMTI_THREAD_STATE_ALIVE;
|
|
258 }
|
|
259 }
|
|
260 }
|
|
261
|
|
262 /** returns value of java.lang.Thread.parkBlocker field */
|
|
263 public static Oop threadOopGetParkBlocker(Oop threadOop) {
|
|
264 initThreadFields();
|
|
265 if (threadParkBlockerField != null) {
|
|
266 return threadParkBlockerField.getValue(threadOop);
|
|
267 }
|
|
268 return null;
|
|
269 }
|
|
270
|
|
271 // initialize fields for java.lang.Class
|
|
272 private static void initClassFields() {
|
|
273 if (hcKlassField == null) {
|
|
274 // hc_klass is a HotSpot magic field and hence we can't
|
|
275 // find it from InstanceKlass for java.lang.Class.
|
|
276 TypeDataBase db = VM.getVM().getTypeDataBase();
|
|
277 int hcKlassOffset = (int) Oop.getHeaderSize();
|
|
278 try {
|
|
279 hcKlassOffset += (db.lookupIntConstant("java_lang_Class::hc_klass_offset").intValue() *
|
|
280 db.getAddressSize());
|
|
281 } catch (RuntimeException re) {
|
|
282 // ignore, currently java_lang_Class::hc_klass_offset is zero
|
|
283 }
|
|
284
|
|
285 hcKlassField = new OopField(new NamedFieldIdentifier("hc_klass"), hcKlassOffset, true);
|
|
286 }
|
|
287 }
|
|
288
|
|
289 /** get klassOop field at offset hc_klass_offset from a java.lang.Class object */
|
|
290 public static Klass classOopToKlass(Oop aClass) {
|
|
291 initClassFields();
|
|
292 return (Klass) hcKlassField.getValue(aClass);
|
|
293 }
|
|
294
|
|
295 // initialize fields for j.u.c.l AbstractOwnableSynchornizer class
|
|
296 private static void initAbsOwnSyncFields() {
|
|
297 if (absOwnSyncOwnerThreadField == null) {
|
|
298 SystemDictionary sysDict = VM.getVM().getSystemDictionary();
|
|
299 InstanceKlass k = sysDict.getAbstractOwnableSynchronizerKlass();
|
|
300 absOwnSyncOwnerThreadField =
|
|
301 (OopField) k.findField("exclusiveOwnerThread",
|
|
302 "Ljava/lang/Thread;");
|
|
303 }
|
|
304 }
|
|
305
|
|
306 // return exclusiveOwnerThread field of AbstractOwnableSynchronizer class
|
|
307 public static Oop abstractOwnableSynchronizerGetOwnerThread(Oop oop) {
|
|
308 initAbsOwnSyncFields();
|
|
309 if (absOwnSyncOwnerThreadField == null) {
|
|
310 return null; // pre-1.6 VM?
|
|
311 } else {
|
|
312 return absOwnSyncOwnerThreadField.getValue(oop);
|
|
313 }
|
|
314 }
|
|
315 }
|