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