--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,1169 @@
+/*
+ * Copyright (c) 2000, 2017, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.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.classfile.ClassLoaderData;
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.memory.*;
+import sun.jvm.hotspot.memory.Dictionary;
+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
+ private static int ACCESS_FLAGS_OFFSET;
+ private static int NAME_INDEX_OFFSET;
+ private static int SIGNATURE_INDEX_OFFSET;
+ private static int INITVAL_INDEX_OFFSET;
+ private static int LOW_OFFSET;
+ private static int HIGH_OFFSET;
+ private static int FIELD_SLOTS;
+ private static short FIELDINFO_TAG_SIZE;
+ private static short FIELDINFO_TAG_MASK;
+ private static short FIELDINFO_TAG_OFFSET;
+
+ // ClassState constants
+ 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;
+
+ // _misc_flags constants
+ private static int MISC_REWRITTEN;
+ private static int MISC_HAS_NONSTATIC_FIELDS;
+ private static int MISC_SHOULD_VERIFY_CLASS;
+ private static int MISC_IS_ANONYMOUS;
+ private static int MISC_IS_CONTENDED;
+ private static int MISC_HAS_NONSTATIC_CONCRETE_METHODS;
+ private static int MISC_DECLARES_NONSTATIC_CONCRETE_METHODS;
+ private static int MISC_HAS_BEEN_REDEFINED;
+ private static int MISC_HAS_PASSED_FINGERPRINT_CHECK;
+ private static int MISC_IS_SCRATCH_CLASS;
+ private static int MISC_IS_SHARED_BOOT_CLASS;
+ private static int MISC_IS_SHARED_PLATFORM_CLASS;
+ private static int MISC_IS_SHARED_APP_CLASS;
+
+ private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
+ Type type = db.lookupType("InstanceKlass");
+ arrayKlasses = new MetadataField(type.getAddressField("_array_klasses"), 0);
+ methods = type.getAddressField("_methods");
+ defaultMethods = type.getAddressField("_default_methods");
+ methodOrdering = type.getAddressField("_method_ordering");
+ localInterfaces = type.getAddressField("_local_interfaces");
+ transitiveInterfaces = type.getAddressField("_transitive_interfaces");
+ fields = type.getAddressField("_fields");
+ javaFieldsCount = new CIntField(type.getCIntegerField("_java_fields_count"), 0);
+ constants = new MetadataField(type.getAddressField("_constants"), 0);
+ sourceDebugExtension = type.getAddressField("_source_debug_extension");
+ innerClasses = type.getAddressField("_inner_classes");
+ sourceFileNameIndex = new CIntField(type.getCIntegerField("_source_file_name_index"), 0);
+ nonstaticFieldSize = new CIntField(type.getCIntegerField("_nonstatic_field_size"), 0);
+ staticFieldSize = new CIntField(type.getCIntegerField("_static_field_size"), 0);
+ staticOopFieldCount = new CIntField(type.getCIntegerField("_static_oop_field_count"), 0);
+ nonstaticOopMapSize = new CIntField(type.getCIntegerField("_nonstatic_oop_map_size"), 0);
+ isMarkedDependent = new CIntField(type.getCIntegerField("_is_marked_dependent"), 0);
+ initState = new CIntField(type.getCIntegerField("_init_state"), 0);
+ itableLen = new CIntField(type.getCIntegerField("_itable_len"), 0);
+ if (VM.getVM().isJvmtiSupported()) {
+ breakpoints = type.getAddressField("_breakpoints");
+ }
+ genericSignatureIndex = new CIntField(type.getCIntegerField("_generic_signature_index"), 0);
+ miscFlags = new CIntField(type.getCIntegerField("_misc_flags"), 0);
+ majorVersion = new CIntField(type.getCIntegerField("_major_version"), 0);
+ minorVersion = new CIntField(type.getCIntegerField("_minor_version"), 0);
+ headerSize = type.getSize();
+
+ // read field offset constants
+ ACCESS_FLAGS_OFFSET = db.lookupIntConstant("FieldInfo::access_flags_offset").intValue();
+ NAME_INDEX_OFFSET = db.lookupIntConstant("FieldInfo::name_index_offset").intValue();
+ SIGNATURE_INDEX_OFFSET = db.lookupIntConstant("FieldInfo::signature_index_offset").intValue();
+ INITVAL_INDEX_OFFSET = db.lookupIntConstant("FieldInfo::initval_index_offset").intValue();
+ LOW_OFFSET = db.lookupIntConstant("FieldInfo::low_packed_offset").intValue();
+ HIGH_OFFSET = db.lookupIntConstant("FieldInfo::high_packed_offset").intValue();
+ FIELD_SLOTS = db.lookupIntConstant("FieldInfo::field_slots").intValue();
+ FIELDINFO_TAG_SIZE = db.lookupIntConstant("FIELDINFO_TAG_SIZE").shortValue();
+ FIELDINFO_TAG_MASK = db.lookupIntConstant("FIELDINFO_TAG_MASK").shortValue();
+ FIELDINFO_TAG_OFFSET = db.lookupIntConstant("FIELDINFO_TAG_OFFSET").shortValue();
+
+ // read ClassState constants
+ 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();
+
+ MISC_REWRITTEN = db.lookupIntConstant("InstanceKlass::_misc_rewritten").intValue();
+ MISC_HAS_NONSTATIC_FIELDS = db.lookupIntConstant("InstanceKlass::_misc_has_nonstatic_fields").intValue();
+ MISC_SHOULD_VERIFY_CLASS = db.lookupIntConstant("InstanceKlass::_misc_should_verify_class").intValue();
+ MISC_IS_ANONYMOUS = db.lookupIntConstant("InstanceKlass::_misc_is_anonymous").intValue();
+ MISC_IS_CONTENDED = db.lookupIntConstant("InstanceKlass::_misc_is_contended").intValue();
+ MISC_HAS_NONSTATIC_CONCRETE_METHODS = db.lookupIntConstant("InstanceKlass::_misc_has_nonstatic_concrete_methods").intValue();
+ MISC_DECLARES_NONSTATIC_CONCRETE_METHODS = db.lookupIntConstant("InstanceKlass::_misc_declares_nonstatic_concrete_methods").intValue();
+ MISC_HAS_BEEN_REDEFINED = db.lookupIntConstant("InstanceKlass::_misc_has_been_redefined").intValue();
+ MISC_HAS_PASSED_FINGERPRINT_CHECK = db.lookupIntConstant("InstanceKlass::_misc_has_passed_fingerprint_check").intValue();
+ MISC_IS_SCRATCH_CLASS = db.lookupIntConstant("InstanceKlass::_misc_is_scratch_class").intValue();
+ MISC_IS_SHARED_BOOT_CLASS = db.lookupIntConstant("InstanceKlass::_misc_is_shared_boot_class").intValue();
+ MISC_IS_SHARED_PLATFORM_CLASS = db.lookupIntConstant("InstanceKlass::_misc_is_shared_platform_class").intValue();
+ MISC_IS_SHARED_APP_CLASS = db.lookupIntConstant("InstanceKlass::_misc_is_shared_app_class").intValue();
+ }
+
+ public InstanceKlass(Address addr) {
+ super(addr);
+ if (getJavaFieldsCount() != getAllFieldsCount()) {
+ // Exercise the injected field logic
+ for (int i = getJavaFieldsCount(); i < getAllFieldsCount(); i++) {
+ getFieldName(i);
+ getFieldSignature(i);
+ }
+ }
+ }
+
+ private static MetadataField arrayKlasses;
+ private static AddressField methods;
+ private static AddressField defaultMethods;
+ private static AddressField methodOrdering;
+ private static AddressField localInterfaces;
+ private static AddressField transitiveInterfaces;
+ private static AddressField fields;
+ private static CIntField javaFieldsCount;
+ private static MetadataField constants;
+ private static AddressField sourceDebugExtension;
+ private static AddressField innerClasses;
+ private static CIntField sourceFileNameIndex;
+ private static CIntField nonstaticFieldSize;
+ private static CIntField staticFieldSize;
+ private static CIntField staticOopFieldCount;
+ private static CIntField nonstaticOopMapSize;
+ private static CIntField isMarkedDependent;
+ private static CIntField initState;
+ private static CIntField itableLen;
+ private static AddressField breakpoints;
+ private static CIntField genericSignatureIndex;
+ private static CIntField miscFlags;
+ private static CIntField majorVersion;
+ private static CIntField minorVersion;
+
+ // type safe enum for ClassState from instanceKlass.hpp
+ public static class ClassState {
+ 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;
+ }
+
+ public int getInitStateAsInt() { return (int) initState.getValue(this); }
+ public ClassState getInitState() {
+ int state = getInitStateAsInt();
+ 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 long getObjectSize(Oop object) {
+ return getSizeHelper() * VM.getVM().getAddressSize();
+ }
+
+ public long getSize() { // in number of bytes
+ long wordLength = VM.getVM().getBytesPerWord();
+ long size = getHeaderSize() +
+ (getVtableLen() +
+ getItableLen() +
+ getNonstaticOopMapSize()) * wordLength;
+ if (isInterface()) {
+ size += wordLength;
+ }
+ if (isAnonymous()) {
+ size += wordLength;
+ }
+ if (hasStoredFingerprint()) {
+ size += 8; // uint64_t
+ }
+ return alignSize(size);
+ }
+
+ private int getMiscFlags() {
+ return (int) miscFlags.getValue(this);
+ }
+
+ public boolean isAnonymous() {
+ return (getMiscFlags() & MISC_IS_ANONYMOUS) != 0;
+ }
+
+ public static boolean shouldStoreFingerprint() {
+ VM vm = VM.getVM();
+ if (vm.getCommandLineBooleanFlag("EnableJVMCI") && !vm.getCommandLineBooleanFlag("UseJVMCICompiler")) {
+ return true;
+ }
+ if (vm.getCommandLineBooleanFlag("DumpSharedSpaces")) {
+ return true;
+ }
+ return false;
+ }
+
+ public boolean hasStoredFingerprint() {
+ return shouldStoreFingerprint() || isShared();
+ }
+
+ public boolean isShared() {
+ VM vm = VM.getVM();
+ if (vm.isSharingEnabled()) {
+ // This is not the same implementation as the C++ function MetaspaceObj::is_shared()
+ // bool MetaspaceObj::is_shared() const {
+ // return MetaspaceShared::is_in_shared_space(this);
+ // }
+ // However, MetaspaceShared::is_in_shared_space is complicated and hard to emulate in
+ // Java code, so let's do this by looking up from the shared dictionary. Of course,
+ // this works for shared InstanceKlass only and does not work for other types of
+ // MetaspaceObj in the CDS shared archive.
+ Dictionary sharedDictionary = vm.getSystemDictionary().sharedDictionary();
+ if (sharedDictionary != null) {
+ if (sharedDictionary.contains(this)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public static long getHeaderSize() { return headerSize; }
+
+ public short getFieldAccessFlags(int index) {
+ return getFields().at(index * FIELD_SLOTS + ACCESS_FLAGS_OFFSET);
+ }
+
+ public short getFieldNameIndex(int index) {
+ if (index >= getJavaFieldsCount()) throw new IndexOutOfBoundsException("not a Java field;");
+ return getFields().at(index * FIELD_SLOTS + NAME_INDEX_OFFSET);
+ }
+
+ public Symbol getFieldName(int index) {
+ int nameIndex = getFields().at(index * FIELD_SLOTS + NAME_INDEX_OFFSET);
+ if (index < getJavaFieldsCount()) {
+ return getConstants().getSymbolAt(nameIndex);
+ } else {
+ return vmSymbols.symbolAt(nameIndex);
+ }
+ }
+
+ public short getFieldSignatureIndex(int index) {
+ if (index >= getJavaFieldsCount()) throw new IndexOutOfBoundsException("not a Java field;");
+ return getFields().at(index * FIELD_SLOTS + SIGNATURE_INDEX_OFFSET);
+ }
+
+ public Symbol getFieldSignature(int index) {
+ int signatureIndex = getFields().at(index * FIELD_SLOTS + SIGNATURE_INDEX_OFFSET);
+ if (index < getJavaFieldsCount()) {
+ return getConstants().getSymbolAt(signatureIndex);
+ } else {
+ return vmSymbols.symbolAt(signatureIndex);
+ }
+ }
+
+ public short getFieldGenericSignatureIndex(int index) {
+ // int len = getFields().length();
+ int allFieldsCount = getAllFieldsCount();
+ int generic_signature_slot = allFieldsCount * FIELD_SLOTS;
+ for (int i = 0; i < allFieldsCount; i++) {
+ short flags = getFieldAccessFlags(i);
+ AccessFlags access = new AccessFlags(flags);
+ if (i == index) {
+ if (access.fieldHasGenericSignature()) {
+ return getFields().at(generic_signature_slot);
+ } else {
+ return 0;
+ }
+ } else {
+ if (access.fieldHasGenericSignature()) {
+ generic_signature_slot ++;
+ }
+ }
+ }
+ return 0;
+ }
+
+ public Symbol getFieldGenericSignature(int index) {
+ short genericSignatureIndex = getFieldGenericSignatureIndex(index);
+ if (genericSignatureIndex != 0) {
+ return getConstants().getSymbolAt(genericSignatureIndex);
+ }
+ return null;
+ }
+
+ public short getFieldInitialValueIndex(int index) {
+ if (index >= getJavaFieldsCount()) throw new IndexOutOfBoundsException("not a Java field;");
+ return getFields().at(index * FIELD_SLOTS + INITVAL_INDEX_OFFSET);
+ }
+
+ public int getFieldOffset(int index) {
+ U2Array fields = getFields();
+ short lo = fields.at(index * FIELD_SLOTS + LOW_OFFSET);
+ short hi = fields.at(index * FIELD_SLOTS + HIGH_OFFSET);
+ if ((lo & FIELDINFO_TAG_MASK) == FIELDINFO_TAG_OFFSET) {
+ return VM.getVM().buildIntFromShorts(lo, hi) >> FIELDINFO_TAG_SIZE;
+ }
+ throw new RuntimeException("should not reach here");
+ }
+
+ // Accessors for declared fields
+ public Klass getArrayKlasses() { return (Klass) arrayKlasses.getValue(this); }
+ public MethodArray getMethods() { return new MethodArray(methods.getValue(getAddress())); }
+
+ public MethodArray getDefaultMethods() {
+ if (defaultMethods != null) {
+ Address addr = defaultMethods.getValue(getAddress());
+ if ((addr != null) && (addr.getAddressAt(0) != null)) {
+ return new MethodArray(addr);
+ } else {
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+
+ public KlassArray getLocalInterfaces() { return new KlassArray(localInterfaces.getValue(getAddress())); }
+ public KlassArray getTransitiveInterfaces() { return new KlassArray(transitiveInterfaces.getValue(getAddress())); }
+ public int getJavaFieldsCount() { return (int) javaFieldsCount.getValue(this); }
+ public int getAllFieldsCount() {
+ int len = getFields().length();
+ int allFieldsCount = 0;
+ for (; allFieldsCount*FIELD_SLOTS < len; allFieldsCount++) {
+ short flags = getFieldAccessFlags(allFieldsCount);
+ AccessFlags access = new AccessFlags(flags);
+ if (access.fieldHasGenericSignature()) {
+ len --;
+ }
+ }
+ return allFieldsCount;
+ }
+ public ConstantPool getConstants() { return (ConstantPool) constants.getValue(this); }
+ public Symbol getSourceFileName() { return getConstants().getSymbolAt(sourceFileNameIndex.getValue(this)); }
+ public String getSourceDebugExtension(){ return CStringUtilities.getString(sourceDebugExtension.getValue(getAddress())); }
+ public long getNonstaticFieldSize() { return nonstaticFieldSize.getValue(this); }
+ public long getStaticOopFieldCount() { return staticOopFieldCount.getValue(this); }
+ public long getNonstaticOopMapSize() { return nonstaticOopMapSize.getValue(this); }
+ public boolean getIsMarkedDependent() { return isMarkedDependent.getValue(this) != 0; }
+ public long getItableLen() { return itableLen.getValue(this); }
+ public long majorVersion() { return majorVersion.getValue(this); }
+ public long minorVersion() { return minorVersion.getValue(this); }
+ public Symbol getGenericSignature() {
+ long index = genericSignatureIndex.getValue(this);
+ if (index != 0) {
+ return getConstants().getSymbolAt(index);
+ } else {
+ return null;
+ }
+ }
+
+ // "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;
+ };
+
+ public static interface EnclosingMethodAttributeOffset {
+ public static final int enclosing_method_class_index_offset = 0;
+ public static final int enclosing_method_method_index_offset = 1;
+ public static final int enclosing_method_attribute_size = 2;
+ };
+
+ // refer to compute_modifier_flags in VM code.
+ public long computeModifierFlags() {
+ long access = getAccessFlags();
+ // But check if it happens to be member class.
+ U2Array innerClassList = getInnerClasses();
+ int length = (innerClassList == null)? 0 : (int) innerClassList.length();
+ if (length > 0) {
+ if (Assert.ASSERTS_ENABLED) {
+ Assert.that(length % InnerClassAttributeOffset.innerClassNextOffset == 0 ||
+ length % InnerClassAttributeOffset.innerClassNextOffset == EnclosingMethodAttributeOffset.enclosing_method_attribute_size,
+ "just checking");
+ }
+ for (int i = 0; i < length; i += InnerClassAttributeOffset.innerClassNextOffset) {
+ if (i == length - EnclosingMethodAttributeOffset.enclosing_method_attribute_size) {
+ break;
+ }
+ int ioff = innerClassList.at(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.
+ Symbol name = getConstants().getKlassNameAt(ioff);
+
+ if (name.equals(getName())) {
+ // This is really a member class
+ access = innerClassList.at(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) {
+ U2Array innerClassList = getInnerClasses();
+ int length = ( innerClassList == null)? 0 : (int) innerClassList.length();
+ if (length > 0) {
+ if (Assert.ASSERTS_ENABLED) {
+ Assert.that(length % InnerClassAttributeOffset.innerClassNextOffset == 0 ||
+ length % InnerClassAttributeOffset.innerClassNextOffset == EnclosingMethodAttributeOffset.enclosing_method_attribute_size,
+ "just checking");
+ }
+ for (int i = 0; i < length; i += InnerClassAttributeOffset.innerClassNextOffset) {
+ if (i == length - EnclosingMethodAttributeOffset.enclosing_method_attribute_size) {
+ break;
+ }
+ int ioff = innerClassList.at(i +
+ InnerClassAttributeOffset.innerClassInnerClassInfoOffset);
+ // 'ioff' can be zero.
+ // refer to JVM spec. section 4.7.5.
+ if (ioff != 0) {
+ Symbol innerName = getConstants().getKlassNameAt(ioff);
+ Symbol myname = getName();
+ int ooff = innerClassList.at(i +
+ InnerClassAttributeOffset.innerClassOuterClassInfoOffset);
+ // for anonymous classes inner_name_index of InnerClasses
+ // attribute is zero.
+ int innerNameIndex = innerClassList.at(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 {
+ Symbol outerName = getConstants().getKlassNameAt(ooff);
+
+ // 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");
+ }
+ KlassArray interfaces = getTransitiveInterfaces();
+ final int len = interfaces.length();
+ for (int i = 0; i < len; i++) {
+ if (interfaces.getAt(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(MetadataVisitor visitor) {
+ super.iterateFields(visitor);
+ visitor.doMetadata(arrayKlasses, true);
+ // visitor.doOop(methods, true);
+ // visitor.doOop(localInterfaces, true);
+ // visitor.doOop(transitiveInterfaces, true);
+ visitor.doCInt(nonstaticFieldSize, true);
+ visitor.doCInt(staticFieldSize, true);
+ visitor.doCInt(staticOopFieldCount, true);
+ visitor.doCInt(nonstaticOopMapSize, true);
+ visitor.doCInt(isMarkedDependent, true);
+ visitor.doCInt(initState, true);
+ visitor.doCInt(itableLen, true);
+ }
+
+ /*
+ * Visit the static fields of this InstanceKlass with the obj of
+ * the visitor set to the oop holding the fields, which is
+ * currently the java mirror.
+ */
+ public void iterateStaticFields(OopVisitor visitor) {
+ visitor.setObj(getJavaMirror());
+ visitor.prologue();
+ iterateStaticFieldsInternal(visitor);
+ visitor.epilogue();
+
+ }
+
+ void iterateStaticFieldsInternal(OopVisitor visitor) {
+ int length = getJavaFieldsCount();
+ for (int index = 0; index < length; index++) {
+ short accessFlags = getFieldAccessFlags(index);
+ FieldType type = new FieldType(getFieldSignature(index));
+ AccessFlags access = new AccessFlags(accessFlags);
+ if (access.isStatic()) {
+ visitField(visitor, type, index);
+ }
+ }
+ }
+
+ public Klass getJavaSuper() {
+ return getSuper();
+ }
+
+ public static class StaticField {
+ public AccessFlags flags;
+ public Field field;
+
+ StaticField(Field field, AccessFlags flags) {
+ this.field = field;
+ this.flags = flags;
+ }
+ }
+
+ public Field[] getStaticFields() {
+ U2Array fields = getFields();
+ int length = getJavaFieldsCount();
+ ArrayList result = new ArrayList();
+ for (int index = 0; index < length; index++) {
+ Field f = newField(index);
+ if (f.isStatic()) {
+ result.add(f);
+ }
+ }
+ return (Field[])result.toArray(new Field[result.size()]);
+ }
+
+ public void iterateNonStaticFields(OopVisitor visitor, Oop obj) {
+ if (getSuper() != null) {
+ ((InstanceKlass) getSuper()).iterateNonStaticFields(visitor, obj);
+ }
+ int length = getJavaFieldsCount();
+ for (int index = 0; index < length; index++) {
+ short accessFlags = getFieldAccessFlags(index);
+ FieldType type = new FieldType(getFieldSignature(index));
+ AccessFlags access = new AccessFlags(accessFlags);
+ if (!access.isStatic()) {
+ visitField(visitor, type, index);
+ }
+ }
+ }
+
+ /** Field access by name. */
+ public Field findLocalField(Symbol name, Symbol sig) {
+ int length = getJavaFieldsCount();
+ for (int i = 0; i < length; i++) {
+ Symbol f_name = getFieldName(i);
+ Symbol f_sig = getFieldSignature(i);
+ 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) {
+ KlassArray interfaces = getLocalInterfaces();
+ int n = interfaces.length();
+ for (int i = 0; i < n; i++) {
+ InstanceKlass intf1 = (InstanceKlass) interfaces.getAt(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 fieldIndex) {
+ return newField(fieldIndex);
+ }
+
+
+ /** 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.
+ int length = getJavaFieldsCount();
+ List immediateFields = new ArrayList(length);
+ for (int index = 0; index < length; index++) {
+ 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.
+
+ KlassArray interfaces = getTransitiveInterfaces();
+ int n = interfaces.length();
+ for (int i = 0; i < n; i++) {
+ InstanceKlass intf1 = (InstanceKlass) interfaces.getAt(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.
+
+ MethodArray methods = getMethods();
+ int length = methods.length();
+ Object[] tmp = new Object[length];
+
+ IntArray methodOrdering = getMethodOrdering();
+ if (methodOrdering.length() != length) {
+ // no ordering info present
+ for (int index = 0; index < length; index++) {
+ tmp[index] = methods.at(index);
+ }
+ } else {
+ for (int index = 0; index < length; index++) {
+ int originalIndex = methodOrdering.at(index);
+ tmp[originalIndex] = methods.at(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.
+
+ KlassArray interfaces = getLocalInterfaces();
+ int length = interfaces.length();
+ List directImplementedInterfaces = new ArrayList(length);
+
+ for (int index = 0; index < length; index ++) {
+ directImplementedInterfaces.add(interfaces.getAt(index));
+ }
+
+ return directImplementedInterfaces;
+ }
+
+ 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 Method* for details) */
+ public BreakpointInfo getBreakpoints() {
+ if (!VM.getVM().isJvmtiSupported()) {
+ return null;
+ }
+ Address addr = getAddress().getAddressAt(breakpoints.getOffset());
+ return (BreakpointInfo) VMObjectFactory.newObject(BreakpointInfo.class, addr);
+ }
+
+ public IntArray getMethodOrdering() {
+ Address addr = getAddress().getAddressAt(methodOrdering.getOffset());
+ return (IntArray) VMObjectFactory.newObject(IntArray.class, addr);
+ }
+
+ public U2Array getFields() {
+ Address addr = getAddress().getAddressAt(fields.getOffset());
+ return (U2Array) VMObjectFactory.newObject(U2Array.class, addr);
+ }
+
+ public U2Array getInnerClasses() {
+ Address addr = getAddress().getAddressAt(innerClasses.getOffset());
+ return (U2Array) VMObjectFactory.newObject(U2Array.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) {
+ FieldType type = new FieldType(getFieldSignature(index));
+ if (type.isOop()) {
+ if (VM.getVM().isCompressedOopsEnabled()) {
+ return new NarrowOopField(this, index);
+ } else {
+ 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(MethodArray methods, Symbol name, Symbol signature) {
+ int len = methods.length();
+ // methods are sorted, so do binary search
+ int l = 0;
+ int h = len - 1;
+ while (l <= h) {
+ int mid = (l + h) >> 1;
+ Method m = methods.at(mid);
+ long 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 = methods.at(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 = methods.at(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(MethodArray methods, Symbol name, Symbol signature) {
+ int len = (int) methods.length();
+ for (int index = 0; index < len; index++) {
+ Method m = methods.at(index);
+ if (m.getSignature().equals(signature) && m.getName().equals(name)) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ public void dumpReplayData(PrintStream out) {
+ ConstantPool cp = getConstants();
+
+ // Try to record related loaded classes
+ Klass sub = getSubklassKlass();
+ while (sub != null) {
+ if (sub instanceof InstanceKlass) {
+ out.println("instanceKlass " + sub.getName().asString());
+ }
+ sub = sub.getNextSiblingKlass();
+ }
+
+ final int length = (int) cp.getLength();
+ out.print("ciInstanceKlass " + getName().asString() + " " + (isLinked() ? 1 : 0) + " " + (isInitialized() ? 1 : 0) + " " + length);
+ for (int index = 1; index < length; index++) {
+ out.print(" " + cp.getTags().at(index));
+ }
+ out.println();
+ if (isInitialized()) {
+ Field[] staticFields = getStaticFields();
+ for (int i = 0; i < staticFields.length; i++) {
+ Field f = staticFields[i];
+ Oop mirror = getJavaMirror();
+ if (f.isFinal() && !f.hasInitialValue()) {
+ out.print("staticfield " + getName().asString() + " " +
+ OopUtilities.escapeString(f.getID().getName()) + " " +
+ f.getFieldType().getSignature().asString() + " ");
+ if (f instanceof ByteField) {
+ ByteField bf = (ByteField)f;
+ out.println(bf.getValue(mirror));
+ } else if (f instanceof BooleanField) {
+ BooleanField bf = (BooleanField)f;
+ out.println(bf.getValue(mirror) ? 1 : 0);
+ } else if (f instanceof ShortField) {
+ ShortField bf = (ShortField)f;
+ out.println(bf.getValue(mirror));
+ } else if (f instanceof CharField) {
+ CharField bf = (CharField)f;
+ out.println(bf.getValue(mirror) & 0xffff);
+ } else if (f instanceof IntField) {
+ IntField bf = (IntField)f;
+ out.println(bf.getValue(mirror));
+ } else if (f instanceof LongField) {
+ LongField bf = (LongField)f;
+ out.println(bf.getValue(mirror));
+ } else if (f instanceof FloatField) {
+ FloatField bf = (FloatField)f;
+ out.println(Float.floatToRawIntBits(bf.getValue(mirror)));
+ } else if (f instanceof DoubleField) {
+ DoubleField bf = (DoubleField)f;
+ out.println(Double.doubleToRawLongBits(bf.getValue(mirror)));
+ } else if (f instanceof OopField) {
+ OopField bf = (OopField)f;
+
+ Oop value = bf.getValue(mirror);
+ if (value == null) {
+ out.println("null");
+ } else if (value.isInstance()) {
+ Instance inst = (Instance)value;
+ if (inst.isA(SystemDictionary.getStringKlass())) {
+ out.println("\"" + OopUtilities.stringOopToEscapedString(inst) + "\"");
+ } else {
+ out.println(inst.getKlass().getName().asString());
+ }
+ } else if (value.isObjArray()) {
+ ObjArray oa = (ObjArray)value;
+ Klass ek = (ObjArrayKlass)oa.getKlass();
+ out.println(oa.getLength() + " " + ek.getName().asString());
+ } else if (value.isTypeArray()) {
+ TypeArray ta = (TypeArray)value;
+ out.println(ta.getLength());
+ } else {
+ out.println(value);
+ }
+ }
+ }
+ }
+ }
+ }
+}