1 /*
2  * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  *
23  */
24 
25 package sun.jvm.hotspot.oops;
26 
27 import java.io.*;
28 import java.util.*;
29 import sun.jvm.hotspot.classfile.ClassLoaderData;
30 import sun.jvm.hotspot.debugger.*;
31 import sun.jvm.hotspot.memory.*;
32 import sun.jvm.hotspot.memory.Dictionary;
33 import sun.jvm.hotspot.runtime.*;
34 import sun.jvm.hotspot.types.*;
35 import sun.jvm.hotspot.utilities.*;
36 
37 // An InstanceKlass is the VM level representation of a Java class.
38 
39 public class InstanceKlass extends Klass {
40   static {
VM.registerVMInitializedObserver(new Observer() { public void update(Observable o, Object data) { initialize(VM.getVM().getTypeDataBase()); } })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_UNSAFE_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 
initialize(TypeDataBase db)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_UNSAFE_ANONYMOUS          = db.lookupIntConstant("InstanceKlass::_misc_is_unsafe_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 
InstanceKlass(Address addr)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 
ClassState(String value)193      private ClassState(String value) {
194         this.value = value;
195      }
196 
toString()197      public String toString() {
198         return value;
199      }
200 
201      private String value;
202   }
203 
getInitStateAsInt()204   public int  getInitStateAsInt() { return (int) initState.getValue(this); }
getInitState()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
isLoaded()225   public boolean isLoaded() {
226      return getInitStateAsInt() >= CLASS_STATE_LOADED;
227   }
228 
isLinked()229   public boolean isLinked() {
230      return getInitStateAsInt() >= CLASS_STATE_LINKED;
231   }
232 
isInitialized()233   public boolean isInitialized() {
234      return getInitStateAsInt() == CLASS_STATE_FULLY_INITIALIZED;
235   }
236 
isNotInitialized()237   public boolean isNotInitialized() {
238      return getInitStateAsInt() < CLASS_STATE_BEING_INITIALIZED;
239   }
240 
isBeingInitialized()241   public boolean isBeingInitialized() {
242      return getInitStateAsInt() == CLASS_STATE_BEING_INITIALIZED;
243   }
244 
isInErrorState()245   public boolean isInErrorState() {
246      return getInitStateAsInt() == CLASS_STATE_INITIALIZATION_ERROR;
247   }
248 
getClassStatus()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 
getObjectSize(Oop object)271   public long getObjectSize(Oop object) {
272     return getSizeHelper() * VM.getVM().getAddressSize();
273   }
274 
getSize()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 (isUnsafeAnonymous()) {
285       size += wordLength;
286     }
287     if (hasStoredFingerprint()) {
288       size += 8; // uint64_t
289     }
290     return alignSize(size);
291   }
292 
getMiscFlags()293   private int getMiscFlags() {
294     return (int) miscFlags.getValue(this);
295   }
296 
isUnsafeAnonymous()297   public boolean isUnsafeAnonymous() {
298     return (getMiscFlags() & MISC_IS_UNSAFE_ANONYMOUS) != 0;
299   }
300 
shouldStoreFingerprint()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 
hasStoredFingerprint()312   public boolean hasStoredFingerprint() {
313     return shouldStoreFingerprint() || isShared();
314   }
315 
getHeaderSize()316   public static long getHeaderSize() { return headerSize; }
317 
getFieldAccessFlags(int index)318   public short getFieldAccessFlags(int index) {
319     return getFields().at(index * FIELD_SLOTS + ACCESS_FLAGS_OFFSET);
320   }
321 
getFieldNameIndex(int index)322   public short getFieldNameIndex(int index) {
323     if (index >= getJavaFieldsCount()) throw new IndexOutOfBoundsException("not a Java field;");
324     return getFields().at(index * FIELD_SLOTS + NAME_INDEX_OFFSET);
325   }
326 
getFieldName(int index)327   public Symbol getFieldName(int index) {
328     int nameIndex = getFields().at(index * FIELD_SLOTS + NAME_INDEX_OFFSET);
329     if (index < getJavaFieldsCount()) {
330       return getConstants().getSymbolAt(nameIndex);
331     } else {
332       return vmSymbols.symbolAt(nameIndex);
333     }
334   }
335 
getFieldSignatureIndex(int index)336   public short getFieldSignatureIndex(int index) {
337     if (index >= getJavaFieldsCount()) throw new IndexOutOfBoundsException("not a Java field;");
338     return getFields().at(index * FIELD_SLOTS + SIGNATURE_INDEX_OFFSET);
339   }
340 
getFieldSignature(int index)341   public Symbol getFieldSignature(int index) {
342     int signatureIndex = getFields().at(index * FIELD_SLOTS + SIGNATURE_INDEX_OFFSET);
343     if (index < getJavaFieldsCount()) {
344       return getConstants().getSymbolAt(signatureIndex);
345     } else {
346       return vmSymbols.symbolAt(signatureIndex);
347     }
348   }
349 
getFieldGenericSignatureIndex(int index)350   public short getFieldGenericSignatureIndex(int index) {
351     // int len = getFields().length();
352     int allFieldsCount = getAllFieldsCount();
353     int generic_signature_slot = allFieldsCount * FIELD_SLOTS;
354     for (int i = 0; i < allFieldsCount; i++) {
355       short flags = getFieldAccessFlags(i);
356       AccessFlags access = new AccessFlags(flags);
357       if (i == index) {
358         if (access.fieldHasGenericSignature()) {
359            return getFields().at(generic_signature_slot);
360         } else {
361           return 0;
362         }
363       } else {
364         if (access.fieldHasGenericSignature()) {
365           generic_signature_slot ++;
366         }
367       }
368     }
369     return 0;
370   }
371 
getFieldGenericSignature(int index)372   public Symbol getFieldGenericSignature(int index) {
373     short genericSignatureIndex = getFieldGenericSignatureIndex(index);
374     if (genericSignatureIndex != 0)  {
375       return getConstants().getSymbolAt(genericSignatureIndex);
376     }
377     return null;
378   }
379 
getFieldInitialValueIndex(int index)380   public short getFieldInitialValueIndex(int index) {
381     if (index >= getJavaFieldsCount()) throw new IndexOutOfBoundsException("not a Java field;");
382     return getFields().at(index * FIELD_SLOTS + INITVAL_INDEX_OFFSET);
383   }
384 
getFieldOffset(int index)385   public int getFieldOffset(int index) {
386     U2Array fields = getFields();
387     short lo = fields.at(index * FIELD_SLOTS + LOW_OFFSET);
388     short hi = fields.at(index * FIELD_SLOTS + HIGH_OFFSET);
389     if ((lo & FIELDINFO_TAG_MASK) == FIELDINFO_TAG_OFFSET) {
390       return VM.getVM().buildIntFromShorts(lo, hi) >> FIELDINFO_TAG_SIZE;
391     }
392     throw new RuntimeException("should not reach here");
393   }
394 
395   // Accessors for declared fields
getArrayKlasses()396   public Klass     getArrayKlasses()        { return (Klass)        arrayKlasses.getValue(this); }
getMethods()397   public MethodArray  getMethods()              { return new MethodArray(methods.getValue(getAddress())); }
398 
getDefaultMethods()399   public MethodArray  getDefaultMethods() {
400     if (defaultMethods != null) {
401       Address addr = defaultMethods.getValue(getAddress());
402       if ((addr != null) && (addr.getAddressAt(0) != null)) {
403         return new MethodArray(addr);
404       } else {
405         return null;
406       }
407     } else {
408       return null;
409     }
410   }
411 
getLocalInterfaces()412   public KlassArray   getLocalInterfaces()      { return new KlassArray(localInterfaces.getValue(getAddress())); }
getTransitiveInterfaces()413   public KlassArray   getTransitiveInterfaces() { return new KlassArray(transitiveInterfaces.getValue(getAddress())); }
getJavaFieldsCount()414   public int       getJavaFieldsCount()     { return                (int) javaFieldsCount.getValue(this); }
getAllFieldsCount()415   public int       getAllFieldsCount()      {
416     int len = getFields().length();
417     int allFieldsCount = 0;
418     for (; allFieldsCount*FIELD_SLOTS < len; allFieldsCount++) {
419       short flags = getFieldAccessFlags(allFieldsCount);
420       AccessFlags access = new AccessFlags(flags);
421       if (access.fieldHasGenericSignature()) {
422         len --;
423       }
424     }
425     return allFieldsCount;
426   }
getConstants()427   public ConstantPool getConstants()        { return (ConstantPool) constants.getValue(this); }
getSourceFileName()428   public Symbol    getSourceFileName()      { return                getConstants().getSymbolAt(sourceFileNameIndex.getValue(this)); }
getSourceDebugExtension()429   public String    getSourceDebugExtension(){ return                CStringUtilities.getString(sourceDebugExtension.getValue(getAddress())); }
getNonstaticFieldSize()430   public long      getNonstaticFieldSize()  { return                nonstaticFieldSize.getValue(this); }
getStaticOopFieldCount()431   public long      getStaticOopFieldCount() { return                staticOopFieldCount.getValue(this); }
getNonstaticOopMapSize()432   public long      getNonstaticOopMapSize() { return                nonstaticOopMapSize.getValue(this); }
getIsMarkedDependent()433   public boolean   getIsMarkedDependent()   { return                isMarkedDependent.getValue(this) != 0; }
getItableLen()434   public long      getItableLen()           { return                itableLen.getValue(this); }
majorVersion()435   public long      majorVersion()           { return                majorVersion.getValue(this); }
minorVersion()436   public long      minorVersion()           { return                minorVersion.getValue(this); }
getGenericSignature()437   public Symbol    getGenericSignature()    {
438     long index = genericSignatureIndex.getValue(this);
439     if (index != 0) {
440       return getConstants().getSymbolAt(index);
441     } else {
442       return null;
443     }
444   }
445 
446   // "size helper" == instance size in words
getSizeHelper()447   public long getSizeHelper() {
448     int lh = getLayoutHelper();
449     if (Assert.ASSERTS_ENABLED) {
450       Assert.that(lh > 0, "layout helper initialized for instance class");
451     }
452     return lh / VM.getVM().getAddressSize();
453   }
454 
455   // same as enum InnerClassAttributeOffset in VM code.
456   private static class InnerClassAttributeOffset {
457     // from JVM spec. "InnerClasses" attribute
458     public static int innerClassInnerClassInfoOffset;
459     public static int innerClassOuterClassInfoOffset;
460     public static int innerClassInnerNameOffset;
461     public static int innerClassAccessFlagsOffset;
462     public static int innerClassNextOffset;
463     static {
VM.registerVMInitializedObserver(new Observer() { public void update(Observable o, Object data) { initialize(VM.getVM().getTypeDataBase()); } })464       VM.registerVMInitializedObserver(new Observer() {
465           public void update(Observable o, Object data) {
466               initialize(VM.getVM().getTypeDataBase());
467           }
468       });
469     }
470 
initialize(TypeDataBase db)471     private static synchronized void initialize(TypeDataBase db) {
472       innerClassInnerClassInfoOffset = db.lookupIntConstant(
473           "InstanceKlass::inner_class_inner_class_info_offset").intValue();
474       innerClassOuterClassInfoOffset = db.lookupIntConstant(
475           "InstanceKlass::inner_class_outer_class_info_offset").intValue();
476       innerClassInnerNameOffset = db.lookupIntConstant(
477           "InstanceKlass::inner_class_inner_name_offset").intValue();
478       innerClassAccessFlagsOffset = db.lookupIntConstant(
479           "InstanceKlass::inner_class_access_flags_offset").intValue();
480       innerClassNextOffset = db.lookupIntConstant(
481           "InstanceKlass::inner_class_next_offset").intValue();
482     }
483   }
484 
485   private static class EnclosingMethodAttributeOffset {
486     public static int enclosingMethodAttributeSize;
487     static {
VM.registerVMInitializedObserver(new Observer() { public void update(Observable o, Object data) { initialize(VM.getVM().getTypeDataBase()); } })488       VM.registerVMInitializedObserver(new Observer() {
489           public void update(Observable o, Object data) {
490               initialize(VM.getVM().getTypeDataBase());
491           }
492       });
493     }
initialize(TypeDataBase db)494     private static synchronized void initialize(TypeDataBase db) {
495       enclosingMethodAttributeSize = db.lookupIntConstant("InstanceKlass::enclosing_method_attribute_size").intValue();
496     }
497   }
498 
499   // refer to compute_modifier_flags in VM code.
computeModifierFlags()500   public long computeModifierFlags() {
501     long access = getAccessFlags();
502     // But check if it happens to be member class.
503     U2Array innerClassList = getInnerClasses();
504     int length = (innerClassList == null)? 0 : (int) innerClassList.length();
505     if (length > 0) {
506        if (Assert.ASSERTS_ENABLED) {
507           Assert.that(length % InnerClassAttributeOffset.innerClassNextOffset == 0 ||
508                       length % InnerClassAttributeOffset.innerClassNextOffset == EnclosingMethodAttributeOffset.enclosingMethodAttributeSize,
509                       "just checking");
510        }
511        for (int i = 0; i < length; i += InnerClassAttributeOffset.innerClassNextOffset) {
512           if (i == length - EnclosingMethodAttributeOffset.enclosingMethodAttributeSize) {
513               break;
514           }
515           int ioff = innerClassList.at(i +
516                          InnerClassAttributeOffset.innerClassInnerClassInfoOffset);
517           // 'ioff' can be zero.
518           // refer to JVM spec. section 4.7.5.
519           if (ioff != 0) {
520              // only look at classes that are already loaded
521              // since we are looking for the flags for our self.
522              Symbol name = getConstants().getKlassNameAt(ioff);
523 
524              if (name.equals(getName())) {
525                 // This is really a member class
526                 access = innerClassList.at(i +
527                         InnerClassAttributeOffset.innerClassAccessFlagsOffset);
528                 break;
529              }
530           }
531        } // for inner classes
532     }
533 
534     // Remember to strip ACC_SUPER bit
535     return (access & (~JVM_ACC_SUPER)) & JVM_ACC_WRITTEN_FLAGS;
536   }
537 
538 
539   // whether given Symbol is name of an inner/nested Klass of this Klass?
540   // anonymous and local classes are excluded.
isInnerClassName(Symbol sym)541   public boolean isInnerClassName(Symbol sym) {
542     return isInInnerClasses(sym, false);
543   }
544 
545   // whether given Symbol is name of an inner/nested Klass of this Klass?
546   // anonymous classes excluded, but local classes are included.
isInnerOrLocalClassName(Symbol sym)547   public boolean isInnerOrLocalClassName(Symbol sym) {
548     return isInInnerClasses(sym, true);
549   }
550 
isInInnerClasses(Symbol sym, boolean includeLocals)551   private boolean isInInnerClasses(Symbol sym, boolean includeLocals) {
552     U2Array innerClassList = getInnerClasses();
553     int length = ( innerClassList == null)? 0 : (int) innerClassList.length();
554     if (length > 0) {
555        if (Assert.ASSERTS_ENABLED) {
556          Assert.that(length % InnerClassAttributeOffset.innerClassNextOffset == 0 ||
557                      length % InnerClassAttributeOffset.innerClassNextOffset == EnclosingMethodAttributeOffset.enclosingMethodAttributeSize,
558                      "just checking");
559        }
560        for (int i = 0; i < length; i += InnerClassAttributeOffset.innerClassNextOffset) {
561          if (i == length - EnclosingMethodAttributeOffset.enclosingMethodAttributeSize) {
562              break;
563          }
564          int ioff = innerClassList.at(i +
565                         InnerClassAttributeOffset.innerClassInnerClassInfoOffset);
566          // 'ioff' can be zero.
567          // refer to JVM spec. section 4.7.5.
568          if (ioff != 0) {
569             Symbol innerName = getConstants().getKlassNameAt(ioff);
570             Symbol myname = getName();
571             int ooff = innerClassList.at(i +
572                         InnerClassAttributeOffset.innerClassOuterClassInfoOffset);
573             // for anonymous classes inner_name_index of InnerClasses
574             // attribute is zero.
575             int innerNameIndex = innerClassList.at(i +
576                         InnerClassAttributeOffset.innerClassInnerNameOffset);
577             // if this is not a member (anonymous, local etc.), 'ooff' will be zero
578             // refer to JVM spec. section 4.7.5.
579             if (ooff == 0) {
580                if (includeLocals) {
581                   // does it looks like my local class?
582                   if (innerName.equals(sym) &&
583                      innerName.asString().startsWith(myname.asString())) {
584                      // exclude anonymous classes.
585                      return (innerNameIndex != 0);
586                   }
587                }
588             } else {
589                Symbol outerName = getConstants().getKlassNameAt(ooff);
590 
591                // include only if current class is outer class.
592                if (outerName.equals(myname) && innerName.equals(sym)) {
593                   return true;
594                }
595            }
596          }
597        } // for inner classes
598        return false;
599     } else {
600        return false;
601     }
602   }
603 
implementsInterface(Klass k)604   public boolean implementsInterface(Klass k) {
605     if (Assert.ASSERTS_ENABLED) {
606       Assert.that(k.isInterface(), "should not reach here");
607     }
608     KlassArray interfaces =  getTransitiveInterfaces();
609     final int len = interfaces.length();
610     for (int i = 0; i < len; i++) {
611       if (interfaces.getAt(i).equals(k)) return true;
612     }
613     return false;
614   }
615 
computeSubtypeOf(Klass k)616   boolean computeSubtypeOf(Klass k) {
617     if (k.isInterface()) {
618       return implementsInterface(k);
619     } else {
620       return super.computeSubtypeOf(k);
621     }
622   }
623 
printValueOn(PrintStream tty)624   public void printValueOn(PrintStream tty) {
625     tty.print("InstanceKlass for " + getName().asString());
626   }
627 
iterateFields(MetadataVisitor visitor)628   public void iterateFields(MetadataVisitor visitor) {
629     super.iterateFields(visitor);
630     visitor.doMetadata(arrayKlasses, true);
631     // visitor.doOop(methods, true);
632     // visitor.doOop(localInterfaces, true);
633     // visitor.doOop(transitiveInterfaces, true);
634       visitor.doCInt(nonstaticFieldSize, true);
635       visitor.doCInt(staticFieldSize, true);
636       visitor.doCInt(staticOopFieldCount, true);
637       visitor.doCInt(nonstaticOopMapSize, true);
638       visitor.doCInt(isMarkedDependent, true);
639       visitor.doCInt(initState, true);
640       visitor.doCInt(itableLen, true);
641     }
642 
643   /*
644    *  Visit the static fields of this InstanceKlass with the obj of
645    *  the visitor set to the oop holding the fields, which is
646    *  currently the java mirror.
647    */
iterateStaticFields(OopVisitor visitor)648   public void iterateStaticFields(OopVisitor visitor) {
649     visitor.setObj(getJavaMirror());
650     visitor.prologue();
651     iterateStaticFieldsInternal(visitor);
652     visitor.epilogue();
653 
654   }
655 
iterateStaticFieldsInternal(OopVisitor visitor)656   void iterateStaticFieldsInternal(OopVisitor visitor) {
657     int length = getJavaFieldsCount();
658     for (int index = 0; index < length; index++) {
659       short accessFlags    = getFieldAccessFlags(index);
660       FieldType   type   = new FieldType(getFieldSignature(index));
661       AccessFlags access = new AccessFlags(accessFlags);
662       if (access.isStatic()) {
663         visitField(visitor, type, index);
664       }
665     }
666   }
667 
getJavaSuper()668   public Klass getJavaSuper() {
669     return getSuper();
670   }
671 
672   public static class StaticField {
673     public AccessFlags flags;
674     public Field field;
675 
StaticField(Field field, AccessFlags flags)676     StaticField(Field field, AccessFlags flags) {
677       this.field = field;
678       this.flags = flags;
679     }
680   }
681 
getStaticFields()682   public Field[] getStaticFields() {
683     U2Array fields = getFields();
684     int length = getJavaFieldsCount();
685     ArrayList result = new ArrayList();
686     for (int index = 0; index < length; index++) {
687       Field f = newField(index);
688       if (f.isStatic()) {
689         result.add(f);
690       }
691     }
692     return (Field[])result.toArray(new Field[result.size()]);
693   }
694 
iterateNonStaticFields(OopVisitor visitor, Oop obj)695   public void iterateNonStaticFields(OopVisitor visitor, Oop obj) {
696     if (getSuper() != null) {
697       ((InstanceKlass) getSuper()).iterateNonStaticFields(visitor, obj);
698     }
699     int length = getJavaFieldsCount();
700     for (int index = 0; index < length; index++) {
701       short accessFlags    = getFieldAccessFlags(index);
702       FieldType   type   = new FieldType(getFieldSignature(index));
703       AccessFlags access = new AccessFlags(accessFlags);
704       if (!access.isStatic()) {
705         visitField(visitor, type, index);
706       }
707     }
708   }
709 
710   /** Field access by name. */
findLocalField(String name, String sig)711   public Field findLocalField(String name, String sig) {
712     int length = getJavaFieldsCount();
713     for (int i = 0; i < length; i++) {
714       Symbol f_name = getFieldName(i);
715       Symbol f_sig  = getFieldSignature(i);
716       if (f_name.equals(name) && f_sig.equals(sig)) {
717         return newField(i);
718       }
719     }
720 
721     return null;
722   }
723 
724   /** Find field in direct superinterfaces. */
findInterfaceField(String name, String sig)725   public Field findInterfaceField(String name, String sig) {
726     KlassArray interfaces = getLocalInterfaces();
727     int n = interfaces.length();
728     for (int i = 0; i < n; i++) {
729       InstanceKlass intf1 = (InstanceKlass) interfaces.getAt(i);
730       if (Assert.ASSERTS_ENABLED) {
731         Assert.that(intf1.isInterface(), "just checking type");
732      }
733       // search for field in current interface
734       Field f = intf1.findLocalField(name, sig);
735       if (f != null) {
736         if (Assert.ASSERTS_ENABLED) {
737           Assert.that(f.getAccessFlagsObj().isStatic(), "interface field must be static");
738         }
739         return f;
740       }
741       // search for field in direct superinterfaces
742       f = intf1.findInterfaceField(name, sig);
743       if (f != null) return f;
744     }
745     // otherwise field lookup fails
746     return null;
747   }
748 
749   /** Find field according to JVM spec 5.4.3.2, returns the klass in
750       which the field is defined. */
findField(String name, String sig)751   public Field findField(String name, String sig) {
752     // search order according to newest JVM spec (5.4.3.2, p.167).
753     // 1) search for field in current klass
754     Field f = findLocalField(name, sig);
755     if (f != null) return f;
756 
757     // 2) search for field recursively in direct superinterfaces
758     f = findInterfaceField(name, sig);
759     if (f != null) return f;
760 
761     // 3) apply field lookup recursively if superclass exists
762     InstanceKlass supr = (InstanceKlass) getSuper();
763     if (supr != null) return supr.findField(name, sig);
764 
765     // 4) otherwise field lookup fails
766     return null;
767   }
768 
769   /** Find field according to JVM spec 5.4.3.2, returns the klass in
770       which the field is defined (retained only for backward
771       compatibility with jdbx) */
findFieldDbg(String name, String sig)772   public Field findFieldDbg(String name, String sig) {
773     return findField(name, sig);
774   }
775 
776   /** Get field by its index in the fields array. Only designed for
777       use in a debugging system. */
getFieldByIndex(int fieldIndex)778   public Field getFieldByIndex(int fieldIndex) {
779     return newField(fieldIndex);
780   }
781 
782 
783     /** Return a List of SA Fields for the fields declared in this class.
784         Inherited fields are not included.
785         Return an empty list if there are no fields declared in this class.
786         Only designed for use in a debugging system. */
getImmediateFields()787     public List getImmediateFields() {
788         // A list of Fields for each field declared in this class/interface,
789         // not including inherited fields.
790         int length = getJavaFieldsCount();
791         List immediateFields = new ArrayList(length);
792         for (int index = 0; index < length; index++) {
793             immediateFields.add(getFieldByIndex(index));
794         }
795 
796         return immediateFields;
797     }
798 
799     /** Return a List of SA Fields for all the java fields in this class,
800         including all inherited fields.  This includes hidden
801         fields.  Thus the returned list can contain fields with
802         the same name.
803         Return an empty list if there are no fields.
804         Only designed for use in a debugging system. */
getAllFields()805     public List getAllFields() {
806         // Contains a Field for each field in this class, including immediate
807         // fields and inherited fields.
808         List  allFields = getImmediateFields();
809 
810         // transitiveInterfaces contains all interfaces implemented
811         // by this class and its superclass chain with no duplicates.
812 
813         KlassArray interfaces = getTransitiveInterfaces();
814         int n = interfaces.length();
815         for (int i = 0; i < n; i++) {
816             InstanceKlass intf1 = (InstanceKlass) interfaces.getAt(i);
817             if (Assert.ASSERTS_ENABLED) {
818                 Assert.that(intf1.isInterface(), "just checking type");
819             }
820             allFields.addAll(intf1.getImmediateFields());
821         }
822 
823         // Get all fields in the superclass, recursively.  But, don't
824         // include fields in interfaces implemented by superclasses;
825         // we already have all those.
826         if (!isInterface()) {
827             InstanceKlass supr;
828             if  ( (supr = (InstanceKlass) getSuper()) != null) {
829                 allFields.addAll(supr.getImmediateFields());
830             }
831         }
832 
833         return allFields;
834     }
835 
836 
837     /** Return a List of SA Methods declared directly in this class/interface.
838         Return an empty list if there are none, or if this isn't a class/
839         interface.
840     */
getImmediateMethods()841     public List getImmediateMethods() {
842       // Contains a Method for each method declared in this class/interface
843       // not including inherited methods.
844 
845       MethodArray methods = getMethods();
846       int length = methods.length();
847       Object[] tmp = new Object[length];
848 
849       IntArray methodOrdering = getMethodOrdering();
850       if (methodOrdering.length() != length) {
851          // no ordering info present
852          for (int index = 0; index < length; index++) {
853             tmp[index] = methods.at(index);
854          }
855       } else {
856          for (int index = 0; index < length; index++) {
857             int originalIndex = methodOrdering.at(index);
858             tmp[originalIndex] = methods.at(index);
859          }
860       }
861 
862       return Arrays.asList(tmp);
863     }
864 
865     /** Return a List containing an SA InstanceKlass for each
866         interface named in this class's 'implements' clause.
867     */
getDirectImplementedInterfaces()868     public List getDirectImplementedInterfaces() {
869         // Contains an InstanceKlass for each interface in this classes
870         // 'implements' clause.
871 
872         KlassArray interfaces = getLocalInterfaces();
873         int length = interfaces.length();
874         List directImplementedInterfaces = new ArrayList(length);
875 
876         for (int index = 0; index < length; index ++) {
877             directImplementedInterfaces.add(interfaces.getAt(index));
878         }
879 
880         return directImplementedInterfaces;
881     }
882 
arrayKlassImpl(boolean orNull, int n)883   public Klass arrayKlassImpl(boolean orNull, int n) {
884     // FIXME: in reflective system this would need to change to
885     // actually allocate
886     if (getArrayKlasses() == null) { return null; }
887     ObjArrayKlass oak = (ObjArrayKlass) getArrayKlasses();
888     if (orNull) {
889       return oak.arrayKlassOrNull(n);
890     }
891     return oak.arrayKlass(n);
892   }
893 
arrayKlassImpl(boolean orNull)894   public Klass arrayKlassImpl(boolean orNull) {
895     return arrayKlassImpl(orNull, 1);
896   }
897 
signature()898   public String signature() {
899      return "L" + super.signature() + ";";
900   }
901 
902   /** Find method in vtable. */
findMethod(String name, String sig)903   public Method findMethod(String name, String sig) {
904     return findMethod(getMethods(), name, sig);
905   }
906 
907   /** Breakpoint support (see methods on Method* for details) */
getBreakpoints()908   public BreakpointInfo getBreakpoints() {
909     if (!VM.getVM().isJvmtiSupported()) {
910       return null;
911     }
912     Address addr = getAddress().getAddressAt(breakpoints.getOffset());
913     return (BreakpointInfo) VMObjectFactory.newObject(BreakpointInfo.class, addr);
914   }
915 
getMethodOrdering()916   public IntArray  getMethodOrdering() {
917     Address addr = getAddress().getAddressAt(methodOrdering.getOffset());
918     return (IntArray) VMObjectFactory.newObject(IntArray.class, addr);
919   }
920 
getFields()921   public U2Array getFields() {
922     Address addr = getAddress().getAddressAt(fields.getOffset());
923     return (U2Array) VMObjectFactory.newObject(U2Array.class, addr);
924   }
925 
getInnerClasses()926   public U2Array getInnerClasses() {
927     Address addr = getAddress().getAddressAt(innerClasses.getOffset());
928     return (U2Array) VMObjectFactory.newObject(U2Array.class, addr);
929   }
930 
931 
932   //----------------------------------------------------------------------
933   // Internals only below this point
934   //
935 
visitField(OopVisitor visitor, FieldType type, int index)936   private void visitField(OopVisitor visitor, FieldType type, int index) {
937     Field f = newField(index);
938     if (type.isOop()) {
939       visitor.doOop((OopField) f, false);
940       return;
941     }
942     if (type.isByte()) {
943       visitor.doByte((ByteField) f, false);
944       return;
945     }
946     if (type.isChar()) {
947       visitor.doChar((CharField) f, false);
948       return;
949     }
950     if (type.isDouble()) {
951       visitor.doDouble((DoubleField) f, false);
952       return;
953     }
954     if (type.isFloat()) {
955       visitor.doFloat((FloatField) f, false);
956       return;
957     }
958     if (type.isInt()) {
959       visitor.doInt((IntField) f, false);
960       return;
961     }
962     if (type.isLong()) {
963       visitor.doLong((LongField) f, false);
964       return;
965     }
966     if (type.isShort()) {
967       visitor.doShort((ShortField) f, false);
968       return;
969     }
970     if (type.isBoolean()) {
971       visitor.doBoolean((BooleanField) f, false);
972       return;
973     }
974   }
975 
976   // Creates new field from index in fields TypeArray
newField(int index)977   private Field newField(int index) {
978     FieldType type = new FieldType(getFieldSignature(index));
979     if (type.isOop()) {
980      if (VM.getVM().isCompressedOopsEnabled()) {
981         return new NarrowOopField(this, index);
982      } else {
983         return new OopField(this, index);
984      }
985     }
986     if (type.isByte()) {
987       return new ByteField(this, index);
988     }
989     if (type.isChar()) {
990       return new CharField(this, index);
991     }
992     if (type.isDouble()) {
993       return new DoubleField(this, index);
994     }
995     if (type.isFloat()) {
996       return new FloatField(this, index);
997     }
998     if (type.isInt()) {
999       return new IntField(this, index);
1000     }
1001     if (type.isLong()) {
1002       return new LongField(this, index);
1003     }
1004     if (type.isShort()) {
1005       return new ShortField(this, index);
1006     }
1007     if (type.isBoolean()) {
1008       return new BooleanField(this, index);
1009     }
1010     throw new RuntimeException("Illegal field type at index " + index);
1011   }
1012 
findMethod(MethodArray methods, String name, String signature)1013   private static Method findMethod(MethodArray methods, String name, String signature) {
1014     int index = linearSearch(methods, name, signature);
1015     if (index != -1) {
1016       return methods.at(index);
1017     } else {
1018       return null;
1019     }
1020   }
1021 
linearSearch(MethodArray methods, String name, String signature)1022   private static int linearSearch(MethodArray methods, String name, String signature) {
1023     int len = (int) methods.length();
1024     for (int index = 0; index < len; index++) {
1025       Method m = methods.at(index);
1026       if (m.getSignature().equals(signature) && m.getName().equals(name)) {
1027         return index;
1028       }
1029     }
1030     return -1;
1031   }
1032 
dumpReplayData(PrintStream out)1033   public void dumpReplayData(PrintStream out) {
1034     ConstantPool cp = getConstants();
1035 
1036     // Try to record related loaded classes
1037     Klass sub = getSubklassKlass();
1038     while (sub != null) {
1039         if (sub instanceof InstanceKlass) {
1040             out.println("instanceKlass " + sub.getName().asString());
1041         }
1042         sub = sub.getNextSiblingKlass();
1043     }
1044 
1045     final int length = (int) cp.getLength();
1046     out.print("ciInstanceKlass " + getName().asString() + " " + (isLinked() ? 1 : 0) + " " + (isInitialized() ? 1 : 0) + " " + length);
1047     for (int index = 1; index < length; index++) {
1048       out.print(" " + cp.getTags().at(index));
1049     }
1050     out.println();
1051     if (isInitialized()) {
1052       Field[] staticFields = getStaticFields();
1053       for (int i = 0; i < staticFields.length; i++) {
1054         Field f = staticFields[i];
1055         Oop mirror = getJavaMirror();
1056         if (f.isFinal() && !f.hasInitialValue()) {
1057           out.print("staticfield " + getName().asString() + " " +
1058                     OopUtilities.escapeString(f.getID().getName()) + " " +
1059                     f.getFieldType().getSignature().asString() + " ");
1060           if (f instanceof ByteField) {
1061             ByteField bf = (ByteField)f;
1062             out.println(bf.getValue(mirror));
1063           } else if (f instanceof BooleanField) {
1064             BooleanField bf = (BooleanField)f;
1065             out.println(bf.getValue(mirror) ? 1 : 0);
1066           } else if (f instanceof ShortField) {
1067             ShortField bf = (ShortField)f;
1068             out.println(bf.getValue(mirror));
1069           } else if (f instanceof CharField) {
1070             CharField bf = (CharField)f;
1071             out.println(bf.getValue(mirror) & 0xffff);
1072           } else if (f instanceof IntField) {
1073             IntField bf = (IntField)f;
1074             out.println(bf.getValue(mirror));
1075           } else  if (f instanceof LongField) {
1076             LongField bf = (LongField)f;
1077             out.println(bf.getValue(mirror));
1078           } else if (f instanceof FloatField) {
1079             FloatField bf = (FloatField)f;
1080             out.println(Float.floatToRawIntBits(bf.getValue(mirror)));
1081           } else if (f instanceof DoubleField) {
1082             DoubleField bf = (DoubleField)f;
1083             out.println(Double.doubleToRawLongBits(bf.getValue(mirror)));
1084           } else if (f instanceof OopField) {
1085             OopField bf = (OopField)f;
1086 
1087             Oop value = bf.getValue(mirror);
1088             if (value == null) {
1089               out.println("null");
1090             } else if (value.isInstance()) {
1091               Instance inst = (Instance)value;
1092               if (inst.isA(SystemDictionary.getStringKlass())) {
1093                 out.println("\"" + OopUtilities.stringOopToEscapedString(inst) + "\"");
1094               } else {
1095                 out.println(inst.getKlass().getName().asString());
1096               }
1097             } else if (value.isObjArray()) {
1098               ObjArray oa = (ObjArray)value;
1099               Klass ek = (ObjArrayKlass)oa.getKlass();
1100               out.println(oa.getLength() + " " + ek.getName().asString());
1101             } else if (value.isTypeArray()) {
1102               TypeArray ta = (TypeArray)value;
1103               out.println(ta.getLength());
1104             } else {
1105               out.println(value);
1106             }
1107           }
1108         }
1109       }
1110     }
1111   }
1112 }
1113