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_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_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 
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 (isAnonymous()) {
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 
isAnonymous()297   public boolean isAnonymous() {
298     return (getMiscFlags() & MISC_IS_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 
isShared()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 
getHeaderSize()337   public static long getHeaderSize() { return headerSize; }
338 
getFieldAccessFlags(int index)339   public short getFieldAccessFlags(int index) {
340     return getFields().at(index * FIELD_SLOTS + ACCESS_FLAGS_OFFSET);
341   }
342 
getFieldNameIndex(int index)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 
getFieldName(int index)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 
getFieldSignatureIndex(int index)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 
getFieldSignature(int index)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 
getFieldGenericSignatureIndex(int index)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 
getFieldGenericSignature(int index)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 
getFieldInitialValueIndex(int index)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 
getFieldOffset(int index)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
getArrayKlasses()417   public Klass     getArrayKlasses()        { return (Klass)        arrayKlasses.getValue(this); }
getMethods()418   public MethodArray  getMethods()              { return new MethodArray(methods.getValue(getAddress())); }
419 
getDefaultMethods()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 
getLocalInterfaces()433   public KlassArray   getLocalInterfaces()      { return new KlassArray(localInterfaces.getValue(getAddress())); }
getTransitiveInterfaces()434   public KlassArray   getTransitiveInterfaces() { return new KlassArray(transitiveInterfaces.getValue(getAddress())); }
getJavaFieldsCount()435   public int       getJavaFieldsCount()     { return                (int) javaFieldsCount.getValue(this); }
getAllFieldsCount()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   }
getConstants()448   public ConstantPool getConstants()        { return (ConstantPool) constants.getValue(this); }
getSourceFileName()449   public Symbol    getSourceFileName()      { return                getConstants().getSymbolAt(sourceFileNameIndex.getValue(this)); }
getSourceDebugExtension()450   public String    getSourceDebugExtension(){ return                CStringUtilities.getString(sourceDebugExtension.getValue(getAddress())); }
getNonstaticFieldSize()451   public long      getNonstaticFieldSize()  { return                nonstaticFieldSize.getValue(this); }
getStaticOopFieldCount()452   public long      getStaticOopFieldCount() { return                staticOopFieldCount.getValue(this); }
getNonstaticOopMapSize()453   public long      getNonstaticOopMapSize() { return                nonstaticOopMapSize.getValue(this); }
getIsMarkedDependent()454   public boolean   getIsMarkedDependent()   { return                isMarkedDependent.getValue(this) != 0; }
getItableLen()455   public long      getItableLen()           { return                itableLen.getValue(this); }
majorVersion()456   public long      majorVersion()           { return                majorVersion.getValue(this); }
minorVersion()457   public long      minorVersion()           { return                minorVersion.getValue(this); }
getGenericSignature()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
getSizeHelper()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   private static class InnerClassAttributeOffset {
478     // from JVM spec. "InnerClasses" attribute
479     public static int innerClassInnerClassInfoOffset;
480     public static int innerClassOuterClassInfoOffset;
481     public static int innerClassInnerNameOffset;
482     public static int innerClassAccessFlagsOffset;
483     public static int innerClassNextOffset;
484     static {
VM.registerVMInitializedObserver(new Observer() { public void update(Observable o, Object data) { initialize(VM.getVM().getTypeDataBase()); } })485       VM.registerVMInitializedObserver(new Observer() {
486           public void update(Observable o, Object data) {
487               initialize(VM.getVM().getTypeDataBase());
488           }
489       });
490     }
491 
initialize(TypeDataBase db)492     private static synchronized void initialize(TypeDataBase db) {
493       innerClassInnerClassInfoOffset = db.lookupIntConstant(
494           "InstanceKlass::inner_class_inner_class_info_offset").intValue();
495       innerClassOuterClassInfoOffset = db.lookupIntConstant(
496           "InstanceKlass::inner_class_outer_class_info_offset").intValue();
497       innerClassInnerNameOffset = db.lookupIntConstant(
498           "InstanceKlass::inner_class_inner_name_offset").intValue();
499       innerClassAccessFlagsOffset = db.lookupIntConstant(
500           "InstanceKlass::inner_class_access_flags_offset").intValue();
501       innerClassNextOffset = db.lookupIntConstant(
502           "InstanceKlass::inner_class_next_offset").intValue();
503     }
504   }
505 
506   private static class EnclosingMethodAttributeOffset {
507     public static int enclosingMethodAttributeSize;
508     static {
VM.registerVMInitializedObserver(new Observer() { public void update(Observable o, Object data) { initialize(VM.getVM().getTypeDataBase()); } })509       VM.registerVMInitializedObserver(new Observer() {
510           public void update(Observable o, Object data) {
511               initialize(VM.getVM().getTypeDataBase());
512           }
513       });
514     }
initialize(TypeDataBase db)515     private static synchronized void initialize(TypeDataBase db) {
516       enclosingMethodAttributeSize = db.lookupIntConstant("InstanceKlass::enclosing_method_attribute_size").intValue();
517     }
518   }
519 
520   // refer to compute_modifier_flags in VM code.
computeModifierFlags()521   public long computeModifierFlags() {
522     long access = getAccessFlags();
523     // But check if it happens to be member class.
524     U2Array innerClassList = getInnerClasses();
525     int length = (innerClassList == null)? 0 : (int) innerClassList.length();
526     if (length > 0) {
527        if (Assert.ASSERTS_ENABLED) {
528           Assert.that(length % InnerClassAttributeOffset.innerClassNextOffset == 0 ||
529                       length % InnerClassAttributeOffset.innerClassNextOffset == EnclosingMethodAttributeOffset.enclosingMethodAttributeSize,
530                       "just checking");
531        }
532        for (int i = 0; i < length; i += InnerClassAttributeOffset.innerClassNextOffset) {
533           if (i == length - EnclosingMethodAttributeOffset.enclosingMethodAttributeSize) {
534               break;
535           }
536           int ioff = innerClassList.at(i +
537                          InnerClassAttributeOffset.innerClassInnerClassInfoOffset);
538           // 'ioff' can be zero.
539           // refer to JVM spec. section 4.7.5.
540           if (ioff != 0) {
541              // only look at classes that are already loaded
542              // since we are looking for the flags for our self.
543              Symbol name = getConstants().getKlassNameAt(ioff);
544 
545              if (name.equals(getName())) {
546                 // This is really a member class
547                 access = innerClassList.at(i +
548                         InnerClassAttributeOffset.innerClassAccessFlagsOffset);
549                 break;
550              }
551           }
552        } // for inner classes
553     }
554 
555     // Remember to strip ACC_SUPER bit
556     return (access & (~JVM_ACC_SUPER)) & JVM_ACC_WRITTEN_FLAGS;
557   }
558 
559 
560   // whether given Symbol is name of an inner/nested Klass of this Klass?
561   // anonymous and local classes are excluded.
isInnerClassName(Symbol sym)562   public boolean isInnerClassName(Symbol sym) {
563     return isInInnerClasses(sym, false);
564   }
565 
566   // whether given Symbol is name of an inner/nested Klass of this Klass?
567   // anonymous classes excluded, but local classes are included.
isInnerOrLocalClassName(Symbol sym)568   public boolean isInnerOrLocalClassName(Symbol sym) {
569     return isInInnerClasses(sym, true);
570   }
571 
isInInnerClasses(Symbol sym, boolean includeLocals)572   private boolean isInInnerClasses(Symbol sym, boolean includeLocals) {
573     U2Array innerClassList = getInnerClasses();
574     int length = ( innerClassList == null)? 0 : (int) innerClassList.length();
575     if (length > 0) {
576        if (Assert.ASSERTS_ENABLED) {
577          Assert.that(length % InnerClassAttributeOffset.innerClassNextOffset == 0 ||
578                      length % InnerClassAttributeOffset.innerClassNextOffset == EnclosingMethodAttributeOffset.enclosingMethodAttributeSize,
579                      "just checking");
580        }
581        for (int i = 0; i < length; i += InnerClassAttributeOffset.innerClassNextOffset) {
582          if (i == length - EnclosingMethodAttributeOffset.enclosingMethodAttributeSize) {
583              break;
584          }
585          int ioff = innerClassList.at(i +
586                         InnerClassAttributeOffset.innerClassInnerClassInfoOffset);
587          // 'ioff' can be zero.
588          // refer to JVM spec. section 4.7.5.
589          if (ioff != 0) {
590             Symbol innerName = getConstants().getKlassNameAt(ioff);
591             Symbol myname = getName();
592             int ooff = innerClassList.at(i +
593                         InnerClassAttributeOffset.innerClassOuterClassInfoOffset);
594             // for anonymous classes inner_name_index of InnerClasses
595             // attribute is zero.
596             int innerNameIndex = innerClassList.at(i +
597                         InnerClassAttributeOffset.innerClassInnerNameOffset);
598             // if this is not a member (anonymous, local etc.), 'ooff' will be zero
599             // refer to JVM spec. section 4.7.5.
600             if (ooff == 0) {
601                if (includeLocals) {
602                   // does it looks like my local class?
603                   if (innerName.equals(sym) &&
604                      innerName.asString().startsWith(myname.asString())) {
605                      // exclude anonymous classes.
606                      return (innerNameIndex != 0);
607                   }
608                }
609             } else {
610                Symbol outerName = getConstants().getKlassNameAt(ooff);
611 
612                // include only if current class is outer class.
613                if (outerName.equals(myname) && innerName.equals(sym)) {
614                   return true;
615                }
616            }
617          }
618        } // for inner classes
619        return false;
620     } else {
621        return false;
622     }
623   }
624 
implementsInterface(Klass k)625   public boolean implementsInterface(Klass k) {
626     if (Assert.ASSERTS_ENABLED) {
627       Assert.that(k.isInterface(), "should not reach here");
628     }
629     KlassArray interfaces =  getTransitiveInterfaces();
630     final int len = interfaces.length();
631     for (int i = 0; i < len; i++) {
632       if (interfaces.getAt(i).equals(k)) return true;
633     }
634     return false;
635   }
636 
computeSubtypeOf(Klass k)637   boolean computeSubtypeOf(Klass k) {
638     if (k.isInterface()) {
639       return implementsInterface(k);
640     } else {
641       return super.computeSubtypeOf(k);
642     }
643   }
644 
printValueOn(PrintStream tty)645   public void printValueOn(PrintStream tty) {
646     tty.print("InstanceKlass for " + getName().asString());
647   }
648 
iterateFields(MetadataVisitor visitor)649   public void iterateFields(MetadataVisitor visitor) {
650     super.iterateFields(visitor);
651     visitor.doMetadata(arrayKlasses, true);
652     // visitor.doOop(methods, true);
653     // visitor.doOop(localInterfaces, true);
654     // visitor.doOop(transitiveInterfaces, true);
655       visitor.doCInt(nonstaticFieldSize, true);
656       visitor.doCInt(staticFieldSize, true);
657       visitor.doCInt(staticOopFieldCount, true);
658       visitor.doCInt(nonstaticOopMapSize, true);
659       visitor.doCInt(isMarkedDependent, true);
660       visitor.doCInt(initState, true);
661       visitor.doCInt(itableLen, true);
662     }
663 
664   /*
665    *  Visit the static fields of this InstanceKlass with the obj of
666    *  the visitor set to the oop holding the fields, which is
667    *  currently the java mirror.
668    */
iterateStaticFields(OopVisitor visitor)669   public void iterateStaticFields(OopVisitor visitor) {
670     visitor.setObj(getJavaMirror());
671     visitor.prologue();
672     iterateStaticFieldsInternal(visitor);
673     visitor.epilogue();
674 
675   }
676 
iterateStaticFieldsInternal(OopVisitor visitor)677   void iterateStaticFieldsInternal(OopVisitor visitor) {
678     int length = getJavaFieldsCount();
679     for (int index = 0; index < length; index++) {
680       short accessFlags    = getFieldAccessFlags(index);
681       FieldType   type   = new FieldType(getFieldSignature(index));
682       AccessFlags access = new AccessFlags(accessFlags);
683       if (access.isStatic()) {
684         visitField(visitor, type, index);
685       }
686     }
687   }
688 
getJavaSuper()689   public Klass getJavaSuper() {
690     return getSuper();
691   }
692 
693   public static class StaticField {
694     public AccessFlags flags;
695     public Field field;
696 
StaticField(Field field, AccessFlags flags)697     StaticField(Field field, AccessFlags flags) {
698       this.field = field;
699       this.flags = flags;
700     }
701   }
702 
getStaticFields()703   public Field[] getStaticFields() {
704     U2Array fields = getFields();
705     int length = getJavaFieldsCount();
706     ArrayList result = new ArrayList();
707     for (int index = 0; index < length; index++) {
708       Field f = newField(index);
709       if (f.isStatic()) {
710         result.add(f);
711       }
712     }
713     return (Field[])result.toArray(new Field[result.size()]);
714   }
715 
iterateNonStaticFields(OopVisitor visitor, Oop obj)716   public void iterateNonStaticFields(OopVisitor visitor, Oop obj) {
717     if (getSuper() != null) {
718       ((InstanceKlass) getSuper()).iterateNonStaticFields(visitor, obj);
719     }
720     int length = getJavaFieldsCount();
721     for (int index = 0; index < length; index++) {
722       short accessFlags    = getFieldAccessFlags(index);
723       FieldType   type   = new FieldType(getFieldSignature(index));
724       AccessFlags access = new AccessFlags(accessFlags);
725       if (!access.isStatic()) {
726         visitField(visitor, type, index);
727       }
728     }
729   }
730 
731   /** Field access by name. */
findLocalField(String name, String sig)732   public Field findLocalField(String name, String sig) {
733     int length = getJavaFieldsCount();
734     for (int i = 0; i < length; i++) {
735       Symbol f_name = getFieldName(i);
736       Symbol f_sig  = getFieldSignature(i);
737       if (f_name.equals(name) && f_sig.equals(sig)) {
738         return newField(i);
739       }
740     }
741 
742     return null;
743   }
744 
745   /** Find field in direct superinterfaces. */
findInterfaceField(String name, String sig)746   public Field findInterfaceField(String name, String sig) {
747     KlassArray interfaces = getLocalInterfaces();
748     int n = interfaces.length();
749     for (int i = 0; i < n; i++) {
750       InstanceKlass intf1 = (InstanceKlass) interfaces.getAt(i);
751       if (Assert.ASSERTS_ENABLED) {
752         Assert.that(intf1.isInterface(), "just checking type");
753      }
754       // search for field in current interface
755       Field f = intf1.findLocalField(name, sig);
756       if (f != null) {
757         if (Assert.ASSERTS_ENABLED) {
758           Assert.that(f.getAccessFlagsObj().isStatic(), "interface field must be static");
759         }
760         return f;
761       }
762       // search for field in direct superinterfaces
763       f = intf1.findInterfaceField(name, sig);
764       if (f != null) return f;
765     }
766     // otherwise field lookup fails
767     return null;
768   }
769 
770   /** Find field according to JVM spec 5.4.3.2, returns the klass in
771       which the field is defined. */
findField(String name, String sig)772   public Field findField(String name, String sig) {
773     // search order according to newest JVM spec (5.4.3.2, p.167).
774     // 1) search for field in current klass
775     Field f = findLocalField(name, sig);
776     if (f != null) return f;
777 
778     // 2) search for field recursively in direct superinterfaces
779     f = findInterfaceField(name, sig);
780     if (f != null) return f;
781 
782     // 3) apply field lookup recursively if superclass exists
783     InstanceKlass supr = (InstanceKlass) getSuper();
784     if (supr != null) return supr.findField(name, sig);
785 
786     // 4) otherwise field lookup fails
787     return null;
788   }
789 
790   /** Find field according to JVM spec 5.4.3.2, returns the klass in
791       which the field is defined (retained only for backward
792       compatibility with jdbx) */
findFieldDbg(String name, String sig)793   public Field findFieldDbg(String name, String sig) {
794     return findField(name, sig);
795   }
796 
797   /** Get field by its index in the fields array. Only designed for
798       use in a debugging system. */
getFieldByIndex(int fieldIndex)799   public Field getFieldByIndex(int fieldIndex) {
800     return newField(fieldIndex);
801   }
802 
803 
804     /** Return a List of SA Fields for the fields declared in this class.
805         Inherited fields are not included.
806         Return an empty list if there are no fields declared in this class.
807         Only designed for use in a debugging system. */
getImmediateFields()808     public List getImmediateFields() {
809         // A list of Fields for each field declared in this class/interface,
810         // not including inherited fields.
811         int length = getJavaFieldsCount();
812         List immediateFields = new ArrayList(length);
813         for (int index = 0; index < length; index++) {
814             immediateFields.add(getFieldByIndex(index));
815         }
816 
817         return immediateFields;
818     }
819 
820     /** Return a List of SA Fields for all the java fields in this class,
821         including all inherited fields.  This includes hidden
822         fields.  Thus the returned list can contain fields with
823         the same name.
824         Return an empty list if there are no fields.
825         Only designed for use in a debugging system. */
getAllFields()826     public List getAllFields() {
827         // Contains a Field for each field in this class, including immediate
828         // fields and inherited fields.
829         List  allFields = getImmediateFields();
830 
831         // transitiveInterfaces contains all interfaces implemented
832         // by this class and its superclass chain with no duplicates.
833 
834         KlassArray interfaces = getTransitiveInterfaces();
835         int n = interfaces.length();
836         for (int i = 0; i < n; i++) {
837             InstanceKlass intf1 = (InstanceKlass) interfaces.getAt(i);
838             if (Assert.ASSERTS_ENABLED) {
839                 Assert.that(intf1.isInterface(), "just checking type");
840             }
841             allFields.addAll(intf1.getImmediateFields());
842         }
843 
844         // Get all fields in the superclass, recursively.  But, don't
845         // include fields in interfaces implemented by superclasses;
846         // we already have all those.
847         if (!isInterface()) {
848             InstanceKlass supr;
849             if  ( (supr = (InstanceKlass) getSuper()) != null) {
850                 allFields.addAll(supr.getImmediateFields());
851             }
852         }
853 
854         return allFields;
855     }
856 
857 
858     /** Return a List of SA Methods declared directly in this class/interface.
859         Return an empty list if there are none, or if this isn't a class/
860         interface.
861     */
getImmediateMethods()862     public List getImmediateMethods() {
863       // Contains a Method for each method declared in this class/interface
864       // not including inherited methods.
865 
866       MethodArray methods = getMethods();
867       int length = methods.length();
868       Object[] tmp = new Object[length];
869 
870       IntArray methodOrdering = getMethodOrdering();
871       if (methodOrdering.length() != length) {
872          // no ordering info present
873          for (int index = 0; index < length; index++) {
874             tmp[index] = methods.at(index);
875          }
876       } else {
877          for (int index = 0; index < length; index++) {
878             int originalIndex = methodOrdering.at(index);
879             tmp[originalIndex] = methods.at(index);
880          }
881       }
882 
883       return Arrays.asList(tmp);
884     }
885 
886     /** Return a List containing an SA InstanceKlass for each
887         interface named in this class's 'implements' clause.
888     */
getDirectImplementedInterfaces()889     public List getDirectImplementedInterfaces() {
890         // Contains an InstanceKlass for each interface in this classes
891         // 'implements' clause.
892 
893         KlassArray interfaces = getLocalInterfaces();
894         int length = interfaces.length();
895         List directImplementedInterfaces = new ArrayList(length);
896 
897         for (int index = 0; index < length; index ++) {
898             directImplementedInterfaces.add(interfaces.getAt(index));
899         }
900 
901         return directImplementedInterfaces;
902     }
903 
arrayKlassImpl(boolean orNull, int n)904   public Klass arrayKlassImpl(boolean orNull, int n) {
905     // FIXME: in reflective system this would need to change to
906     // actually allocate
907     if (getArrayKlasses() == null) { return null; }
908     ObjArrayKlass oak = (ObjArrayKlass) getArrayKlasses();
909     if (orNull) {
910       return oak.arrayKlassOrNull(n);
911     }
912     return oak.arrayKlass(n);
913   }
914 
arrayKlassImpl(boolean orNull)915   public Klass arrayKlassImpl(boolean orNull) {
916     return arrayKlassImpl(orNull, 1);
917   }
918 
signature()919   public String signature() {
920      return "L" + super.signature() + ";";
921   }
922 
923   /** Find method in vtable. */
findMethod(String name, String sig)924   public Method findMethod(String name, String sig) {
925     return findMethod(getMethods(), name, sig);
926   }
927 
928   /** Breakpoint support (see methods on Method* for details) */
getBreakpoints()929   public BreakpointInfo getBreakpoints() {
930     if (!VM.getVM().isJvmtiSupported()) {
931       return null;
932     }
933     Address addr = getAddress().getAddressAt(breakpoints.getOffset());
934     return (BreakpointInfo) VMObjectFactory.newObject(BreakpointInfo.class, addr);
935   }
936 
getMethodOrdering()937   public IntArray  getMethodOrdering() {
938     Address addr = getAddress().getAddressAt(methodOrdering.getOffset());
939     return (IntArray) VMObjectFactory.newObject(IntArray.class, addr);
940   }
941 
getFields()942   public U2Array getFields() {
943     Address addr = getAddress().getAddressAt(fields.getOffset());
944     return (U2Array) VMObjectFactory.newObject(U2Array.class, addr);
945   }
946 
getInnerClasses()947   public U2Array getInnerClasses() {
948     Address addr = getAddress().getAddressAt(innerClasses.getOffset());
949     return (U2Array) VMObjectFactory.newObject(U2Array.class, addr);
950   }
951 
952 
953   //----------------------------------------------------------------------
954   // Internals only below this point
955   //
956 
visitField(OopVisitor visitor, FieldType type, int index)957   private void visitField(OopVisitor visitor, FieldType type, int index) {
958     Field f = newField(index);
959     if (type.isOop()) {
960       visitor.doOop((OopField) f, false);
961       return;
962     }
963     if (type.isByte()) {
964       visitor.doByte((ByteField) f, false);
965       return;
966     }
967     if (type.isChar()) {
968       visitor.doChar((CharField) f, false);
969       return;
970     }
971     if (type.isDouble()) {
972       visitor.doDouble((DoubleField) f, false);
973       return;
974     }
975     if (type.isFloat()) {
976       visitor.doFloat((FloatField) f, false);
977       return;
978     }
979     if (type.isInt()) {
980       visitor.doInt((IntField) f, false);
981       return;
982     }
983     if (type.isLong()) {
984       visitor.doLong((LongField) f, false);
985       return;
986     }
987     if (type.isShort()) {
988       visitor.doShort((ShortField) f, false);
989       return;
990     }
991     if (type.isBoolean()) {
992       visitor.doBoolean((BooleanField) f, false);
993       return;
994     }
995   }
996 
997   // Creates new field from index in fields TypeArray
newField(int index)998   private Field newField(int index) {
999     FieldType type = new FieldType(getFieldSignature(index));
1000     if (type.isOop()) {
1001      if (VM.getVM().isCompressedOopsEnabled()) {
1002         return new NarrowOopField(this, index);
1003      } else {
1004         return new OopField(this, index);
1005      }
1006     }
1007     if (type.isByte()) {
1008       return new ByteField(this, index);
1009     }
1010     if (type.isChar()) {
1011       return new CharField(this, index);
1012     }
1013     if (type.isDouble()) {
1014       return new DoubleField(this, index);
1015     }
1016     if (type.isFloat()) {
1017       return new FloatField(this, index);
1018     }
1019     if (type.isInt()) {
1020       return new IntField(this, index);
1021     }
1022     if (type.isLong()) {
1023       return new LongField(this, index);
1024     }
1025     if (type.isShort()) {
1026       return new ShortField(this, index);
1027     }
1028     if (type.isBoolean()) {
1029       return new BooleanField(this, index);
1030     }
1031     throw new RuntimeException("Illegal field type at index " + index);
1032   }
1033 
findMethod(MethodArray methods, String name, String signature)1034   private static Method findMethod(MethodArray methods, String name, String signature) {
1035     int index = linearSearch(methods, name, signature);
1036     if (index != -1) {
1037       return methods.at(index);
1038     } else {
1039       return null;
1040     }
1041   }
1042 
linearSearch(MethodArray methods, String name, String signature)1043   private static int linearSearch(MethodArray methods, String name, String signature) {
1044     int len = (int) methods.length();
1045     for (int index = 0; index < len; index++) {
1046       Method m = methods.at(index);
1047       if (m.getSignature().equals(signature) && m.getName().equals(name)) {
1048         return index;
1049       }
1050     }
1051     return -1;
1052   }
1053 
dumpReplayData(PrintStream out)1054   public void dumpReplayData(PrintStream out) {
1055     ConstantPool cp = getConstants();
1056 
1057     // Try to record related loaded classes
1058     Klass sub = getSubklassKlass();
1059     while (sub != null) {
1060         if (sub instanceof InstanceKlass) {
1061             out.println("instanceKlass " + sub.getName().asString());
1062         }
1063         sub = sub.getNextSiblingKlass();
1064     }
1065 
1066     final int length = (int) cp.getLength();
1067     out.print("ciInstanceKlass " + getName().asString() + " " + (isLinked() ? 1 : 0) + " " + (isInitialized() ? 1 : 0) + " " + length);
1068     for (int index = 1; index < length; index++) {
1069       out.print(" " + cp.getTags().at(index));
1070     }
1071     out.println();
1072     if (isInitialized()) {
1073       Field[] staticFields = getStaticFields();
1074       for (int i = 0; i < staticFields.length; i++) {
1075         Field f = staticFields[i];
1076         Oop mirror = getJavaMirror();
1077         if (f.isFinal() && !f.hasInitialValue()) {
1078           out.print("staticfield " + getName().asString() + " " +
1079                     OopUtilities.escapeString(f.getID().getName()) + " " +
1080                     f.getFieldType().getSignature().asString() + " ");
1081           if (f instanceof ByteField) {
1082             ByteField bf = (ByteField)f;
1083             out.println(bf.getValue(mirror));
1084           } else if (f instanceof BooleanField) {
1085             BooleanField bf = (BooleanField)f;
1086             out.println(bf.getValue(mirror) ? 1 : 0);
1087           } else if (f instanceof ShortField) {
1088             ShortField bf = (ShortField)f;
1089             out.println(bf.getValue(mirror));
1090           } else if (f instanceof CharField) {
1091             CharField bf = (CharField)f;
1092             out.println(bf.getValue(mirror) & 0xffff);
1093           } else if (f instanceof IntField) {
1094             IntField bf = (IntField)f;
1095             out.println(bf.getValue(mirror));
1096           } else  if (f instanceof LongField) {
1097             LongField bf = (LongField)f;
1098             out.println(bf.getValue(mirror));
1099           } else if (f instanceof FloatField) {
1100             FloatField bf = (FloatField)f;
1101             out.println(Float.floatToRawIntBits(bf.getValue(mirror)));
1102           } else if (f instanceof DoubleField) {
1103             DoubleField bf = (DoubleField)f;
1104             out.println(Double.doubleToRawLongBits(bf.getValue(mirror)));
1105           } else if (f instanceof OopField) {
1106             OopField bf = (OopField)f;
1107 
1108             Oop value = bf.getValue(mirror);
1109             if (value == null) {
1110               out.println("null");
1111             } else if (value.isInstance()) {
1112               Instance inst = (Instance)value;
1113               if (inst.isA(SystemDictionary.getStringKlass())) {
1114                 out.println("\"" + OopUtilities.stringOopToEscapedString(inst) + "\"");
1115               } else {
1116                 out.println(inst.getKlass().getName().asString());
1117               }
1118             } else if (value.isObjArray()) {
1119               ObjArray oa = (ObjArray)value;
1120               Klass ek = (ObjArrayKlass)oa.getKlass();
1121               out.println(oa.getLength() + " " + ek.getName().asString());
1122             } else if (value.isTypeArray()) {
1123               TypeArray ta = (TypeArray)value;
1124               out.println(ta.getLength());
1125             } else {
1126               out.println(value);
1127             }
1128           }
1129         }
1130       }
1131     }
1132   }
1133 }
1134