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