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