1 /*
   2  * Copyright 2000-2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  20  * CA 95054 USA or visit www.sun.com if you need additional information or
  21  * have any 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       = new OopField(type.getOopField("_source_file_name"), Oop.getHeaderSize());
  86     sourceDebugExtension = new OopField(type.getOopField("_source_debug_extension"), Oop.getHeaderSize());
  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     staticOopFieldSize   = new CIntField(type.getCIntegerField("_static_oop_field_size"), 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     = new OopField(type.getOopField("_generic_signature"), Oop.getHeaderSize());
  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 OopField  sourceFileName;
 139   private static OopField  sourceDebugExtension;
 140   private static OopField  innerClasses;
 141   private static CIntField nonstaticFieldSize;
 142   private static CIntField staticFieldSize;
 143   private static CIntField staticOopFieldSize;
 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 OopField  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 static long getHeaderSize() { return headerSize; }
 245 
 246   // Accessors for declared fields
 247   public Klass     getArrayKlasses()        { return (Klass)        arrayKlasses.getValue(this); }
 248   public ObjArray  getMethods()             { return (ObjArray)     methods.getValue(this); }
 249   public TypeArray getMethodOrdering()      { return (TypeArray)    methodOrdering.getValue(this); }
 250   public ObjArray  getLocalInterfaces()     { return (ObjArray)     localInterfaces.getValue(this); }
 251   public ObjArray  getTransitiveInterfaces() { return (ObjArray)     transitiveInterfaces.getValue(this); }
 252   public long      nofImplementors()        { return                nofImplementors.getValue(this); }
 253   public Klass     getImplementor()         { return (Klass)        implementors[0].getValue(this); }
 254   public Klass     getImplementor(int i)    { return (Klass)        implementors[i].getValue(this); }
 255   public TypeArray getFields()              { return (TypeArray)    fields.getValue(this); }
 256   public ConstantPool getConstants()        { return (ConstantPool) constants.getValue(this); }
 257   public Oop       getClassLoader()         { return                classLoader.getValue(this); }
 258   public Oop       getProtectionDomain()    { return                protectionDomain.getValue(this); }
 259   public ObjArray  getSigners()             { return (ObjArray)     signers.getValue(this); }
 260   public Symbol    getSourceFileName()      { return (Symbol)       sourceFileName.getValue(this); }
 261   public Symbol    getSourceDebugExtension(){ return (Symbol)       sourceDebugExtension.getValue(this); }
 262   public TypeArray getInnerClasses()        { return (TypeArray)    innerClasses.getValue(this); }
 263   public long      getNonstaticFieldSize()  { return                nonstaticFieldSize.getValue(this); }
 264   public long      getStaticFieldSize()     { return                staticFieldSize.getValue(this); }
 265   public long      getStaticOopFieldSize()  { return                staticOopFieldSize.getValue(this); }
 266   public long      getNonstaticOopMapSize() { return                nonstaticOopMapSize.getValue(this); }
 267   public boolean   getIsMarkedDependent()   { return                isMarkedDependent.getValue(this) != 0; }
 268   public long      getVtableLen()           { return                vtableLen.getValue(this); }
 269   public long      getItableLen()           { return                itableLen.getValue(this); }
 270   public Symbol    getGenericSignature()    { return (Symbol)       genericSignature.getValue(this); }
 271   public long      majorVersion()           { return                majorVersion.getValue(this); }
 272   public long      minorVersion()           { return                minorVersion.getValue(this); }
 273 
 274   // "size helper" == instance size in words
 275   public long getSizeHelper() {
 276     int lh = getLayoutHelper();
 277     if (Assert.ASSERTS_ENABLED) {
 278       Assert.that(lh > 0, "layout helper initialized for instance class");
 279     }
 280     return lh / VM.getVM().getAddressSize();
 281   }
 282 
 283   // same as enum InnerClassAttributeOffset in VM code.
 284   public static interface InnerClassAttributeOffset {
 285     // from JVM spec. "InnerClasses" attribute
 286     public static final int innerClassInnerClassInfoOffset = 0;
 287     public static final int innerClassOuterClassInfoOffset = 1;
 288     public static final int innerClassInnerNameOffset = 2;
 289     public static final int innerClassAccessFlagsOffset = 3;
 290     public static final int innerClassNextOffset = 4;
 291   };
 292 
 293   // refer to compute_modifier_flags in VM code.
 294   public long computeModifierFlags() {
 295     long access = getAccessFlags();
 296     // But check if it happens to be member class.
 297     TypeArray innerClassList = getInnerClasses();
 298     int length = ( innerClassList == null)? 0 : (int) innerClassList.getLength();
 299     if (length > 0) {
 300        if (Assert.ASSERTS_ENABLED) {
 301           Assert.that(length % InnerClassAttributeOffset.innerClassNextOffset == 0, "just checking");
 302        }
 303        for (int i = 0; i < length; i += InnerClassAttributeOffset.innerClassNextOffset) {
 304           int ioff = innerClassList.getShortAt(i +
 305                          InnerClassAttributeOffset.innerClassInnerClassInfoOffset);
 306           // 'ioff' can be zero.
 307           // refer to JVM spec. section 4.7.5.
 308           if (ioff != 0) {
 309              // only look at classes that are already loaded
 310              // since we are looking for the flags for our self.
 311              Oop classInfo = getConstants().getObjAt(ioff);
 312              Symbol name = null;
 313              if (classInfo instanceof Klass) {
 314                 name = ((Klass) classInfo).getName();
 315              } else if (classInfo instanceof Symbol) {
 316                 name = (Symbol) classInfo;
 317              } else {
 318                 throw new RuntimeException("should not reach here");
 319              }
 320 
 321              if (name.equals(getName())) {
 322                 // This is really a member class
 323                 access = innerClassList.getShortAt(i +
 324                         InnerClassAttributeOffset.innerClassAccessFlagsOffset);
 325                 break;
 326              }
 327           }
 328        } // for inner classes
 329     }
 330 
 331     // Remember to strip ACC_SUPER bit
 332     return (access & (~JVM_ACC_SUPER)) & JVM_ACC_WRITTEN_FLAGS;
 333   }
 334 
 335 
 336   // whether given Symbol is name of an inner/nested Klass of this Klass?
 337   // anonymous and local classes are excluded.
 338   public boolean isInnerClassName(Symbol sym) {
 339     return isInInnerClasses(sym, false);
 340   }
 341 
 342   // whether given Symbol is name of an inner/nested Klass of this Klass?
 343   // anonymous classes excluded, but local classes are included.
 344   public boolean isInnerOrLocalClassName(Symbol sym) {
 345     return isInInnerClasses(sym, true);
 346   }
 347 
 348   private boolean isInInnerClasses(Symbol sym, boolean includeLocals) {
 349     TypeArray innerClassList = getInnerClasses();
 350     int length = ( innerClassList == null)? 0 : (int) innerClassList.getLength();
 351     if (length > 0) {
 352        if (Assert.ASSERTS_ENABLED) {
 353          Assert.that(length % InnerClassAttributeOffset.innerClassNextOffset == 0, "just checking");
 354        }
 355        for (int i = 0; i < length; i += InnerClassAttributeOffset.innerClassNextOffset) {
 356          int ioff = innerClassList.getShortAt(i +
 357                         InnerClassAttributeOffset.innerClassInnerClassInfoOffset);
 358          // 'ioff' can be zero.
 359          // refer to JVM spec. section 4.7.5.
 360          if (ioff != 0) {
 361             Oop iclassInfo = getConstants().getObjAt(ioff);
 362             Symbol innerName = null;
 363             if (iclassInfo instanceof Klass) {
 364                innerName = ((Klass) iclassInfo).getName();
 365             } else if (iclassInfo instanceof Symbol) {
 366                innerName = (Symbol) iclassInfo;
 367             } else {
 368                throw new RuntimeException("should not reach here");
 369             }
 370 
 371             Symbol myname = getName();
 372             int ooff = innerClassList.getShortAt(i +
 373                         InnerClassAttributeOffset.innerClassOuterClassInfoOffset);
 374             // for anonymous classes inner_name_index of InnerClasses
 375             // attribute is zero.
 376             int innerNameIndex = innerClassList.getShortAt(i +
 377                         InnerClassAttributeOffset.innerClassInnerNameOffset);
 378             // if this is not a member (anonymous, local etc.), 'ooff' will be zero
 379             // refer to JVM spec. section 4.7.5.
 380             if (ooff == 0) {
 381                if (includeLocals) {
 382                   // does it looks like my local class?
 383                   if (innerName.equals(sym) &&
 384                      innerName.asString().startsWith(myname.asString())) {
 385                      // exclude anonymous classes.
 386                      return (innerNameIndex != 0);
 387                   }
 388                }
 389             } else {
 390                Oop oclassInfo = getConstants().getObjAt(ooff);
 391                Symbol outerName = null;
 392                if (oclassInfo instanceof Klass) {
 393                   outerName = ((Klass) oclassInfo).getName();
 394                } else if (oclassInfo instanceof Symbol) {
 395                   outerName = (Symbol) oclassInfo;
 396                } else {
 397                   throw new RuntimeException("should not reach here");
 398                }
 399 
 400                // include only if current class is outer class.
 401                if (outerName.equals(myname) && innerName.equals(sym)) {
 402                   return true;
 403                }
 404            }
 405          }
 406        } // for inner classes
 407        return false;
 408     } else {
 409        return false;
 410     }
 411   }
 412 
 413   public boolean implementsInterface(Klass k) {
 414     if (Assert.ASSERTS_ENABLED) {
 415       Assert.that(k.isInterface(), "should not reach here");
 416     }
 417     ObjArray interfaces =  getTransitiveInterfaces();
 418     final int len = (int) interfaces.getLength();
 419     for (int i = 0; i < len; i++) {
 420       if (interfaces.getObjAt(i).equals(k)) return true;
 421     }
 422     return false;
 423   }
 424 
 425   boolean computeSubtypeOf(Klass k) {
 426     if (k.isInterface()) {
 427       return implementsInterface(k);
 428     } else {
 429       return super.computeSubtypeOf(k);
 430     }
 431   }
 432 
 433   public void printValueOn(PrintStream tty) {
 434     tty.print("InstanceKlass for " + getName().asString());
 435   }
 436 
 437   public void iterateFields(OopVisitor visitor, boolean doVMFields) {
 438     super.iterateFields(visitor, doVMFields);
 439     if (doVMFields) {
 440       visitor.doOop(arrayKlasses, true);
 441       visitor.doOop(methods, true);
 442       visitor.doOop(methodOrdering, true);
 443       visitor.doOop(localInterfaces, true);
 444       visitor.doOop(transitiveInterfaces, true);
 445       visitor.doCInt(nofImplementors, true);
 446       for (int i = 0; i < IMPLEMENTORS_LIMIT; i++)
 447         visitor.doOop(implementors[i], true);
 448       visitor.doOop(fields, true);
 449       visitor.doOop(constants, true);
 450       visitor.doOop(classLoader, true);
 451       visitor.doOop(protectionDomain, true);
 452       visitor.doOop(signers, true);
 453       visitor.doOop(sourceFileName, true);
 454       visitor.doOop(innerClasses, true);
 455       visitor.doCInt(nonstaticFieldSize, true);
 456       visitor.doCInt(staticFieldSize, true);
 457       visitor.doCInt(staticOopFieldSize, true);
 458       visitor.doCInt(nonstaticOopMapSize, true);
 459       visitor.doCInt(isMarkedDependent, true);
 460       visitor.doCInt(initState, true);
 461       visitor.doCInt(vtableLen, true);
 462       visitor.doCInt(itableLen, true);
 463     }
 464 
 465     TypeArray fields = getFields();
 466     int length = (int) fields.getLength();
 467     for (int index = 0; index < length; index += NEXT_OFFSET) {
 468       short accessFlags    = fields.getShortAt(index + ACCESS_FLAGS_OFFSET);
 469       short signatureIndex = fields.getShortAt(index + SIGNATURE_INDEX_OFFSET);
 470       FieldType   type   = new FieldType((Symbol) getConstants().getObjAt(signatureIndex));
 471       AccessFlags access = new AccessFlags(accessFlags);
 472       if (access.isStatic()) {
 473         visitField(visitor, type, index);
 474       }
 475     }
 476   }
 477 
 478   public Klass getJavaSuper() {
 479     return getSuper();
 480   }
 481 
 482   public void iterateNonStaticFields(OopVisitor visitor) {
 483     if (getSuper() != null) {
 484       ((InstanceKlass) getSuper()).iterateNonStaticFields(visitor);
 485     }
 486     TypeArray fields = getFields();
 487 
 488     int length = (int) fields.getLength();
 489     for (int index = 0; index < length; index += NEXT_OFFSET) {
 490       short accessFlags    = fields.getShortAt(index + ACCESS_FLAGS_OFFSET);
 491       short signatureIndex = fields.getShortAt(index + SIGNATURE_INDEX_OFFSET);
 492 
 493       FieldType   type   = new FieldType((Symbol) getConstants().getObjAt(signatureIndex));
 494       AccessFlags access = new AccessFlags(accessFlags);
 495       if (!access.isStatic()) {
 496         visitField(visitor, type, index);
 497       }
 498     }
 499   }
 500 
 501   /** Field access by name. */
 502   public Field findLocalField(Symbol name, Symbol sig) {
 503     TypeArray fields = getFields();
 504     int n = (int) fields.getLength();
 505     ConstantPool cp = getConstants();
 506     for (int i = 0; i < n; i += NEXT_OFFSET) {
 507       int nameIndex = fields.getShortAt(i + NAME_INDEX_OFFSET);
 508       int sigIndex  = fields.getShortAt(i + SIGNATURE_INDEX_OFFSET);
 509       Symbol f_name = cp.getSymbolAt(nameIndex);
 510       Symbol f_sig  = cp.getSymbolAt(sigIndex);
 511       if (name.equals(f_name) && sig.equals(f_sig)) {
 512         return newField(i);
 513       }
 514     }
 515 
 516     return null;
 517   }
 518 
 519   /** Find field in direct superinterfaces. */
 520   public Field findInterfaceField(Symbol name, Symbol sig) {
 521     ObjArray interfaces = getLocalInterfaces();
 522     int n = (int) interfaces.getLength();
 523     for (int i = 0; i < n; i++) {
 524       InstanceKlass intf1 = (InstanceKlass) interfaces.getObjAt(i);
 525       if (Assert.ASSERTS_ENABLED) {
 526         Assert.that(intf1.isInterface(), "just checking type");
 527       }
 528       // search for field in current interface
 529       Field f = intf1.findLocalField(name, sig);
 530       if (f != null) {
 531         if (Assert.ASSERTS_ENABLED) {
 532           Assert.that(f.getAccessFlagsObj().isStatic(), "interface field must be static");
 533         }
 534         return f;
 535       }
 536       // search for field in direct superinterfaces
 537       f = intf1.findInterfaceField(name, sig);
 538       if (f != null) return f;
 539     }
 540     // otherwise field lookup fails
 541     return null;
 542   }
 543 
 544   /** Find field according to JVM spec 5.4.3.2, returns the klass in
 545       which the field is defined. */
 546   public Field findField(Symbol name, Symbol sig) {
 547     // search order according to newest JVM spec (5.4.3.2, p.167).
 548     // 1) search for field in current klass
 549     Field f = findLocalField(name, sig);
 550     if (f != null) return f;
 551 
 552     // 2) search for field recursively in direct superinterfaces
 553     f = findInterfaceField(name, sig);
 554     if (f != null) return f;
 555 
 556     // 3) apply field lookup recursively if superclass exists
 557     InstanceKlass supr = (InstanceKlass) getSuper();
 558     if (supr != null) return supr.findField(name, sig);
 559 
 560     // 4) otherwise field lookup fails
 561     return null;
 562   }
 563 
 564   /** Find field according to JVM spec 5.4.3.2, returns the klass in
 565       which the field is defined (convenience routine) */
 566   public Field findField(String name, String sig) {
 567     SymbolTable symbols = VM.getVM().getSymbolTable();
 568     Symbol nameSym = symbols.probe(name);
 569     Symbol sigSym  = symbols.probe(sig);
 570     if (nameSym == null || sigSym == null) {
 571       return null;
 572     }
 573     return findField(nameSym, sigSym);
 574   }
 575 
 576   /** Find field according to JVM spec 5.4.3.2, returns the klass in
 577       which the field is defined (retained only for backward
 578       compatibility with jdbx) */
 579   public Field findFieldDbg(String name, String sig) {
 580     return findField(name, sig);
 581   }
 582 
 583   /** Get field by its index in the fields array. Only designed for
 584       use in a debugging system. */
 585   public Field getFieldByIndex(int fieldArrayIndex) {
 586     return newField(fieldArrayIndex);
 587   }
 588 
 589 
 590     /** Return a List of SA Fields for the fields declared in this class.
 591         Inherited fields are not included.
 592         Return an empty list if there are no fields declared in this class.
 593         Only designed for use in a debugging system. */
 594     public List getImmediateFields() {
 595         // A list of Fields for each field declared in this class/interface,
 596         // not including inherited fields.
 597         TypeArray fields = getFields();
 598 
 599         int length = (int) fields.getLength();
 600         List immediateFields = new ArrayList(length / NEXT_OFFSET);
 601         for (int index = 0; index < length; index += NEXT_OFFSET) {
 602             immediateFields.add(getFieldByIndex(index));
 603         }
 604 
 605         return immediateFields;
 606     }
 607 
 608     /** Return a List of SA Fields for all the java fields in this class,
 609         including all inherited fields.  This includes hidden
 610         fields.  Thus the returned list can contain fields with
 611         the same name.
 612         Return an empty list if there are no fields.
 613         Only designed for use in a debugging system. */
 614     public List getAllFields() {
 615         // Contains a Field for each field in this class, including immediate
 616         // fields and inherited fields.
 617         List  allFields = getImmediateFields();
 618 
 619         // transitiveInterfaces contains all interfaces implemented
 620         // by this class and its superclass chain with no duplicates.
 621 
 622         ObjArray interfaces = getTransitiveInterfaces();
 623         int n = (int) interfaces.getLength();
 624         for (int i = 0; i < n; i++) {
 625             InstanceKlass intf1 = (InstanceKlass) interfaces.getObjAt(i);
 626             if (Assert.ASSERTS_ENABLED) {
 627                 Assert.that(intf1.isInterface(), "just checking type");
 628             }
 629             allFields.addAll(intf1.getImmediateFields());
 630         }
 631 
 632         // Get all fields in the superclass, recursively.  But, don't
 633         // include fields in interfaces implemented by superclasses;
 634         // we already have all those.
 635         if (!isInterface()) {
 636             InstanceKlass supr;
 637             if  ( (supr = (InstanceKlass) getSuper()) != null) {
 638                 allFields.addAll(supr.getImmediateFields());
 639             }
 640         }
 641 
 642         return allFields;
 643     }
 644 
 645 
 646     /** Return a List of SA Methods declared directly in this class/interface.
 647         Return an empty list if there are none, or if this isn't a class/
 648         interface.
 649     */
 650     public List getImmediateMethods() {
 651       // Contains a Method for each method declared in this class/interface
 652       // not including inherited methods.
 653 
 654       ObjArray methods = getMethods();
 655       int length = (int)methods.getLength();
 656       Object[] tmp = new Object[length];
 657 
 658       TypeArray methodOrdering = getMethodOrdering();
 659       if (methodOrdering.getLength() != length) {
 660          // no ordering info present
 661          for (int index = 0; index < length; index++) {
 662             tmp[index] = methods.getObjAt(index);
 663          }
 664       } else {
 665          for (int index = 0; index < length; index++) {
 666             int originalIndex = getMethodOrdering().getIntAt(index);
 667             tmp[originalIndex] = methods.getObjAt(index);
 668          }
 669       }
 670 
 671       return Arrays.asList(tmp);
 672     }
 673 
 674     /** Return a List containing an SA InstanceKlass for each
 675         interface named in this class's 'implements' clause.
 676     */
 677     public List getDirectImplementedInterfaces() {
 678         // Contains an InstanceKlass for each interface in this classes
 679         // 'implements' clause.
 680 
 681         ObjArray interfaces = getLocalInterfaces();
 682         int length = (int) interfaces.getLength();
 683         List directImplementedInterfaces = new ArrayList(length);
 684 
 685         for (int index = 0; index < length; index ++) {
 686             directImplementedInterfaces.add(interfaces.getObjAt(index));
 687         }
 688 
 689         return directImplementedInterfaces;
 690     }
 691 
 692 
 693   public long getObjectSize() {
 694     long bodySize =    alignObjectOffset(getVtableLen() * getHeap().getOopSize())
 695                      + alignObjectOffset(getItableLen() * getHeap().getOopSize())
 696                      + (getStaticFieldSize() + getNonstaticOopMapSize()) * getHeap().getOopSize();
 697     return alignObjectSize(headerSize + bodySize);
 698   }
 699 
 700   public Klass arrayKlassImpl(boolean orNull, int n) {
 701     // FIXME: in reflective system this would need to change to
 702     // actually allocate
 703     if (getArrayKlasses() == null) { return null; }
 704     ObjArrayKlass oak = (ObjArrayKlass) getArrayKlasses();
 705     if (orNull) {
 706       return oak.arrayKlassOrNull(n);
 707     }
 708     return oak.arrayKlass(n);
 709   }
 710 
 711   public Klass arrayKlassImpl(boolean orNull) {
 712     return arrayKlassImpl(orNull, 1);
 713   }
 714 
 715   public String signature() {
 716      return "L" + super.signature() + ";";
 717   }
 718 
 719   /** Convenience routine taking Strings; lookup is done in
 720       SymbolTable. */
 721   public Method findMethod(String name, String sig) {
 722     SymbolTable syms = VM.getVM().getSymbolTable();
 723     Symbol nameSym = syms.probe(name);
 724     Symbol sigSym  = syms.probe(sig);
 725     if (nameSym == null || sigSym == null) {
 726       return null;
 727     }
 728     return findMethod(nameSym, sigSym);
 729   }
 730 
 731   /** Find method in vtable. */
 732   public Method findMethod(Symbol name, Symbol sig) {
 733     return findMethod(getMethods(), name, sig);
 734   }
 735 
 736   /** Breakpoint support (see methods on methodOop for details) */
 737   public BreakpointInfo getBreakpoints() {
 738     Address addr = getHandle().getAddressAt(Oop.getHeaderSize() + breakpoints.getOffset());
 739     return (BreakpointInfo) VMObjectFactory.newObject(BreakpointInfo.class, addr);
 740   }
 741 
 742   //----------------------------------------------------------------------
 743   // Internals only below this point
 744   //
 745 
 746   private void visitField(OopVisitor visitor, FieldType type, int index) {
 747     Field f = newField(index);
 748     if (type.isOop()) {
 749       visitor.doOop((OopField) f, false);
 750       return;
 751     }
 752     if (type.isByte()) {
 753       visitor.doByte((ByteField) f, false);
 754       return;
 755     }
 756     if (type.isChar()) {
 757       visitor.doChar((CharField) f, false);
 758       return;
 759     }
 760     if (type.isDouble()) {
 761       visitor.doDouble((DoubleField) f, false);
 762       return;
 763     }
 764     if (type.isFloat()) {
 765       visitor.doFloat((FloatField) f, false);
 766       return;
 767     }
 768     if (type.isInt()) {
 769       visitor.doInt((IntField) f, false);
 770       return;
 771     }
 772     if (type.isLong()) {
 773       visitor.doLong((LongField) f, false);
 774       return;
 775     }
 776     if (type.isShort()) {
 777       visitor.doShort((ShortField) f, false);
 778       return;
 779     }
 780     if (type.isBoolean()) {
 781       visitor.doBoolean((BooleanField) f, false);
 782       return;
 783     }
 784   }
 785 
 786   // Creates new field from index in fields TypeArray
 787   private Field newField(int index) {
 788     TypeArray fields = getFields();
 789     short signatureIndex = fields.getShortAt(index + SIGNATURE_INDEX_OFFSET);
 790     FieldType type = new FieldType((Symbol) getConstants().getObjAt(signatureIndex));
 791     if (type.isOop()) {
 792      if (VM.getVM().isCompressedOopsEnabled()) {
 793         return new NarrowOopField(this, index);
 794      } else {
 795         return new OopField(this, index);
 796      }
 797     }
 798     if (type.isByte()) {
 799       return new ByteField(this, index);
 800     }
 801     if (type.isChar()) {
 802       return new CharField(this, index);
 803     }
 804     if (type.isDouble()) {
 805       return new DoubleField(this, index);
 806     }
 807     if (type.isFloat()) {
 808       return new FloatField(this, index);
 809     }
 810     if (type.isInt()) {
 811       return new IntField(this, index);
 812     }
 813     if (type.isLong()) {
 814       return new LongField(this, index);
 815     }
 816     if (type.isShort()) {
 817       return new ShortField(this, index);
 818     }
 819     if (type.isBoolean()) {
 820       return new BooleanField(this, index);
 821     }
 822     throw new RuntimeException("Illegal field type at index " + index);
 823   }
 824 
 825   private static Method findMethod(ObjArray methods, Symbol name, Symbol signature) {
 826     int len = (int) methods.getLength();
 827     // methods are sorted, so do binary search
 828     int l = 0;
 829     int h = len - 1;
 830     while (l <= h) {
 831       int mid = (l + h) >> 1;
 832       Method m = (Method) methods.getObjAt(mid);
 833       int res = m.getName().fastCompare(name);
 834       if (res == 0) {
 835         // found matching name; do linear search to find matching signature
 836         // first, quick check for common case
 837         if (m.getSignature().equals(signature)) return m;
 838         // search downwards through overloaded methods
 839         int i;
 840         for (i = mid - 1; i >= l; i--) {
 841           Method m1 = (Method) methods.getObjAt(i);
 842           if (!m1.getName().equals(name)) break;
 843           if (m1.getSignature().equals(signature)) return m1;
 844         }
 845         // search upwards
 846         for (i = mid + 1; i <= h; i++) {
 847           Method m1 = (Method) methods.getObjAt(i);
 848           if (!m1.getName().equals(name)) break;
 849           if (m1.getSignature().equals(signature)) return m1;
 850         }
 851         // not found
 852         if (Assert.ASSERTS_ENABLED) {
 853           int index = linearSearch(methods, name, signature);
 854           if (index != -1) {
 855             throw new DebuggerException("binary search bug: should have found entry " + index);
 856           }
 857         }
 858         return null;
 859       } else if (res < 0) {
 860         l = mid + 1;
 861       } else {
 862         h = mid - 1;
 863       }
 864     }
 865     if (Assert.ASSERTS_ENABLED) {
 866       int index = linearSearch(methods, name, signature);
 867       if (index != -1) {
 868         throw new DebuggerException("binary search bug: should have found entry " + index);
 869       }
 870     }
 871     return null;
 872   }
 873 
 874   private static int linearSearch(ObjArray methods, Symbol name, Symbol signature) {
 875     int len = (int) methods.getLength();
 876     for (int index = 0; index < len; index++) {
 877       Method m = (Method) methods.getObjAt(index);
 878       if (m.getSignature().equals(signature) && m.getName().equals(name)) {
 879         return index;
 880       }
 881     }
 882     return -1;
 883   }
 884 }