Mercurial > hg > truffle
diff agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java @ 0:a61af66fc99e jdk7-b24
Initial load
author | duke |
---|---|
date | Sat, 01 Dec 2007 00:00:00 +0000 |
parents | |
children | ba764ed4b6f2 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java Sat Dec 01 00:00:00 2007 +0000 @@ -0,0 +1,881 @@ +/* + * Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +package sun.jvm.hotspot.oops; + +import java.io.*; +import java.util.*; +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.memory.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.types.*; +import sun.jvm.hotspot.utilities.*; + +// An InstanceKlass is the VM level representation of a Java class. + +public class InstanceKlass extends Klass { + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + // field offset constants + public static int ACCESS_FLAGS_OFFSET; + public static int NAME_INDEX_OFFSET; + public static int SIGNATURE_INDEX_OFFSET; + public static int INITVAL_INDEX_OFFSET; + public static int LOW_OFFSET; + public static int HIGH_OFFSET; + public static int GENERIC_SIGNATURE_INDEX_OFFSET; + public static int NEXT_OFFSET; + public static int IMPLEMENTORS_LIMIT; + + // ClassState constants + private static int CLASS_STATE_UNPARSABLE_BY_GC; + private static int CLASS_STATE_ALLOCATED; + private static int CLASS_STATE_LOADED; + private static int CLASS_STATE_LINKED; + private static int CLASS_STATE_BEING_INITIALIZED; + private static int CLASS_STATE_FULLY_INITIALIZED; + private static int CLASS_STATE_INITIALIZATION_ERROR; + + private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { + Type type = db.lookupType("instanceKlass"); + arrayKlasses = new OopField(type.getOopField("_array_klasses"), Oop.getHeaderSize()); + methods = new OopField(type.getOopField("_methods"), Oop.getHeaderSize()); + methodOrdering = new OopField(type.getOopField("_method_ordering"), Oop.getHeaderSize()); + localInterfaces = new OopField(type.getOopField("_local_interfaces"), Oop.getHeaderSize()); + transitiveInterfaces = new OopField(type.getOopField("_transitive_interfaces"), Oop.getHeaderSize()); + nofImplementors = new CIntField(type.getCIntegerField("_nof_implementors"), Oop.getHeaderSize()); + IMPLEMENTORS_LIMIT = db.lookupIntConstant("instanceKlass::implementors_limit").intValue(); + implementors = new OopField[IMPLEMENTORS_LIMIT]; + for (int i = 0; i < IMPLEMENTORS_LIMIT; i++) { + long arrayOffset = Oop.getHeaderSize() + (i * db.getAddressSize()); + implementors[i] = new OopField(type.getOopField("_implementors[0]"), arrayOffset); + } + fields = new OopField(type.getOopField("_fields"), Oop.getHeaderSize()); + constants = new OopField(type.getOopField("_constants"), Oop.getHeaderSize()); + classLoader = new OopField(type.getOopField("_class_loader"), Oop.getHeaderSize()); + protectionDomain = new OopField(type.getOopField("_protection_domain"), Oop.getHeaderSize()); + signers = new OopField(type.getOopField("_signers"), Oop.getHeaderSize()); + sourceFileName = new OopField(type.getOopField("_source_file_name"), Oop.getHeaderSize()); + sourceDebugExtension = new OopField(type.getOopField("_source_debug_extension"), Oop.getHeaderSize()); + innerClasses = new OopField(type.getOopField("_inner_classes"), Oop.getHeaderSize()); + nonstaticFieldSize = new CIntField(type.getCIntegerField("_nonstatic_field_size"), Oop.getHeaderSize()); + staticFieldSize = new CIntField(type.getCIntegerField("_static_field_size"), Oop.getHeaderSize()); + staticOopFieldSize = new CIntField(type.getCIntegerField("_static_oop_field_size"), Oop.getHeaderSize()); + nonstaticOopMapSize = new CIntField(type.getCIntegerField("_nonstatic_oop_map_size"), Oop.getHeaderSize()); + isMarkedDependent = new CIntField(type.getCIntegerField("_is_marked_dependent"), Oop.getHeaderSize()); + initState = new CIntField(type.getCIntegerField("_init_state"), Oop.getHeaderSize()); + vtableLen = new CIntField(type.getCIntegerField("_vtable_len"), Oop.getHeaderSize()); + itableLen = new CIntField(type.getCIntegerField("_itable_len"), Oop.getHeaderSize()); + breakpoints = type.getAddressField("_breakpoints"); + genericSignature = new OopField(type.getOopField("_generic_signature"), Oop.getHeaderSize()); + majorVersion = new CIntField(type.getCIntegerField("_major_version"), Oop.getHeaderSize()); + minorVersion = new CIntField(type.getCIntegerField("_minor_version"), Oop.getHeaderSize()); + headerSize = alignObjectOffset(Oop.getHeaderSize() + type.getSize()); + + // read field offset constants + ACCESS_FLAGS_OFFSET = db.lookupIntConstant("instanceKlass::access_flags_offset").intValue(); + NAME_INDEX_OFFSET = db.lookupIntConstant("instanceKlass::name_index_offset").intValue(); + SIGNATURE_INDEX_OFFSET = db.lookupIntConstant("instanceKlass::signature_index_offset").intValue(); + INITVAL_INDEX_OFFSET = db.lookupIntConstant("instanceKlass::initval_index_offset").intValue(); + LOW_OFFSET = db.lookupIntConstant("instanceKlass::low_offset").intValue(); + HIGH_OFFSET = db.lookupIntConstant("instanceKlass::high_offset").intValue(); + GENERIC_SIGNATURE_INDEX_OFFSET = db.lookupIntConstant("instanceKlass::generic_signature_offset").intValue(); + NEXT_OFFSET = db.lookupIntConstant("instanceKlass::next_offset").intValue(); + // read ClassState constants + CLASS_STATE_UNPARSABLE_BY_GC = db.lookupIntConstant("instanceKlass::unparsable_by_gc").intValue(); + CLASS_STATE_ALLOCATED = db.lookupIntConstant("instanceKlass::allocated").intValue(); + CLASS_STATE_LOADED = db.lookupIntConstant("instanceKlass::loaded").intValue(); + CLASS_STATE_LINKED = db.lookupIntConstant("instanceKlass::linked").intValue(); + CLASS_STATE_BEING_INITIALIZED = db.lookupIntConstant("instanceKlass::being_initialized").intValue(); + CLASS_STATE_FULLY_INITIALIZED = db.lookupIntConstant("instanceKlass::fully_initialized").intValue(); + CLASS_STATE_INITIALIZATION_ERROR = db.lookupIntConstant("instanceKlass::initialization_error").intValue(); + + } + + InstanceKlass(OopHandle handle, ObjectHeap heap) { + super(handle, heap); + } + + private static OopField arrayKlasses; + private static OopField methods; + private static OopField methodOrdering; + private static OopField localInterfaces; + private static OopField transitiveInterfaces; + private static CIntField nofImplementors; + private static OopField[] implementors; + private static OopField fields; + private static OopField constants; + private static OopField classLoader; + private static OopField protectionDomain; + private static OopField signers; + private static OopField sourceFileName; + private static OopField sourceDebugExtension; + private static OopField innerClasses; + private static CIntField nonstaticFieldSize; + private static CIntField staticFieldSize; + private static CIntField staticOopFieldSize; + private static CIntField nonstaticOopMapSize; + private static CIntField isMarkedDependent; + private static CIntField initState; + private static CIntField vtableLen; + private static CIntField itableLen; + private static AddressField breakpoints; + private static OopField genericSignature; + private static CIntField majorVersion; + private static CIntField minorVersion; + + // type safe enum for ClassState from instanceKlass.hpp + public static class ClassState { + public static final ClassState UNPARSABLE_BY_GC = new ClassState("unparsable_by_gc"); + public static final ClassState ALLOCATED = new ClassState("allocated"); + public static final ClassState LOADED = new ClassState("loaded"); + public static final ClassState LINKED = new ClassState("linked"); + public static final ClassState BEING_INITIALIZED = new ClassState("beingInitialized"); + public static final ClassState FULLY_INITIALIZED = new ClassState("fullyInitialized"); + public static final ClassState INITIALIZATION_ERROR = new ClassState("initializationError"); + + private ClassState(String value) { + this.value = value; + } + + public String toString() { + return value; + } + + private String value; + } + + private int getInitStateAsInt() { return (int) initState.getValue(this); } + public ClassState getInitState() { + int state = getInitStateAsInt(); + if (state == CLASS_STATE_UNPARSABLE_BY_GC) { + return ClassState.UNPARSABLE_BY_GC; + } else if (state == CLASS_STATE_ALLOCATED) { + return ClassState.ALLOCATED; + } else if (state == CLASS_STATE_LOADED) { + return ClassState.LOADED; + } else if (state == CLASS_STATE_LINKED) { + return ClassState.LINKED; + } else if (state == CLASS_STATE_BEING_INITIALIZED) { + return ClassState.BEING_INITIALIZED; + } else if (state == CLASS_STATE_FULLY_INITIALIZED) { + return ClassState.FULLY_INITIALIZED; + } else if (state == CLASS_STATE_INITIALIZATION_ERROR) { + return ClassState.INITIALIZATION_ERROR; + } else { + throw new RuntimeException("should not reach here"); + } + } + + // initialization state quaries + public boolean isLoaded() { + return getInitStateAsInt() >= CLASS_STATE_LOADED; + } + + public boolean isLinked() { + return getInitStateAsInt() >= CLASS_STATE_LINKED; + } + + public boolean isInitialized() { + return getInitStateAsInt() == CLASS_STATE_FULLY_INITIALIZED; + } + + public boolean isNotInitialized() { + return getInitStateAsInt() < CLASS_STATE_BEING_INITIALIZED; + } + + public boolean isBeingInitialized() { + return getInitStateAsInt() == CLASS_STATE_BEING_INITIALIZED; + } + + public boolean isInErrorState() { + return getInitStateAsInt() == CLASS_STATE_INITIALIZATION_ERROR; + } + + public int getClassStatus() { + int result = 0; + if (isLinked()) { + result |= JVMDIClassStatus.VERIFIED | JVMDIClassStatus.PREPARED; + } + + if (isInitialized()) { + if (Assert.ASSERTS_ENABLED) { + Assert.that(isLinked(), "Class status is not consistent"); + } + result |= JVMDIClassStatus.INITIALIZED; + } + + if (isInErrorState()) { + result |= JVMDIClassStatus.ERROR; + } + return result; + } + + // Byteside of the header + private static long headerSize; + + public static long getHeaderSize() { return headerSize; } + + // Accessors for declared fields + public Klass getArrayKlasses() { return (Klass) arrayKlasses.getValue(this); } + public ObjArray getMethods() { return (ObjArray) methods.getValue(this); } + public TypeArray getMethodOrdering() { return (TypeArray) methodOrdering.getValue(this); } + public ObjArray getLocalInterfaces() { return (ObjArray) localInterfaces.getValue(this); } + public ObjArray getTransitiveInterfaces() { return (ObjArray) transitiveInterfaces.getValue(this); } + public long nofImplementors() { return nofImplementors.getValue(this); } + public Klass getImplementor() { return (Klass) implementors[0].getValue(this); } + public Klass getImplementor(int i) { return (Klass) implementors[i].getValue(this); } + public TypeArray getFields() { return (TypeArray) fields.getValue(this); } + public ConstantPool getConstants() { return (ConstantPool) constants.getValue(this); } + public Oop getClassLoader() { return classLoader.getValue(this); } + public Oop getProtectionDomain() { return protectionDomain.getValue(this); } + public ObjArray getSigners() { return (ObjArray) signers.getValue(this); } + public Symbol getSourceFileName() { return (Symbol) sourceFileName.getValue(this); } + public Symbol getSourceDebugExtension(){ return (Symbol) sourceDebugExtension.getValue(this); } + public TypeArray getInnerClasses() { return (TypeArray) innerClasses.getValue(this); } + public long getNonstaticFieldSize() { return nonstaticFieldSize.getValue(this); } + public long getStaticFieldSize() { return staticFieldSize.getValue(this); } + public long getStaticOopFieldSize() { return staticOopFieldSize.getValue(this); } + public long getNonstaticOopMapSize() { return nonstaticOopMapSize.getValue(this); } + public boolean getIsMarkedDependent() { return isMarkedDependent.getValue(this) != 0; } + public long getVtableLen() { return vtableLen.getValue(this); } + public long getItableLen() { return itableLen.getValue(this); } + public Symbol getGenericSignature() { return (Symbol) genericSignature.getValue(this); } + public long majorVersion() { return majorVersion.getValue(this); } + public long minorVersion() { return minorVersion.getValue(this); } + + // "size helper" == instance size in words + public long getSizeHelper() { + int lh = getLayoutHelper(); + if (Assert.ASSERTS_ENABLED) { + Assert.that(lh > 0, "layout helper initialized for instance class"); + } + return lh / VM.getVM().getAddressSize(); + } + + // same as enum InnerClassAttributeOffset in VM code. + public static interface InnerClassAttributeOffset { + // from JVM spec. "InnerClasses" attribute + public static final int innerClassInnerClassInfoOffset = 0; + public static final int innerClassOuterClassInfoOffset = 1; + public static final int innerClassInnerNameOffset = 2; + public static final int innerClassAccessFlagsOffset = 3; + public static final int innerClassNextOffset = 4; + }; + + // refer to compute_modifier_flags in VM code. + public long computeModifierFlags() { + long access = getAccessFlags(); + // But check if it happens to be member class. + TypeArray innerClassList = getInnerClasses(); + int length = ( innerClassList == null)? 0 : (int) innerClassList.getLength(); + if (length > 0) { + if (Assert.ASSERTS_ENABLED) { + Assert.that(length % InnerClassAttributeOffset.innerClassNextOffset == 0, "just checking"); + } + for (int i = 0; i < length; i += InnerClassAttributeOffset.innerClassNextOffset) { + int ioff = innerClassList.getShortAt(i + + InnerClassAttributeOffset.innerClassInnerClassInfoOffset); + // 'ioff' can be zero. + // refer to JVM spec. section 4.7.5. + if (ioff != 0) { + // only look at classes that are already loaded + // since we are looking for the flags for our self. + Oop classInfo = getConstants().getObjAt(ioff); + Symbol name = null; + if (classInfo instanceof Klass) { + name = ((Klass) classInfo).getName(); + } else if (classInfo instanceof Symbol) { + name = (Symbol) classInfo; + } else { + throw new RuntimeException("should not reach here"); + } + + if (name.equals(getName())) { + // This is really a member class + access = innerClassList.getShortAt(i + + InnerClassAttributeOffset.innerClassAccessFlagsOffset); + break; + } + } + } // for inner classes + } + + // Remember to strip ACC_SUPER bit + return (access & (~JVM_ACC_SUPER)) & JVM_ACC_WRITTEN_FLAGS; + } + + + // whether given Symbol is name of an inner/nested Klass of this Klass? + // anonymous and local classes are excluded. + public boolean isInnerClassName(Symbol sym) { + return isInInnerClasses(sym, false); + } + + // whether given Symbol is name of an inner/nested Klass of this Klass? + // anonymous classes excluded, but local classes are included. + public boolean isInnerOrLocalClassName(Symbol sym) { + return isInInnerClasses(sym, true); + } + + private boolean isInInnerClasses(Symbol sym, boolean includeLocals) { + TypeArray innerClassList = getInnerClasses(); + int length = ( innerClassList == null)? 0 : (int) innerClassList.getLength(); + if (length > 0) { + if (Assert.ASSERTS_ENABLED) { + Assert.that(length % InnerClassAttributeOffset.innerClassNextOffset == 0, "just checking"); + } + for (int i = 0; i < length; i += InnerClassAttributeOffset.innerClassNextOffset) { + int ioff = innerClassList.getShortAt(i + + InnerClassAttributeOffset.innerClassInnerClassInfoOffset); + // 'ioff' can be zero. + // refer to JVM spec. section 4.7.5. + if (ioff != 0) { + Oop iclassInfo = getConstants().getObjAt(ioff); + Symbol innerName = null; + if (iclassInfo instanceof Klass) { + innerName = ((Klass) iclassInfo).getName(); + } else if (iclassInfo instanceof Symbol) { + innerName = (Symbol) iclassInfo; + } else { + throw new RuntimeException("should not reach here"); + } + + Symbol myname = getName(); + int ooff = innerClassList.getShortAt(i + + InnerClassAttributeOffset.innerClassOuterClassInfoOffset); + // for anonymous classes inner_name_index of InnerClasses + // attribute is zero. + int innerNameIndex = innerClassList.getShortAt(i + + InnerClassAttributeOffset.innerClassInnerNameOffset); + // if this is not a member (anonymous, local etc.), 'ooff' will be zero + // refer to JVM spec. section 4.7.5. + if (ooff == 0) { + if (includeLocals) { + // does it looks like my local class? + if (innerName.equals(sym) && + innerName.asString().startsWith(myname.asString())) { + // exclude anonymous classes. + return (innerNameIndex != 0); + } + } + } else { + Oop oclassInfo = getConstants().getObjAt(ooff); + Symbol outerName = null; + if (oclassInfo instanceof Klass) { + outerName = ((Klass) oclassInfo).getName(); + } else if (oclassInfo instanceof Symbol) { + outerName = (Symbol) oclassInfo; + } else { + throw new RuntimeException("should not reach here"); + } + + // include only if current class is outer class. + if (outerName.equals(myname) && innerName.equals(sym)) { + return true; + } + } + } + } // for inner classes + return false; + } else { + return false; + } + } + + public boolean implementsInterface(Klass k) { + if (Assert.ASSERTS_ENABLED) { + Assert.that(k.isInterface(), "should not reach here"); + } + ObjArray interfaces = getTransitiveInterfaces(); + final int len = (int) interfaces.getLength(); + for (int i = 0; i < len; i++) { + if (interfaces.getObjAt(i).equals(k)) return true; + } + return false; + } + + boolean computeSubtypeOf(Klass k) { + if (k.isInterface()) { + return implementsInterface(k); + } else { + return super.computeSubtypeOf(k); + } + } + + public void printValueOn(PrintStream tty) { + tty.print("InstanceKlass for " + getName().asString()); + } + + public void iterateFields(OopVisitor visitor, boolean doVMFields) { + super.iterateFields(visitor, doVMFields); + if (doVMFields) { + visitor.doOop(arrayKlasses, true); + visitor.doOop(methods, true); + visitor.doOop(methodOrdering, true); + visitor.doOop(localInterfaces, true); + visitor.doOop(transitiveInterfaces, true); + visitor.doCInt(nofImplementors, true); + for (int i = 0; i < IMPLEMENTORS_LIMIT; i++) + visitor.doOop(implementors[i], true); + visitor.doOop(fields, true); + visitor.doOop(constants, true); + visitor.doOop(classLoader, true); + visitor.doOop(protectionDomain, true); + visitor.doOop(signers, true); + visitor.doOop(sourceFileName, true); + visitor.doOop(innerClasses, true); + visitor.doCInt(nonstaticFieldSize, true); + visitor.doCInt(staticFieldSize, true); + visitor.doCInt(staticOopFieldSize, true); + visitor.doCInt(nonstaticOopMapSize, true); + visitor.doCInt(isMarkedDependent, true); + visitor.doCInt(initState, true); + visitor.doCInt(vtableLen, true); + visitor.doCInt(itableLen, true); + } + + TypeArray fields = getFields(); + int length = (int) fields.getLength(); + for (int index = 0; index < length; index += NEXT_OFFSET) { + short accessFlags = fields.getShortAt(index + ACCESS_FLAGS_OFFSET); + short signatureIndex = fields.getShortAt(index + SIGNATURE_INDEX_OFFSET); + + FieldType type = new FieldType((Symbol) getConstants().getObjAt(signatureIndex)); + AccessFlags access = new AccessFlags(accessFlags); + if (access.isStatic()) { + visitField(visitor, type, index); + } + } + } + + public Klass getJavaSuper() { + return getSuper(); + } + + public void iterateNonStaticFields(OopVisitor visitor) { + if (getSuper() != null) { + ((InstanceKlass) getSuper()).iterateNonStaticFields(visitor); + } + TypeArray fields = getFields(); + + int length = (int) fields.getLength(); + for (int index = 0; index < length; index += NEXT_OFFSET) { + short accessFlags = fields.getShortAt(index + ACCESS_FLAGS_OFFSET); + short signatureIndex = fields.getShortAt(index + SIGNATURE_INDEX_OFFSET); + + FieldType type = new FieldType((Symbol) getConstants().getObjAt(signatureIndex)); + AccessFlags access = new AccessFlags(accessFlags); + if (!access.isStatic()) { + visitField(visitor, type, index); + } + } + } + + /** Field access by name. */ + public Field findLocalField(Symbol name, Symbol sig) { + TypeArray fields = getFields(); + int n = (int) fields.getLength(); + ConstantPool cp = getConstants(); + for (int i = 0; i < n; i += NEXT_OFFSET) { + int nameIndex = fields.getShortAt(i + NAME_INDEX_OFFSET); + int sigIndex = fields.getShortAt(i + SIGNATURE_INDEX_OFFSET); + Symbol f_name = cp.getSymbolAt(nameIndex); + Symbol f_sig = cp.getSymbolAt(sigIndex); + if (name.equals(f_name) && sig.equals(f_sig)) { + return newField(i); + } + } + + return null; + } + + /** Find field in direct superinterfaces. */ + public Field findInterfaceField(Symbol name, Symbol sig) { + ObjArray interfaces = getLocalInterfaces(); + int n = (int) interfaces.getLength(); + for (int i = 0; i < n; i++) { + InstanceKlass intf1 = (InstanceKlass) interfaces.getObjAt(i); + if (Assert.ASSERTS_ENABLED) { + Assert.that(intf1.isInterface(), "just checking type"); + } + // search for field in current interface + Field f = intf1.findLocalField(name, sig); + if (f != null) { + if (Assert.ASSERTS_ENABLED) { + Assert.that(f.getAccessFlagsObj().isStatic(), "interface field must be static"); + } + return f; + } + // search for field in direct superinterfaces + f = intf1.findInterfaceField(name, sig); + if (f != null) return f; + } + // otherwise field lookup fails + return null; + } + + /** Find field according to JVM spec 5.4.3.2, returns the klass in + which the field is defined. */ + public Field findField(Symbol name, Symbol sig) { + // search order according to newest JVM spec (5.4.3.2, p.167). + // 1) search for field in current klass + Field f = findLocalField(name, sig); + if (f != null) return f; + + // 2) search for field recursively in direct superinterfaces + f = findInterfaceField(name, sig); + if (f != null) return f; + + // 3) apply field lookup recursively if superclass exists + InstanceKlass supr = (InstanceKlass) getSuper(); + if (supr != null) return supr.findField(name, sig); + + // 4) otherwise field lookup fails + return null; + } + + /** Find field according to JVM spec 5.4.3.2, returns the klass in + which the field is defined (convenience routine) */ + public Field findField(String name, String sig) { + SymbolTable symbols = VM.getVM().getSymbolTable(); + Symbol nameSym = symbols.probe(name); + Symbol sigSym = symbols.probe(sig); + if (nameSym == null || sigSym == null) { + return null; + } + return findField(nameSym, sigSym); + } + + /** Find field according to JVM spec 5.4.3.2, returns the klass in + which the field is defined (retained only for backward + compatibility with jdbx) */ + public Field findFieldDbg(String name, String sig) { + return findField(name, sig); + } + + /** Get field by its index in the fields array. Only designed for + use in a debugging system. */ + public Field getFieldByIndex(int fieldArrayIndex) { + return newField(fieldArrayIndex); + } + + + /** Return a List of SA Fields for the fields declared in this class. + Inherited fields are not included. + Return an empty list if there are no fields declared in this class. + Only designed for use in a debugging system. */ + public List getImmediateFields() { + // A list of Fields for each field declared in this class/interface, + // not including inherited fields. + TypeArray fields = getFields(); + + int length = (int) fields.getLength(); + List immediateFields = new ArrayList(length / NEXT_OFFSET); + for (int index = 0; index < length; index += NEXT_OFFSET) { + immediateFields.add(getFieldByIndex(index)); + } + + return immediateFields; + } + + /** Return a List of SA Fields for all the java fields in this class, + including all inherited fields. This includes hidden + fields. Thus the returned list can contain fields with + the same name. + Return an empty list if there are no fields. + Only designed for use in a debugging system. */ + public List getAllFields() { + // Contains a Field for each field in this class, including immediate + // fields and inherited fields. + List allFields = getImmediateFields(); + + // transitiveInterfaces contains all interfaces implemented + // by this class and its superclass chain with no duplicates. + + ObjArray interfaces = getTransitiveInterfaces(); + int n = (int) interfaces.getLength(); + for (int i = 0; i < n; i++) { + InstanceKlass intf1 = (InstanceKlass) interfaces.getObjAt(i); + if (Assert.ASSERTS_ENABLED) { + Assert.that(intf1.isInterface(), "just checking type"); + } + allFields.addAll(intf1.getImmediateFields()); + } + + // Get all fields in the superclass, recursively. But, don't + // include fields in interfaces implemented by superclasses; + // we already have all those. + if (!isInterface()) { + InstanceKlass supr; + if ( (supr = (InstanceKlass) getSuper()) != null) { + allFields.addAll(supr.getImmediateFields()); + } + } + + return allFields; + } + + + /** Return a List of SA Methods declared directly in this class/interface. + Return an empty list if there are none, or if this isn't a class/ + interface. + */ + public List getImmediateMethods() { + // Contains a Method for each method declared in this class/interface + // not including inherited methods. + + ObjArray methods = getMethods(); + int length = (int)methods.getLength(); + Object[] tmp = new Object[length]; + + TypeArray methodOrdering = getMethodOrdering(); + if (methodOrdering.getLength() != length) { + // no ordering info present + for (int index = 0; index < length; index++) { + tmp[index] = methods.getObjAt(index); + } + } else { + for (int index = 0; index < length; index++) { + int originalIndex = getMethodOrdering().getIntAt(index); + tmp[originalIndex] = methods.getObjAt(index); + } + } + + return Arrays.asList(tmp); + } + + /** Return a List containing an SA InstanceKlass for each + interface named in this class's 'implements' clause. + */ + public List getDirectImplementedInterfaces() { + // Contains an InstanceKlass for each interface in this classes + // 'implements' clause. + + ObjArray interfaces = getLocalInterfaces(); + int length = (int) interfaces.getLength(); + List directImplementedInterfaces = new ArrayList(length); + + for (int index = 0; index < length; index ++) { + directImplementedInterfaces.add(interfaces.getObjAt(index)); + } + + return directImplementedInterfaces; + } + + + public long getObjectSize() { + long bodySize = alignObjectOffset(getVtableLen() * getHeap().getOopSize()) + + alignObjectOffset(getItableLen() * getHeap().getOopSize()) + + (getStaticFieldSize() + getNonstaticOopMapSize()) * getHeap().getOopSize(); + return alignObjectSize(headerSize + bodySize); + } + + public Klass arrayKlassImpl(boolean orNull, int n) { + // FIXME: in reflective system this would need to change to + // actually allocate + if (getArrayKlasses() == null) { return null; } + ObjArrayKlass oak = (ObjArrayKlass) getArrayKlasses(); + if (orNull) { + return oak.arrayKlassOrNull(n); + } + return oak.arrayKlass(n); + } + + public Klass arrayKlassImpl(boolean orNull) { + return arrayKlassImpl(orNull, 1); + } + + public String signature() { + return "L" + super.signature() + ";"; + } + + /** Convenience routine taking Strings; lookup is done in + SymbolTable. */ + public Method findMethod(String name, String sig) { + SymbolTable syms = VM.getVM().getSymbolTable(); + Symbol nameSym = syms.probe(name); + Symbol sigSym = syms.probe(sig); + if (nameSym == null || sigSym == null) { + return null; + } + return findMethod(nameSym, sigSym); + } + + /** Find method in vtable. */ + public Method findMethod(Symbol name, Symbol sig) { + return findMethod(getMethods(), name, sig); + } + + /** Breakpoint support (see methods on methodOop for details) */ + public BreakpointInfo getBreakpoints() { + Address addr = getHandle().getAddressAt(Oop.getHeaderSize() + breakpoints.getOffset()); + return (BreakpointInfo) VMObjectFactory.newObject(BreakpointInfo.class, addr); + } + + //---------------------------------------------------------------------- + // Internals only below this point + // + + private void visitField(OopVisitor visitor, FieldType type, int index) { + Field f = newField(index); + if (type.isOop()) { + visitor.doOop((OopField) f, false); + return; + } + if (type.isByte()) { + visitor.doByte((ByteField) f, false); + return; + } + if (type.isChar()) { + visitor.doChar((CharField) f, false); + return; + } + if (type.isDouble()) { + visitor.doDouble((DoubleField) f, false); + return; + } + if (type.isFloat()) { + visitor.doFloat((FloatField) f, false); + return; + } + if (type.isInt()) { + visitor.doInt((IntField) f, false); + return; + } + if (type.isLong()) { + visitor.doLong((LongField) f, false); + return; + } + if (type.isShort()) { + visitor.doShort((ShortField) f, false); + return; + } + if (type.isBoolean()) { + visitor.doBoolean((BooleanField) f, false); + return; + } + } + + // Creates new field from index in fields TypeArray + private Field newField(int index) { + TypeArray fields = getFields(); + short signatureIndex = fields.getShortAt(index + SIGNATURE_INDEX_OFFSET); + FieldType type = new FieldType((Symbol) getConstants().getObjAt(signatureIndex)); + if (type.isOop()) { + return new OopField(this, index); + } + if (type.isByte()) { + return new ByteField(this, index); + } + if (type.isChar()) { + return new CharField(this, index); + } + if (type.isDouble()) { + return new DoubleField(this, index); + } + if (type.isFloat()) { + return new FloatField(this, index); + } + if (type.isInt()) { + return new IntField(this, index); + } + if (type.isLong()) { + return new LongField(this, index); + } + if (type.isShort()) { + return new ShortField(this, index); + } + if (type.isBoolean()) { + return new BooleanField(this, index); + } + throw new RuntimeException("Illegal field type at index " + index); + } + + private static Method findMethod(ObjArray methods, Symbol name, Symbol signature) { + int len = (int) methods.getLength(); + // methods are sorted, so do binary search + int l = 0; + int h = len - 1; + while (l <= h) { + int mid = (l + h) >> 1; + Method m = (Method) methods.getObjAt(mid); + int res = m.getName().fastCompare(name); + if (res == 0) { + // found matching name; do linear search to find matching signature + // first, quick check for common case + if (m.getSignature().equals(signature)) return m; + // search downwards through overloaded methods + int i; + for (i = mid - 1; i >= l; i--) { + Method m1 = (Method) methods.getObjAt(i); + if (!m1.getName().equals(name)) break; + if (m1.getSignature().equals(signature)) return m1; + } + // search upwards + for (i = mid + 1; i <= h; i++) { + Method m1 = (Method) methods.getObjAt(i); + if (!m1.getName().equals(name)) break; + if (m1.getSignature().equals(signature)) return m1; + } + // not found + if (Assert.ASSERTS_ENABLED) { + int index = linearSearch(methods, name, signature); + if (index != -1) { + throw new DebuggerException("binary search bug: should have found entry " + index); + } + } + return null; + } else if (res < 0) { + l = mid + 1; + } else { + h = mid - 1; + } + } + if (Assert.ASSERTS_ENABLED) { + int index = linearSearch(methods, name, signature); + if (index != -1) { + throw new DebuggerException("binary search bug: should have found entry " + index); + } + } + return null; + } + + private static int linearSearch(ObjArray methods, Symbol name, Symbol signature) { + int len = (int) methods.getLength(); + for (int index = 0; index < len; index++) { + Method m = (Method) methods.getObjAt(index); + if (m.getSignature().equals(signature) && m.getName().equals(name)) { + return index; + } + } + return -1; + } +}