1 /*
   2  * Copyright (c) 2000, 2011, 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.debugger.*;
  30 import sun.jvm.hotspot.memory.*;
  31 import sun.jvm.hotspot.runtime.*;
  32 import sun.jvm.hotspot.types.*;
  33 import sun.jvm.hotspot.utilities.*;
  34 
  35 // An InstanceKlass is the VM level representation of a Java class.
  36 
  37 public class InstanceKlass extends Klass {
  38   static {
  39     VM.registerVMInitializedObserver(new Observer() {
  40         public void update(Observable o, Object data) {
  41           initialize(VM.getVM().getTypeDataBase());
  42         }
  43       });
  44   }
  45 
  46   // field offset constants
  47   public static int ACCESS_FLAGS_OFFSET;
  48   public static int NAME_INDEX_OFFSET;
  49   public static int SIGNATURE_INDEX_OFFSET;
  50   public static int INITVAL_INDEX_OFFSET;
  51   public static int LOW_OFFSET;
  52   public static int HIGH_OFFSET;
  53   public static int GENERIC_SIGNATURE_INDEX_OFFSET;
  54   public static int FIELD_SLOTS;
  55   public static int IMPLEMENTORS_LIMIT;
  56 
  57   // ClassState constants
  58   private static int CLASS_STATE_UNPARSABLE_BY_GC;
  59   private static int CLASS_STATE_ALLOCATED;
  60   private static int CLASS_STATE_LOADED;
  61   private static int CLASS_STATE_LINKED;
  62   private static int CLASS_STATE_BEING_INITIALIZED;
  63   private static int CLASS_STATE_FULLY_INITIALIZED;
  64   private static int CLASS_STATE_INITIALIZATION_ERROR;
  65 
  66   private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
  67     Type type            = db.lookupType("instanceKlass");
  68     arrayKlasses         = new OopField(type.getOopField("_array_klasses"), Oop.getHeaderSize());
  69     methods              = new OopField(type.getOopField("_methods"), Oop.getHeaderSize());
  70     methodOrdering       = new OopField(type.getOopField("_method_ordering"), Oop.getHeaderSize());
  71     localInterfaces      = new OopField(type.getOopField("_local_interfaces"), Oop.getHeaderSize());
  72     transitiveInterfaces = new OopField(type.getOopField("_transitive_interfaces"), Oop.getHeaderSize());
  73     nofImplementors      = new CIntField(type.getCIntegerField("_nof_implementors"), Oop.getHeaderSize());
  74     IMPLEMENTORS_LIMIT   = db.lookupIntConstant("instanceKlass::implementors_limit").intValue();
  75     implementors         = new OopField[IMPLEMENTORS_LIMIT];
  76     for (int i = 0; i < IMPLEMENTORS_LIMIT; i++) {
  77       long arrayOffset = Oop.getHeaderSize() + (i * db.getAddressSize());
  78       implementors[i]    = new OopField(type.getOopField("_implementors[0]"), arrayOffset);
  79     }
  80     fields               = new OopField(type.getOopField("_fields"), Oop.getHeaderSize());
  81     javaFieldsCount      = new CIntField(type.getCIntegerField("_java_fields_count"), Oop.getHeaderSize());
  82     constants            = new OopField(type.getOopField("_constants"), Oop.getHeaderSize());
  83     classLoader          = new OopField(type.getOopField("_class_loader"), Oop.getHeaderSize());
  84     protectionDomain     = new OopField(type.getOopField("_protection_domain"), Oop.getHeaderSize());
  85     signers              = new OopField(type.getOopField("_signers"), Oop.getHeaderSize());
  86     sourceFileName       = type.getAddressField("_source_file_name");
  87     sourceDebugExtension = type.getAddressField("_source_debug_extension");
  88     innerClasses         = new OopField(type.getOopField("_inner_classes"), Oop.getHeaderSize());
  89     nonstaticFieldSize   = new CIntField(type.getCIntegerField("_nonstatic_field_size"), Oop.getHeaderSize());
  90     staticFieldSize      = new CIntField(type.getCIntegerField("_static_field_size"), Oop.getHeaderSize());
  91     staticOopFieldCount   = new CIntField(type.getCIntegerField("_static_oop_field_count"), Oop.getHeaderSize());
  92     nonstaticOopMapSize  = new CIntField(type.getCIntegerField("_nonstatic_oop_map_size"), Oop.getHeaderSize());
  93     isMarkedDependent    = new CIntField(type.getCIntegerField("_is_marked_dependent"), Oop.getHeaderSize());
  94     initState            = new CIntField(type.getCIntegerField("_init_state"), Oop.getHeaderSize());
  95     vtableLen            = new CIntField(type.getCIntegerField("_vtable_len"), Oop.getHeaderSize());
  96     itableLen            = new CIntField(type.getCIntegerField("_itable_len"), Oop.getHeaderSize());
  97     breakpoints          = type.getAddressField("_breakpoints");
  98     genericSignature     = type.getAddressField("_generic_signature");
  99     majorVersion         = new CIntField(type.getCIntegerField("_major_version"), Oop.getHeaderSize());
 100     minorVersion         = new CIntField(type.getCIntegerField("_minor_version"), Oop.getHeaderSize());
 101     headerSize           = alignObjectOffset(Oop.getHeaderSize() + type.getSize());
 102 
 103     // read field offset constants
 104     ACCESS_FLAGS_OFFSET            = db.lookupIntConstant("FieldInfo::access_flags_offset").intValue();
 105     NAME_INDEX_OFFSET              = db.lookupIntConstant("FieldInfo::name_index_offset").intValue();
 106     SIGNATURE_INDEX_OFFSET         = db.lookupIntConstant("FieldInfo::signature_index_offset").intValue();
 107     INITVAL_INDEX_OFFSET           = db.lookupIntConstant("FieldInfo::initval_index_offset").intValue();
 108     LOW_OFFSET                     = db.lookupIntConstant("FieldInfo::low_offset").intValue();
 109     HIGH_OFFSET                    = db.lookupIntConstant("FieldInfo::high_offset").intValue();
 110     GENERIC_SIGNATURE_INDEX_OFFSET = db.lookupIntConstant("FieldInfo::generic_signature_offset").intValue();
 111     FIELD_SLOTS                    = db.lookupIntConstant("FieldInfo::field_slots").intValue();
 112     // read ClassState constants
 113     CLASS_STATE_UNPARSABLE_BY_GC = db.lookupIntConstant("instanceKlass::unparsable_by_gc").intValue();
 114     CLASS_STATE_ALLOCATED = db.lookupIntConstant("instanceKlass::allocated").intValue();
 115     CLASS_STATE_LOADED = db.lookupIntConstant("instanceKlass::loaded").intValue();
 116     CLASS_STATE_LINKED = db.lookupIntConstant("instanceKlass::linked").intValue();
 117     CLASS_STATE_BEING_INITIALIZED = db.lookupIntConstant("instanceKlass::being_initialized").intValue();
 118     CLASS_STATE_FULLY_INITIALIZED = db.lookupIntConstant("instanceKlass::fully_initialized").intValue();
 119     CLASS_STATE_INITIALIZATION_ERROR = db.lookupIntConstant("instanceKlass::initialization_error").intValue();
 120 
 121   }
 122 
 123   InstanceKlass(OopHandle handle, ObjectHeap heap) {
 124     super(handle, heap);
 125   }
 126 
 127   private static OopField  arrayKlasses;
 128   private static OopField  methods;
 129   private static OopField  methodOrdering;
 130   private static OopField  localInterfaces;
 131   private static OopField  transitiveInterfaces;
 132   private static CIntField nofImplementors;
 133   private static OopField[] implementors;
 134   private static OopField  fields;
 135   private static CIntField javaFieldsCount;
 136   private static OopField  constants;
 137   private static OopField  classLoader;
 138   private static OopField  protectionDomain;
 139   private static OopField  signers;
 140   private static AddressField  sourceFileName;
 141   private static AddressField  sourceDebugExtension;
 142   private static OopField  innerClasses;
 143   private static CIntField nonstaticFieldSize;
 144   private static CIntField staticFieldSize;
 145   private static CIntField staticOopFieldCount;
 146   private static CIntField nonstaticOopMapSize;
 147   private static CIntField isMarkedDependent;
 148   private static CIntField initState;
 149   private static CIntField vtableLen;
 150   private static CIntField itableLen;
 151   private static AddressField breakpoints;
 152   private static AddressField  genericSignature;
 153   private static CIntField majorVersion;
 154   private static CIntField minorVersion;
 155 
 156   // type safe enum for ClassState from instanceKlass.hpp
 157   public static class ClassState {
 158      public static final ClassState UNPARSABLE_BY_GC = new ClassState("unparsable_by_gc");
 159      public static final ClassState ALLOCATED    = new ClassState("allocated");
 160      public static final ClassState LOADED       = new ClassState("loaded");
 161      public static final ClassState LINKED       = new ClassState("linked");
 162      public static final ClassState BEING_INITIALIZED      = new ClassState("beingInitialized");
 163      public static final ClassState FULLY_INITIALIZED    = new ClassState("fullyInitialized");
 164      public static final ClassState INITIALIZATION_ERROR = new ClassState("initializationError");
 165 
 166      private ClassState(String value) {
 167         this.value = value;
 168      }
 169 
 170      public String toString() {
 171         return value;
 172      }
 173 
 174      private String value;
 175   }
 176 
 177   public int  getInitStateAsInt() { return (int) initState.getValue(this); }
 178   public ClassState getInitState() {
 179      int state = getInitStateAsInt();
 180      if (state == CLASS_STATE_UNPARSABLE_BY_GC) {
 181         return ClassState.UNPARSABLE_BY_GC;
 182      } else if (state == CLASS_STATE_ALLOCATED) {
 183         return ClassState.ALLOCATED;
 184      } else if (state == CLASS_STATE_LOADED) {
 185         return ClassState.LOADED;
 186      } else if (state == CLASS_STATE_LINKED) {
 187         return ClassState.LINKED;
 188      } else if (state == CLASS_STATE_BEING_INITIALIZED) {
 189         return ClassState.BEING_INITIALIZED;
 190      } else if (state == CLASS_STATE_FULLY_INITIALIZED) {
 191         return ClassState.FULLY_INITIALIZED;
 192      } else if (state == CLASS_STATE_INITIALIZATION_ERROR) {
 193         return ClassState.INITIALIZATION_ERROR;
 194      } else {
 195         throw new RuntimeException("should not reach here");
 196      }
 197   }
 198 
 199   // initialization state quaries
 200   public boolean isLoaded() {
 201      return getInitStateAsInt() >= CLASS_STATE_LOADED;
 202   }
 203 
 204   public boolean isLinked() {
 205      return getInitStateAsInt() >= CLASS_STATE_LINKED;
 206   }
 207 
 208   public boolean isInitialized() {
 209      return getInitStateAsInt() == CLASS_STATE_FULLY_INITIALIZED;
 210   }
 211 
 212   public boolean isNotInitialized() {
 213      return getInitStateAsInt() < CLASS_STATE_BEING_INITIALIZED;
 214   }
 215 
 216   public boolean isBeingInitialized() {
 217      return getInitStateAsInt() == CLASS_STATE_BEING_INITIALIZED;
 218   }
 219 
 220   public boolean isInErrorState() {
 221      return getInitStateAsInt() == CLASS_STATE_INITIALIZATION_ERROR;
 222   }
 223 
 224   public int getClassStatus() {
 225      int result = 0;
 226      if (isLinked()) {
 227         result |= JVMDIClassStatus.VERIFIED | JVMDIClassStatus.PREPARED;
 228      }
 229 
 230      if (isInitialized()) {
 231         if (Assert.ASSERTS_ENABLED) {
 232            Assert.that(isLinked(), "Class status is not consistent");
 233         }
 234         result |= JVMDIClassStatus.INITIALIZED;
 235      }
 236 
 237      if (isInErrorState()) {
 238         result |= JVMDIClassStatus.ERROR;
 239      }
 240      return result;
 241   }
 242 
 243   // Byteside of the header
 244   private static long headerSize;
 245 
 246   public long getObjectSize(Oop object) {
 247     return getSizeHelper() * VM.getVM().getAddressSize();
 248   }
 249 
 250   public static long getHeaderSize() { return headerSize; }
 251 
 252   public short getFieldAccessFlags(int index) {
 253     return getFields().getShortAt(index * FIELD_SLOTS + ACCESS_FLAGS_OFFSET);
 254   }
 255 
 256   public Symbol getFieldName(int index) {
 257     int nameIndex = getFields().getShortAt(index * FIELD_SLOTS + NAME_INDEX_OFFSET);
 258     return getConstants().getSymbolAt(nameIndex);
 259   }
 260 
 261   public Symbol getFieldSignature(int index) {
 262     int signatureIndex = getFields().getShortAt(index * FIELD_SLOTS + SIGNATURE_INDEX_OFFSET);
 263     return getConstants().getSymbolAt(signatureIndex);
 264   }
 265 
 266   public Symbol getFieldGenericSignature(int index) {
 267     short genericSignatureIndex = getFields().getShortAt(index * FIELD_SLOTS + GENERIC_SIGNATURE_INDEX_OFFSET);
 268     if (genericSignatureIndex != 0)  {
 269       return getConstants().getSymbolAt(genericSignatureIndex);
 270     }
 271     return null;
 272   }
 273 
 274   public int getFieldOffset(int index) {
 275     TypeArray fields = getFields();
 276     return VM.getVM().buildIntFromShorts(fields.getShortAt(index * FIELD_SLOTS + LOW_OFFSET),
 277                                          fields.getShortAt(index * FIELD_SLOTS + HIGH_OFFSET));
 278   }
 279 
 280   // Accessors for declared fields
 281   public Klass     getArrayKlasses()        { return (Klass)        arrayKlasses.getValue(this); }
 282   public ObjArray  getMethods()             { return (ObjArray)     methods.getValue(this); }
 283   public TypeArray getMethodOrdering()      { return (TypeArray)    methodOrdering.getValue(this); }
 284   public ObjArray  getLocalInterfaces()     { return (ObjArray)     localInterfaces.getValue(this); }
 285   public ObjArray  getTransitiveInterfaces() { return (ObjArray)     transitiveInterfaces.getValue(this); }
 286   public long      nofImplementors()        { return                nofImplementors.getValue(this); }
 287   public Klass     getImplementor()         { return (Klass)        implementors[0].getValue(this); }
 288   public Klass     getImplementor(int i)    { return (Klass)        implementors[i].getValue(this); }
 289   public TypeArray getFields()              { return (TypeArray)    fields.getValue(this); }
 290   public int       getJavaFieldsCount()     { return                (int) javaFieldsCount.getValue(this); }
 291   public int       getAllFieldsCount()      { return                (int)getFields().getLength(); }
 292   public ConstantPool getConstants()        { return (ConstantPool) constants.getValue(this); }
 293   public Oop       getClassLoader()         { return                classLoader.getValue(this); }
 294   public Oop       getProtectionDomain()    { return                protectionDomain.getValue(this); }
 295   public ObjArray  getSigners()             { return (ObjArray)     signers.getValue(this); }
 296   public Symbol    getSourceFileName()      { return getSymbol(sourceFileName); }
 297   public Symbol    getSourceDebugExtension(){ return getSymbol(sourceDebugExtension); }
 298   public TypeArray getInnerClasses()        { return (TypeArray)    innerClasses.getValue(this); }
 299   public long      getNonstaticFieldSize()  { return                nonstaticFieldSize.getValue(this); }
 300   public long      getStaticOopFieldCount() { return                staticOopFieldCount.getValue(this); }
 301   public long      getNonstaticOopMapSize() { return                nonstaticOopMapSize.getValue(this); }
 302   public boolean   getIsMarkedDependent()   { return                isMarkedDependent.getValue(this) != 0; }
 303   public long      getVtableLen()           { return                vtableLen.getValue(this); }
 304   public long      getItableLen()           { return                itableLen.getValue(this); }
 305   public Symbol    getGenericSignature()    { return getSymbol(genericSignature); }
 306   public long      majorVersion()           { return                majorVersion.getValue(this); }
 307   public long      minorVersion()           { return                minorVersion.getValue(this); }
 308 
 309   // "size helper" == instance size in words
 310   public long getSizeHelper() {
 311     int lh = getLayoutHelper();
 312     if (Assert.ASSERTS_ENABLED) {
 313       Assert.that(lh > 0, "layout helper initialized for instance class");
 314     }
 315     return lh / VM.getVM().getAddressSize();
 316   }
 317 
 318   // same as enum InnerClassAttributeOffset in VM code.
 319   public static interface InnerClassAttributeOffset {
 320     // from JVM spec. "InnerClasses" attribute
 321     public static final int innerClassInnerClassInfoOffset = 0;
 322     public static final int innerClassOuterClassInfoOffset = 1;
 323     public static final int innerClassInnerNameOffset = 2;
 324     public static final int innerClassAccessFlagsOffset = 3;
 325     public static final int innerClassNextOffset = 4;
 326   };
 327 
 328   // refer to compute_modifier_flags in VM code.
 329   public long computeModifierFlags() {
 330     long access = getAccessFlags();
 331     // But check if it happens to be member class.
 332     TypeArray innerClassList = getInnerClasses();
 333     int length = ( innerClassList == null)? 0 : (int) innerClassList.getLength();
 334     if (length > 0) {
 335        if (Assert.ASSERTS_ENABLED) {
 336           Assert.that(length % InnerClassAttributeOffset.innerClassNextOffset == 0, "just checking");
 337        }
 338        for (int i = 0; i < length; i += InnerClassAttributeOffset.innerClassNextOffset) {
 339           int ioff = innerClassList.getShortAt(i +
 340                          InnerClassAttributeOffset.innerClassInnerClassInfoOffset);
 341           // 'ioff' can be zero.
 342           // refer to JVM spec. section 4.7.5.
 343           if (ioff != 0) {
 344              // only look at classes that are already loaded
 345              // since we are looking for the flags for our self.
 346              ConstantPool.CPSlot classInfo = getConstants().getSlotAt(ioff);
 347              Symbol name = null;
 348              if (classInfo.isOop()) {
 349                name = ((Klass) classInfo.getOop()).getName();
 350              } else if (classInfo.isMetaData()) {
 351                name = classInfo.getSymbol();
 352              } else {
 353                 throw new RuntimeException("should not reach here");
 354              }
 355 
 356              if (name.equals(getName())) {
 357                 // This is really a member class
 358                 access = innerClassList.getShortAt(i +
 359                         InnerClassAttributeOffset.innerClassAccessFlagsOffset);
 360                 break;
 361              }
 362           }
 363        } // for inner classes
 364     }
 365 
 366     // Remember to strip ACC_SUPER bit
 367     return (access & (~JVM_ACC_SUPER)) & JVM_ACC_WRITTEN_FLAGS;
 368   }
 369 
 370 
 371   // whether given Symbol is name of an inner/nested Klass of this Klass?
 372   // anonymous and local classes are excluded.
 373   public boolean isInnerClassName(Symbol sym) {
 374     return isInInnerClasses(sym, false);
 375   }
 376 
 377   // whether given Symbol is name of an inner/nested Klass of this Klass?
 378   // anonymous classes excluded, but local classes are included.
 379   public boolean isInnerOrLocalClassName(Symbol sym) {
 380     return isInInnerClasses(sym, true);
 381   }
 382 
 383   private boolean isInInnerClasses(Symbol sym, boolean includeLocals) {
 384     TypeArray innerClassList = getInnerClasses();
 385     int length = ( innerClassList == null)? 0 : (int) innerClassList.getLength();
 386     if (length > 0) {
 387        if (Assert.ASSERTS_ENABLED) {
 388          Assert.that(length % InnerClassAttributeOffset.innerClassNextOffset == 0, "just checking");
 389        }
 390        for (int i = 0; i < length; i += InnerClassAttributeOffset.innerClassNextOffset) {
 391          int ioff = innerClassList.getShortAt(i +
 392                         InnerClassAttributeOffset.innerClassInnerClassInfoOffset);
 393          // 'ioff' can be zero.
 394          // refer to JVM spec. section 4.7.5.
 395          if (ioff != 0) {
 396             ConstantPool.CPSlot iclassInfo = getConstants().getSlotAt(ioff);
 397             Symbol innerName = null;
 398             if (iclassInfo.isOop()) {
 399               innerName = ((Klass) iclassInfo.getOop()).getName();
 400             } else if (iclassInfo.isMetaData()) {
 401               innerName = iclassInfo.getSymbol();
 402             } else {
 403                throw new RuntimeException("should not reach here");
 404             }
 405 
 406             Symbol myname = getName();
 407             int ooff = innerClassList.getShortAt(i +
 408                         InnerClassAttributeOffset.innerClassOuterClassInfoOffset);
 409             // for anonymous classes inner_name_index of InnerClasses
 410             // attribute is zero.
 411             int innerNameIndex = innerClassList.getShortAt(i +
 412                         InnerClassAttributeOffset.innerClassInnerNameOffset);
 413             // if this is not a member (anonymous, local etc.), 'ooff' will be zero
 414             // refer to JVM spec. section 4.7.5.
 415             if (ooff == 0) {
 416                if (includeLocals) {
 417                   // does it looks like my local class?
 418                   if (innerName.equals(sym) &&
 419                      innerName.asString().startsWith(myname.asString())) {
 420                      // exclude anonymous classes.
 421                      return (innerNameIndex != 0);
 422                   }
 423                }
 424             } else {
 425                ConstantPool.CPSlot oclassInfo = getConstants().getSlotAt(ooff);
 426                Symbol outerName = null;
 427                if (oclassInfo.isOop()) {
 428                  outerName = ((Klass) oclassInfo.getOop()).getName();
 429                } else if (oclassInfo.isMetaData()) {
 430                  outerName = oclassInfo.getSymbol();
 431                } else {
 432                   throw new RuntimeException("should not reach here");
 433                }
 434 
 435                // include only if current class is outer class.
 436                if (outerName.equals(myname) && innerName.equals(sym)) {
 437                   return true;
 438                }
 439            }
 440          }
 441        } // for inner classes
 442        return false;
 443     } else {
 444        return false;
 445     }
 446   }
 447 
 448   public boolean implementsInterface(Klass k) {
 449     if (Assert.ASSERTS_ENABLED) {
 450       Assert.that(k.isInterface(), "should not reach here");
 451     }
 452     ObjArray interfaces =  getTransitiveInterfaces();
 453     final int len = (int) interfaces.getLength();
 454     for (int i = 0; i < len; i++) {
 455       if (interfaces.getObjAt(i).equals(k)) return true;
 456     }
 457     return false;
 458   }
 459 
 460   boolean computeSubtypeOf(Klass k) {
 461     if (k.isInterface()) {
 462       return implementsInterface(k);
 463     } else {
 464       return super.computeSubtypeOf(k);
 465     }
 466   }
 467 
 468   public void printValueOn(PrintStream tty) {
 469     tty.print("InstanceKlass for " + getName().asString());
 470   }
 471 
 472   public void iterateFields(OopVisitor visitor, boolean doVMFields) {
 473     super.iterateFields(visitor, doVMFields);
 474     if (doVMFields) {
 475       visitor.doOop(arrayKlasses, true);
 476       visitor.doOop(methods, true);
 477       visitor.doOop(methodOrdering, true);
 478       visitor.doOop(localInterfaces, true);
 479       visitor.doOop(transitiveInterfaces, true);
 480       visitor.doCInt(nofImplementors, true);
 481       for (int i = 0; i < IMPLEMENTORS_LIMIT; i++)
 482         visitor.doOop(implementors[i], true);
 483       visitor.doOop(fields, true);
 484       visitor.doOop(constants, true);
 485       visitor.doOop(classLoader, true);
 486       visitor.doOop(protectionDomain, true);
 487       visitor.doOop(signers, true);
 488       visitor.doOop(innerClasses, true);
 489       visitor.doCInt(nonstaticFieldSize, true);
 490       visitor.doCInt(staticFieldSize, true);
 491       visitor.doCInt(staticOopFieldCount, true);
 492       visitor.doCInt(nonstaticOopMapSize, true);
 493       visitor.doCInt(isMarkedDependent, true);
 494       visitor.doCInt(initState, true);
 495       visitor.doCInt(vtableLen, true);
 496       visitor.doCInt(itableLen, true);
 497     }
 498   }
 499 
 500   /*
 501    *  Visit the static fields of this InstanceKlass with the obj of
 502    *  the visitor set to the oop holding the fields, which is
 503    *  currently the java mirror.
 504    */
 505   public void iterateStaticFields(OopVisitor visitor) {
 506     visitor.setObj(getJavaMirror());
 507     visitor.prologue();
 508     iterateStaticFieldsInternal(visitor);
 509     visitor.epilogue();
 510 
 511   }
 512 
 513   void iterateStaticFieldsInternal(OopVisitor visitor) {
 514     TypeArray fields = getFields();
 515     int length = getJavaFieldsCount();
 516     for (int index = 0; index < length; index += FIELD_SLOTS) {
 517       short accessFlags    = fields.getShortAt(index + ACCESS_FLAGS_OFFSET);
 518       short signatureIndex = fields.getShortAt(index + SIGNATURE_INDEX_OFFSET);
 519       FieldType   type   = new FieldType(getConstants().getSymbolAt(signatureIndex));
 520       AccessFlags access = new AccessFlags(accessFlags);
 521       if (access.isStatic()) {
 522         visitField(visitor, type, index);
 523       }
 524     }
 525   }
 526 
 527   public Klass getJavaSuper() {
 528     return getSuper();
 529   }
 530 
 531   public static class StaticField {
 532     public AccessFlags flags;
 533     public Field field;
 534 
 535     StaticField(Field field, AccessFlags flags) {
 536       this.field = field;
 537       this.flags = flags;
 538     }
 539   }
 540 
 541   public void iterateNonStaticFields(OopVisitor visitor, Oop obj) {
 542     if (getSuper() != null) {
 543       ((InstanceKlass) getSuper()).iterateNonStaticFields(visitor, obj);
 544     }
 545     TypeArray fields = getFields();
 546 
 547     int length = getJavaFieldsCount();
 548     for (int index = 0; index < length; index += FIELD_SLOTS) {
 549       short accessFlags    = fields.getShortAt(index + ACCESS_FLAGS_OFFSET);
 550       short signatureIndex = fields.getShortAt(index + SIGNATURE_INDEX_OFFSET);
 551 
 552       FieldType   type   = new FieldType(getConstants().getSymbolAt(signatureIndex));
 553       AccessFlags access = new AccessFlags(accessFlags);
 554       if (!access.isStatic()) {
 555         visitField(visitor, type, index);
 556       }
 557     }
 558   }
 559 
 560   /** Field access by name. */
 561   public Field findLocalField(Symbol name, Symbol sig) {
 562     TypeArray fields = getFields();
 563     int length = (int) fields.getLength();
 564     ConstantPool cp = getConstants();
 565     for (int i = 0; i < length; i += FIELD_SLOTS) {
 566       int nameIndex = fields.getShortAt(i + NAME_INDEX_OFFSET);
 567       int sigIndex  = fields.getShortAt(i + SIGNATURE_INDEX_OFFSET);
 568       Symbol f_name = cp.getSymbolAt(nameIndex);
 569       Symbol f_sig  = cp.getSymbolAt(sigIndex);
 570       if (name.equals(f_name) && sig.equals(f_sig)) {
 571         return newField(i);
 572       }
 573     }
 574 
 575     return null;
 576   }
 577 
 578   /** Find field in direct superinterfaces. */
 579   public Field findInterfaceField(Symbol name, Symbol sig) {
 580     ObjArray interfaces = getLocalInterfaces();
 581     int n = (int) interfaces.getLength();
 582     for (int i = 0; i < n; i++) {
 583       InstanceKlass intf1 = (InstanceKlass) interfaces.getObjAt(i);
 584       if (Assert.ASSERTS_ENABLED) {
 585         Assert.that(intf1.isInterface(), "just checking type");
 586       }
 587       // search for field in current interface
 588       Field f = intf1.findLocalField(name, sig);
 589       if (f != null) {
 590         if (Assert.ASSERTS_ENABLED) {
 591           Assert.that(f.getAccessFlagsObj().isStatic(), "interface field must be static");
 592         }
 593         return f;
 594       }
 595       // search for field in direct superinterfaces
 596       f = intf1.findInterfaceField(name, sig);
 597       if (f != null) return f;
 598     }
 599     // otherwise field lookup fails
 600     return null;
 601   }
 602 
 603   /** Find field according to JVM spec 5.4.3.2, returns the klass in
 604       which the field is defined. */
 605   public Field findField(Symbol name, Symbol sig) {
 606     // search order according to newest JVM spec (5.4.3.2, p.167).
 607     // 1) search for field in current klass
 608     Field f = findLocalField(name, sig);
 609     if (f != null) return f;
 610 
 611     // 2) search for field recursively in direct superinterfaces
 612     f = findInterfaceField(name, sig);
 613     if (f != null) return f;
 614 
 615     // 3) apply field lookup recursively if superclass exists
 616     InstanceKlass supr = (InstanceKlass) getSuper();
 617     if (supr != null) return supr.findField(name, sig);
 618 
 619     // 4) otherwise field lookup fails
 620     return null;
 621   }
 622 
 623   /** Find field according to JVM spec 5.4.3.2, returns the klass in
 624       which the field is defined (convenience routine) */
 625   public Field findField(String name, String sig) {
 626     SymbolTable symbols = VM.getVM().getSymbolTable();
 627     Symbol nameSym = symbols.probe(name);
 628     Symbol sigSym  = symbols.probe(sig);
 629     if (nameSym == null || sigSym == null) {
 630       return null;
 631     }
 632     return findField(nameSym, sigSym);
 633   }
 634 
 635   /** Find field according to JVM spec 5.4.3.2, returns the klass in
 636       which the field is defined (retained only for backward
 637       compatibility with jdbx) */
 638   public Field findFieldDbg(String name, String sig) {
 639     return findField(name, sig);
 640   }
 641 
 642   /** Get field by its index in the fields array. Only designed for
 643       use in a debugging system. */
 644   public Field getFieldByIndex(int fieldArrayIndex) {
 645     return newField(fieldArrayIndex);
 646   }
 647 
 648 
 649     /** Return a List of SA Fields for the fields declared in this class.
 650         Inherited fields are not included.
 651         Return an empty list if there are no fields declared in this class.
 652         Only designed for use in a debugging system. */
 653     public List getImmediateFields() {
 654         // A list of Fields for each field declared in this class/interface,
 655         // not including inherited fields.
 656         TypeArray fields = getFields();
 657 
 658         int length = getJavaFieldsCount();
 659         List immediateFields = new ArrayList(length);
 660         for (int index = 0; index < length; index += FIELD_SLOTS) {
 661             immediateFields.add(getFieldByIndex(index));
 662         }
 663 
 664         return immediateFields;
 665     }
 666 
 667     /** Return a List of SA Fields for all the java fields in this class,
 668         including all inherited fields.  This includes hidden
 669         fields.  Thus the returned list can contain fields with
 670         the same name.
 671         Return an empty list if there are no fields.
 672         Only designed for use in a debugging system. */
 673     public List getAllFields() {
 674         // Contains a Field for each field in this class, including immediate
 675         // fields and inherited fields.
 676         List  allFields = getImmediateFields();
 677 
 678         // transitiveInterfaces contains all interfaces implemented
 679         // by this class and its superclass chain with no duplicates.
 680 
 681         ObjArray interfaces = getTransitiveInterfaces();
 682         int n = (int) interfaces.getLength();
 683         for (int i = 0; i < n; i++) {
 684             InstanceKlass intf1 = (InstanceKlass) interfaces.getObjAt(i);
 685             if (Assert.ASSERTS_ENABLED) {
 686                 Assert.that(intf1.isInterface(), "just checking type");
 687             }
 688             allFields.addAll(intf1.getImmediateFields());
 689         }
 690 
 691         // Get all fields in the superclass, recursively.  But, don't
 692         // include fields in interfaces implemented by superclasses;
 693         // we already have all those.
 694         if (!isInterface()) {
 695             InstanceKlass supr;
 696             if  ( (supr = (InstanceKlass) getSuper()) != null) {
 697                 allFields.addAll(supr.getImmediateFields());
 698             }
 699         }
 700 
 701         return allFields;
 702     }
 703 
 704 
 705     /** Return a List of SA Methods declared directly in this class/interface.
 706         Return an empty list if there are none, or if this isn't a class/
 707         interface.
 708     */
 709     public List getImmediateMethods() {
 710       // Contains a Method for each method declared in this class/interface
 711       // not including inherited methods.
 712 
 713       ObjArray methods = getMethods();
 714       int length = (int)methods.getLength();
 715       Object[] tmp = new Object[length];
 716 
 717       TypeArray methodOrdering = getMethodOrdering();
 718       if (methodOrdering.getLength() != length) {
 719          // no ordering info present
 720          for (int index = 0; index < length; index++) {
 721             tmp[index] = methods.getObjAt(index);
 722          }
 723       } else {
 724          for (int index = 0; index < length; index++) {
 725             int originalIndex = getMethodOrdering().getIntAt(index);
 726             tmp[originalIndex] = methods.getObjAt(index);
 727          }
 728       }
 729 
 730       return Arrays.asList(tmp);
 731     }
 732 
 733     /** Return a List containing an SA InstanceKlass for each
 734         interface named in this class's 'implements' clause.
 735     */
 736     public List getDirectImplementedInterfaces() {
 737         // Contains an InstanceKlass for each interface in this classes
 738         // 'implements' clause.
 739 
 740         ObjArray interfaces = getLocalInterfaces();
 741         int length = (int) interfaces.getLength();
 742         List directImplementedInterfaces = new ArrayList(length);
 743 
 744         for (int index = 0; index < length; index ++) {
 745             directImplementedInterfaces.add(interfaces.getObjAt(index));
 746         }
 747 
 748         return directImplementedInterfaces;
 749     }
 750 
 751 
 752   public long getObjectSize() {
 753     long bodySize =    alignObjectOffset(getVtableLen() * getHeap().getOopSize())
 754                      + alignObjectOffset(getItableLen() * getHeap().getOopSize())
 755                      + (getNonstaticOopMapSize()) * getHeap().getOopSize();
 756     return alignObjectSize(headerSize + bodySize);
 757   }
 758 
 759   public Klass arrayKlassImpl(boolean orNull, int n) {
 760     // FIXME: in reflective system this would need to change to
 761     // actually allocate
 762     if (getArrayKlasses() == null) { return null; }
 763     ObjArrayKlass oak = (ObjArrayKlass) getArrayKlasses();
 764     if (orNull) {
 765       return oak.arrayKlassOrNull(n);
 766     }
 767     return oak.arrayKlass(n);
 768   }
 769 
 770   public Klass arrayKlassImpl(boolean orNull) {
 771     return arrayKlassImpl(orNull, 1);
 772   }
 773 
 774   public String signature() {
 775      return "L" + super.signature() + ";";
 776   }
 777 
 778   /** Convenience routine taking Strings; lookup is done in
 779       SymbolTable. */
 780   public Method findMethod(String name, String sig) {
 781     SymbolTable syms = VM.getVM().getSymbolTable();
 782     Symbol nameSym = syms.probe(name);
 783     Symbol sigSym  = syms.probe(sig);
 784     if (nameSym == null || sigSym == null) {
 785       return null;
 786     }
 787     return findMethod(nameSym, sigSym);
 788   }
 789 
 790   /** Find method in vtable. */
 791   public Method findMethod(Symbol name, Symbol sig) {
 792     return findMethod(getMethods(), name, sig);
 793   }
 794 
 795   /** Breakpoint support (see methods on methodOop for details) */
 796   public BreakpointInfo getBreakpoints() {
 797     Address addr = getHandle().getAddressAt(Oop.getHeaderSize() + breakpoints.getOffset());
 798     return (BreakpointInfo) VMObjectFactory.newObject(BreakpointInfo.class, addr);
 799   }
 800 
 801   //----------------------------------------------------------------------
 802   // Internals only below this point
 803   //
 804 
 805   private void visitField(OopVisitor visitor, FieldType type, int index) {
 806     Field f = newField(index);
 807     if (type.isOop()) {
 808       visitor.doOop((OopField) f, false);
 809       return;
 810     }
 811     if (type.isByte()) {
 812       visitor.doByte((ByteField) f, false);
 813       return;
 814     }
 815     if (type.isChar()) {
 816       visitor.doChar((CharField) f, false);
 817       return;
 818     }
 819     if (type.isDouble()) {
 820       visitor.doDouble((DoubleField) f, false);
 821       return;
 822     }
 823     if (type.isFloat()) {
 824       visitor.doFloat((FloatField) f, false);
 825       return;
 826     }
 827     if (type.isInt()) {
 828       visitor.doInt((IntField) f, false);
 829       return;
 830     }
 831     if (type.isLong()) {
 832       visitor.doLong((LongField) f, false);
 833       return;
 834     }
 835     if (type.isShort()) {
 836       visitor.doShort((ShortField) f, false);
 837       return;
 838     }
 839     if (type.isBoolean()) {
 840       visitor.doBoolean((BooleanField) f, false);
 841       return;
 842     }
 843   }
 844 
 845   // Creates new field from index in fields TypeArray
 846   private Field newField(int index) {
 847     TypeArray fields = getFields();
 848     short signatureIndex = fields.getShortAt(index + SIGNATURE_INDEX_OFFSET);
 849     FieldType type = new FieldType(getConstants().getSymbolAt(signatureIndex));
 850     if (type.isOop()) {
 851      if (VM.getVM().isCompressedOopsEnabled()) {
 852         return new NarrowOopField(this, index);
 853      } else {
 854         return new OopField(this, index);
 855      }
 856     }
 857     if (type.isByte()) {
 858       return new ByteField(this, index);
 859     }
 860     if (type.isChar()) {
 861       return new CharField(this, index);
 862     }
 863     if (type.isDouble()) {
 864       return new DoubleField(this, index);
 865     }
 866     if (type.isFloat()) {
 867       return new FloatField(this, index);
 868     }
 869     if (type.isInt()) {
 870       return new IntField(this, index);
 871     }
 872     if (type.isLong()) {
 873       return new LongField(this, index);
 874     }
 875     if (type.isShort()) {
 876       return new ShortField(this, index);
 877     }
 878     if (type.isBoolean()) {
 879       return new BooleanField(this, index);
 880     }
 881     throw new RuntimeException("Illegal field type at index " + index);
 882   }
 883 
 884   private static Method findMethod(ObjArray methods, Symbol name, Symbol signature) {
 885     int len = (int) methods.getLength();
 886     // methods are sorted, so do binary search
 887     int l = 0;
 888     int h = len - 1;
 889     while (l <= h) {
 890       int mid = (l + h) >> 1;
 891       Method m = (Method) methods.getObjAt(mid);
 892       int res = m.getName().fastCompare(name);
 893       if (res == 0) {
 894         // found matching name; do linear search to find matching signature
 895         // first, quick check for common case
 896         if (m.getSignature().equals(signature)) return m;
 897         // search downwards through overloaded methods
 898         int i;
 899         for (i = mid - 1; i >= l; i--) {
 900           Method m1 = (Method) methods.getObjAt(i);
 901           if (!m1.getName().equals(name)) break;
 902           if (m1.getSignature().equals(signature)) return m1;
 903         }
 904         // search upwards
 905         for (i = mid + 1; i <= h; i++) {
 906           Method m1 = (Method) methods.getObjAt(i);
 907           if (!m1.getName().equals(name)) break;
 908           if (m1.getSignature().equals(signature)) return m1;
 909         }
 910         // not found
 911         if (Assert.ASSERTS_ENABLED) {
 912           int index = linearSearch(methods, name, signature);
 913           if (index != -1) {
 914             throw new DebuggerException("binary search bug: should have found entry " + index);
 915           }
 916         }
 917         return null;
 918       } else if (res < 0) {
 919         l = mid + 1;
 920       } else {
 921         h = mid - 1;
 922       }
 923     }
 924     if (Assert.ASSERTS_ENABLED) {
 925       int index = linearSearch(methods, name, signature);
 926       if (index != -1) {
 927         throw new DebuggerException("binary search bug: should have found entry " + index);
 928       }
 929     }
 930     return null;
 931   }
 932 
 933   private static int linearSearch(ObjArray methods, Symbol name, Symbol signature) {
 934     int len = (int) methods.getLength();
 935     for (int index = 0; index < len; index++) {
 936       Method m = (Method) methods.getObjAt(index);
 937       if (m.getSignature().equals(signature) && m.getName().equals(name)) {
 938         return index;
 939       }
 940     }
 941     return -1;
 942   }
 943 }