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