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   private 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 void iterateNonStaticFields(OopVisitor visitor, Oop obj) {
 500     if (getSuper() != null) {
 501       ((InstanceKlass) getSuper()).iterateNonStaticFields(visitor, obj);
 502     }
 503     TypeArray fields = getFields();
 504 
 505     int length = (int) fields.getLength();
 506     for (int index = 0; index < length; index += NEXT_OFFSET) {
 507       short accessFlags    = fields.getShortAt(index + ACCESS_FLAGS_OFFSET);
 508       short signatureIndex = fields.getShortAt(index + SIGNATURE_INDEX_OFFSET);
 509 
 510       FieldType   type   = new FieldType(getConstants().getSymbolAt(signatureIndex));
 511       AccessFlags access = new AccessFlags(accessFlags);
 512       if (!access.isStatic()) {
 513         visitField(visitor, type, index);
 514       }
 515     }
 516   }
 517 
 518   /** Field access by name. */
 519   public Field findLocalField(Symbol name, Symbol sig) {
 520     TypeArray fields = getFields();
 521     int n = (int) fields.getLength();
 522     ConstantPool cp = getConstants();
 523     for (int i = 0; i < n; i += NEXT_OFFSET) {
 524       int nameIndex = fields.getShortAt(i + NAME_INDEX_OFFSET);
 525       int sigIndex  = fields.getShortAt(i + SIGNATURE_INDEX_OFFSET);
 526       Symbol f_name = cp.getSymbolAt(nameIndex);
 527       Symbol f_sig  = cp.getSymbolAt(sigIndex);
 528       if (name.equals(f_name) && sig.equals(f_sig)) {
 529         return newField(i);
 530       }
 531     }
 532 
 533     return null;
 534   }
 535 
 536   /** Find field in direct superinterfaces. */
 537   public Field findInterfaceField(Symbol name, Symbol sig) {
 538     ObjArray interfaces = getLocalInterfaces();
 539     int n = (int) interfaces.getLength();
 540     for (int i = 0; i < n; i++) {
 541       InstanceKlass intf1 = (InstanceKlass) interfaces.getObjAt(i);
 542       if (Assert.ASSERTS_ENABLED) {
 543         Assert.that(intf1.isInterface(), "just checking type");
 544       }
 545       // search for field in current interface
 546       Field f = intf1.findLocalField(name, sig);
 547       if (f != null) {
 548         if (Assert.ASSERTS_ENABLED) {
 549           Assert.that(f.getAccessFlagsObj().isStatic(), "interface field must be static");
 550         }
 551         return f;
 552       }
 553       // search for field in direct superinterfaces
 554       f = intf1.findInterfaceField(name, sig);
 555       if (f != null) return f;
 556     }
 557     // otherwise field lookup fails
 558     return null;
 559   }
 560 
 561   /** Find field according to JVM spec 5.4.3.2, returns the klass in
 562       which the field is defined. */
 563   public Field findField(Symbol name, Symbol sig) {
 564     // search order according to newest JVM spec (5.4.3.2, p.167).
 565     // 1) search for field in current klass
 566     Field f = findLocalField(name, sig);
 567     if (f != null) return f;
 568 
 569     // 2) search for field recursively in direct superinterfaces
 570     f = findInterfaceField(name, sig);
 571     if (f != null) return f;
 572 
 573     // 3) apply field lookup recursively if superclass exists
 574     InstanceKlass supr = (InstanceKlass) getSuper();
 575     if (supr != null) return supr.findField(name, sig);
 576 
 577     // 4) otherwise field lookup fails
 578     return null;
 579   }
 580 
 581   /** Find field according to JVM spec 5.4.3.2, returns the klass in
 582       which the field is defined (convenience routine) */
 583   public Field findField(String name, String sig) {
 584     SymbolTable symbols = VM.getVM().getSymbolTable();
 585     Symbol nameSym = symbols.probe(name);
 586     Symbol sigSym  = symbols.probe(sig);
 587     if (nameSym == null || sigSym == null) {
 588       return null;
 589     }
 590     return findField(nameSym, sigSym);
 591   }
 592 
 593   /** Find field according to JVM spec 5.4.3.2, returns the klass in
 594       which the field is defined (retained only for backward
 595       compatibility with jdbx) */
 596   public Field findFieldDbg(String name, String sig) {
 597     return findField(name, sig);
 598   }
 599 
 600   /** Get field by its index in the fields array. Only designed for
 601       use in a debugging system. */
 602   public Field getFieldByIndex(int fieldArrayIndex) {
 603     return newField(fieldArrayIndex);
 604   }
 605 
 606 
 607     /** Return a List of SA Fields for the fields declared in this class.
 608         Inherited fields are not included.
 609         Return an empty list if there are no fields declared in this class.
 610         Only designed for use in a debugging system. */
 611     public List getImmediateFields() {
 612         // A list of Fields for each field declared in this class/interface,
 613         // not including inherited fields.
 614         TypeArray fields = getFields();
 615 
 616         int length = (int) fields.getLength();
 617         List immediateFields = new ArrayList(length / NEXT_OFFSET);
 618         for (int index = 0; index < length; index += NEXT_OFFSET) {
 619             immediateFields.add(getFieldByIndex(index));
 620         }
 621 
 622         return immediateFields;
 623     }
 624 
 625     /** Return a List of SA Fields for all the java fields in this class,
 626         including all inherited fields.  This includes hidden
 627         fields.  Thus the returned list can contain fields with
 628         the same name.
 629         Return an empty list if there are no fields.
 630         Only designed for use in a debugging system. */
 631     public List getAllFields() {
 632         // Contains a Field for each field in this class, including immediate
 633         // fields and inherited fields.
 634         List  allFields = getImmediateFields();
 635 
 636         // transitiveInterfaces contains all interfaces implemented
 637         // by this class and its superclass chain with no duplicates.
 638 
 639         ObjArray interfaces = getTransitiveInterfaces();
 640         int n = (int) interfaces.getLength();
 641         for (int i = 0; i < n; i++) {
 642             InstanceKlass intf1 = (InstanceKlass) interfaces.getObjAt(i);
 643             if (Assert.ASSERTS_ENABLED) {
 644                 Assert.that(intf1.isInterface(), "just checking type");
 645             }
 646             allFields.addAll(intf1.getImmediateFields());
 647         }
 648 
 649         // Get all fields in the superclass, recursively.  But, don't
 650         // include fields in interfaces implemented by superclasses;
 651         // we already have all those.
 652         if (!isInterface()) {
 653             InstanceKlass supr;
 654             if  ( (supr = (InstanceKlass) getSuper()) != null) {
 655                 allFields.addAll(supr.getImmediateFields());
 656             }
 657         }
 658 
 659         return allFields;
 660     }
 661 
 662 
 663     /** Return a List of SA Methods declared directly in this class/interface.
 664         Return an empty list if there are none, or if this isn't a class/
 665         interface.
 666     */
 667     public List getImmediateMethods() {
 668       // Contains a Method for each method declared in this class/interface
 669       // not including inherited methods.
 670 
 671       ObjArray methods = getMethods();
 672       int length = (int)methods.getLength();
 673       Object[] tmp = new Object[length];
 674 
 675       TypeArray methodOrdering = getMethodOrdering();
 676       if (methodOrdering.getLength() != length) {
 677          // no ordering info present
 678          for (int index = 0; index < length; index++) {
 679             tmp[index] = methods.getObjAt(index);
 680          }
 681       } else {
 682          for (int index = 0; index < length; index++) {
 683             int originalIndex = getMethodOrdering().getIntAt(index);
 684             tmp[originalIndex] = methods.getObjAt(index);
 685          }
 686       }
 687 
 688       return Arrays.asList(tmp);
 689     }
 690 
 691     /** Return a List containing an SA InstanceKlass for each
 692         interface named in this class's 'implements' clause.
 693     */
 694     public List getDirectImplementedInterfaces() {
 695         // Contains an InstanceKlass for each interface in this classes
 696         // 'implements' clause.
 697 
 698         ObjArray interfaces = getLocalInterfaces();
 699         int length = (int) interfaces.getLength();
 700         List directImplementedInterfaces = new ArrayList(length);
 701 
 702         for (int index = 0; index < length; index ++) {
 703             directImplementedInterfaces.add(interfaces.getObjAt(index));
 704         }
 705 
 706         return directImplementedInterfaces;
 707     }
 708 
 709 
 710   public long getObjectSize() {
 711     long bodySize =    alignObjectOffset(getVtableLen() * getHeap().getOopSize())
 712                      + alignObjectOffset(getItableLen() * getHeap().getOopSize())
 713                      + (getNonstaticOopMapSize()) * getHeap().getOopSize();
 714     return alignObjectSize(headerSize + bodySize);
 715   }
 716 
 717   public Klass arrayKlassImpl(boolean orNull, int n) {
 718     // FIXME: in reflective system this would need to change to
 719     // actually allocate
 720     if (getArrayKlasses() == null) { return null; }
 721     ObjArrayKlass oak = (ObjArrayKlass) getArrayKlasses();
 722     if (orNull) {
 723       return oak.arrayKlassOrNull(n);
 724     }
 725     return oak.arrayKlass(n);
 726   }
 727 
 728   public Klass arrayKlassImpl(boolean orNull) {
 729     return arrayKlassImpl(orNull, 1);
 730   }
 731 
 732   public String signature() {
 733      return "L" + super.signature() + ";";
 734   }
 735 
 736   /** Convenience routine taking Strings; lookup is done in
 737       SymbolTable. */
 738   public Method findMethod(String name, String sig) {
 739     SymbolTable syms = VM.getVM().getSymbolTable();
 740     Symbol nameSym = syms.probe(name);
 741     Symbol sigSym  = syms.probe(sig);
 742     if (nameSym == null || sigSym == null) {
 743       return null;
 744     }
 745     return findMethod(nameSym, sigSym);
 746   }
 747 
 748   /** Find method in vtable. */
 749   public Method findMethod(Symbol name, Symbol sig) {
 750     return findMethod(getMethods(), name, sig);
 751   }
 752 
 753   /** Breakpoint support (see methods on methodOop for details) */
 754   public BreakpointInfo getBreakpoints() {
 755     Address addr = getHandle().getAddressAt(Oop.getHeaderSize() + breakpoints.getOffset());
 756     return (BreakpointInfo) VMObjectFactory.newObject(BreakpointInfo.class, addr);
 757   }
 758 
 759   //----------------------------------------------------------------------
 760   // Internals only below this point
 761   //
 762 
 763   private void visitField(OopVisitor visitor, FieldType type, int index) {
 764     Field f = newField(index);
 765     if (type.isOop()) {
 766       visitor.doOop((OopField) f, false);
 767       return;
 768     }
 769     if (type.isByte()) {
 770       visitor.doByte((ByteField) f, false);
 771       return;
 772     }
 773     if (type.isChar()) {
 774       visitor.doChar((CharField) f, false);
 775       return;
 776     }
 777     if (type.isDouble()) {
 778       visitor.doDouble((DoubleField) f, false);
 779       return;
 780     }
 781     if (type.isFloat()) {
 782       visitor.doFloat((FloatField) f, false);
 783       return;
 784     }
 785     if (type.isInt()) {
 786       visitor.doInt((IntField) f, false);
 787       return;
 788     }
 789     if (type.isLong()) {
 790       visitor.doLong((LongField) f, false);
 791       return;
 792     }
 793     if (type.isShort()) {
 794       visitor.doShort((ShortField) f, false);
 795       return;
 796     }
 797     if (type.isBoolean()) {
 798       visitor.doBoolean((BooleanField) f, false);
 799       return;
 800     }
 801   }
 802 
 803   // Creates new field from index in fields TypeArray
 804   private Field newField(int index) {
 805     TypeArray fields = getFields();
 806     short signatureIndex = fields.getShortAt(index + SIGNATURE_INDEX_OFFSET);
 807     FieldType type = new FieldType(getConstants().getSymbolAt(signatureIndex));
 808     if (type.isOop()) {
 809      if (VM.getVM().isCompressedOopsEnabled()) {
 810         return new NarrowOopField(this, index);
 811      } else {
 812         return new OopField(this, index);
 813      }
 814     }
 815     if (type.isByte()) {
 816       return new ByteField(this, index);
 817     }
 818     if (type.isChar()) {
 819       return new CharField(this, index);
 820     }
 821     if (type.isDouble()) {
 822       return new DoubleField(this, index);
 823     }
 824     if (type.isFloat()) {
 825       return new FloatField(this, index);
 826     }
 827     if (type.isInt()) {
 828       return new IntField(this, index);
 829     }
 830     if (type.isLong()) {
 831       return new LongField(this, index);
 832     }
 833     if (type.isShort()) {
 834       return new ShortField(this, index);
 835     }
 836     if (type.isBoolean()) {
 837       return new BooleanField(this, index);
 838     }
 839     throw new RuntimeException("Illegal field type at index " + index);
 840   }
 841 
 842   private static Method findMethod(ObjArray methods, Symbol name, Symbol signature) {
 843     int len = (int) methods.getLength();
 844     // methods are sorted, so do binary search
 845     int l = 0;
 846     int h = len - 1;
 847     while (l <= h) {
 848       int mid = (l + h) >> 1;
 849       Method m = (Method) methods.getObjAt(mid);
 850       int res = m.getName().fastCompare(name);
 851       if (res == 0) {
 852         // found matching name; do linear search to find matching signature
 853         // first, quick check for common case
 854         if (m.getSignature().equals(signature)) return m;
 855         // search downwards through overloaded methods
 856         int i;
 857         for (i = mid - 1; i >= l; i--) {
 858           Method m1 = (Method) methods.getObjAt(i);
 859           if (!m1.getName().equals(name)) break;
 860           if (m1.getSignature().equals(signature)) return m1;
 861         }
 862         // search upwards
 863         for (i = mid + 1; i <= h; i++) {
 864           Method m1 = (Method) methods.getObjAt(i);
 865           if (!m1.getName().equals(name)) break;
 866           if (m1.getSignature().equals(signature)) return m1;
 867         }
 868         // not found
 869         if (Assert.ASSERTS_ENABLED) {
 870           int index = linearSearch(methods, name, signature);
 871           if (index != -1) {
 872             throw new DebuggerException("binary search bug: should have found entry " + index);
 873           }
 874         }
 875         return null;
 876       } else if (res < 0) {
 877         l = mid + 1;
 878       } else {
 879         h = mid - 1;
 880       }
 881     }
 882     if (Assert.ASSERTS_ENABLED) {
 883       int index = linearSearch(methods, name, signature);
 884       if (index != -1) {
 885         throw new DebuggerException("binary search bug: should have found entry " + index);
 886       }
 887     }
 888     return null;
 889   }
 890 
 891   private static int linearSearch(ObjArray methods, Symbol name, Symbol signature) {
 892     int len = (int) methods.getLength();
 893     for (int index = 0; index < len; index++) {
 894       Method m = (Method) methods.getObjAt(index);
 895       if (m.getSignature().equals(signature) && m.getName().equals(name)) {
 896         return index;
 897       }
 898     }
 899     return -1;
 900   }
 901 }