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