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