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