1 /*
   2  * Copyright (c) 2000, 2017, 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.io.*;
  28 import java.util.*;
  29 import sun.jvm.hotspot.classfile.ClassLoaderData;
  30 import sun.jvm.hotspot.debugger.*;
  31 import sun.jvm.hotspot.memory.*;
  32 import sun.jvm.hotspot.memory.Dictionary;
  33 import sun.jvm.hotspot.runtime.*;
  34 import sun.jvm.hotspot.types.*;
  35 import sun.jvm.hotspot.utilities.*;
  36 
  37 // An InstanceKlass is the VM level representation of a Java class.
  38 
  39 public class InstanceKlass extends Klass {
  40   static {
  41     VM.registerVMInitializedObserver(new Observer() {
  42         public void update(Observable o, Object data) {
  43           initialize(VM.getVM().getTypeDataBase());
  44         }
  45       });
  46   }
  47 
  48   // field offset constants
  49   private static int ACCESS_FLAGS_OFFSET;
  50   private static int NAME_INDEX_OFFSET;
  51   private static int SIGNATURE_INDEX_OFFSET;
  52   private static int INITVAL_INDEX_OFFSET;
  53   private static int LOW_OFFSET;
  54   private static int HIGH_OFFSET;
  55   private static int FIELD_SLOTS;
  56   private static short FIELDINFO_TAG_SIZE;
  57   private static short FIELDINFO_TAG_MASK;
  58   private static short FIELDINFO_TAG_OFFSET;
  59 
  60   // ClassState constants
  61   private static int CLASS_STATE_ALLOCATED;
  62   private static int CLASS_STATE_LOADED;
  63   private static int CLASS_STATE_LINKED;
  64   private static int CLASS_STATE_BEING_INITIALIZED;
  65   private static int CLASS_STATE_FULLY_INITIALIZED;
  66   private static int CLASS_STATE_INITIALIZATION_ERROR;
  67 
  68   // _misc_flags constants
  69   private static int MISC_REWRITTEN;
  70   private static int MISC_HAS_NONSTATIC_FIELDS;
  71   private static int MISC_SHOULD_VERIFY_CLASS;
  72   private static int MISC_IS_ANONYMOUS;
  73   private static int MISC_IS_CONTENDED;
  74   private static int MISC_HAS_NONSTATIC_CONCRETE_METHODS;
  75   private static int MISC_DECLARES_NONSTATIC_CONCRETE_METHODS;
  76   private static int MISC_HAS_BEEN_REDEFINED;
  77   private static int MISC_HAS_PASSED_FINGERPRINT_CHECK;
  78   private static int MISC_IS_SCRATCH_CLASS;
  79   private static int MISC_IS_SHARED_BOOT_CLASS;
  80   private static int MISC_IS_SHARED_PLATFORM_CLASS;
  81   private static int MISC_IS_SHARED_APP_CLASS;
  82 
  83   private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
  84     Type type            = db.lookupType("InstanceKlass");
  85     arrayKlasses         = new MetadataField(type.getAddressField("_array_klasses"), 0);
  86     methods              = type.getAddressField("_methods");
  87     defaultMethods       = type.getAddressField("_default_methods");
  88     methodOrdering       = type.getAddressField("_method_ordering");
  89     localInterfaces      = type.getAddressField("_local_interfaces");
  90     transitiveInterfaces = type.getAddressField("_transitive_interfaces");
  91     fields               = type.getAddressField("_fields");
  92     javaFieldsCount      = new CIntField(type.getCIntegerField("_java_fields_count"), 0);
  93     constants            = new MetadataField(type.getAddressField("_constants"), 0);
  94     sourceDebugExtension = type.getAddressField("_source_debug_extension");
  95     innerClasses         = type.getAddressField("_inner_classes");
  96     sourceFileNameIndex  = new CIntField(type.getCIntegerField("_source_file_name_index"), 0);
  97     nonstaticFieldSize   = new CIntField(type.getCIntegerField("_nonstatic_field_size"), 0);
  98     staticFieldSize      = new CIntField(type.getCIntegerField("_static_field_size"), 0);
  99     staticOopFieldCount  = new CIntField(type.getCIntegerField("_static_oop_field_count"), 0);
 100     nonstaticOopMapSize  = new CIntField(type.getCIntegerField("_nonstatic_oop_map_size"), 0);
 101     isMarkedDependent    = new CIntField(type.getCIntegerField("_is_marked_dependent"), 0);
 102     initState            = new CIntField(type.getCIntegerField("_init_state"), 0);
 103     itableLen            = new CIntField(type.getCIntegerField("_itable_len"), 0);
 104     if (VM.getVM().isJvmtiSupported()) {
 105       breakpoints        = type.getAddressField("_breakpoints");
 106     }
 107     genericSignatureIndex = new CIntField(type.getCIntegerField("_generic_signature_index"), 0);
 108     miscFlags            = new CIntField(type.getCIntegerField("_misc_flags"), 0);
 109     majorVersion         = new CIntField(type.getCIntegerField("_major_version"), 0);
 110     minorVersion         = new CIntField(type.getCIntegerField("_minor_version"), 0);
 111     headerSize           = type.getSize();
 112 
 113     // read field offset constants
 114     ACCESS_FLAGS_OFFSET            = db.lookupIntConstant("FieldInfo::access_flags_offset").intValue();
 115     NAME_INDEX_OFFSET              = db.lookupIntConstant("FieldInfo::name_index_offset").intValue();
 116     SIGNATURE_INDEX_OFFSET         = db.lookupIntConstant("FieldInfo::signature_index_offset").intValue();
 117     INITVAL_INDEX_OFFSET           = db.lookupIntConstant("FieldInfo::initval_index_offset").intValue();
 118     LOW_OFFSET                     = db.lookupIntConstant("FieldInfo::low_packed_offset").intValue();
 119     HIGH_OFFSET                    = db.lookupIntConstant("FieldInfo::high_packed_offset").intValue();
 120     FIELD_SLOTS                    = db.lookupIntConstant("FieldInfo::field_slots").intValue();
 121     FIELDINFO_TAG_SIZE             = db.lookupIntConstant("FIELDINFO_TAG_SIZE").shortValue();
 122     FIELDINFO_TAG_MASK             = db.lookupIntConstant("FIELDINFO_TAG_MASK").shortValue();
 123     FIELDINFO_TAG_OFFSET           = db.lookupIntConstant("FIELDINFO_TAG_OFFSET").shortValue();
 124 
 125     // read ClassState constants
 126     CLASS_STATE_ALLOCATED = db.lookupIntConstant("InstanceKlass::allocated").intValue();
 127     CLASS_STATE_LOADED = db.lookupIntConstant("InstanceKlass::loaded").intValue();
 128     CLASS_STATE_LINKED = db.lookupIntConstant("InstanceKlass::linked").intValue();
 129     CLASS_STATE_BEING_INITIALIZED = db.lookupIntConstant("InstanceKlass::being_initialized").intValue();
 130     CLASS_STATE_FULLY_INITIALIZED = db.lookupIntConstant("InstanceKlass::fully_initialized").intValue();
 131     CLASS_STATE_INITIALIZATION_ERROR = db.lookupIntConstant("InstanceKlass::initialization_error").intValue();
 132 
 133     MISC_REWRITTEN                    = db.lookupIntConstant("InstanceKlass::_misc_rewritten").intValue();
 134     MISC_HAS_NONSTATIC_FIELDS         = db.lookupIntConstant("InstanceKlass::_misc_has_nonstatic_fields").intValue();
 135     MISC_SHOULD_VERIFY_CLASS          = db.lookupIntConstant("InstanceKlass::_misc_should_verify_class").intValue();
 136     MISC_IS_ANONYMOUS                 = db.lookupIntConstant("InstanceKlass::_misc_is_anonymous").intValue();
 137     MISC_IS_CONTENDED                 = db.lookupIntConstant("InstanceKlass::_misc_is_contended").intValue();
 138     MISC_HAS_NONSTATIC_CONCRETE_METHODS      = db.lookupIntConstant("InstanceKlass::_misc_has_nonstatic_concrete_methods").intValue();
 139     MISC_DECLARES_NONSTATIC_CONCRETE_METHODS = db.lookupIntConstant("InstanceKlass::_misc_declares_nonstatic_concrete_methods").intValue();
 140     MISC_HAS_BEEN_REDEFINED           = db.lookupIntConstant("InstanceKlass::_misc_has_been_redefined").intValue();
 141     MISC_HAS_PASSED_FINGERPRINT_CHECK = db.lookupIntConstant("InstanceKlass::_misc_has_passed_fingerprint_check").intValue();
 142     MISC_IS_SCRATCH_CLASS             = db.lookupIntConstant("InstanceKlass::_misc_is_scratch_class").intValue();
 143     MISC_IS_SHARED_BOOT_CLASS         = db.lookupIntConstant("InstanceKlass::_misc_is_shared_boot_class").intValue();
 144     MISC_IS_SHARED_PLATFORM_CLASS     = db.lookupIntConstant("InstanceKlass::_misc_is_shared_platform_class").intValue();
 145     MISC_IS_SHARED_APP_CLASS          = db.lookupIntConstant("InstanceKlass::_misc_is_shared_app_class").intValue();
 146   }
 147 
 148   public InstanceKlass(Address addr) {
 149     super(addr);
 150     if (getJavaFieldsCount() != getAllFieldsCount()) {
 151       // Exercise the injected field logic
 152       for (int i = getJavaFieldsCount(); i < getAllFieldsCount(); i++) {
 153         getFieldName(i);
 154         getFieldSignature(i);
 155       }
 156     }
 157   }
 158 
 159   private static MetadataField arrayKlasses;
 160   private static AddressField  methods;
 161   private static AddressField  defaultMethods;
 162   private static AddressField  methodOrdering;
 163   private static AddressField  localInterfaces;
 164   private static AddressField  transitiveInterfaces;
 165   private static AddressField fields;
 166   private static CIntField javaFieldsCount;
 167   private static MetadataField constants;
 168   private static AddressField  sourceDebugExtension;
 169   private static AddressField  innerClasses;
 170   private static CIntField sourceFileNameIndex;
 171   private static CIntField nonstaticFieldSize;
 172   private static CIntField staticFieldSize;
 173   private static CIntField staticOopFieldCount;
 174   private static CIntField nonstaticOopMapSize;
 175   private static CIntField isMarkedDependent;
 176   private static CIntField initState;
 177   private static CIntField itableLen;
 178   private static AddressField breakpoints;
 179   private static CIntField genericSignatureIndex;
 180   private static CIntField miscFlags;
 181   private static CIntField majorVersion;
 182   private static CIntField minorVersion;
 183 
 184   // type safe enum for ClassState from instanceKlass.hpp
 185   public static class ClassState {
 186      public static final ClassState ALLOCATED    = new ClassState("allocated");
 187      public static final ClassState LOADED       = new ClassState("loaded");
 188      public static final ClassState LINKED       = new ClassState("linked");
 189      public static final ClassState BEING_INITIALIZED      = new ClassState("beingInitialized");
 190      public static final ClassState FULLY_INITIALIZED    = new ClassState("fullyInitialized");
 191      public static final ClassState INITIALIZATION_ERROR = new ClassState("initializationError");
 192 
 193      private ClassState(String value) {
 194         this.value = value;
 195      }
 196 
 197      public String toString() {
 198         return value;
 199      }
 200 
 201      private String value;
 202   }
 203 
 204   public int  getInitStateAsInt() { return (int) initState.getValue(this); }
 205   public ClassState getInitState() {
 206      int state = getInitStateAsInt();
 207      if (state == CLASS_STATE_ALLOCATED) {
 208         return ClassState.ALLOCATED;
 209      } else if (state == CLASS_STATE_LOADED) {
 210         return ClassState.LOADED;
 211      } else if (state == CLASS_STATE_LINKED) {
 212         return ClassState.LINKED;
 213      } else if (state == CLASS_STATE_BEING_INITIALIZED) {
 214         return ClassState.BEING_INITIALIZED;
 215      } else if (state == CLASS_STATE_FULLY_INITIALIZED) {
 216         return ClassState.FULLY_INITIALIZED;
 217      } else if (state == CLASS_STATE_INITIALIZATION_ERROR) {
 218         return ClassState.INITIALIZATION_ERROR;
 219      } else {
 220         throw new RuntimeException("should not reach here");
 221      }
 222   }
 223 
 224   // initialization state quaries
 225   public boolean isLoaded() {
 226      return getInitStateAsInt() >= CLASS_STATE_LOADED;
 227   }
 228 
 229   public boolean isLinked() {
 230      return getInitStateAsInt() >= CLASS_STATE_LINKED;
 231   }
 232 
 233   public boolean isInitialized() {
 234      return getInitStateAsInt() == CLASS_STATE_FULLY_INITIALIZED;
 235   }
 236 
 237   public boolean isNotInitialized() {
 238      return getInitStateAsInt() < CLASS_STATE_BEING_INITIALIZED;
 239   }
 240 
 241   public boolean isBeingInitialized() {
 242      return getInitStateAsInt() == CLASS_STATE_BEING_INITIALIZED;
 243   }
 244 
 245   public boolean isInErrorState() {
 246      return getInitStateAsInt() == CLASS_STATE_INITIALIZATION_ERROR;
 247   }
 248 
 249   public int getClassStatus() {
 250      int result = 0;
 251      if (isLinked()) {
 252         result |= JVMDIClassStatus.VERIFIED | JVMDIClassStatus.PREPARED;
 253      }
 254 
 255      if (isInitialized()) {
 256         if (Assert.ASSERTS_ENABLED) {
 257            Assert.that(isLinked(), "Class status is not consistent");
 258         }
 259         result |= JVMDIClassStatus.INITIALIZED;
 260      }
 261 
 262      if (isInErrorState()) {
 263         result |= JVMDIClassStatus.ERROR;
 264      }
 265      return result;
 266   }
 267 
 268   // Byteside of the header
 269   private static long headerSize;
 270 
 271   public long getObjectSize(Oop object) {
 272     return getSizeHelper() * VM.getVM().getAddressSize();
 273   }
 274 
 275   public long getSize() { // in number of bytes
 276     long wordLength = VM.getVM().getBytesPerWord();
 277     long size = getHeaderSize() +
 278                 (getVtableLen() +
 279                  getItableLen() +
 280                  getNonstaticOopMapSize()) * wordLength;
 281     if (isInterface()) {
 282       size += wordLength;
 283     }
 284     if (isAnonymous()) {
 285       size += wordLength;
 286     }
 287     if (hasStoredFingerprint()) {
 288       size += 8; // uint64_t
 289     }
 290     return alignSize(size);
 291   }
 292 
 293   private int getMiscFlags() {
 294     return (int) miscFlags.getValue(this);
 295   }
 296 
 297   public boolean isAnonymous() {
 298     return (getMiscFlags() & MISC_IS_ANONYMOUS) != 0;
 299   }
 300 
 301   public static boolean shouldStoreFingerprint() {
 302     VM vm = VM.getVM();
 303     if (vm.getCommandLineBooleanFlag("EnableJVMCI") && !vm.getCommandLineBooleanFlag("UseJVMCICompiler")) {
 304       return true;
 305     }
 306     if (vm.getCommandLineBooleanFlag("DumpSharedSpaces")) {
 307       return true;
 308     }
 309     return false;
 310   }
 311 
 312   public boolean hasStoredFingerprint() {
 313     return shouldStoreFingerprint() || isShared();
 314   }
 315 
 316   public boolean isShared() {
 317     VM vm = VM.getVM();
 318     if (vm.isSharingEnabled()) {
 319       // This is not the same implementation as the C++ function MetaspaceObj::is_shared()
 320       //     bool MetaspaceObj::is_shared() const {
 321       //       return MetaspaceShared::is_in_shared_space(this);
 322       //     }
 323       // However, MetaspaceShared::is_in_shared_space is complicated and hard to emulate in
 324       // Java code, so let's do this by looking up from the shared dictionary. Of course,
 325       // this works for shared InstanceKlass only and does not work for other types of
 326       // MetaspaceObj in the CDS shared archive.
 327       Dictionary sharedDictionary = vm.getSystemDictionary().sharedDictionary();
 328       if (sharedDictionary != null) {
 329         if (sharedDictionary.contains(this)) {
 330           return true;
 331         }
 332       }
 333     }
 334     return false;
 335   }
 336 
 337   public static long getHeaderSize() { return headerSize; }
 338 
 339   public short getFieldAccessFlags(int index) {
 340     return getFields().at(index * FIELD_SLOTS + ACCESS_FLAGS_OFFSET);
 341   }
 342 
 343   public short getFieldNameIndex(int index) {
 344     if (index >= getJavaFieldsCount()) throw new IndexOutOfBoundsException("not a Java field;");
 345     return getFields().at(index * FIELD_SLOTS + NAME_INDEX_OFFSET);
 346   }
 347 
 348   public Symbol getFieldName(int index) {
 349     int nameIndex = getFields().at(index * FIELD_SLOTS + NAME_INDEX_OFFSET);
 350     if (index < getJavaFieldsCount()) {
 351       return getConstants().getSymbolAt(nameIndex);
 352     } else {
 353       return vmSymbols.symbolAt(nameIndex);
 354     }
 355   }
 356 
 357   public short getFieldSignatureIndex(int index) {
 358     if (index >= getJavaFieldsCount()) throw new IndexOutOfBoundsException("not a Java field;");
 359     return getFields().at(index * FIELD_SLOTS + SIGNATURE_INDEX_OFFSET);
 360   }
 361 
 362   public Symbol getFieldSignature(int index) {
 363     int signatureIndex = getFields().at(index * FIELD_SLOTS + SIGNATURE_INDEX_OFFSET);
 364     if (index < getJavaFieldsCount()) {
 365       return getConstants().getSymbolAt(signatureIndex);
 366     } else {
 367       return vmSymbols.symbolAt(signatureIndex);
 368     }
 369   }
 370 
 371   public short getFieldGenericSignatureIndex(int index) {
 372     // int len = getFields().length();
 373     int allFieldsCount = getAllFieldsCount();
 374     int generic_signature_slot = allFieldsCount * FIELD_SLOTS;
 375     for (int i = 0; i < allFieldsCount; i++) {
 376       short flags = getFieldAccessFlags(i);
 377       AccessFlags access = new AccessFlags(flags);
 378       if (i == index) {
 379         if (access.fieldHasGenericSignature()) {
 380            return getFields().at(generic_signature_slot);
 381         } else {
 382           return 0;
 383         }
 384       } else {
 385         if (access.fieldHasGenericSignature()) {
 386           generic_signature_slot ++;
 387         }
 388       }
 389     }
 390     return 0;
 391   }
 392 
 393   public Symbol getFieldGenericSignature(int index) {
 394     short genericSignatureIndex = getFieldGenericSignatureIndex(index);
 395     if (genericSignatureIndex != 0)  {
 396       return getConstants().getSymbolAt(genericSignatureIndex);
 397     }
 398     return null;
 399   }
 400 
 401   public short getFieldInitialValueIndex(int index) {
 402     if (index >= getJavaFieldsCount()) throw new IndexOutOfBoundsException("not a Java field;");
 403     return getFields().at(index * FIELD_SLOTS + INITVAL_INDEX_OFFSET);
 404   }
 405 
 406   public int getFieldOffset(int index) {
 407     U2Array fields = getFields();
 408     short lo = fields.at(index * FIELD_SLOTS + LOW_OFFSET);
 409     short hi = fields.at(index * FIELD_SLOTS + HIGH_OFFSET);
 410     if ((lo & FIELDINFO_TAG_MASK) == FIELDINFO_TAG_OFFSET) {
 411       return VM.getVM().buildIntFromShorts(lo, hi) >> FIELDINFO_TAG_SIZE;
 412     }
 413     throw new RuntimeException("should not reach here");
 414   }
 415 
 416   // Accessors for declared fields
 417   public Klass     getArrayKlasses()        { return (Klass)        arrayKlasses.getValue(this); }
 418   public MethodArray  getMethods()              { return new MethodArray(methods.getValue(getAddress())); }
 419 
 420   public MethodArray  getDefaultMethods() {
 421     if (defaultMethods != null) {
 422       Address addr = defaultMethods.getValue(getAddress());
 423       if ((addr != null) && (addr.getAddressAt(0) != null)) {
 424         return new MethodArray(addr);
 425       } else {
 426         return null;
 427       }
 428     } else {
 429       return null;
 430     }
 431   }
 432 
 433   public KlassArray   getLocalInterfaces()      { return new KlassArray(localInterfaces.getValue(getAddress())); }
 434   public KlassArray   getTransitiveInterfaces() { return new KlassArray(transitiveInterfaces.getValue(getAddress())); }
 435   public int       getJavaFieldsCount()     { return                (int) javaFieldsCount.getValue(this); }
 436   public int       getAllFieldsCount()      {
 437     int len = getFields().length();
 438     int allFieldsCount = 0;
 439     for (; allFieldsCount*FIELD_SLOTS < len; allFieldsCount++) {
 440       short flags = getFieldAccessFlags(allFieldsCount);
 441       AccessFlags access = new AccessFlags(flags);
 442       if (access.fieldHasGenericSignature()) {
 443         len --;
 444       }
 445     }
 446     return allFieldsCount;
 447   }
 448   public ConstantPool getConstants()        { return (ConstantPool) constants.getValue(this); }
 449   public Symbol    getSourceFileName()      { return                getConstants().getSymbolAt(sourceFileNameIndex.getValue(this)); }
 450   public String    getSourceDebugExtension(){ return                CStringUtilities.getString(sourceDebugExtension.getValue(getAddress())); }
 451   public long      getNonstaticFieldSize()  { return                nonstaticFieldSize.getValue(this); }
 452   public long      getStaticOopFieldCount() { return                staticOopFieldCount.getValue(this); }
 453   public long      getNonstaticOopMapSize() { return                nonstaticOopMapSize.getValue(this); }
 454   public boolean   getIsMarkedDependent()   { return                isMarkedDependent.getValue(this) != 0; }
 455   public long      getItableLen()           { return                itableLen.getValue(this); }
 456   public long      majorVersion()           { return                majorVersion.getValue(this); }
 457   public long      minorVersion()           { return                minorVersion.getValue(this); }
 458   public Symbol    getGenericSignature()    {
 459     long index = genericSignatureIndex.getValue(this);
 460     if (index != 0) {
 461       return getConstants().getSymbolAt(index);
 462     } else {
 463       return null;
 464     }
 465   }
 466 
 467   // "size helper" == instance size in words
 468   public long getSizeHelper() {
 469     int lh = getLayoutHelper();
 470     if (Assert.ASSERTS_ENABLED) {
 471       Assert.that(lh > 0, "layout helper initialized for instance class");
 472     }
 473     return lh / VM.getVM().getAddressSize();
 474   }
 475 
 476   // same as enum InnerClassAttributeOffset in VM code.
 477   private static class InnerClassAttributeOffset {
 478     // from JVM spec. "InnerClasses" attribute
 479     public static int innerClassInnerClassInfoOffset;
 480     public static int innerClassOuterClassInfoOffset;
 481     public static int innerClassInnerNameOffset;
 482     public static int innerClassAccessFlagsOffset;
 483     public static int innerClassNextOffset;
 484     static {
 485       VM.registerVMInitializedObserver(new Observer() {
 486           public void update(Observable o, Object data) {
 487               initialize(VM.getVM().getTypeDataBase());
 488           }
 489       });
 490     }
 491 
 492     private static synchronized void initialize(TypeDataBase db) {
 493       innerClassInnerClassInfoOffset = db.lookupIntConstant(
 494           "InstanceKlass::inner_class_inner_class_info_offset").intValue();
 495       innerClassOuterClassInfoOffset = db.lookupIntConstant(
 496           "InstanceKlass::inner_class_outer_class_info_offset").intValue();
 497       innerClassInnerNameOffset = db.lookupIntConstant(
 498           "InstanceKlass::inner_class_inner_name_offset").intValue();
 499       innerClassAccessFlagsOffset = db.lookupIntConstant(
 500           "InstanceKlass::inner_class_access_flags_offset").intValue();
 501       innerClassNextOffset = db.lookupIntConstant(
 502           "InstanceKlass::inner_class_next_offset").intValue();
 503     }
 504   }
 505 
 506   private static class EnclosingMethodAttributeOffset {
 507     public static int enclosingMethodAttributeSize;
 508     static {
 509       VM.registerVMInitializedObserver(new Observer() {
 510           public void update(Observable o, Object data) {
 511               initialize(VM.getVM().getTypeDataBase());
 512           }
 513       });
 514     }
 515     private static synchronized void initialize(TypeDataBase db) {
 516       enclosingMethodAttributeSize = db.lookupIntConstant("InstanceKlass::enclosing_method_attribute_size").intValue();
 517     }
 518   }
 519 
 520   // refer to compute_modifier_flags in VM code.
 521   public long computeModifierFlags() {
 522     long access = getAccessFlags();
 523     // But check if it happens to be member class.
 524     U2Array innerClassList = getInnerClasses();
 525     int length = (innerClassList == null)? 0 : (int) innerClassList.length();
 526     if (length > 0) {
 527        if (Assert.ASSERTS_ENABLED) {
 528           Assert.that(length % InnerClassAttributeOffset.innerClassNextOffset == 0 ||
 529                       length % InnerClassAttributeOffset.innerClassNextOffset == EnclosingMethodAttributeOffset.enclosingMethodAttributeSize,
 530                       "just checking");
 531        }
 532        for (int i = 0; i < length; i += InnerClassAttributeOffset.innerClassNextOffset) {
 533           if (i == length - EnclosingMethodAttributeOffset.enclosingMethodAttributeSize) {
 534               break;
 535           }
 536           int ioff = innerClassList.at(i +
 537                          InnerClassAttributeOffset.innerClassInnerClassInfoOffset);
 538           // 'ioff' can be zero.
 539           // refer to JVM spec. section 4.7.5.
 540           if (ioff != 0) {
 541              // only look at classes that are already loaded
 542              // since we are looking for the flags for our self.
 543              Symbol name = getConstants().getKlassNameAt(ioff);
 544 
 545              if (name.equals(getName())) {
 546                 // This is really a member class
 547                 access = innerClassList.at(i +
 548                         InnerClassAttributeOffset.innerClassAccessFlagsOffset);
 549                 break;
 550              }
 551           }
 552        } // for inner classes
 553     }
 554 
 555     // Remember to strip ACC_SUPER bit
 556     return (access & (~JVM_ACC_SUPER)) & JVM_ACC_WRITTEN_FLAGS;
 557   }
 558 
 559 
 560   // whether given Symbol is name of an inner/nested Klass of this Klass?
 561   // anonymous and local classes are excluded.
 562   public boolean isInnerClassName(Symbol sym) {
 563     return isInInnerClasses(sym, false);
 564   }
 565 
 566   // whether given Symbol is name of an inner/nested Klass of this Klass?
 567   // anonymous classes excluded, but local classes are included.
 568   public boolean isInnerOrLocalClassName(Symbol sym) {
 569     return isInInnerClasses(sym, true);
 570   }
 571 
 572   private boolean isInInnerClasses(Symbol sym, boolean includeLocals) {
 573     U2Array innerClassList = getInnerClasses();
 574     int length = ( innerClassList == null)? 0 : (int) innerClassList.length();
 575     if (length > 0) {
 576        if (Assert.ASSERTS_ENABLED) {
 577          Assert.that(length % InnerClassAttributeOffset.innerClassNextOffset == 0 ||
 578                      length % InnerClassAttributeOffset.innerClassNextOffset == EnclosingMethodAttributeOffset.enclosingMethodAttributeSize,
 579                      "just checking");
 580        }
 581        for (int i = 0; i < length; i += InnerClassAttributeOffset.innerClassNextOffset) {
 582          if (i == length - EnclosingMethodAttributeOffset.enclosingMethodAttributeSize) {
 583              break;
 584          }
 585          int ioff = innerClassList.at(i +
 586                         InnerClassAttributeOffset.innerClassInnerClassInfoOffset);
 587          // 'ioff' can be zero.
 588          // refer to JVM spec. section 4.7.5.
 589          if (ioff != 0) {
 590             Symbol innerName = getConstants().getKlassNameAt(ioff);
 591             Symbol myname = getName();
 592             int ooff = innerClassList.at(i +
 593                         InnerClassAttributeOffset.innerClassOuterClassInfoOffset);
 594             // for anonymous classes inner_name_index of InnerClasses
 595             // attribute is zero.
 596             int innerNameIndex = innerClassList.at(i +
 597                         InnerClassAttributeOffset.innerClassInnerNameOffset);
 598             // if this is not a member (anonymous, local etc.), 'ooff' will be zero
 599             // refer to JVM spec. section 4.7.5.
 600             if (ooff == 0) {
 601                if (includeLocals) {
 602                   // does it looks like my local class?
 603                   if (innerName.equals(sym) &&
 604                      innerName.asString().startsWith(myname.asString())) {
 605                      // exclude anonymous classes.
 606                      return (innerNameIndex != 0);
 607                   }
 608                }
 609             } else {
 610                Symbol outerName = getConstants().getKlassNameAt(ooff);
 611 
 612                // include only if current class is outer class.
 613                if (outerName.equals(myname) && innerName.equals(sym)) {
 614                   return true;
 615                }
 616            }
 617          }
 618        } // for inner classes
 619        return false;
 620     } else {
 621        return false;
 622     }
 623   }
 624 
 625   public boolean implementsInterface(Klass k) {
 626     if (Assert.ASSERTS_ENABLED) {
 627       Assert.that(k.isInterface(), "should not reach here");
 628     }
 629     KlassArray interfaces =  getTransitiveInterfaces();
 630     final int len = interfaces.length();
 631     for (int i = 0; i < len; i++) {
 632       if (interfaces.getAt(i).equals(k)) return true;
 633     }
 634     return false;
 635   }
 636 
 637   boolean computeSubtypeOf(Klass k) {
 638     if (k.isInterface()) {
 639       return implementsInterface(k);
 640     } else {
 641       return super.computeSubtypeOf(k);
 642     }
 643   }
 644 
 645   public void printValueOn(PrintStream tty) {
 646     tty.print("InstanceKlass for " + getName().asString());
 647   }
 648 
 649   public void iterateFields(MetadataVisitor visitor) {
 650     super.iterateFields(visitor);
 651     visitor.doMetadata(arrayKlasses, true);
 652     // visitor.doOop(methods, true);
 653     // visitor.doOop(localInterfaces, true);
 654     // visitor.doOop(transitiveInterfaces, true);
 655       visitor.doCInt(nonstaticFieldSize, true);
 656       visitor.doCInt(staticFieldSize, true);
 657       visitor.doCInt(staticOopFieldCount, true);
 658       visitor.doCInt(nonstaticOopMapSize, true);
 659       visitor.doCInt(isMarkedDependent, true);
 660       visitor.doCInt(initState, true);
 661       visitor.doCInt(itableLen, true);
 662     }
 663 
 664   /*
 665    *  Visit the static fields of this InstanceKlass with the obj of
 666    *  the visitor set to the oop holding the fields, which is
 667    *  currently the java mirror.
 668    */
 669   public void iterateStaticFields(OopVisitor visitor) {
 670     visitor.setObj(getJavaMirror());
 671     visitor.prologue();
 672     iterateStaticFieldsInternal(visitor);
 673     visitor.epilogue();
 674 
 675   }
 676 
 677   void iterateStaticFieldsInternal(OopVisitor visitor) {
 678     int length = getJavaFieldsCount();
 679     for (int index = 0; index < length; index++) {
 680       short accessFlags    = getFieldAccessFlags(index);
 681       FieldType   type   = new FieldType(getFieldSignature(index));
 682       AccessFlags access = new AccessFlags(accessFlags);
 683       if (access.isStatic()) {
 684         visitField(visitor, type, index);
 685       }
 686     }
 687   }
 688 
 689   public Klass getJavaSuper() {
 690     return getSuper();
 691   }
 692 
 693   public static class StaticField {
 694     public AccessFlags flags;
 695     public Field field;
 696 
 697     StaticField(Field field, AccessFlags flags) {
 698       this.field = field;
 699       this.flags = flags;
 700     }
 701   }
 702 
 703   public Field[] getStaticFields() {
 704     U2Array fields = getFields();
 705     int length = getJavaFieldsCount();
 706     ArrayList result = new ArrayList();
 707     for (int index = 0; index < length; index++) {
 708       Field f = newField(index);
 709       if (f.isStatic()) {
 710         result.add(f);
 711       }
 712     }
 713     return (Field[])result.toArray(new Field[result.size()]);
 714   }
 715 
 716   public void iterateNonStaticFields(OopVisitor visitor, Oop obj) {
 717     if (getSuper() != null) {
 718       ((InstanceKlass) getSuper()).iterateNonStaticFields(visitor, obj);
 719     }
 720     int length = getJavaFieldsCount();
 721     for (int index = 0; index < length; index++) {
 722       short accessFlags    = getFieldAccessFlags(index);
 723       FieldType   type   = new FieldType(getFieldSignature(index));
 724       AccessFlags access = new AccessFlags(accessFlags);
 725       if (!access.isStatic()) {
 726         visitField(visitor, type, index);
 727       }
 728     }
 729   }
 730 
 731   /** Field access by name. */
 732   public Field findLocalField(String name, String sig) {
 733     int length = getJavaFieldsCount();
 734     for (int i = 0; i < length; i++) {
 735       Symbol f_name = getFieldName(i);
 736       Symbol f_sig  = getFieldSignature(i);
 737       if (f_name.equals(name) && f_sig.equals(sig)) {
 738         return newField(i);
 739       }
 740     }
 741 
 742     return null;
 743   }
 744 
 745   /** Find field in direct superinterfaces. */
 746   public Field findInterfaceField(String name, String sig) {
 747     KlassArray interfaces = getLocalInterfaces();
 748     int n = interfaces.length();
 749     for (int i = 0; i < n; i++) {
 750       InstanceKlass intf1 = (InstanceKlass) interfaces.getAt(i);
 751       if (Assert.ASSERTS_ENABLED) {
 752         Assert.that(intf1.isInterface(), "just checking type");
 753      }
 754       // search for field in current interface
 755       Field f = intf1.findLocalField(name, sig);
 756       if (f != null) {
 757         if (Assert.ASSERTS_ENABLED) {
 758           Assert.that(f.getAccessFlagsObj().isStatic(), "interface field must be static");
 759         }
 760         return f;
 761       }
 762       // search for field in direct superinterfaces
 763       f = intf1.findInterfaceField(name, sig);
 764       if (f != null) return f;
 765     }
 766     // otherwise field lookup fails
 767     return null;
 768   }
 769 
 770   /** Find field according to JVM spec 5.4.3.2, returns the klass in
 771       which the field is defined. */
 772   public Field findField(String name, String sig) {
 773     // search order according to newest JVM spec (5.4.3.2, p.167).
 774     // 1) search for field in current klass
 775     Field f = findLocalField(name, sig);
 776     if (f != null) return f;
 777 
 778     // 2) search for field recursively in direct superinterfaces
 779     f = findInterfaceField(name, sig);
 780     if (f != null) return f;
 781 
 782     // 3) apply field lookup recursively if superclass exists
 783     InstanceKlass supr = (InstanceKlass) getSuper();
 784     if (supr != null) return supr.findField(name, sig);
 785 
 786     // 4) otherwise field lookup fails
 787     return null;
 788   }
 789 
 790   /** Find field according to JVM spec 5.4.3.2, returns the klass in
 791       which the field is defined (retained only for backward
 792       compatibility with jdbx) */
 793   public Field findFieldDbg(String name, String sig) {
 794     return findField(name, sig);
 795   }
 796 
 797   /** Get field by its index in the fields array. Only designed for
 798       use in a debugging system. */
 799   public Field getFieldByIndex(int fieldIndex) {
 800     return newField(fieldIndex);
 801   }
 802 
 803 
 804     /** Return a List of SA Fields for the fields declared in this class.
 805         Inherited fields are not included.
 806         Return an empty list if there are no fields declared in this class.
 807         Only designed for use in a debugging system. */
 808     public List getImmediateFields() {
 809         // A list of Fields for each field declared in this class/interface,
 810         // not including inherited fields.
 811         int length = getJavaFieldsCount();
 812         List immediateFields = new ArrayList(length);
 813         for (int index = 0; index < length; index++) {
 814             immediateFields.add(getFieldByIndex(index));
 815         }
 816 
 817         return immediateFields;
 818     }
 819 
 820     /** Return a List of SA Fields for all the java fields in this class,
 821         including all inherited fields.  This includes hidden
 822         fields.  Thus the returned list can contain fields with
 823         the same name.
 824         Return an empty list if there are no fields.
 825         Only designed for use in a debugging system. */
 826     public List getAllFields() {
 827         // Contains a Field for each field in this class, including immediate
 828         // fields and inherited fields.
 829         List  allFields = getImmediateFields();
 830 
 831         // transitiveInterfaces contains all interfaces implemented
 832         // by this class and its superclass chain with no duplicates.
 833 
 834         KlassArray interfaces = getTransitiveInterfaces();
 835         int n = interfaces.length();
 836         for (int i = 0; i < n; i++) {
 837             InstanceKlass intf1 = (InstanceKlass) interfaces.getAt(i);
 838             if (Assert.ASSERTS_ENABLED) {
 839                 Assert.that(intf1.isInterface(), "just checking type");
 840             }
 841             allFields.addAll(intf1.getImmediateFields());
 842         }
 843 
 844         // Get all fields in the superclass, recursively.  But, don't
 845         // include fields in interfaces implemented by superclasses;
 846         // we already have all those.
 847         if (!isInterface()) {
 848             InstanceKlass supr;
 849             if  ( (supr = (InstanceKlass) getSuper()) != null) {
 850                 allFields.addAll(supr.getImmediateFields());
 851             }
 852         }
 853 
 854         return allFields;
 855     }
 856 
 857 
 858     /** Return a List of SA Methods declared directly in this class/interface.
 859         Return an empty list if there are none, or if this isn't a class/
 860         interface.
 861     */
 862     public List getImmediateMethods() {
 863       // Contains a Method for each method declared in this class/interface
 864       // not including inherited methods.
 865 
 866       MethodArray methods = getMethods();
 867       int length = methods.length();
 868       Object[] tmp = new Object[length];
 869 
 870       IntArray methodOrdering = getMethodOrdering();
 871       if (methodOrdering.length() != length) {
 872          // no ordering info present
 873          for (int index = 0; index < length; index++) {
 874             tmp[index] = methods.at(index);
 875          }
 876       } else {
 877          for (int index = 0; index < length; index++) {
 878             int originalIndex = methodOrdering.at(index);
 879             tmp[originalIndex] = methods.at(index);
 880          }
 881       }
 882 
 883       return Arrays.asList(tmp);
 884     }
 885 
 886     /** Return a List containing an SA InstanceKlass for each
 887         interface named in this class's 'implements' clause.
 888     */
 889     public List getDirectImplementedInterfaces() {
 890         // Contains an InstanceKlass for each interface in this classes
 891         // 'implements' clause.
 892 
 893         KlassArray interfaces = getLocalInterfaces();
 894         int length = interfaces.length();
 895         List directImplementedInterfaces = new ArrayList(length);
 896 
 897         for (int index = 0; index < length; index ++) {
 898             directImplementedInterfaces.add(interfaces.getAt(index));
 899         }
 900 
 901         return directImplementedInterfaces;
 902     }
 903 
 904   public Klass arrayKlassImpl(boolean orNull, int n) {
 905     // FIXME: in reflective system this would need to change to
 906     // actually allocate
 907     if (getArrayKlasses() == null) { return null; }
 908     ObjArrayKlass oak = (ObjArrayKlass) getArrayKlasses();
 909     if (orNull) {
 910       return oak.arrayKlassOrNull(n);
 911     }
 912     return oak.arrayKlass(n);
 913   }
 914 
 915   public Klass arrayKlassImpl(boolean orNull) {
 916     return arrayKlassImpl(orNull, 1);
 917   }
 918 
 919   public String signature() {
 920      return "L" + super.signature() + ";";
 921   }
 922 
 923   /** Find method in vtable. */
 924   public Method findMethod(String name, String sig) {
 925     return findMethod(getMethods(), name, sig);
 926   }
 927 
 928   /** Breakpoint support (see methods on Method* for details) */
 929   public BreakpointInfo getBreakpoints() {
 930     if (!VM.getVM().isJvmtiSupported()) {
 931       return null;
 932     }
 933     Address addr = getAddress().getAddressAt(breakpoints.getOffset());
 934     return (BreakpointInfo) VMObjectFactory.newObject(BreakpointInfo.class, addr);
 935   }
 936 
 937   public IntArray  getMethodOrdering() {
 938     Address addr = getAddress().getAddressAt(methodOrdering.getOffset());
 939     return (IntArray) VMObjectFactory.newObject(IntArray.class, addr);
 940   }
 941 
 942   public U2Array getFields() {
 943     Address addr = getAddress().getAddressAt(fields.getOffset());
 944     return (U2Array) VMObjectFactory.newObject(U2Array.class, addr);
 945   }
 946 
 947   public U2Array getInnerClasses() {
 948     Address addr = getAddress().getAddressAt(innerClasses.getOffset());
 949     return (U2Array) VMObjectFactory.newObject(U2Array.class, addr);
 950   }
 951 
 952 
 953   //----------------------------------------------------------------------
 954   // Internals only below this point
 955   //
 956 
 957   private void visitField(OopVisitor visitor, FieldType type, int index) {
 958     Field f = newField(index);
 959     if (type.isOop()) {
 960       visitor.doOop((OopField) f, false);
 961       return;
 962     }
 963     if (type.isByte()) {
 964       visitor.doByte((ByteField) f, false);
 965       return;
 966     }
 967     if (type.isChar()) {
 968       visitor.doChar((CharField) f, false);
 969       return;
 970     }
 971     if (type.isDouble()) {
 972       visitor.doDouble((DoubleField) f, false);
 973       return;
 974     }
 975     if (type.isFloat()) {
 976       visitor.doFloat((FloatField) f, false);
 977       return;
 978     }
 979     if (type.isInt()) {
 980       visitor.doInt((IntField) f, false);
 981       return;
 982     }
 983     if (type.isLong()) {
 984       visitor.doLong((LongField) f, false);
 985       return;
 986     }
 987     if (type.isShort()) {
 988       visitor.doShort((ShortField) f, false);
 989       return;
 990     }
 991     if (type.isBoolean()) {
 992       visitor.doBoolean((BooleanField) f, false);
 993       return;
 994     }
 995   }
 996 
 997   // Creates new field from index in fields TypeArray
 998   private Field newField(int index) {
 999     FieldType type = new FieldType(getFieldSignature(index));
1000     if (type.isOop()) {
1001      if (VM.getVM().isCompressedOopsEnabled()) {
1002         return new NarrowOopField(this, index);
1003      } else {
1004         return new OopField(this, index);
1005      }
1006     }
1007     if (type.isByte()) {
1008       return new ByteField(this, index);
1009     }
1010     if (type.isChar()) {
1011       return new CharField(this, index);
1012     }
1013     if (type.isDouble()) {
1014       return new DoubleField(this, index);
1015     }
1016     if (type.isFloat()) {
1017       return new FloatField(this, index);
1018     }
1019     if (type.isInt()) {
1020       return new IntField(this, index);
1021     }
1022     if (type.isLong()) {
1023       return new LongField(this, index);
1024     }
1025     if (type.isShort()) {
1026       return new ShortField(this, index);
1027     }
1028     if (type.isBoolean()) {
1029       return new BooleanField(this, index);
1030     }
1031     throw new RuntimeException("Illegal field type at index " + index);
1032   }
1033 
1034   private static Method findMethod(MethodArray methods, String name, String signature) {
1035     int index = linearSearch(methods, name, signature);
1036     if (index != -1) {
1037       return methods.at(index);
1038     } else {
1039       return null;
1040     }
1041   }
1042 
1043   private static int linearSearch(MethodArray methods, String name, String signature) {
1044     int len = (int) methods.length();
1045     for (int index = 0; index < len; index++) {
1046       Method m = methods.at(index);
1047       if (m.getSignature().equals(signature) && m.getName().equals(name)) {
1048         return index;
1049       }
1050     }
1051     return -1;
1052   }
1053 
1054   public void dumpReplayData(PrintStream out) {
1055     ConstantPool cp = getConstants();
1056 
1057     // Try to record related loaded classes
1058     Klass sub = getSubklassKlass();
1059     while (sub != null) {
1060         if (sub instanceof InstanceKlass) {
1061             out.println("instanceKlass " + sub.getName().asString());
1062         }
1063         sub = sub.getNextSiblingKlass();
1064     }
1065 
1066     final int length = (int) cp.getLength();
1067     out.print("ciInstanceKlass " + getName().asString() + " " + (isLinked() ? 1 : 0) + " " + (isInitialized() ? 1 : 0) + " " + length);
1068     for (int index = 1; index < length; index++) {
1069       out.print(" " + cp.getTags().at(index));
1070     }
1071     out.println();
1072     if (isInitialized()) {
1073       Field[] staticFields = getStaticFields();
1074       for (int i = 0; i < staticFields.length; i++) {
1075         Field f = staticFields[i];
1076         Oop mirror = getJavaMirror();
1077         if (f.isFinal() && !f.hasInitialValue()) {
1078           out.print("staticfield " + getName().asString() + " " +
1079                     OopUtilities.escapeString(f.getID().getName()) + " " +
1080                     f.getFieldType().getSignature().asString() + " ");
1081           if (f instanceof ByteField) {
1082             ByteField bf = (ByteField)f;
1083             out.println(bf.getValue(mirror));
1084           } else if (f instanceof BooleanField) {
1085             BooleanField bf = (BooleanField)f;
1086             out.println(bf.getValue(mirror) ? 1 : 0);
1087           } else if (f instanceof ShortField) {
1088             ShortField bf = (ShortField)f;
1089             out.println(bf.getValue(mirror));
1090           } else if (f instanceof CharField) {
1091             CharField bf = (CharField)f;
1092             out.println(bf.getValue(mirror) & 0xffff);
1093           } else if (f instanceof IntField) {
1094             IntField bf = (IntField)f;
1095             out.println(bf.getValue(mirror));
1096           } else  if (f instanceof LongField) {
1097             LongField bf = (LongField)f;
1098             out.println(bf.getValue(mirror));
1099           } else if (f instanceof FloatField) {
1100             FloatField bf = (FloatField)f;
1101             out.println(Float.floatToRawIntBits(bf.getValue(mirror)));
1102           } else if (f instanceof DoubleField) {
1103             DoubleField bf = (DoubleField)f;
1104             out.println(Double.doubleToRawLongBits(bf.getValue(mirror)));
1105           } else if (f instanceof OopField) {
1106             OopField bf = (OopField)f;
1107 
1108             Oop value = bf.getValue(mirror);
1109             if (value == null) {
1110               out.println("null");
1111             } else if (value.isInstance()) {
1112               Instance inst = (Instance)value;
1113               if (inst.isA(SystemDictionary.getStringKlass())) {
1114                 out.println("\"" + OopUtilities.stringOopToEscapedString(inst) + "\"");
1115               } else {
1116                 out.println(inst.getKlass().getName().asString());
1117               }
1118             } else if (value.isObjArray()) {
1119               ObjArray oa = (ObjArray)value;
1120               Klass ek = (ObjArrayKlass)oa.getKlass();
1121               out.println(oa.getLength() + " " + ek.getName().asString());
1122             } else if (value.isTypeArray()) {
1123               TypeArray ta = (TypeArray)value;
1124               out.println(ta.getLength());
1125             } else {
1126               out.println(value);
1127             }
1128           }
1129         }
1130       }
1131     }
1132   }
1133 }