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