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