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