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