1 /*
2 * Copyright (c) 2000, 2016, 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.debugger.*;
31 import sun.jvm.hotspot.memory.*;
32 import sun.jvm.hotspot.runtime.*;
33 import sun.jvm.hotspot.types.*;
34 import sun.jvm.hotspot.utilities.*;
35
36 // An InstanceKlass is the VM level representation of a Java class.
37
38 public class InstanceKlass extends Klass {
39 static {
40 VM.registerVMInitializedObserver(new Observer() {
41 public void update(Observable o, Object data) {
42 initialize(VM.getVM().getTypeDataBase());
43 }
44 });
45 }
46
47 // field offset constants
48 private static int ACCESS_FLAGS_OFFSET;
49 private static int NAME_INDEX_OFFSET;
50 private static int SIGNATURE_INDEX_OFFSET;
51 private static int INITVAL_INDEX_OFFSET;
52 private static int LOW_OFFSET;
53 private static int HIGH_OFFSET;
54 private static int FIELD_SLOTS;
55 private static short FIELDINFO_TAG_SIZE;
56 private static short FIELDINFO_TAG_MASK;
57 private static short FIELDINFO_TAG_OFFSET;
58
59 // ClassState constants
60 private static int CLASS_STATE_ALLOCATED;
61 private static int CLASS_STATE_LOADED;
62 private static int CLASS_STATE_LINKED;
63 private static int CLASS_STATE_BEING_INITIALIZED;
64 private static int CLASS_STATE_FULLY_INITIALIZED;
65 private static int CLASS_STATE_INITIALIZATION_ERROR;
66
67 private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
68 Type type = db.lookupType("InstanceKlass");
69 arrayKlasses = new MetadataField(type.getAddressField("_array_klasses"), 0);
70 methods = type.getAddressField("_methods");
71 methodOrdering = type.getAddressField("_method_ordering");
72 localInterfaces = type.getAddressField("_local_interfaces");
73 transitiveInterfaces = type.getAddressField("_transitive_interfaces");
74 fields = type.getAddressField("_fields");
75 javaFieldsCount = new CIntField(type.getCIntegerField("_java_fields_count"), 0);
76 constants = new MetadataField(type.getAddressField("_constants"), 0);
77 classLoaderData = type.getAddressField("_class_loader_data");
78 sourceDebugExtension = type.getAddressField("_source_debug_extension");
79 innerClasses = type.getAddressField("_inner_classes");
80 sourceFileNameIndex = new CIntField(type.getCIntegerField("_source_file_name_index"), 0);
81 nonstaticFieldSize = new CIntField(type.getCIntegerField("_nonstatic_field_size"), 0);
82 staticFieldSize = new CIntField(type.getCIntegerField("_static_field_size"), 0);
83 staticOopFieldCount = new CIntField(type.getCIntegerField("_static_oop_field_count"), 0);
84 nonstaticOopMapSize = new CIntField(type.getCIntegerField("_nonstatic_oop_map_size"), 0);
85 isMarkedDependent = new CIntField(type.getCIntegerField("_is_marked_dependent"), 0);
86 initState = new CIntField(type.getCIntegerField("_init_state"), 0);
87 vtableLen = new CIntField(type.getCIntegerField("_vtable_len"), 0);
88 itableLen = new CIntField(type.getCIntegerField("_itable_len"), 0);
89 breakpoints = type.getAddressField("_breakpoints");
90 genericSignatureIndex = new CIntField(type.getCIntegerField("_generic_signature_index"), 0);
91 majorVersion = new CIntField(type.getCIntegerField("_major_version"), 0);
92 minorVersion = new CIntField(type.getCIntegerField("_minor_version"), 0);
93 headerSize = type.getSize();
94
95 // read field offset constants
96 ACCESS_FLAGS_OFFSET = db.lookupIntConstant("FieldInfo::access_flags_offset").intValue();
97 NAME_INDEX_OFFSET = db.lookupIntConstant("FieldInfo::name_index_offset").intValue();
98 SIGNATURE_INDEX_OFFSET = db.lookupIntConstant("FieldInfo::signature_index_offset").intValue();
99 INITVAL_INDEX_OFFSET = db.lookupIntConstant("FieldInfo::initval_index_offset").intValue();
100 LOW_OFFSET = db.lookupIntConstant("FieldInfo::low_packed_offset").intValue();
101 HIGH_OFFSET = db.lookupIntConstant("FieldInfo::high_packed_offset").intValue();
102 FIELD_SLOTS = db.lookupIntConstant("FieldInfo::field_slots").intValue();
103 FIELDINFO_TAG_SIZE = db.lookupIntConstant("FIELDINFO_TAG_SIZE").shortValue();
104 FIELDINFO_TAG_MASK = db.lookupIntConstant("FIELDINFO_TAG_MASK").shortValue();
105 FIELDINFO_TAG_OFFSET = db.lookupIntConstant("FIELDINFO_TAG_OFFSET").shortValue();
106
107 // read ClassState constants
108 CLASS_STATE_ALLOCATED = db.lookupIntConstant("InstanceKlass::allocated").intValue();
109 CLASS_STATE_LOADED = db.lookupIntConstant("InstanceKlass::loaded").intValue();
110 CLASS_STATE_LINKED = db.lookupIntConstant("InstanceKlass::linked").intValue();
111 CLASS_STATE_BEING_INITIALIZED = db.lookupIntConstant("InstanceKlass::being_initialized").intValue();
112 CLASS_STATE_FULLY_INITIALIZED = db.lookupIntConstant("InstanceKlass::fully_initialized").intValue();
113 CLASS_STATE_INITIALIZATION_ERROR = db.lookupIntConstant("InstanceKlass::initialization_error").intValue();
114
115 }
116
117 public InstanceKlass(Address addr) {
118 super(addr);
119 if (getJavaFieldsCount() != getAllFieldsCount()) {
120 // Exercise the injected field logic
121 for (int i = getJavaFieldsCount(); i < getAllFieldsCount(); i++) {
122 getFieldName(i);
123 getFieldSignature(i);
124 }
125 }
126 }
127
128 private static MetadataField arrayKlasses;
129 private static AddressField methods;
130 private static AddressField methodOrdering;
131 private static AddressField localInterfaces;
132 private static AddressField transitiveInterfaces;
133 private static AddressField fields;
134 private static CIntField javaFieldsCount;
135 private static MetadataField constants;
136 private static AddressField classLoaderData;
137 private static AddressField sourceDebugExtension;
138 private static AddressField innerClasses;
139 private static CIntField sourceFileNameIndex;
140 private static CIntField nonstaticFieldSize;
141 private static CIntField staticFieldSize;
142 private static CIntField staticOopFieldCount;
143 private static CIntField nonstaticOopMapSize;
144 private static CIntField isMarkedDependent;
145 private static CIntField initState;
146 private static CIntField vtableLen;
147 private static CIntField itableLen;
148 private static AddressField breakpoints;
149 private static CIntField genericSignatureIndex;
150 private static CIntField majorVersion;
151 private static CIntField minorVersion;
152
153 // type safe enum for ClassState from instanceKlass.hpp
154 public static class ClassState {
155 public static final ClassState ALLOCATED = new ClassState("allocated");
156 public static final ClassState LOADED = new ClassState("loaded");
157 public static final ClassState LINKED = new ClassState("linked");
158 public static final ClassState BEING_INITIALIZED = new ClassState("beingInitialized");
159 public static final ClassState FULLY_INITIALIZED = new ClassState("fullyInitialized");
160 public static final ClassState INITIALIZATION_ERROR = new ClassState("initializationError");
161
162 private ClassState(String value) {
163 this.value = value;
164 }
165
166 public String toString() {
167 return value;
168 }
169
170 private String value;
171 }
172
173 public int getInitStateAsInt() { return (int) initState.getValue(this); }
174 public ClassState getInitState() {
175 int state = getInitStateAsInt();
176 if (state == CLASS_STATE_ALLOCATED) {
177 return ClassState.ALLOCATED;
178 } else if (state == CLASS_STATE_LOADED) {
179 return ClassState.LOADED;
180 } else if (state == CLASS_STATE_LINKED) {
181 return ClassState.LINKED;
182 } else if (state == CLASS_STATE_BEING_INITIALIZED) {
183 return ClassState.BEING_INITIALIZED;
184 } else if (state == CLASS_STATE_FULLY_INITIALIZED) {
185 return ClassState.FULLY_INITIALIZED;
186 } else if (state == CLASS_STATE_INITIALIZATION_ERROR) {
187 return ClassState.INITIALIZATION_ERROR;
188 } else {
189 throw new RuntimeException("should not reach here");
190 }
191 }
192
193 // initialization state quaries
194 public boolean isLoaded() {
195 return getInitStateAsInt() >= CLASS_STATE_LOADED;
196 }
197
198 public boolean isLinked() {
199 return getInitStateAsInt() >= CLASS_STATE_LINKED;
200 }
201
202 public boolean isInitialized() {
203 return getInitStateAsInt() == CLASS_STATE_FULLY_INITIALIZED;
204 }
205
206 public boolean isNotInitialized() {
207 return getInitStateAsInt() < CLASS_STATE_BEING_INITIALIZED;
208 }
209
210 public boolean isBeingInitialized() {
211 return getInitStateAsInt() == CLASS_STATE_BEING_INITIALIZED;
212 }
213
214 public boolean isInErrorState() {
215 return getInitStateAsInt() == CLASS_STATE_INITIALIZATION_ERROR;
216 }
217
218 public int getClassStatus() {
219 int result = 0;
220 if (isLinked()) {
221 result |= JVMDIClassStatus.VERIFIED | JVMDIClassStatus.PREPARED;
222 }
223
224 if (isInitialized()) {
225 if (Assert.ASSERTS_ENABLED) {
226 Assert.that(isLinked(), "Class status is not consistent");
227 }
228 result |= JVMDIClassStatus.INITIALIZED;
229 }
230
231 if (isInErrorState()) {
232 result |= JVMDIClassStatus.ERROR;
233 }
234 return result;
235 }
236
237 // Byteside of the header
238 private static long headerSize;
239
240 public long getObjectSize(Oop object) {
241 return getSizeHelper() * VM.getVM().getAddressSize();
242 }
243
244 public long getSize() {
245 return alignSize(getHeaderSize() + getVtableLen() + getItableLen() + getNonstaticOopMapSize());
246 }
247
248 public static long getHeaderSize() { return headerSize; }
249
250 public short getFieldAccessFlags(int index) {
251 return getFields().at(index * FIELD_SLOTS + ACCESS_FLAGS_OFFSET);
252 }
253
254 public short getFieldNameIndex(int index) {
255 if (index >= getJavaFieldsCount()) throw new IndexOutOfBoundsException("not a Java field;");
256 return getFields().at(index * FIELD_SLOTS + NAME_INDEX_OFFSET);
257 }
258
259 public Symbol getFieldName(int index) {
260 int nameIndex = getFields().at(index * FIELD_SLOTS + NAME_INDEX_OFFSET);
261 if (index < getJavaFieldsCount()) {
262 return getConstants().getSymbolAt(nameIndex);
263 } else {
264 return vmSymbols.symbolAt(nameIndex);
265 }
266 }
267
268 public short getFieldSignatureIndex(int index) {
269 if (index >= getJavaFieldsCount()) throw new IndexOutOfBoundsException("not a Java field;");
270 return getFields().at(index * FIELD_SLOTS + SIGNATURE_INDEX_OFFSET);
271 }
272
273 public Symbol getFieldSignature(int index) {
274 int signatureIndex = getFields().at(index * FIELD_SLOTS + SIGNATURE_INDEX_OFFSET);
275 if (index < getJavaFieldsCount()) {
276 return getConstants().getSymbolAt(signatureIndex);
277 } else {
278 return vmSymbols.symbolAt(signatureIndex);
279 }
280 }
281
282 public short getFieldGenericSignatureIndex(int index) {
283 // int len = getFields().length();
284 int allFieldsCount = getAllFieldsCount();
285 int generic_signature_slot = allFieldsCount * FIELD_SLOTS;
286 for (int i = 0; i < allFieldsCount; i++) {
287 short flags = getFieldAccessFlags(i);
288 AccessFlags access = new AccessFlags(flags);
289 if (i == index) {
290 if (access.fieldHasGenericSignature()) {
291 return getFields().at(generic_signature_slot);
292 } else {
293 return 0;
294 }
295 } else {
296 if (access.fieldHasGenericSignature()) {
297 generic_signature_slot ++;
298 }
299 }
300 }
301 return 0;
302 }
303
304 public Symbol getFieldGenericSignature(int index) {
305 short genericSignatureIndex = getFieldGenericSignatureIndex(index);
306 if (genericSignatureIndex != 0) {
307 return getConstants().getSymbolAt(genericSignatureIndex);
308 }
309 return null;
310 }
311
312 public short getFieldInitialValueIndex(int index) {
313 if (index >= getJavaFieldsCount()) throw new IndexOutOfBoundsException("not a Java field;");
314 return getFields().at(index * FIELD_SLOTS + INITVAL_INDEX_OFFSET);
315 }
316
317 public int getFieldOffset(int index) {
318 U2Array fields = getFields();
319 short lo = fields.at(index * FIELD_SLOTS + LOW_OFFSET);
320 short hi = fields.at(index * FIELD_SLOTS + HIGH_OFFSET);
321 if ((lo & FIELDINFO_TAG_MASK) == FIELDINFO_TAG_OFFSET) {
322 return VM.getVM().buildIntFromShorts(lo, hi) >> FIELDINFO_TAG_SIZE;
323 }
324 throw new RuntimeException("should not reach here");
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 public KlassArray getLocalInterfaces() { return new KlassArray(localInterfaces.getValue(getAddress())); }
331 public KlassArray getTransitiveInterfaces() { return new KlassArray(transitiveInterfaces.getValue(getAddress())); }
332 public int getJavaFieldsCount() { return (int) javaFieldsCount.getValue(this); }
333 public int getAllFieldsCount() {
334 int len = getFields().length();
335 int allFieldsCount = 0;
336 for (; allFieldsCount*FIELD_SLOTS < len; allFieldsCount++) {
337 short flags = getFieldAccessFlags(allFieldsCount);
338 AccessFlags access = new AccessFlags(flags);
339 if (access.fieldHasGenericSignature()) {
340 len --;
341 }
342 }
343 return allFieldsCount;
344 }
345 public ConstantPool getConstants() { return (ConstantPool) constants.getValue(this); }
346 public ClassLoaderData getClassLoaderData() { return ClassLoaderData.instantiateWrapperFor(classLoaderData.getValue(getAddress())); }
347 public Oop getClassLoader() { return getClassLoaderData().getClassLoader(); }
348 public Symbol getSourceFileName() { return getConstants().getSymbolAt(sourceFileNameIndex.getValue(this)); }
349 public String getSourceDebugExtension(){ return CStringUtilities.getString(sourceDebugExtension.getValue(getAddress())); }
350 public long getNonstaticFieldSize() { return nonstaticFieldSize.getValue(this); }
351 public long getStaticOopFieldCount() { return staticOopFieldCount.getValue(this); }
352 public long getNonstaticOopMapSize() { return nonstaticOopMapSize.getValue(this); }
353 public boolean getIsMarkedDependent() { return isMarkedDependent.getValue(this) != 0; }
354 public long getVtableLen() { return vtableLen.getValue(this); }
355 public long getItableLen() { return itableLen.getValue(this); }
356 public long majorVersion() { return majorVersion.getValue(this); }
357 public long minorVersion() { return minorVersion.getValue(this); }
358 public Symbol getGenericSignature() {
359 long index = genericSignatureIndex.getValue(this);
360 if (index != 0) {
361 return getConstants().getSymbolAt(index);
362 } else {
363 return null;
364 }
365 }
366
367 // "size helper" == instance size in words
368 public long getSizeHelper() {
369 int lh = getLayoutHelper();
370 if (Assert.ASSERTS_ENABLED) {
371 Assert.that(lh > 0, "layout helper initialized for instance class");
372 }
373 return lh / VM.getVM().getAddressSize();
374 }
375
376 // same as enum InnerClassAttributeOffset in VM code.
377 public static interface InnerClassAttributeOffset {
378 // from JVM spec. "InnerClasses" attribute
379 public static final int innerClassInnerClassInfoOffset = 0;
380 public static final int innerClassOuterClassInfoOffset = 1;
381 public static final int innerClassInnerNameOffset = 2;
382 public static final int innerClassAccessFlagsOffset = 3;
383 public static final int innerClassNextOffset = 4;
384 };
385
386 public static interface EnclosingMethodAttributeOffset {
387 public static final int enclosing_method_class_index_offset = 0;
388 public static final int enclosing_method_method_index_offset = 1;
389 public static final int enclosing_method_attribute_size = 2;
390 };
391
392 // refer to compute_modifier_flags in VM code.
393 public long computeModifierFlags() {
394 long access = getAccessFlags();
395 // But check if it happens to be member class.
396 U2Array innerClassList = getInnerClasses();
397 int length = (innerClassList == null)? 0 : (int) innerClassList.length();
398 if (length > 0) {
399 if (Assert.ASSERTS_ENABLED) {
400 Assert.that(length % InnerClassAttributeOffset.innerClassNextOffset == 0 ||
401 length % InnerClassAttributeOffset.innerClassNextOffset == EnclosingMethodAttributeOffset.enclosing_method_attribute_size,
402 "just checking");
403 }
404 for (int i = 0; i < length; i += InnerClassAttributeOffset.innerClassNextOffset) {
405 if (i == length - EnclosingMethodAttributeOffset.enclosing_method_attribute_size) {
406 break;
407 }
408 int ioff = innerClassList.at(i +
409 InnerClassAttributeOffset.innerClassInnerClassInfoOffset);
410 // 'ioff' can be zero.
411 // refer to JVM spec. section 4.7.5.
412 if (ioff != 0) {
413 // only look at classes that are already loaded
414 // since we are looking for the flags for our self.
415 ConstantPool.CPSlot classInfo = getConstants().getSlotAt(ioff);
416 Symbol name = null;
417 if (classInfo.isResolved()) {
418 name = classInfo.getKlass().getName();
419 } else if (classInfo.isUnresolved()) {
420 name = classInfo.getSymbol();
421 } else {
422 throw new RuntimeException("should not reach here");
423 }
424
425 if (name.equals(getName())) {
426 // This is really a member class
427 access = innerClassList.at(i +
428 InnerClassAttributeOffset.innerClassAccessFlagsOffset);
429 break;
430 }
431 }
432 } // for inner classes
433 }
434
435 // Remember to strip ACC_SUPER bit
436 return (access & (~JVM_ACC_SUPER)) & JVM_ACC_WRITTEN_FLAGS;
437 }
438
439
440 // whether given Symbol is name of an inner/nested Klass of this Klass?
441 // anonymous and local classes are excluded.
442 public boolean isInnerClassName(Symbol sym) {
443 return isInInnerClasses(sym, false);
444 }
445
446 // whether given Symbol is name of an inner/nested Klass of this Klass?
447 // anonymous classes excluded, but local classes are included.
448 public boolean isInnerOrLocalClassName(Symbol sym) {
449 return isInInnerClasses(sym, true);
450 }
451
452 private boolean isInInnerClasses(Symbol sym, boolean includeLocals) {
453 U2Array innerClassList = getInnerClasses();
454 int length = ( innerClassList == null)? 0 : (int) innerClassList.length();
455 if (length > 0) {
456 if (Assert.ASSERTS_ENABLED) {
457 Assert.that(length % InnerClassAttributeOffset.innerClassNextOffset == 0 ||
458 length % InnerClassAttributeOffset.innerClassNextOffset == EnclosingMethodAttributeOffset.enclosing_method_attribute_size,
459 "just checking");
460 }
461 for (int i = 0; i < length; i += InnerClassAttributeOffset.innerClassNextOffset) {
462 if (i == length - EnclosingMethodAttributeOffset.enclosing_method_attribute_size) {
463 break;
464 }
465 int ioff = innerClassList.at(i +
466 InnerClassAttributeOffset.innerClassInnerClassInfoOffset);
467 // 'ioff' can be zero.
468 // refer to JVM spec. section 4.7.5.
469 if (ioff != 0) {
470 ConstantPool.CPSlot iclassInfo = getConstants().getSlotAt(ioff);
471 Symbol innerName = getConstants().getKlassNameAt(ioff);
472 Symbol myname = getName();
473 int ooff = innerClassList.at(i +
474 InnerClassAttributeOffset.innerClassOuterClassInfoOffset);
475 // for anonymous classes inner_name_index of InnerClasses
476 // attribute is zero.
477 int innerNameIndex = innerClassList.at(i +
478 InnerClassAttributeOffset.innerClassInnerNameOffset);
479 // if this is not a member (anonymous, local etc.), 'ooff' will be zero
480 // refer to JVM spec. section 4.7.5.
481 if (ooff == 0) {
482 if (includeLocals) {
483 // does it looks like my local class?
484 if (innerName.equals(sym) &&
485 innerName.asString().startsWith(myname.asString())) {
486 // exclude anonymous classes.
487 return (innerNameIndex != 0);
488 }
489 }
490 } else {
491 ConstantPool.CPSlot oclassInfo = getConstants().getSlotAt(ooff);
492 Symbol outerName = null;
493 if (oclassInfo.isResolved()) {
494 outerName = oclassInfo.getKlass().getName();
495 } else if (oclassInfo.isUnresolved()) {
496 outerName = oclassInfo.getSymbol();
497 } else {
498 throw new RuntimeException("should not reach here");
499 }
500
501 // include only if current class is outer class.
502 if (outerName.equals(myname) && innerName.equals(sym)) {
503 return true;
504 }
505 }
506 }
507 } // for inner classes
508 return false;
509 } else {
510 return false;
511 }
512 }
513
514 public boolean implementsInterface(Klass k) {
515 if (Assert.ASSERTS_ENABLED) {
516 Assert.that(k.isInterface(), "should not reach here");
517 }
518 KlassArray interfaces = getTransitiveInterfaces();
519 final int len = interfaces.length();
520 for (int i = 0; i < len; i++) {
521 if (interfaces.getAt(i).equals(k)) return true;
522 }
523 return false;
524 }
525
526 boolean computeSubtypeOf(Klass k) {
527 if (k.isInterface()) {
528 return implementsInterface(k);
529 } else {
530 return super.computeSubtypeOf(k);
531 }
532 }
533
534 public void printValueOn(PrintStream tty) {
535 tty.print("InstanceKlass for " + getName().asString());
536 }
537
538 public void iterateFields(MetadataVisitor visitor) {
539 super.iterateFields(visitor);
540 visitor.doMetadata(arrayKlasses, true);
541 // visitor.doOop(methods, true);
542 // visitor.doOop(localInterfaces, true);
543 // visitor.doOop(transitiveInterfaces, true);
544 visitor.doCInt(nonstaticFieldSize, true);
545 visitor.doCInt(staticFieldSize, true);
546 visitor.doCInt(staticOopFieldCount, true);
547 visitor.doCInt(nonstaticOopMapSize, true);
548 visitor.doCInt(isMarkedDependent, true);
549 visitor.doCInt(initState, true);
550 visitor.doCInt(vtableLen, true);
551 visitor.doCInt(itableLen, true);
552 }
553
554 /*
555 * Visit the static fields of this InstanceKlass with the obj of
556 * the visitor set to the oop holding the fields, which is
557 * currently the java mirror.
558 */
559 public void iterateStaticFields(OopVisitor visitor) {
560 visitor.setObj(getJavaMirror());
561 visitor.prologue();
562 iterateStaticFieldsInternal(visitor);
563 visitor.epilogue();
564
565 }
566
567 void iterateStaticFieldsInternal(OopVisitor visitor) {
568 int length = getJavaFieldsCount();
569 for (int index = 0; index < length; index++) {
570 short accessFlags = getFieldAccessFlags(index);
571 FieldType type = new FieldType(getFieldSignature(index));
572 AccessFlags access = new AccessFlags(accessFlags);
573 if (access.isStatic()) {
574 visitField(visitor, type, index);
575 }
576 }
577 }
578
579 public Klass getJavaSuper() {
580 return getSuper();
581 }
582
583 public static class StaticField {
584 public AccessFlags flags;
585 public Field field;
586
587 StaticField(Field field, AccessFlags flags) {
588 this.field = field;
589 this.flags = flags;
590 }
591 }
592
593 public Field[] getStaticFields() {
594 U2Array fields = getFields();
595 int length = getJavaFieldsCount();
596 ArrayList result = new ArrayList();
597 for (int index = 0; index < length; index++) {
598 Field f = newField(index);
599 if (f.isStatic()) {
600 result.add(f);
601 }
602 }
603 return (Field[])result.toArray(new Field[result.size()]);
604 }
605
606 public void iterateNonStaticFields(OopVisitor visitor, Oop obj) {
607 if (getSuper() != null) {
608 ((InstanceKlass) getSuper()).iterateNonStaticFields(visitor, obj);
609 }
610 int length = getJavaFieldsCount();
611 for (int index = 0; index < length; index++) {
612 short accessFlags = getFieldAccessFlags(index);
613 FieldType type = new FieldType(getFieldSignature(index));
614 AccessFlags access = new AccessFlags(accessFlags);
615 if (!access.isStatic()) {
616 visitField(visitor, type, index);
617 }
618 }
619 }
620
621 /** Field access by name. */
622 public Field findLocalField(Symbol name, Symbol sig) {
623 int length = getJavaFieldsCount();
624 for (int i = 0; i < length; i++) {
625 Symbol f_name = getFieldName(i);
626 Symbol f_sig = getFieldSignature(i);
627 if (name.equals(f_name) && sig.equals(f_sig)) {
628 return newField(i);
629 }
630 }
631
632 return null;
633 }
634
635 /** Find field in direct superinterfaces. */
636 public Field findInterfaceField(Symbol name, Symbol sig) {
637 KlassArray interfaces = getLocalInterfaces();
638 int n = interfaces.length();
639 for (int i = 0; i < n; i++) {
640 InstanceKlass intf1 = (InstanceKlass) interfaces.getAt(i);
641 if (Assert.ASSERTS_ENABLED) {
642 Assert.that(intf1.isInterface(), "just checking type");
643 }
644 // search for field in current interface
645 Field f = intf1.findLocalField(name, sig);
646 if (f != null) {
647 if (Assert.ASSERTS_ENABLED) {
648 Assert.that(f.getAccessFlagsObj().isStatic(), "interface field must be static");
649 }
650 return f;
651 }
652 // search for field in direct superinterfaces
653 f = intf1.findInterfaceField(name, sig);
654 if (f != null) return f;
655 }
656 // otherwise field lookup fails
657 return null;
658 }
659
660 /** Find field according to JVM spec 5.4.3.2, returns the klass in
661 which the field is defined. */
662 public Field findField(Symbol name, Symbol sig) {
663 // search order according to newest JVM spec (5.4.3.2, p.167).
664 // 1) search for field in current klass
665 Field f = findLocalField(name, sig);
666 if (f != null) return f;
667
668 // 2) search for field recursively in direct superinterfaces
669 f = findInterfaceField(name, sig);
670 if (f != null) return f;
671
672 // 3) apply field lookup recursively if superclass exists
673 InstanceKlass supr = (InstanceKlass) getSuper();
674 if (supr != null) return supr.findField(name, sig);
675
676 // 4) otherwise field lookup fails
677 return null;
678 }
679
680 /** Find field according to JVM spec 5.4.3.2, returns the klass in
681 which the field is defined (convenience routine) */
682 public Field findField(String name, String sig) {
683 SymbolTable symbols = VM.getVM().getSymbolTable();
684 Symbol nameSym = symbols.probe(name);
685 Symbol sigSym = symbols.probe(sig);
686 if (nameSym == null || sigSym == null) {
687 return null;
688 }
689 return findField(nameSym, sigSym);
690 }
691
692 /** Find field according to JVM spec 5.4.3.2, returns the klass in
693 which the field is defined (retained only for backward
694 compatibility with jdbx) */
695 public Field findFieldDbg(String name, String sig) {
696 return findField(name, sig);
697 }
698
699 /** Get field by its index in the fields array. Only designed for
700 use in a debugging system. */
701 public Field getFieldByIndex(int fieldIndex) {
702 return newField(fieldIndex);
703 }
704
705
706 /** Return a List of SA Fields for the fields declared in this class.
707 Inherited fields are not included.
708 Return an empty list if there are no fields declared in this class.
709 Only designed for use in a debugging system. */
710 public List getImmediateFields() {
711 // A list of Fields for each field declared in this class/interface,
712 // not including inherited fields.
713 int length = getJavaFieldsCount();
714 List immediateFields = new ArrayList(length);
715 for (int index = 0; index < length; index++) {
716 immediateFields.add(getFieldByIndex(index));
717 }
718
719 return immediateFields;
720 }
721
722 /** Return a List of SA Fields for all the java fields in this class,
723 including all inherited fields. This includes hidden
724 fields. Thus the returned list can contain fields with
725 the same name.
726 Return an empty list if there are no fields.
727 Only designed for use in a debugging system. */
728 public List getAllFields() {
729 // Contains a Field for each field in this class, including immediate
730 // fields and inherited fields.
731 List allFields = getImmediateFields();
732
733 // transitiveInterfaces contains all interfaces implemented
734 // by this class and its superclass chain with no duplicates.
735
736 KlassArray interfaces = getTransitiveInterfaces();
737 int n = interfaces.length();
738 for (int i = 0; i < n; i++) {
739 InstanceKlass intf1 = (InstanceKlass) interfaces.getAt(i);
740 if (Assert.ASSERTS_ENABLED) {
741 Assert.that(intf1.isInterface(), "just checking type");
742 }
743 allFields.addAll(intf1.getImmediateFields());
744 }
745
746 // Get all fields in the superclass, recursively. But, don't
747 // include fields in interfaces implemented by superclasses;
748 // we already have all those.
749 if (!isInterface()) {
750 InstanceKlass supr;
751 if ( (supr = (InstanceKlass) getSuper()) != null) {
752 allFields.addAll(supr.getImmediateFields());
753 }
754 }
755
756 return allFields;
757 }
758
759
760 /** Return a List of SA Methods declared directly in this class/interface.
761 Return an empty list if there are none, or if this isn't a class/
762 interface.
763 */
764 public List getImmediateMethods() {
765 // Contains a Method for each method declared in this class/interface
766 // not including inherited methods.
767
768 MethodArray methods = getMethods();
769 int length = methods.length();
770 Object[] tmp = new Object[length];
771
772 IntArray methodOrdering = getMethodOrdering();
773 if (methodOrdering.length() != length) {
774 // no ordering info present
775 for (int index = 0; index < length; index++) {
776 tmp[index] = methods.at(index);
777 }
778 } else {
779 for (int index = 0; index < length; index++) {
780 int originalIndex = methodOrdering.at(index);
781 tmp[originalIndex] = methods.at(index);
782 }
783 }
784
785 return Arrays.asList(tmp);
786 }
787
788 /** Return a List containing an SA InstanceKlass for each
789 interface named in this class's 'implements' clause.
790 */
791 public List getDirectImplementedInterfaces() {
792 // Contains an InstanceKlass for each interface in this classes
793 // 'implements' clause.
794
795 KlassArray interfaces = getLocalInterfaces();
796 int length = interfaces.length();
797 List directImplementedInterfaces = new ArrayList(length);
798
799 for (int index = 0; index < length; index ++) {
800 directImplementedInterfaces.add(interfaces.getAt(index));
801 }
802
803 return directImplementedInterfaces;
804 }
805
806 public Klass arrayKlassImpl(boolean orNull, int n) {
807 // FIXME: in reflective system this would need to change to
808 // actually allocate
809 if (getArrayKlasses() == null) { return null; }
810 ObjArrayKlass oak = (ObjArrayKlass) getArrayKlasses();
811 if (orNull) {
812 return oak.arrayKlassOrNull(n);
813 }
814 return oak.arrayKlass(n);
815 }
816
817 public Klass arrayKlassImpl(boolean orNull) {
818 return arrayKlassImpl(orNull, 1);
819 }
820
821 public String signature() {
822 return "L" + super.signature() + ";";
823 }
824
825 /** Convenience routine taking Strings; lookup is done in
826 SymbolTable. */
827 public Method findMethod(String name, String sig) {
828 SymbolTable syms = VM.getVM().getSymbolTable();
829 Symbol nameSym = syms.probe(name);
830 Symbol sigSym = syms.probe(sig);
831 if (nameSym == null || sigSym == null) {
832 return null;
833 }
834 return findMethod(nameSym, sigSym);
835 }
836
837 /** Find method in vtable. */
838 public Method findMethod(Symbol name, Symbol sig) {
839 return findMethod(getMethods(), name, sig);
840 }
841
842 /** Breakpoint support (see methods on Method* for details) */
843 public BreakpointInfo getBreakpoints() {
844 Address addr = getAddress().getAddressAt(breakpoints.getOffset());
845 return (BreakpointInfo) VMObjectFactory.newObject(BreakpointInfo.class, addr);
846 }
847
848 public IntArray getMethodOrdering() {
849 Address addr = getAddress().getAddressAt(methodOrdering.getOffset());
850 return (IntArray) VMObjectFactory.newObject(IntArray.class, addr);
851 }
852
853 public U2Array getFields() {
854 Address addr = getAddress().getAddressAt(fields.getOffset());
855 return (U2Array) VMObjectFactory.newObject(U2Array.class, addr);
856 }
857
858 public U2Array getInnerClasses() {
859 Address addr = getAddress().getAddressAt(innerClasses.getOffset());
860 return (U2Array) VMObjectFactory.newObject(U2Array.class, addr);
861 }
862
863
864 //----------------------------------------------------------------------
865 // Internals only below this point
866 //
867
868 private void visitField(OopVisitor visitor, FieldType type, int index) {
869 Field f = newField(index);
870 if (type.isOop()) {
871 visitor.doOop((OopField) f, false);
872 return;
873 }
874 if (type.isByte()) {
875 visitor.doByte((ByteField) f, false);
876 return;
877 }
878 if (type.isChar()) {
879 visitor.doChar((CharField) f, false);
880 return;
881 }
882 if (type.isDouble()) {
883 visitor.doDouble((DoubleField) f, false);
884 return;
885 }
886 if (type.isFloat()) {
887 visitor.doFloat((FloatField) f, false);
888 return;
889 }
890 if (type.isInt()) {
891 visitor.doInt((IntField) f, false);
892 return;
893 }
894 if (type.isLong()) {
895 visitor.doLong((LongField) f, false);
896 return;
897 }
898 if (type.isShort()) {
899 visitor.doShort((ShortField) f, false);
900 return;
901 }
902 if (type.isBoolean()) {
903 visitor.doBoolean((BooleanField) f, false);
904 return;
905 }
906 }
907
908 // Creates new field from index in fields TypeArray
909 private Field newField(int index) {
910 FieldType type = new FieldType(getFieldSignature(index));
911 if (type.isOop()) {
912 if (VM.getVM().isCompressedOopsEnabled()) {
913 return new NarrowOopField(this, index);
914 } else {
915 return new OopField(this, index);
916 }
917 }
918 if (type.isByte()) {
919 return new ByteField(this, index);
920 }
921 if (type.isChar()) {
922 return new CharField(this, index);
923 }
924 if (type.isDouble()) {
925 return new DoubleField(this, index);
926 }
927 if (type.isFloat()) {
928 return new FloatField(this, index);
929 }
930 if (type.isInt()) {
931 return new IntField(this, index);
932 }
933 if (type.isLong()) {
934 return new LongField(this, index);
935 }
936 if (type.isShort()) {
937 return new ShortField(this, index);
938 }
939 if (type.isBoolean()) {
940 return new BooleanField(this, index);
941 }
942 throw new RuntimeException("Illegal field type at index " + index);
943 }
944
945 private static Method findMethod(MethodArray methods, Symbol name, Symbol signature) {
946 int len = methods.length();
947 // methods are sorted, so do binary search
948 int l = 0;
949 int h = len - 1;
950 while (l <= h) {
951 int mid = (l + h) >> 1;
952 Method m = methods.at(mid);
953 int res = m.getName().fastCompare(name);
954 if (res == 0) {
955 // found matching name; do linear search to find matching signature
956 // first, quick check for common case
957 if (m.getSignature().equals(signature)) return m;
958 // search downwards through overloaded methods
959 int i;
960 for (i = mid - 1; i >= l; i--) {
961 Method m1 = methods.at(i);
962 if (!m1.getName().equals(name)) break;
963 if (m1.getSignature().equals(signature)) return m1;
964 }
965 // search upwards
966 for (i = mid + 1; i <= h; i++) {
967 Method m1 = methods.at(i);
968 if (!m1.getName().equals(name)) break;
969 if (m1.getSignature().equals(signature)) return m1;
970 }
971 // not found
972 if (Assert.ASSERTS_ENABLED) {
973 int index = linearSearch(methods, name, signature);
974 if (index != -1) {
975 throw new DebuggerException("binary search bug: should have found entry " + index);
976 }
977 }
978 return null;
979 } else if (res < 0) {
980 l = mid + 1;
981 } else {
982 h = mid - 1;
983 }
984 }
985 if (Assert.ASSERTS_ENABLED) {
986 int index = linearSearch(methods, name, signature);
987 if (index != -1) {
988 throw new DebuggerException("binary search bug: should have found entry " + index);
989 }
990 }
991 return null;
992 }
993
994 private static int linearSearch(MethodArray methods, Symbol name, Symbol signature) {
995 int len = (int) methods.length();
996 for (int index = 0; index < len; index++) {
997 Method m = methods.at(index);
998 if (m.getSignature().equals(signature) && m.getName().equals(name)) {
999 return index;
1000 }
1001 }
1002 return -1;
1003 }
1004
1005 public void dumpReplayData(PrintStream out) {
1006 ConstantPool cp = getConstants();
1007
1008 // Try to record related loaded classes
1009 Klass sub = getSubklassKlass();
1010 while (sub != null) {
1011 if (sub instanceof InstanceKlass) {
1012 out.println("instanceKlass " + sub.getName().asString());
1013 }
1014 sub = sub.getNextSiblingKlass();
1015 }
1016
1017 final int length = (int) cp.getLength();
1018 out.print("ciInstanceKlass " + getName().asString() + " " + (isLinked() ? 1 : 0) + " " + (isInitialized() ? 1 : 0) + " " + length);
1019 for (int index = 1; index < length; index++) {
1020 out.print(" " + cp.getTags().at(index));
1021 }
1022 out.println();
1023 if (isInitialized()) {
1024 Field[] staticFields = getStaticFields();
1025 for (int i = 0; i < staticFields.length; i++) {
1026 Field f = staticFields[i];
1027 Oop mirror = getJavaMirror();
1028 if (f.isFinal() && !f.hasInitialValue()) {
1029 out.print("staticfield " + getName().asString() + " " +
1030 OopUtilities.escapeString(f.getID().getName()) + " " +
1031 f.getFieldType().getSignature().asString() + " ");
1032 if (f instanceof ByteField) {
1033 ByteField bf = (ByteField)f;
1034 out.println(bf.getValue(mirror));
1035 } else if (f instanceof BooleanField) {
1036 BooleanField bf = (BooleanField)f;
1037 out.println(bf.getValue(mirror) ? 1 : 0);
1038 } else if (f instanceof ShortField) {
1039 ShortField bf = (ShortField)f;
1040 out.println(bf.getValue(mirror));
1041 } else if (f instanceof CharField) {
1042 CharField bf = (CharField)f;
1043 out.println(bf.getValue(mirror) & 0xffff);
1044 } else if (f instanceof IntField) {
1045 IntField bf = (IntField)f;
1046 out.println(bf.getValue(mirror));
1047 } else if (f instanceof LongField) {
1048 LongField bf = (LongField)f;
1049 out.println(bf.getValue(mirror));
1050 } else if (f instanceof FloatField) {
1051 FloatField bf = (FloatField)f;
1052 out.println(Float.floatToRawIntBits(bf.getValue(mirror)));
1053 } else if (f instanceof DoubleField) {
1054 DoubleField bf = (DoubleField)f;
1055 out.println(Double.doubleToRawLongBits(bf.getValue(mirror)));
1056 } else if (f instanceof OopField) {
1057 OopField bf = (OopField)f;
1058
1059 Oop value = bf.getValue(mirror);
1060 if (value == null) {
1061 out.println("null");
1062 } else if (value.isInstance()) {
1063 Instance inst = (Instance)value;
1064 if (inst.isA(SystemDictionary.getStringKlass())) {
1065 out.println("\"" + OopUtilities.stringOopToEscapedString(inst) + "\"");
1066 } else {
1067 out.println(inst.getKlass().getName().asString());
1068 }
1069 } else if (value.isObjArray()) {
1070 ObjArray oa = (ObjArray)value;
1071 Klass ek = (ObjArrayKlass)oa.getKlass();
1072 out.println(oa.getLength() + " " + ek.getName().asString());
1073 } else if (value.isTypeArray()) {
1074 TypeArray ta = (TypeArray)value;
1075 out.println(ta.getLength());
1076 } else {
1077 out.println(value);
1078 }
1079 }
1080 }
1081 }
1082 }
1083 }
1084 }
--- EOF ---