0N/A/*
3475N/A * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
0N/A * published by the Free Software Foundation.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
1472N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1472N/A * or visit www.oracle.com if you need additional information or have any
1472N/A * questions.
0N/A *
0N/A */
0N/A
0N/Apackage sun.jvm.hotspot.oops;
0N/A
0N/Aimport java.util.*;
0N/A
0N/Aimport sun.jvm.hotspot.debugger.*;
0N/Aimport sun.jvm.hotspot.memory.*;
0N/Aimport sun.jvm.hotspot.runtime.*;
0N/Aimport sun.jvm.hotspot.types.TypeDataBase;
0N/Aimport sun.jvm.hotspot.utilities.*;
0N/Aimport sun.jvm.hotspot.jdi.JVMTIThreadState;
0N/A
0N/A/** A utility class encapsulating useful oop operations */
0N/A
0N/Apublic class OopUtilities implements /* imports */ JVMTIThreadState {
0N/A
0N/A // FIXME: access should be synchronized and cleared when VM is
0N/A // resumed
0N/A // String fields
0N/A private static IntField offsetField;
0N/A private static IntField countField;
0N/A private static OopField valueField;
0N/A // ThreadGroup fields
0N/A private static OopField threadGroupParentField;
0N/A private static OopField threadGroupNameField;
0N/A private static IntField threadGroupNThreadsField;
0N/A private static OopField threadGroupThreadsField;
0N/A private static IntField threadGroupNGroupsField;
0N/A private static OopField threadGroupGroupsField;
0N/A // Thread fields
0N/A private static OopField threadNameField;
0N/A private static OopField threadGroupField;
0N/A private static LongField threadEETopField;
0N/A // threadStatus field is new since 1.5
0N/A private static IntField threadStatusField;
0N/A // parkBlocker field is new since 1.6
0N/A private static OopField threadParkBlockerField;
0N/A
0N/A // possible values of java_lang_Thread::ThreadStatus
0N/A private static int THREAD_STATUS_NEW;
0N/A /*
0N/A Other enum constants are not needed as of now. Uncomment these as and when needed.
0N/A
0N/A private static int THREAD_STATUS_RUNNABLE;
0N/A private static int THREAD_STATUS_SLEEPING;
0N/A private static int THREAD_STATUS_IN_OBJECT_WAIT;
0N/A private static int THREAD_STATUS_IN_OBJECT_WAIT_TIMED;
0N/A private static int THREAD_STATUS_PARKED;
0N/A private static int THREAD_STATUS_PARKED_TIMED;
0N/A private static int THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER;
0N/A private static int THREAD_STATUS_TERMINATED;
0N/A */
0N/A
0N/A // java.util.concurrent.locks.AbstractOwnableSynchronizer fields
0N/A private static OopField absOwnSyncOwnerThreadField;
0N/A
0N/A static {
0N/A VM.registerVMInitializedObserver(new Observer() {
0N/A public void update(Observable o, Object data) {
0N/A initialize(VM.getVM().getTypeDataBase());
0N/A }
0N/A });
0N/A }
0N/A
0N/A private static synchronized void initialize(TypeDataBase db) {
0N/A // FIXME: don't need this observer; however, do need a VM resumed
0N/A // and suspended observer to refetch fields
0N/A }
0N/A
0N/A public static String charArrayToString(TypeArray charArray) {
0N/A if (charArray == null) {
0N/A return null;
0N/A }
0N/A return charArrayToString(charArray, 0, (int) charArray.getLength());
0N/A }
0N/A
0N/A public static String charArrayToString(TypeArray charArray, int offset, int length) {
0N/A if (charArray == null) {
0N/A return null;
0N/A }
0N/A final int limit = offset + length;
0N/A if (Assert.ASSERTS_ENABLED) {
0N/A Assert.that(offset >= 0 && limit <= charArray.getLength(), "out of bounds");
0N/A }
0N/A StringBuffer buf = new StringBuffer(length);
0N/A for (int i = offset; i < limit; i++) {
0N/A buf.append(charArray.getCharAt(i));
0N/A }
0N/A return buf.toString();
0N/A }
0N/A
2772N/A public static String escapeString(String s) {
2772N/A StringBuilder sb = null;
2772N/A for (int index = 0; index < s.length(); index++) {
2772N/A char value = s.charAt(index);
2772N/A if (value >= 32 && value < 127 || value == '\'' || value == '\\') {
2772N/A if (sb != null) {
2772N/A sb.append(value);
2772N/A }
2772N/A } else {
2772N/A if (sb == null) {
2772N/A sb = new StringBuilder(s.length() * 2);
2772N/A sb.append(s, 0, index);
2772N/A }
2772N/A sb.append("\\u");
2772N/A if (value < 0x10) sb.append("000");
2772N/A else if (value < 0x100) sb.append("00");
2772N/A else if (value < 0x1000) sb.append("0");
2772N/A sb.append(Integer.toHexString(value));
2772N/A }
2772N/A }
2772N/A if (sb != null) {
2772N/A return sb.toString();
2772N/A }
2772N/A return s;
2772N/A }
2772N/A
0N/A public static String stringOopToString(Oop stringOop) {
0N/A if (offsetField == null) {
0N/A InstanceKlass k = (InstanceKlass) stringOop.getKlass();
3475N/A offsetField = (IntField) k.findField("offset", "I"); // optional
3475N/A countField = (IntField) k.findField("count", "I"); // optional
0N/A valueField = (OopField) k.findField("value", "[C");
0N/A if (Assert.ASSERTS_ENABLED) {
3475N/A Assert.that(valueField != null, "Field \'value\' of java.lang.String not found");
0N/A }
0N/A }
3475N/A if (offsetField != null && countField != null) {
3475N/A return charArrayToString((TypeArray) valueField.getValue(stringOop),
3475N/A offsetField.getValue(stringOop),
3475N/A countField.getValue(stringOop));
3475N/A }
3475N/A return charArrayToString((TypeArray) valueField.getValue(stringOop));
0N/A }
0N/A
2772N/A public static String stringOopToEscapedString(Oop stringOop) {
2772N/A return escapeString(stringOopToString(stringOop));
2772N/A }
2772N/A
0N/A private static void initThreadGroupFields() {
0N/A if (threadGroupParentField == null) {
0N/A SystemDictionary sysDict = VM.getVM().getSystemDictionary();
0N/A InstanceKlass k = sysDict.getThreadGroupKlass();
0N/A threadGroupParentField = (OopField) k.findField("parent", "Ljava/lang/ThreadGroup;");
0N/A threadGroupNameField = (OopField) k.findField("name", "Ljava/lang/String;");
0N/A threadGroupNThreadsField = (IntField) k.findField("nthreads", "I");
0N/A threadGroupThreadsField = (OopField) k.findField("threads", "[Ljava/lang/Thread;");
0N/A threadGroupNGroupsField = (IntField) k.findField("ngroups", "I");
0N/A threadGroupGroupsField = (OopField) k.findField("groups", "[Ljava/lang/ThreadGroup;");
0N/A if (Assert.ASSERTS_ENABLED) {
0N/A Assert.that(threadGroupParentField != null &&
0N/A threadGroupNameField != null &&
0N/A threadGroupNThreadsField != null &&
0N/A threadGroupThreadsField != null &&
0N/A threadGroupNGroupsField != null &&
0N/A threadGroupGroupsField != null, "must find all java.lang.ThreadGroup fields");
0N/A }
0N/A }
0N/A }
0N/A
0N/A public static Oop threadGroupOopGetParent(Oop threadGroupOop) {
0N/A initThreadGroupFields();
0N/A return threadGroupParentField.getValue(threadGroupOop);
0N/A }
0N/A
0N/A public static String threadGroupOopGetName(Oop threadGroupOop) {
0N/A initThreadGroupFields();
0N/A return stringOopToString(threadGroupNameField.getValue(threadGroupOop));
0N/A }
0N/A
0N/A public static Oop[] threadGroupOopGetThreads(Oop threadGroupOop) {
0N/A initThreadGroupFields();
0N/A int nthreads = threadGroupNThreadsField.getValue(threadGroupOop);
0N/A Oop[] result = new Oop[nthreads];
0N/A ObjArray threads = (ObjArray) threadGroupThreadsField.getValue(threadGroupOop);
0N/A for (int i = 0; i < nthreads; i++) {
0N/A result[i] = threads.getObjAt(i);
0N/A }
0N/A return result;
0N/A }
0N/A
0N/A public static Oop[] threadGroupOopGetGroups(Oop threadGroupOop) {
0N/A initThreadGroupFields();
0N/A int ngroups = threadGroupNGroupsField.getValue(threadGroupOop);
0N/A Oop[] result = new Oop[ngroups];
0N/A ObjArray groups = (ObjArray) threadGroupGroupsField.getValue(threadGroupOop);
0N/A for (int i = 0; i < ngroups; i++) {
0N/A result[i] = groups.getObjAt(i);
0N/A }
0N/A return result;
0N/A }
0N/A
0N/A private static void initThreadFields() {
0N/A if (threadNameField == null) {
0N/A SystemDictionary sysDict = VM.getVM().getSystemDictionary();
0N/A InstanceKlass k = sysDict.getThreadKlass();
0N/A threadNameField = (OopField) k.findField("name", "[C");
0N/A threadGroupField = (OopField) k.findField("group", "Ljava/lang/ThreadGroup;");
0N/A threadEETopField = (LongField) k.findField("eetop", "J");
0N/A threadStatusField = (IntField) k.findField("threadStatus", "I");
0N/A threadParkBlockerField = (OopField) k.findField("parkBlocker",
0N/A "Ljava/lang/Object;");
0N/A TypeDataBase db = VM.getVM().getTypeDataBase();
0N/A THREAD_STATUS_NEW = db.lookupIntConstant("java_lang_Thread::NEW").intValue();
0N/A /*
0N/A Other enum constants are not needed as of now. Uncomment these as and when needed.
0N/A
0N/A THREAD_STATUS_RUNNABLE = db.lookupIntConstant("java_lang_Thread::RUNNABLE").intValue();
0N/A THREAD_STATUS_SLEEPING = db.lookupIntConstant("java_lang_Thread::SLEEPING").intValue();
0N/A THREAD_STATUS_IN_OBJECT_WAIT = db.lookupIntConstant("java_lang_Thread::IN_OBJECT_WAIT").intValue();
0N/A THREAD_STATUS_IN_OBJECT_WAIT_TIMED = db.lookupIntConstant("java_lang_Thread::IN_OBJECT_WAIT_TIMED").intValue();
0N/A THREAD_STATUS_PARKED = db.lookupIntConstant("java_lang_Thread::PARKED").intValue();
0N/A THREAD_STATUS_PARKED_TIMED = db.lookupIntConstant("java_lang_Thread::PARKED_TIMED").intValue();
0N/A THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER = db.lookupIntConstant("java_lang_Thread::BLOCKED_ON_MONITOR_ENTER").intValue();
0N/A THREAD_STATUS_TERMINATED = db.lookupIntConstant("java_lang_Thread::TERMINATED").intValue();
0N/A */
0N/A
0N/A if (Assert.ASSERTS_ENABLED) {
0N/A // it is okay to miss threadStatusField, because this was
0N/A // introduced only in 1.5 JDK.
0N/A Assert.that(threadNameField != null &&
0N/A threadGroupField != null &&
0N/A threadEETopField != null, "must find all java.lang.Thread fields");
0N/A }
0N/A }
0N/A }
0N/A
0N/A public static Oop threadOopGetThreadGroup(Oop threadOop) {
0N/A initThreadFields();
0N/A return threadGroupField.getValue(threadOop);
0N/A }
0N/A
0N/A public static String threadOopGetName(Oop threadOop) {
0N/A initThreadFields();
0N/A return charArrayToString((TypeArray) threadNameField.getValue(threadOop));
0N/A }
0N/A
0N/A /** May return null if, e.g., thread was not started */
0N/A public static JavaThread threadOopGetJavaThread(Oop threadOop) {
0N/A initThreadFields();
0N/A Address addr = threadOop.getHandle().getAddressAt(threadEETopField.getOffset());
0N/A if (addr == null) {
0N/A return null;
0N/A }
0N/A return VM.getVM().getThreads().createJavaThreadWrapper(addr);
0N/A }
0N/A
0N/A /** returns value of java.lang.Thread.threadStatus field */
0N/A public static int threadOopGetThreadStatus(Oop threadOop) {
0N/A initThreadFields();
0N/A // The threadStatus is only present starting in 1.5
0N/A if (threadStatusField != null) {
0N/A return (int) threadStatusField.getValue(threadOop);
0N/A } else {
0N/A // All we can easily figure out is if it is alive, but that is
0N/A // enough info for a valid unknown status.
0N/A JavaThread thr = threadOopGetJavaThread(threadOop);
0N/A if (thr == null) {
0N/A // the thread hasn't run yet or is in the process of exiting
0N/A return THREAD_STATUS_NEW;
0N/A } else {
0N/A return JVMTI_THREAD_STATE_ALIVE;
0N/A }
0N/A }
0N/A }
0N/A
0N/A /** returns value of java.lang.Thread.parkBlocker field */
0N/A public static Oop threadOopGetParkBlocker(Oop threadOop) {
0N/A initThreadFields();
0N/A if (threadParkBlockerField != null) {
0N/A return threadParkBlockerField.getValue(threadOop);
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A // initialize fields for j.u.c.l AbstractOwnableSynchornizer class
0N/A private static void initAbsOwnSyncFields() {
0N/A if (absOwnSyncOwnerThreadField == null) {
0N/A SystemDictionary sysDict = VM.getVM().getSystemDictionary();
0N/A InstanceKlass k = sysDict.getAbstractOwnableSynchronizerKlass();
0N/A absOwnSyncOwnerThreadField =
0N/A (OopField) k.findField("exclusiveOwnerThread",
0N/A "Ljava/lang/Thread;");
0N/A }
0N/A }
0N/A
0N/A // return exclusiveOwnerThread field of AbstractOwnableSynchronizer class
0N/A public static Oop abstractOwnableSynchronizerGetOwnerThread(Oop oop) {
0N/A initAbsOwnSyncFields();
0N/A if (absOwnSyncOwnerThreadField == null) {
0N/A return null; // pre-1.6 VM?
0N/A } else {
0N/A return absOwnSyncOwnerThreadField.getValue(oop);
0N/A }
0N/A }
0N/A}