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