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