1 /* 2 * Copyright (c) 2000, 2008, 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.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) db.lookupType("java_lang_Class").getCIntegerField("klass_offset").getValue(); 278 if (VM.getVM().isCompressedOopsEnabled()) { 279 hcKlassField = new NarrowOopField(new NamedFieldIdentifier("hc_klass"), hcKlassOffset, true); 280 } else { 281 hcKlassField = new OopField(new NamedFieldIdentifier("hc_klass"), hcKlassOffset, true); 282 } 283 } 284 } 285 286 /** get klassOop field at offset hc_klass_offset from a java.lang.Class object */ 287 public static Klass classOopToKlass(Oop aClass) { 288 initClassFields(); 289 return (Klass) hcKlassField.getValue(aClass); 290 } 291 292 // initialize fields for j.u.c.l AbstractOwnableSynchornizer class 293 private static void initAbsOwnSyncFields() { 294 if (absOwnSyncOwnerThreadField == null) { 295 SystemDictionary sysDict = VM.getVM().getSystemDictionary(); 296 InstanceKlass k = sysDict.getAbstractOwnableSynchronizerKlass(); 297 absOwnSyncOwnerThreadField = 298 (OopField) k.findField("exclusiveOwnerThread", 299 "Ljava/lang/Thread;"); 300 } 301 } 302 303 // return exclusiveOwnerThread field of AbstractOwnableSynchronizer class 304 public static Oop abstractOwnableSynchronizerGetOwnerThread(Oop oop) { 305 initAbsOwnSyncFields(); 306 if (absOwnSyncOwnerThreadField == null) { 307 return null; // pre-1.6 VM? 308 } else { 309 return absOwnSyncOwnerThreadField.getValue(oop); 310 } 311 } 312 }