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