1 /* 2 * Copyright (c) 2000, 2011, 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.util.concurrent.locks.AbstractOwnableSynchronizer fields 78 private static OopField absOwnSyncOwnerThreadField; 79 80 static { 81 VM.registerVMInitializedObserver(new Observer() { 82 public void update(Observable o, Object data) { 83 initialize(VM.getVM().getTypeDataBase()); 84 } 85 }); 86 } 87 88 private static synchronized void initialize(TypeDataBase db) { 89 // FIXME: don't need this observer; however, do need a VM resumed 90 // and suspended observer to refetch fields 91 } 92 93 public static String charArrayToString(TypeArray charArray) { 94 if (charArray == null) { 95 return null; 96 } 97 return charArrayToString(charArray, 0, (int) charArray.getLength()); 98 } 99 100 public static String charArrayToString(TypeArray charArray, int offset, int length) { 101 if (charArray == null) { 102 return null; 103 } 104 final int limit = offset + length; 105 if (Assert.ASSERTS_ENABLED) { 106 Assert.that(offset >= 0 && limit <= charArray.getLength(), "out of bounds"); 107 } 108 StringBuffer buf = new StringBuffer(length); 109 for (int i = offset; i < limit; i++) { 110 buf.append(charArray.getCharAt(i)); 111 } 112 return buf.toString(); 113 } 114 115 public static String stringOopToString(Oop stringOop) { 116 if (offsetField == null) { 117 InstanceKlass k = (InstanceKlass) stringOop.getKlass(); 118 offsetField = (IntField) k.findField("offset", "I"); 119 countField = (IntField) k.findField("count", "I"); 120 valueField = (OopField) k.findField("value", "[C"); 121 if (Assert.ASSERTS_ENABLED) { 122 Assert.that(offsetField != null && 123 countField != null && 124 valueField != null, "must find all java.lang.String fields"); 125 } 126 } 127 return charArrayToString((TypeArray) valueField.getValue(stringOop), 128 offsetField.getValue(stringOop), 129 countField.getValue(stringOop)); 130 } 131 132 private static void initThreadGroupFields() { 133 if (threadGroupParentField == null) { 134 SystemDictionary sysDict = VM.getVM().getSystemDictionary(); 135 InstanceKlass k = sysDict.getThreadGroupKlass(); 136 threadGroupParentField = (OopField) k.findField("parent", "Ljava/lang/ThreadGroup;"); 137 threadGroupNameField = (OopField) k.findField("name", "Ljava/lang/String;"); 138 threadGroupNThreadsField = (IntField) k.findField("nthreads", "I"); 139 threadGroupThreadsField = (OopField) k.findField("threads", "[Ljava/lang/Thread;"); 140 threadGroupNGroupsField = (IntField) k.findField("ngroups", "I"); 141 threadGroupGroupsField = (OopField) k.findField("groups", "[Ljava/lang/ThreadGroup;"); 142 if (Assert.ASSERTS_ENABLED) { 143 Assert.that(threadGroupParentField != null && 144 threadGroupNameField != null && 145 threadGroupNThreadsField != null && 146 threadGroupThreadsField != null && 147 threadGroupNGroupsField != null && 148 threadGroupGroupsField != null, "must find all java.lang.ThreadGroup fields"); 149 } 150 } 151 } 152 153 public static Oop threadGroupOopGetParent(Oop threadGroupOop) { 154 initThreadGroupFields(); 155 return threadGroupParentField.getValue(threadGroupOop); 156 } 157 158 public static String threadGroupOopGetName(Oop threadGroupOop) { 159 initThreadGroupFields(); 160 return stringOopToString(threadGroupNameField.getValue(threadGroupOop)); 161 } 162 163 public static Oop[] threadGroupOopGetThreads(Oop threadGroupOop) { 164 initThreadGroupFields(); 165 int nthreads = threadGroupNThreadsField.getValue(threadGroupOop); 166 Oop[] result = new Oop[nthreads]; 167 ObjArray threads = (ObjArray) threadGroupThreadsField.getValue(threadGroupOop); 168 for (int i = 0; i < nthreads; i++) { 169 result[i] = threads.getObjAt(i); 170 } 171 return result; 172 } 173 174 public static Oop[] threadGroupOopGetGroups(Oop threadGroupOop) { 175 initThreadGroupFields(); 176 int ngroups = threadGroupNGroupsField.getValue(threadGroupOop); 177 Oop[] result = new Oop[ngroups]; 178 ObjArray groups = (ObjArray) threadGroupGroupsField.getValue(threadGroupOop); 179 for (int i = 0; i < ngroups; i++) { 180 result[i] = groups.getObjAt(i); 181 } 182 return result; 183 } 184 185 private static void initThreadFields() { 186 if (threadNameField == null) { 187 SystemDictionary sysDict = VM.getVM().getSystemDictionary(); 188 InstanceKlass k = sysDict.getThreadKlass(); 189 threadNameField = (OopField) k.findField("name", "[C"); 190 threadGroupField = (OopField) k.findField("group", "Ljava/lang/ThreadGroup;"); 191 threadEETopField = (LongField) k.findField("eetop", "J"); 192 threadStatusField = (IntField) k.findField("threadStatus", "I"); 193 threadParkBlockerField = (OopField) k.findField("parkBlocker", 194 "Ljava/lang/Object;"); 195 TypeDataBase db = VM.getVM().getTypeDataBase(); 196 THREAD_STATUS_NEW = db.lookupIntConstant("java_lang_Thread::NEW").intValue(); 197 /* 198 Other enum constants are not needed as of now. Uncomment these as and when needed. 199 200 THREAD_STATUS_RUNNABLE = db.lookupIntConstant("java_lang_Thread::RUNNABLE").intValue(); 201 THREAD_STATUS_SLEEPING = db.lookupIntConstant("java_lang_Thread::SLEEPING").intValue(); 202 THREAD_STATUS_IN_OBJECT_WAIT = db.lookupIntConstant("java_lang_Thread::IN_OBJECT_WAIT").intValue(); 203 THREAD_STATUS_IN_OBJECT_WAIT_TIMED = db.lookupIntConstant("java_lang_Thread::IN_OBJECT_WAIT_TIMED").intValue(); 204 THREAD_STATUS_PARKED = db.lookupIntConstant("java_lang_Thread::PARKED").intValue(); 205 THREAD_STATUS_PARKED_TIMED = db.lookupIntConstant("java_lang_Thread::PARKED_TIMED").intValue(); 206 THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER = db.lookupIntConstant("java_lang_Thread::BLOCKED_ON_MONITOR_ENTER").intValue(); 207 THREAD_STATUS_TERMINATED = db.lookupIntConstant("java_lang_Thread::TERMINATED").intValue(); 208 */ 209 210 if (Assert.ASSERTS_ENABLED) { 211 // it is okay to miss threadStatusField, because this was 212 // introduced only in 1.5 JDK. 213 Assert.that(threadNameField != null && 214 threadGroupField != null && 215 threadEETopField != null, "must find all java.lang.Thread fields"); 216 } 217 } 218 } 219 220 public static Oop threadOopGetThreadGroup(Oop threadOop) { 221 initThreadFields(); 222 return threadGroupField.getValue(threadOop); 223 } 224 225 public static String threadOopGetName(Oop threadOop) { 226 initThreadFields(); 227 return charArrayToString((TypeArray) threadNameField.getValue(threadOop)); 228 } 229 230 /** May return null if, e.g., thread was not started */ 231 public static JavaThread threadOopGetJavaThread(Oop threadOop) { 232 initThreadFields(); 233 Address addr = threadOop.getHandle().getAddressAt(threadEETopField.getOffset()); 234 if (addr == null) { 235 return null; 236 } 237 return VM.getVM().getThreads().createJavaThreadWrapper(addr); 238 } 239 240 /** returns value of java.lang.Thread.threadStatus field */ 241 public static int threadOopGetThreadStatus(Oop threadOop) { 242 initThreadFields(); 243 // The threadStatus is only present starting in 1.5 244 if (threadStatusField != null) { 245 return (int) threadStatusField.getValue(threadOop); 246 } else { 247 // All we can easily figure out is if it is alive, but that is 248 // enough info for a valid unknown status. 249 JavaThread thr = threadOopGetJavaThread(threadOop); 250 if (thr == null) { 251 // the thread hasn't run yet or is in the process of exiting 252 return THREAD_STATUS_NEW; 253 } else { 254 return JVMTI_THREAD_STATE_ALIVE; 255 } 256 } 257 } 258 259 /** returns value of java.lang.Thread.parkBlocker field */ 260 public static Oop threadOopGetParkBlocker(Oop threadOop) { 261 initThreadFields(); 262 if (threadParkBlockerField != null) { 263 return threadParkBlockerField.getValue(threadOop); 264 } 265 return null; 266 } 267 268 // initialize fields for j.u.c.l AbstractOwnableSynchornizer class 269 private static void initAbsOwnSyncFields() { 270 if (absOwnSyncOwnerThreadField == null) { 271 SystemDictionary sysDict = VM.getVM().getSystemDictionary(); 272 InstanceKlass k = sysDict.getAbstractOwnableSynchronizerKlass(); 273 absOwnSyncOwnerThreadField = 274 (OopField) k.findField("exclusiveOwnerThread", 275 "Ljava/lang/Thread;"); 276 } 277 } 278 279 // return exclusiveOwnerThread field of AbstractOwnableSynchronizer class 280 public static Oop abstractOwnableSynchronizerGetOwnerThread(Oop oop) { 281 initAbsOwnSyncFields(); 282 if (absOwnSyncOwnerThreadField == null) { 283 return null; // pre-1.6 VM? 284 } else { 285 return absOwnSyncOwnerThreadField.getValue(oop); 286 } 287 } 288 }