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