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