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