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