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