1 /*
   2  * Copyright (c) 2000, 2016, 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_DEFAULT_METHODS;
  75   private static int MISC_DECLARES_DEFAULT_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_DEFAULT_METHODS          = db.lookupIntConstant("InstanceKlass::_misc_has_default_methods").intValue();
 140     MISC_DECLARES_DEFAULT_METHODS     = db.lookupIntConstant("InstanceKlass::_misc_declares_default_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              ConstantPool.CPSlot classInfo = getConstants().getSlotAt(ioff);
 520              Symbol name = null;
 521              if (classInfo.isResolved()) {
 522                name = classInfo.getKlass().getName();
 523              } else if (classInfo.isUnresolved()) {
 524                name = classInfo.getSymbol();
 525              } else {
 526                 throw new RuntimeException("should not reach here");
 527              }
 528 
 529              if (name.equals(getName())) {
 530                 // This is really a member class
 531                 access = innerClassList.at(i +
 532                         InnerClassAttributeOffset.innerClassAccessFlagsOffset);
 533                 break;
 534              }
 535           }
 536        } // for inner classes
 537     }
 538 
 539     // Remember to strip ACC_SUPER bit
 540     return (access & (~JVM_ACC_SUPER)) & JVM_ACC_WRITTEN_FLAGS;
 541   }
 542 
 543 
 544   // whether given Symbol is name of an inner/nested Klass of this Klass?
 545   // anonymous and local classes are excluded.
 546   public boolean isInnerClassName(Symbol sym) {
 547     return isInInnerClasses(sym, false);
 548   }
 549 
 550   // whether given Symbol is name of an inner/nested Klass of this Klass?
 551   // anonymous classes excluded, but local classes are included.
 552   public boolean isInnerOrLocalClassName(Symbol sym) {
 553     return isInInnerClasses(sym, true);
 554   }
 555 
 556   private boolean isInInnerClasses(Symbol sym, boolean includeLocals) {
 557     U2Array innerClassList = getInnerClasses();
 558     int length = ( innerClassList == null)? 0 : (int) innerClassList.length();
 559     if (length > 0) {
 560        if (Assert.ASSERTS_ENABLED) {
 561          Assert.that(length % InnerClassAttributeOffset.innerClassNextOffset == 0 ||
 562                      length % InnerClassAttributeOffset.innerClassNextOffset == EnclosingMethodAttributeOffset.enclosing_method_attribute_size,
 563                      "just checking");
 564        }
 565        for (int i = 0; i < length; i += InnerClassAttributeOffset.innerClassNextOffset) {
 566          if (i == length - EnclosingMethodAttributeOffset.enclosing_method_attribute_size) {
 567              break;
 568          }
 569          int ioff = innerClassList.at(i +
 570                         InnerClassAttributeOffset.innerClassInnerClassInfoOffset);
 571          // 'ioff' can be zero.
 572          // refer to JVM spec. section 4.7.5.
 573          if (ioff != 0) {
 574             ConstantPool.CPSlot iclassInfo = getConstants().getSlotAt(ioff);
 575             Symbol innerName = getConstants().getKlassNameAt(ioff);
 576             Symbol myname = getName();
 577             int ooff = innerClassList.at(i +
 578                         InnerClassAttributeOffset.innerClassOuterClassInfoOffset);
 579             // for anonymous classes inner_name_index of InnerClasses
 580             // attribute is zero.
 581             int innerNameIndex = innerClassList.at(i +
 582                         InnerClassAttributeOffset.innerClassInnerNameOffset);
 583             // if this is not a member (anonymous, local etc.), 'ooff' will be zero
 584             // refer to JVM spec. section 4.7.5.
 585             if (ooff == 0) {
 586                if (includeLocals) {
 587                   // does it looks like my local class?
 588                   if (innerName.equals(sym) &&
 589                      innerName.asString().startsWith(myname.asString())) {
 590                      // exclude anonymous classes.
 591                      return (innerNameIndex != 0);
 592                   }
 593                }
 594             } else {
 595                ConstantPool.CPSlot oclassInfo = getConstants().getSlotAt(ooff);
 596                Symbol outerName = null;
 597                if (oclassInfo.isResolved()) {
 598                  outerName = oclassInfo.getKlass().getName();
 599                } else if (oclassInfo.isUnresolved()) {
 600                  outerName = oclassInfo.getSymbol();
 601                } else {
 602                   throw new RuntimeException("should not reach here");
 603                }
 604 
 605                // include only if current class is outer class.
 606                if (outerName.equals(myname) && innerName.equals(sym)) {
 607                   return true;
 608                }
 609            }
 610          }
 611        } // for inner classes
 612        return false;
 613     } else {
 614        return false;
 615     }
 616   }
 617 
 618   public boolean implementsInterface(Klass k) {
 619     if (Assert.ASSERTS_ENABLED) {
 620       Assert.that(k.isInterface(), "should not reach here");
 621     }
 622     KlassArray interfaces =  getTransitiveInterfaces();
 623     final int len = interfaces.length();
 624     for (int i = 0; i < len; i++) {
 625       if (interfaces.getAt(i).equals(k)) return true;
 626     }
 627     return false;
 628   }
 629 
 630   boolean computeSubtypeOf(Klass k) {
 631     if (k.isInterface()) {
 632       return implementsInterface(k);
 633     } else {
 634       return super.computeSubtypeOf(k);
 635     }
 636   }
 637 
 638   public void printValueOn(PrintStream tty) {
 639     tty.print("InstanceKlass for " + getName().asString());
 640   }
 641 
 642   public void iterateFields(MetadataVisitor visitor) {
 643     super.iterateFields(visitor);
 644     visitor.doMetadata(arrayKlasses, true);
 645     // visitor.doOop(methods, true);
 646     // visitor.doOop(localInterfaces, true);
 647     // visitor.doOop(transitiveInterfaces, true);
 648       visitor.doCInt(nonstaticFieldSize, true);
 649       visitor.doCInt(staticFieldSize, true);
 650       visitor.doCInt(staticOopFieldCount, true);
 651       visitor.doCInt(nonstaticOopMapSize, true);
 652       visitor.doCInt(isMarkedDependent, true);
 653       visitor.doCInt(initState, true);
 654       visitor.doCInt(itableLen, true);
 655     }
 656 
 657   /*
 658    *  Visit the static fields of this InstanceKlass with the obj of
 659    *  the visitor set to the oop holding the fields, which is
 660    *  currently the java mirror.
 661    */
 662   public void iterateStaticFields(OopVisitor visitor) {
 663     visitor.setObj(getJavaMirror());
 664     visitor.prologue();
 665     iterateStaticFieldsInternal(visitor);
 666     visitor.epilogue();
 667 
 668   }
 669 
 670   void iterateStaticFieldsInternal(OopVisitor visitor) {
 671     int length = getJavaFieldsCount();
 672     for (int index = 0; index < length; index++) {
 673       short accessFlags    = getFieldAccessFlags(index);
 674       FieldType   type   = new FieldType(getFieldSignature(index));
 675       AccessFlags access = new AccessFlags(accessFlags);
 676       if (access.isStatic()) {
 677         visitField(visitor, type, index);
 678       }
 679     }
 680   }
 681 
 682   public Klass getJavaSuper() {
 683     return getSuper();
 684   }
 685 
 686   public static class StaticField {
 687     public AccessFlags flags;
 688     public Field field;
 689 
 690     StaticField(Field field, AccessFlags flags) {
 691       this.field = field;
 692       this.flags = flags;
 693     }
 694   }
 695 
 696   public Field[] getStaticFields() {
 697     U2Array fields = getFields();
 698     int length = getJavaFieldsCount();
 699     ArrayList result = new ArrayList();
 700     for (int index = 0; index < length; index++) {
 701       Field f = newField(index);
 702       if (f.isStatic()) {
 703         result.add(f);
 704       }
 705     }
 706     return (Field[])result.toArray(new Field[result.size()]);
 707   }
 708 
 709   public void iterateNonStaticFields(OopVisitor visitor, Oop obj) {
 710     if (getSuper() != null) {
 711       ((InstanceKlass) getSuper()).iterateNonStaticFields(visitor, obj);
 712     }
 713     int length = getJavaFieldsCount();
 714     for (int index = 0; index < length; index++) {
 715       short accessFlags    = getFieldAccessFlags(index);
 716       FieldType   type   = new FieldType(getFieldSignature(index));
 717       AccessFlags access = new AccessFlags(accessFlags);
 718       if (!access.isStatic()) {
 719         visitField(visitor, type, index);
 720       }
 721     }
 722   }
 723 
 724   /** Field access by name. */
 725   public Field findLocalField(Symbol name, Symbol sig) {
 726     int length = getJavaFieldsCount();
 727     for (int i = 0; i < length; i++) {
 728       Symbol f_name = getFieldName(i);
 729       Symbol f_sig  = getFieldSignature(i);
 730       if (name.equals(f_name) && sig.equals(f_sig)) {
 731         return newField(i);
 732       }
 733     }
 734 
 735     return null;
 736   }
 737 
 738   /** Find field in direct superinterfaces. */
 739   public Field findInterfaceField(Symbol name, Symbol sig) {
 740     KlassArray interfaces = getLocalInterfaces();
 741     int n = interfaces.length();
 742     for (int i = 0; i < n; i++) {
 743       InstanceKlass intf1 = (InstanceKlass) interfaces.getAt(i);
 744       if (Assert.ASSERTS_ENABLED) {
 745         Assert.that(intf1.isInterface(), "just checking type");
 746       }
 747       // search for field in current interface
 748       Field f = intf1.findLocalField(name, sig);
 749       if (f != null) {
 750         if (Assert.ASSERTS_ENABLED) {
 751           Assert.that(f.getAccessFlagsObj().isStatic(), "interface field must be static");
 752         }
 753         return f;
 754       }
 755       // search for field in direct superinterfaces
 756       f = intf1.findInterfaceField(name, sig);
 757       if (f != null) return f;
 758     }
 759     // otherwise field lookup fails
 760     return null;
 761   }
 762 
 763   /** Find field according to JVM spec 5.4.3.2, returns the klass in
 764       which the field is defined. */
 765   public Field findField(Symbol name, Symbol sig) {
 766     // search order according to newest JVM spec (5.4.3.2, p.167).
 767     // 1) search for field in current klass
 768     Field f = findLocalField(name, sig);
 769     if (f != null) return f;
 770 
 771     // 2) search for field recursively in direct superinterfaces
 772     f = findInterfaceField(name, sig);
 773     if (f != null) return f;
 774 
 775     // 3) apply field lookup recursively if superclass exists
 776     InstanceKlass supr = (InstanceKlass) getSuper();
 777     if (supr != null) return supr.findField(name, sig);
 778 
 779     // 4) otherwise field lookup fails
 780     return null;
 781   }
 782 
 783   /** Find field according to JVM spec 5.4.3.2, returns the klass in
 784       which the field is defined (convenience routine) */
 785   public Field findField(String name, String sig) {
 786     SymbolTable symbols = VM.getVM().getSymbolTable();
 787     Symbol nameSym = symbols.probe(name);
 788     Symbol sigSym  = symbols.probe(sig);
 789     if (nameSym == null || sigSym == null) {
 790       return null;
 791     }
 792     return findField(nameSym, sigSym);
 793   }
 794 
 795   /** Find field according to JVM spec 5.4.3.2, returns the klass in
 796       which the field is defined (retained only for backward
 797       compatibility with jdbx) */
 798   public Field findFieldDbg(String name, String sig) {
 799     return findField(name, sig);
 800   }
 801 
 802   /** Get field by its index in the fields array. Only designed for
 803       use in a debugging system. */
 804   public Field getFieldByIndex(int fieldIndex) {
 805     return newField(fieldIndex);
 806   }
 807 
 808 
 809     /** Return a List of SA Fields for the fields declared in this class.
 810         Inherited fields are not included.
 811         Return an empty list if there are no fields declared in this class.
 812         Only designed for use in a debugging system. */
 813     public List getImmediateFields() {
 814         // A list of Fields for each field declared in this class/interface,
 815         // not including inherited fields.
 816         int length = getJavaFieldsCount();
 817         List immediateFields = new ArrayList(length);
 818         for (int index = 0; index < length; index++) {
 819             immediateFields.add(getFieldByIndex(index));
 820         }
 821 
 822         return immediateFields;
 823     }
 824 
 825     /** Return a List of SA Fields for all the java fields in this class,
 826         including all inherited fields.  This includes hidden
 827         fields.  Thus the returned list can contain fields with
 828         the same name.
 829         Return an empty list if there are no fields.
 830         Only designed for use in a debugging system. */
 831     public List getAllFields() {
 832         // Contains a Field for each field in this class, including immediate
 833         // fields and inherited fields.
 834         List  allFields = getImmediateFields();
 835 
 836         // transitiveInterfaces contains all interfaces implemented
 837         // by this class and its superclass chain with no duplicates.
 838 
 839         KlassArray interfaces = getTransitiveInterfaces();
 840         int n = interfaces.length();
 841         for (int i = 0; i < n; i++) {
 842             InstanceKlass intf1 = (InstanceKlass) interfaces.getAt(i);
 843             if (Assert.ASSERTS_ENABLED) {
 844                 Assert.that(intf1.isInterface(), "just checking type");
 845             }
 846             allFields.addAll(intf1.getImmediateFields());
 847         }
 848 
 849         // Get all fields in the superclass, recursively.  But, don't
 850         // include fields in interfaces implemented by superclasses;
 851         // we already have all those.
 852         if (!isInterface()) {
 853             InstanceKlass supr;
 854             if  ( (supr = (InstanceKlass) getSuper()) != null) {
 855                 allFields.addAll(supr.getImmediateFields());
 856             }
 857         }
 858 
 859         return allFields;
 860     }
 861 
 862 
 863     /** Return a List of SA Methods declared directly in this class/interface.
 864         Return an empty list if there are none, or if this isn't a class/
 865         interface.
 866     */
 867     public List getImmediateMethods() {
 868       // Contains a Method for each method declared in this class/interface
 869       // not including inherited methods.
 870 
 871       MethodArray methods = getMethods();
 872       int length = methods.length();
 873       Object[] tmp = new Object[length];
 874 
 875       IntArray methodOrdering = getMethodOrdering();
 876       if (methodOrdering.length() != length) {
 877          // no ordering info present
 878          for (int index = 0; index < length; index++) {
 879             tmp[index] = methods.at(index);
 880          }
 881       } else {
 882          for (int index = 0; index < length; index++) {
 883             int originalIndex = methodOrdering.at(index);
 884             tmp[originalIndex] = methods.at(index);
 885          }
 886       }
 887 
 888       return Arrays.asList(tmp);
 889     }
 890 
 891     /** Return a List containing an SA InstanceKlass for each
 892         interface named in this class's 'implements' clause.
 893     */
 894     public List getDirectImplementedInterfaces() {
 895         // Contains an InstanceKlass for each interface in this classes
 896         // 'implements' clause.
 897 
 898         KlassArray interfaces = getLocalInterfaces();
 899         int length = interfaces.length();
 900         List directImplementedInterfaces = new ArrayList(length);
 901 
 902         for (int index = 0; index < length; index ++) {
 903             directImplementedInterfaces.add(interfaces.getAt(index));
 904         }
 905 
 906         return directImplementedInterfaces;
 907     }
 908 
 909   public Klass arrayKlassImpl(boolean orNull, int n) {
 910     // FIXME: in reflective system this would need to change to
 911     // actually allocate
 912     if (getArrayKlasses() == null) { return null; }
 913     ObjArrayKlass oak = (ObjArrayKlass) getArrayKlasses();
 914     if (orNull) {
 915       return oak.arrayKlassOrNull(n);
 916     }
 917     return oak.arrayKlass(n);
 918   }
 919 
 920   public Klass arrayKlassImpl(boolean orNull) {
 921     return arrayKlassImpl(orNull, 1);
 922   }
 923 
 924   public String signature() {
 925      return "L" + super.signature() + ";";
 926   }
 927 
 928   /** Convenience routine taking Strings; lookup is done in
 929       SymbolTable. */
 930   public Method findMethod(String name, String sig) {
 931     SymbolTable syms = VM.getVM().getSymbolTable();
 932     Symbol nameSym = syms.probe(name);
 933     Symbol sigSym  = syms.probe(sig);
 934     if (nameSym == null || sigSym == null) {
 935       return null;
 936     }
 937     return findMethod(nameSym, sigSym);
 938   }
 939 
 940   /** Find method in vtable. */
 941   public Method findMethod(Symbol name, Symbol sig) {
 942     return findMethod(getMethods(), name, sig);
 943   }
 944 
 945   /** Breakpoint support (see methods on Method* for details) */
 946   public BreakpointInfo getBreakpoints() {
 947     if (!VM.getVM().isJvmtiSupported()) {
 948       return null;
 949     }
 950     Address addr = getAddress().getAddressAt(breakpoints.getOffset());
 951     return (BreakpointInfo) VMObjectFactory.newObject(BreakpointInfo.class, addr);
 952   }
 953 
 954   public IntArray  getMethodOrdering() {
 955     Address addr = getAddress().getAddressAt(methodOrdering.getOffset());
 956     return (IntArray) VMObjectFactory.newObject(IntArray.class, addr);
 957   }
 958 
 959   public U2Array getFields() {
 960     Address addr = getAddress().getAddressAt(fields.getOffset());
 961     return (U2Array) VMObjectFactory.newObject(U2Array.class, addr);
 962   }
 963 
 964   public U2Array getInnerClasses() {
 965     Address addr = getAddress().getAddressAt(innerClasses.getOffset());
 966     return (U2Array) VMObjectFactory.newObject(U2Array.class, addr);
 967   }
 968 
 969 
 970   //----------------------------------------------------------------------
 971   // Internals only below this point
 972   //
 973 
 974   private void visitField(OopVisitor visitor, FieldType type, int index) {
 975     Field f = newField(index);
 976     if (type.isOop()) {
 977       visitor.doOop((OopField) f, false);
 978       return;
 979     }
 980     if (type.isByte()) {
 981       visitor.doByte((ByteField) f, false);
 982       return;
 983     }
 984     if (type.isChar()) {
 985       visitor.doChar((CharField) f, false);
 986       return;
 987     }
 988     if (type.isDouble()) {
 989       visitor.doDouble((DoubleField) f, false);
 990       return;
 991     }
 992     if (type.isFloat()) {
 993       visitor.doFloat((FloatField) f, false);
 994       return;
 995     }
 996     if (type.isInt()) {
 997       visitor.doInt((IntField) f, false);
 998       return;
 999     }
1000     if (type.isLong()) {
1001       visitor.doLong((LongField) f, false);
1002       return;
1003     }
1004     if (type.isShort()) {
1005       visitor.doShort((ShortField) f, false);
1006       return;
1007     }
1008     if (type.isBoolean()) {
1009       visitor.doBoolean((BooleanField) f, false);
1010       return;
1011     }
1012   }
1013 
1014   // Creates new field from index in fields TypeArray
1015   private Field newField(int index) {
1016     FieldType type = new FieldType(getFieldSignature(index));
1017     if (type.isOop()) {
1018      if (VM.getVM().isCompressedOopsEnabled()) {
1019         return new NarrowOopField(this, index);
1020      } else {
1021         return new OopField(this, index);
1022      }
1023     }
1024     if (type.isByte()) {
1025       return new ByteField(this, index);
1026     }
1027     if (type.isChar()) {
1028       return new CharField(this, index);
1029     }
1030     if (type.isDouble()) {
1031       return new DoubleField(this, index);
1032     }
1033     if (type.isFloat()) {
1034       return new FloatField(this, index);
1035     }
1036     if (type.isInt()) {
1037       return new IntField(this, index);
1038     }
1039     if (type.isLong()) {
1040       return new LongField(this, index);
1041     }
1042     if (type.isShort()) {
1043       return new ShortField(this, index);
1044     }
1045     if (type.isBoolean()) {
1046       return new BooleanField(this, index);
1047     }
1048     throw new RuntimeException("Illegal field type at index " + index);
1049   }
1050 
1051   private static Method findMethod(MethodArray methods, Symbol name, Symbol signature) {
1052     int len = methods.length();
1053     // methods are sorted, so do binary search
1054     int l = 0;
1055     int h = len - 1;
1056     while (l <= h) {
1057       int mid = (l + h) >> 1;
1058       Method m = methods.at(mid);
1059       int res = m.getName().fastCompare(name);
1060       if (res == 0) {
1061         // found matching name; do linear search to find matching signature
1062         // first, quick check for common case
1063         if (m.getSignature().equals(signature)) return m;
1064         // search downwards through overloaded methods
1065         int i;
1066         for (i = mid - 1; i >= l; i--) {
1067           Method m1 = methods.at(i);
1068           if (!m1.getName().equals(name)) break;
1069           if (m1.getSignature().equals(signature)) return m1;
1070         }
1071         // search upwards
1072         for (i = mid + 1; i <= h; i++) {
1073           Method m1 = methods.at(i);
1074           if (!m1.getName().equals(name)) break;
1075           if (m1.getSignature().equals(signature)) return m1;
1076         }
1077         // not found
1078         if (Assert.ASSERTS_ENABLED) {
1079           int index = linearSearch(methods, name, signature);
1080           if (index != -1) {
1081             throw new DebuggerException("binary search bug: should have found entry " + index);
1082           }
1083         }
1084         return null;
1085       } else if (res < 0) {
1086         l = mid + 1;
1087       } else {
1088         h = mid - 1;
1089       }
1090     }
1091     if (Assert.ASSERTS_ENABLED) {
1092       int index = linearSearch(methods, name, signature);
1093       if (index != -1) {
1094         throw new DebuggerException("binary search bug: should have found entry " + index);
1095       }
1096     }
1097     return null;
1098   }
1099 
1100   private static int linearSearch(MethodArray methods, Symbol name, Symbol signature) {
1101     int len = (int) methods.length();
1102     for (int index = 0; index < len; index++) {
1103       Method m = methods.at(index);
1104       if (m.getSignature().equals(signature) && m.getName().equals(name)) {
1105         return index;
1106       }
1107     }
1108     return -1;
1109   }
1110 
1111   public void dumpReplayData(PrintStream out) {
1112     ConstantPool cp = getConstants();
1113 
1114     // Try to record related loaded classes
1115     Klass sub = getSubklassKlass();
1116     while (sub != null) {
1117         if (sub instanceof InstanceKlass) {
1118             out.println("instanceKlass " + sub.getName().asString());
1119         }
1120         sub = sub.getNextSiblingKlass();
1121     }
1122 
1123     final int length = (int) cp.getLength();
1124     out.print("ciInstanceKlass " + getName().asString() + " " + (isLinked() ? 1 : 0) + " " + (isInitialized() ? 1 : 0) + " " + length);
1125     for (int index = 1; index < length; index++) {
1126       out.print(" " + cp.getTags().at(index));
1127     }
1128     out.println();
1129     if (isInitialized()) {
1130       Field[] staticFields = getStaticFields();
1131       for (int i = 0; i < staticFields.length; i++) {
1132         Field f = staticFields[i];
1133         Oop mirror = getJavaMirror();
1134         if (f.isFinal() && !f.hasInitialValue()) {
1135           out.print("staticfield " + getName().asString() + " " +
1136                     OopUtilities.escapeString(f.getID().getName()) + " " +
1137                     f.getFieldType().getSignature().asString() + " ");
1138           if (f instanceof ByteField) {
1139             ByteField bf = (ByteField)f;
1140             out.println(bf.getValue(mirror));
1141           } else if (f instanceof BooleanField) {
1142             BooleanField bf = (BooleanField)f;
1143             out.println(bf.getValue(mirror) ? 1 : 0);
1144           } else if (f instanceof ShortField) {
1145             ShortField bf = (ShortField)f;
1146             out.println(bf.getValue(mirror));
1147           } else if (f instanceof CharField) {
1148             CharField bf = (CharField)f;
1149             out.println(bf.getValue(mirror) & 0xffff);
1150           } else if (f instanceof IntField) {
1151             IntField bf = (IntField)f;
1152             out.println(bf.getValue(mirror));
1153           } else  if (f instanceof LongField) {
1154             LongField bf = (LongField)f;
1155             out.println(bf.getValue(mirror));
1156           } else if (f instanceof FloatField) {
1157             FloatField bf = (FloatField)f;
1158             out.println(Float.floatToRawIntBits(bf.getValue(mirror)));
1159           } else if (f instanceof DoubleField) {
1160             DoubleField bf = (DoubleField)f;
1161             out.println(Double.doubleToRawLongBits(bf.getValue(mirror)));
1162           } else if (f instanceof OopField) {
1163             OopField bf = (OopField)f;
1164 
1165             Oop value = bf.getValue(mirror);
1166             if (value == null) {
1167               out.println("null");
1168             } else if (value.isInstance()) {
1169               Instance inst = (Instance)value;
1170               if (inst.isA(SystemDictionary.getStringKlass())) {
1171                 out.println("\"" + OopUtilities.stringOopToEscapedString(inst) + "\"");
1172               } else {
1173                 out.println(inst.getKlass().getName().asString());
1174               }
1175             } else if (value.isObjArray()) {
1176               ObjArray oa = (ObjArray)value;
1177               Klass ek = (ObjArrayKlass)oa.getKlass();
1178               out.println(oa.getLength() + " " + ek.getName().asString());
1179             } else if (value.isTypeArray()) {
1180               TypeArray ta = (TypeArray)value;
1181               out.println(ta.getLength());
1182             } else {
1183               out.println(value);
1184             }
1185           }
1186         }
1187       }
1188     }
1189   }
1190 }