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