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