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