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