1 /*
2 * Copyright 2000-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 *
23 */
24
25 package sun.jvm.hotspot.oops;
26
27 import java.io.*;
28 import java.util.*;
29 import sun.jvm.hotspot.debugger.*;
30 import sun.jvm.hotspot.memory.*;
31 import sun.jvm.hotspot.runtime.*;
32 import sun.jvm.hotspot.types.*;
33 import sun.jvm.hotspot.utilities.*;
34
35 // An InstanceKlass is the VM level representation of a Java class.
36
37 public class InstanceKlass extends Klass {
38 static {
39 VM.registerVMInitializedObserver(new Observer() {
40 public void update(Observable o, Object data) {
41 initialize(VM.getVM().getTypeDataBase());
42 }
43 });
44 }
45
46 // field offset constants
47 public static int ACCESS_FLAGS_OFFSET;
48 public static int NAME_INDEX_OFFSET;
49 public static int SIGNATURE_INDEX_OFFSET;
50 public static int INITVAL_INDEX_OFFSET;
51 public static int LOW_OFFSET;
52 public static int HIGH_OFFSET;
53 public static int GENERIC_SIGNATURE_INDEX_OFFSET;
54 public static int NEXT_OFFSET;
55 public static int IMPLEMENTORS_LIMIT;
56
57 // ClassState constants
58 private static int CLASS_STATE_UNPARSABLE_BY_GC;
59 private static int CLASS_STATE_ALLOCATED;
60 private static int CLASS_STATE_LOADED;
61 private static int CLASS_STATE_LINKED;
62 private static int CLASS_STATE_BEING_INITIALIZED;
63 private static int CLASS_STATE_FULLY_INITIALIZED;
64 private static int CLASS_STATE_INITIALIZATION_ERROR;
65
66 private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
67 Type type = db.lookupType("instanceKlass");
68 arrayKlasses = new OopField(type.getOopField("_array_klasses"), Oop.getHeaderSize());
69 methods = new OopField(type.getOopField("_methods"), Oop.getHeaderSize());
70 methodOrdering = new OopField(type.getOopField("_method_ordering"), Oop.getHeaderSize());
71 localInterfaces = new OopField(type.getOopField("_local_interfaces"), Oop.getHeaderSize());
72 transitiveInterfaces = new OopField(type.getOopField("_transitive_interfaces"), Oop.getHeaderSize());
73 nofImplementors = new CIntField(type.getCIntegerField("_nof_implementors"), Oop.getHeaderSize());
74 IMPLEMENTORS_LIMIT = db.lookupIntConstant("instanceKlass::implementors_limit").intValue();
75 implementors = new OopField[IMPLEMENTORS_LIMIT];
76 for (int i = 0; i < IMPLEMENTORS_LIMIT; i++) {
77 long arrayOffset = Oop.getHeaderSize() + (i * db.getAddressSize());
78 implementors[i] = new OopField(type.getOopField("_implementors[0]"), arrayOffset);
79 }
80 fields = new OopField(type.getOopField("_fields"), Oop.getHeaderSize());
81 constants = new OopField(type.getOopField("_constants"), Oop.getHeaderSize());
82 classLoader = new OopField(type.getOopField("_class_loader"), Oop.getHeaderSize());
83 protectionDomain = new OopField(type.getOopField("_protection_domain"), Oop.getHeaderSize());
84 signers = new OopField(type.getOopField("_signers"), Oop.getHeaderSize());
85 sourceFileName = new OopField(type.getOopField("_source_file_name"), Oop.getHeaderSize());
86 sourceDebugExtension = new OopField(type.getOopField("_source_debug_extension"), Oop.getHeaderSize());
87 innerClasses = new OopField(type.getOopField("_inner_classes"), Oop.getHeaderSize());
88 nonstaticFieldSize = new CIntField(type.getCIntegerField("_nonstatic_field_size"), Oop.getHeaderSize());
89 staticFieldSize = new CIntField(type.getCIntegerField("_static_field_size"), Oop.getHeaderSize());
90 staticOopFieldSize = new CIntField(type.getCIntegerField("_static_oop_field_size"), Oop.getHeaderSize());
91 nonstaticOopMapSize = new CIntField(type.getCIntegerField("_nonstatic_oop_map_size"), Oop.getHeaderSize());
92 isMarkedDependent = new CIntField(type.getCIntegerField("_is_marked_dependent"), Oop.getHeaderSize());
93 initState = new CIntField(type.getCIntegerField("_init_state"), Oop.getHeaderSize());
94 vtableLen = new CIntField(type.getCIntegerField("_vtable_len"), Oop.getHeaderSize());
95 itableLen = new CIntField(type.getCIntegerField("_itable_len"), Oop.getHeaderSize());
96 breakpoints = type.getAddressField("_breakpoints");
97 genericSignature = new OopField(type.getOopField("_generic_signature"), Oop.getHeaderSize());
98 majorVersion = new CIntField(type.getCIntegerField("_major_version"), Oop.getHeaderSize());
99 minorVersion = new CIntField(type.getCIntegerField("_minor_version"), Oop.getHeaderSize());
100 headerSize = alignObjectOffset(Oop.getHeaderSize() + type.getSize());
101
102 // read field offset constants
103 ACCESS_FLAGS_OFFSET = db.lookupIntConstant("instanceKlass::access_flags_offset").intValue();
104 NAME_INDEX_OFFSET = db.lookupIntConstant("instanceKlass::name_index_offset").intValue();
105 SIGNATURE_INDEX_OFFSET = db.lookupIntConstant("instanceKlass::signature_index_offset").intValue();
106 INITVAL_INDEX_OFFSET = db.lookupIntConstant("instanceKlass::initval_index_offset").intValue();
107 LOW_OFFSET = db.lookupIntConstant("instanceKlass::low_offset").intValue();
108 HIGH_OFFSET = db.lookupIntConstant("instanceKlass::high_offset").intValue();
109 GENERIC_SIGNATURE_INDEX_OFFSET = db.lookupIntConstant("instanceKlass::generic_signature_offset").intValue();
110 NEXT_OFFSET = db.lookupIntConstant("instanceKlass::next_offset").intValue();
111 // read ClassState constants
112 CLASS_STATE_UNPARSABLE_BY_GC = db.lookupIntConstant("instanceKlass::unparsable_by_gc").intValue();
113 CLASS_STATE_ALLOCATED = db.lookupIntConstant("instanceKlass::allocated").intValue();
114 CLASS_STATE_LOADED = db.lookupIntConstant("instanceKlass::loaded").intValue();
115 CLASS_STATE_LINKED = db.lookupIntConstant("instanceKlass::linked").intValue();
116 CLASS_STATE_BEING_INITIALIZED = db.lookupIntConstant("instanceKlass::being_initialized").intValue();
117 CLASS_STATE_FULLY_INITIALIZED = db.lookupIntConstant("instanceKlass::fully_initialized").intValue();
118 CLASS_STATE_INITIALIZATION_ERROR = db.lookupIntConstant("instanceKlass::initialization_error").intValue();
119
120 }
121
122 InstanceKlass(OopHandle handle, ObjectHeap heap) {
123 super(handle, heap);
124 }
125
126 private static OopField arrayKlasses;
127 private static OopField methods;
128 private static OopField methodOrdering;
129 private static OopField localInterfaces;
130 private static OopField transitiveInterfaces;
131 private static CIntField nofImplementors;
132 private static OopField[] implementors;
133 private static OopField fields;
134 private static OopField constants;
135 private static OopField classLoader;
136 private static OopField protectionDomain;
137 private static OopField signers;
138 private static OopField sourceFileName;
139 private static OopField sourceDebugExtension;
140 private static OopField innerClasses;
141 private static CIntField nonstaticFieldSize;
142 private static CIntField staticFieldSize;
143 private static CIntField staticOopFieldSize;
144 private static CIntField nonstaticOopMapSize;
145 private static CIntField isMarkedDependent;
146 private static CIntField initState;
147 private static CIntField vtableLen;
148 private static CIntField itableLen;
149 private static AddressField breakpoints;
150 private static OopField genericSignature;
151 private static CIntField majorVersion;
152 private static CIntField minorVersion;
153
154 // type safe enum for ClassState from instanceKlass.hpp
155 public static class ClassState {
156 public static final ClassState UNPARSABLE_BY_GC = new ClassState("unparsable_by_gc");
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 private int getInitStateAsInt() { return (int) initState.getValue(this); }
176 public ClassState getInitState() {
177 int state = getInitStateAsInt();
178 if (state == CLASS_STATE_UNPARSABLE_BY_GC) {
179 return ClassState.UNPARSABLE_BY_GC;
180 } else 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 static long getHeaderSize() { return headerSize; }
245
246 // Accessors for declared fields
247 public Klass getArrayKlasses() { return (Klass) arrayKlasses.getValue(this); }
248 public ObjArray getMethods() { return (ObjArray) methods.getValue(this); }
249 public TypeArray getMethodOrdering() { return (TypeArray) methodOrdering.getValue(this); }
250 public ObjArray getLocalInterfaces() { return (ObjArray) localInterfaces.getValue(this); }
251 public ObjArray getTransitiveInterfaces() { return (ObjArray) transitiveInterfaces.getValue(this); }
252 public long nofImplementors() { return nofImplementors.getValue(this); }
253 public Klass getImplementor() { return (Klass) implementors[0].getValue(this); }
254 public Klass getImplementor(int i) { return (Klass) implementors[i].getValue(this); }
255 public TypeArray getFields() { return (TypeArray) fields.getValue(this); }
256 public ConstantPool getConstants() { return (ConstantPool) constants.getValue(this); }
257 public Oop getClassLoader() { return classLoader.getValue(this); }
258 public Oop getProtectionDomain() { return protectionDomain.getValue(this); }
259 public ObjArray getSigners() { return (ObjArray) signers.getValue(this); }
260 public Symbol getSourceFileName() { return (Symbol) sourceFileName.getValue(this); }
261 public Symbol getSourceDebugExtension(){ return (Symbol) sourceDebugExtension.getValue(this); }
262 public TypeArray getInnerClasses() { return (TypeArray) innerClasses.getValue(this); }
263 public long getNonstaticFieldSize() { return nonstaticFieldSize.getValue(this); }
264 public long getStaticFieldSize() { return staticFieldSize.getValue(this); }
265 public long getStaticOopFieldSize() { return staticOopFieldSize.getValue(this); }
266 public long getNonstaticOopMapSize() { return nonstaticOopMapSize.getValue(this); }
267 public boolean getIsMarkedDependent() { return isMarkedDependent.getValue(this) != 0; }
268 public long getVtableLen() { return vtableLen.getValue(this); }
269 public long getItableLen() { return itableLen.getValue(this); }
270 public Symbol getGenericSignature() { return (Symbol) genericSignature.getValue(this); }
271 public long majorVersion() { return majorVersion.getValue(this); }
272 public long minorVersion() { return minorVersion.getValue(this); }
273
274 // "size helper" == instance size in words
275 public long getSizeHelper() {
276 int lh = getLayoutHelper();
277 if (Assert.ASSERTS_ENABLED) {
278 Assert.that(lh > 0, "layout helper initialized for instance class");
279 }
280 return lh / VM.getVM().getAddressSize();
281 }
282
283 // same as enum InnerClassAttributeOffset in VM code.
284 public static interface InnerClassAttributeOffset {
285 // from JVM spec. "InnerClasses" attribute
286 public static final int innerClassInnerClassInfoOffset = 0;
287 public static final int innerClassOuterClassInfoOffset = 1;
288 public static final int innerClassInnerNameOffset = 2;
289 public static final int innerClassAccessFlagsOffset = 3;
290 public static final int innerClassNextOffset = 4;
291 };
292
293 // refer to compute_modifier_flags in VM code.
294 public long computeModifierFlags() {
295 long access = getAccessFlags();
296 // But check if it happens to be member class.
297 TypeArray innerClassList = getInnerClasses();
298 int length = ( innerClassList == null)? 0 : (int) innerClassList.getLength();
299 if (length > 0) {
300 if (Assert.ASSERTS_ENABLED) {
301 Assert.that(length % InnerClassAttributeOffset.innerClassNextOffset == 0, "just checking");
302 }
303 for (int i = 0; i < length; i += InnerClassAttributeOffset.innerClassNextOffset) {
304 int ioff = innerClassList.getShortAt(i +
305 InnerClassAttributeOffset.innerClassInnerClassInfoOffset);
306 // 'ioff' can be zero.
307 // refer to JVM spec. section 4.7.5.
308 if (ioff != 0) {
309 // only look at classes that are already loaded
310 // since we are looking for the flags for our self.
311 Oop classInfo = getConstants().getObjAt(ioff);
312 Symbol name = null;
313 if (classInfo instanceof Klass) {
314 name = ((Klass) classInfo).getName();
315 } else if (classInfo instanceof Symbol) {
316 name = (Symbol) classInfo;
317 } else {
318 throw new RuntimeException("should not reach here");
319 }
320
321 if (name.equals(getName())) {
322 // This is really a member class
323 access = innerClassList.getShortAt(i +
324 InnerClassAttributeOffset.innerClassAccessFlagsOffset);
325 break;
326 }
327 }
328 } // for inner classes
329 }
330
331 // Remember to strip ACC_SUPER bit
332 return (access & (~JVM_ACC_SUPER)) & JVM_ACC_WRITTEN_FLAGS;
333 }
334
335
336 // whether given Symbol is name of an inner/nested Klass of this Klass?
337 // anonymous and local classes are excluded.
338 public boolean isInnerClassName(Symbol sym) {
339 return isInInnerClasses(sym, false);
340 }
341
342 // whether given Symbol is name of an inner/nested Klass of this Klass?
343 // anonymous classes excluded, but local classes are included.
344 public boolean isInnerOrLocalClassName(Symbol sym) {
345 return isInInnerClasses(sym, true);
346 }
347
348 private boolean isInInnerClasses(Symbol sym, boolean includeLocals) {
349 TypeArray innerClassList = getInnerClasses();
350 int length = ( innerClassList == null)? 0 : (int) innerClassList.getLength();
351 if (length > 0) {
352 if (Assert.ASSERTS_ENABLED) {
353 Assert.that(length % InnerClassAttributeOffset.innerClassNextOffset == 0, "just checking");
354 }
355 for (int i = 0; i < length; i += InnerClassAttributeOffset.innerClassNextOffset) {
356 int ioff = innerClassList.getShortAt(i +
357 InnerClassAttributeOffset.innerClassInnerClassInfoOffset);
358 // 'ioff' can be zero.
359 // refer to JVM spec. section 4.7.5.
360 if (ioff != 0) {
361 Oop iclassInfo = getConstants().getObjAt(ioff);
362 Symbol innerName = null;
363 if (iclassInfo instanceof Klass) {
364 innerName = ((Klass) iclassInfo).getName();
365 } else if (iclassInfo instanceof Symbol) {
366 innerName = (Symbol) iclassInfo;
367 } else {
368 throw new RuntimeException("should not reach here");
369 }
370
371 Symbol myname = getName();
372 int ooff = innerClassList.getShortAt(i +
373 InnerClassAttributeOffset.innerClassOuterClassInfoOffset);
374 // for anonymous classes inner_name_index of InnerClasses
375 // attribute is zero.
376 int innerNameIndex = innerClassList.getShortAt(i +
377 InnerClassAttributeOffset.innerClassInnerNameOffset);
378 // if this is not a member (anonymous, local etc.), 'ooff' will be zero
379 // refer to JVM spec. section 4.7.5.
380 if (ooff == 0) {
381 if (includeLocals) {
382 // does it looks like my local class?
383 if (innerName.equals(sym) &&
384 innerName.asString().startsWith(myname.asString())) {
385 // exclude anonymous classes.
386 return (innerNameIndex != 0);
387 }
388 }
389 } else {
390 Oop oclassInfo = getConstants().getObjAt(ooff);
391 Symbol outerName = null;
392 if (oclassInfo instanceof Klass) {
393 outerName = ((Klass) oclassInfo).getName();
394 } else if (oclassInfo instanceof Symbol) {
395 outerName = (Symbol) oclassInfo;
396 } else {
397 throw new RuntimeException("should not reach here");
398 }
399
400 // include only if current class is outer class.
401 if (outerName.equals(myname) && innerName.equals(sym)) {
402 return true;
403 }
404 }
405 }
406 } // for inner classes
407 return false;
408 } else {
409 return false;
410 }
411 }
412
413 public boolean implementsInterface(Klass k) {
414 if (Assert.ASSERTS_ENABLED) {
415 Assert.that(k.isInterface(), "should not reach here");
416 }
417 ObjArray interfaces = getTransitiveInterfaces();
418 final int len = (int) interfaces.getLength();
419 for (int i = 0; i < len; i++) {
420 if (interfaces.getObjAt(i).equals(k)) return true;
421 }
422 return false;
423 }
424
425 boolean computeSubtypeOf(Klass k) {
426 if (k.isInterface()) {
427 return implementsInterface(k);
428 } else {
429 return super.computeSubtypeOf(k);
430 }
431 }
432
433 public void printValueOn(PrintStream tty) {
434 tty.print("InstanceKlass for " + getName().asString());
435 }
436
437 public void iterateFields(OopVisitor visitor, boolean doVMFields) {
438 super.iterateFields(visitor, doVMFields);
439 if (doVMFields) {
440 visitor.doOop(arrayKlasses, true);
441 visitor.doOop(methods, true);
442 visitor.doOop(methodOrdering, true);
443 visitor.doOop(localInterfaces, true);
444 visitor.doOop(transitiveInterfaces, true);
445 visitor.doCInt(nofImplementors, true);
446 for (int i = 0; i < IMPLEMENTORS_LIMIT; i++)
447 visitor.doOop(implementors[i], true);
448 visitor.doOop(fields, true);
449 visitor.doOop(constants, true);
450 visitor.doOop(classLoader, true);
451 visitor.doOop(protectionDomain, true);
452 visitor.doOop(signers, true);
453 visitor.doOop(sourceFileName, true);
454 visitor.doOop(innerClasses, true);
455 visitor.doCInt(nonstaticFieldSize, true);
456 visitor.doCInt(staticFieldSize, true);
457 visitor.doCInt(staticOopFieldSize, true);
458 visitor.doCInt(nonstaticOopMapSize, true);
459 visitor.doCInt(isMarkedDependent, true);
460 visitor.doCInt(initState, true);
461 visitor.doCInt(vtableLen, true);
462 visitor.doCInt(itableLen, true);
463 }
464
465 TypeArray fields = getFields();
466 int length = (int) fields.getLength();
467 for (int index = 0; index < length; index += NEXT_OFFSET) {
468 short accessFlags = fields.getShortAt(index + ACCESS_FLAGS_OFFSET);
469 short signatureIndex = fields.getShortAt(index + SIGNATURE_INDEX_OFFSET);
470 FieldType type = new FieldType((Symbol) getConstants().getObjAt(signatureIndex));
471 AccessFlags access = new AccessFlags(accessFlags);
472 if (access.isStatic()) {
473 visitField(visitor, type, index);
474 }
475 }
476 }
477
478 public Klass getJavaSuper() {
479 return getSuper();
480 }
481
482 public void iterateNonStaticFields(OopVisitor visitor) {
483 if (getSuper() != null) {
484 ((InstanceKlass) getSuper()).iterateNonStaticFields(visitor);
485 }
486 TypeArray fields = getFields();
487
488 int length = (int) fields.getLength();
489 for (int index = 0; index < length; index += NEXT_OFFSET) {
490 short accessFlags = fields.getShortAt(index + ACCESS_FLAGS_OFFSET);
491 short signatureIndex = fields.getShortAt(index + SIGNATURE_INDEX_OFFSET);
492
493 FieldType type = new FieldType((Symbol) getConstants().getObjAt(signatureIndex));
494 AccessFlags access = new AccessFlags(accessFlags);
495 if (!access.isStatic()) {
496 visitField(visitor, type, index);
497 }
498 }
499 }
500
501 /** Field access by name. */
502 public Field findLocalField(Symbol name, Symbol sig) {
503 TypeArray fields = getFields();
504 int n = (int) fields.getLength();
505 ConstantPool cp = getConstants();
506 for (int i = 0; i < n; i += NEXT_OFFSET) {
507 int nameIndex = fields.getShortAt(i + NAME_INDEX_OFFSET);
508 int sigIndex = fields.getShortAt(i + SIGNATURE_INDEX_OFFSET);
509 Symbol f_name = cp.getSymbolAt(nameIndex);
510 Symbol f_sig = cp.getSymbolAt(sigIndex);
511 if (name.equals(f_name) && sig.equals(f_sig)) {
512 return newField(i);
513 }
514 }
515
516 return null;
517 }
518
519 /** Find field in direct superinterfaces. */
520 public Field findInterfaceField(Symbol name, Symbol sig) {
521 ObjArray interfaces = getLocalInterfaces();
522 int n = (int) interfaces.getLength();
523 for (int i = 0; i < n; i++) {
524 InstanceKlass intf1 = (InstanceKlass) interfaces.getObjAt(i);
525 if (Assert.ASSERTS_ENABLED) {
526 Assert.that(intf1.isInterface(), "just checking type");
527 }
528 // search for field in current interface
529 Field f = intf1.findLocalField(name, sig);
530 if (f != null) {
531 if (Assert.ASSERTS_ENABLED) {
532 Assert.that(f.getAccessFlagsObj().isStatic(), "interface field must be static");
533 }
534 return f;
535 }
536 // search for field in direct superinterfaces
537 f = intf1.findInterfaceField(name, sig);
538 if (f != null) return f;
539 }
540 // otherwise field lookup fails
541 return null;
542 }
543
544 /** Find field according to JVM spec 5.4.3.2, returns the klass in
545 which the field is defined. */
546 public Field findField(Symbol name, Symbol sig) {
547 // search order according to newest JVM spec (5.4.3.2, p.167).
548 // 1) search for field in current klass
549 Field f = findLocalField(name, sig);
550 if (f != null) return f;
551
552 // 2) search for field recursively in direct superinterfaces
553 f = findInterfaceField(name, sig);
554 if (f != null) return f;
555
556 // 3) apply field lookup recursively if superclass exists
557 InstanceKlass supr = (InstanceKlass) getSuper();
558 if (supr != null) return supr.findField(name, sig);
559
560 // 4) otherwise field lookup fails
561 return null;
562 }
563
564 /** Find field according to JVM spec 5.4.3.2, returns the klass in
565 which the field is defined (convenience routine) */
566 public Field findField(String name, String sig) {
567 SymbolTable symbols = VM.getVM().getSymbolTable();
568 Symbol nameSym = symbols.probe(name);
569 Symbol sigSym = symbols.probe(sig);
570 if (nameSym == null || sigSym == null) {
571 return null;
572 }
573 return findField(nameSym, sigSym);
574 }
575
576 /** Find field according to JVM spec 5.4.3.2, returns the klass in
577 which the field is defined (retained only for backward
578 compatibility with jdbx) */
579 public Field findFieldDbg(String name, String sig) {
580 return findField(name, sig);
581 }
582
583 /** Get field by its index in the fields array. Only designed for
584 use in a debugging system. */
585 public Field getFieldByIndex(int fieldArrayIndex) {
586 return newField(fieldArrayIndex);
587 }
588
589
590 /** Return a List of SA Fields for the fields declared in this class.
591 Inherited fields are not included.
592 Return an empty list if there are no fields declared in this class.
593 Only designed for use in a debugging system. */
594 public List getImmediateFields() {
595 // A list of Fields for each field declared in this class/interface,
596 // not including inherited fields.
597 TypeArray fields = getFields();
598
599 int length = (int) fields.getLength();
600 List immediateFields = new ArrayList(length / NEXT_OFFSET);
601 for (int index = 0; index < length; index += NEXT_OFFSET) {
602 immediateFields.add(getFieldByIndex(index));
603 }
604
605 return immediateFields;
606 }
607
608 /** Return a List of SA Fields for all the java fields in this class,
609 including all inherited fields. This includes hidden
610 fields. Thus the returned list can contain fields with
611 the same name.
612 Return an empty list if there are no fields.
613 Only designed for use in a debugging system. */
614 public List getAllFields() {
615 // Contains a Field for each field in this class, including immediate
616 // fields and inherited fields.
617 List allFields = getImmediateFields();
618
619 // transitiveInterfaces contains all interfaces implemented
620 // by this class and its superclass chain with no duplicates.
621
622 ObjArray interfaces = getTransitiveInterfaces();
623 int n = (int) interfaces.getLength();
624 for (int i = 0; i < n; i++) {
625 InstanceKlass intf1 = (InstanceKlass) interfaces.getObjAt(i);
626 if (Assert.ASSERTS_ENABLED) {
627 Assert.that(intf1.isInterface(), "just checking type");
628 }
629 allFields.addAll(intf1.getImmediateFields());
630 }
631
632 // Get all fields in the superclass, recursively. But, don't
633 // include fields in interfaces implemented by superclasses;
634 // we already have all those.
635 if (!isInterface()) {
636 InstanceKlass supr;
637 if ( (supr = (InstanceKlass) getSuper()) != null) {
638 allFields.addAll(supr.getImmediateFields());
639 }
640 }
641
642 return allFields;
643 }
644
645
646 /** Return a List of SA Methods declared directly in this class/interface.
647 Return an empty list if there are none, or if this isn't a class/
648 interface.
649 */
650 public List getImmediateMethods() {
651 // Contains a Method for each method declared in this class/interface
652 // not including inherited methods.
653
654 ObjArray methods = getMethods();
655 int length = (int)methods.getLength();
656 Object[] tmp = new Object[length];
657
658 TypeArray methodOrdering = getMethodOrdering();
659 if (methodOrdering.getLength() != length) {
660 // no ordering info present
661 for (int index = 0; index < length; index++) {
662 tmp[index] = methods.getObjAt(index);
663 }
664 } else {
665 for (int index = 0; index < length; index++) {
666 int originalIndex = getMethodOrdering().getIntAt(index);
667 tmp[originalIndex] = methods.getObjAt(index);
668 }
669 }
670
671 return Arrays.asList(tmp);
672 }
673
674 /** Return a List containing an SA InstanceKlass for each
675 interface named in this class's 'implements' clause.
676 */
677 public List getDirectImplementedInterfaces() {
678 // Contains an InstanceKlass for each interface in this classes
679 // 'implements' clause.
680
681 ObjArray interfaces = getLocalInterfaces();
682 int length = (int) interfaces.getLength();
683 List directImplementedInterfaces = new ArrayList(length);
684
685 for (int index = 0; index < length; index ++) {
686 directImplementedInterfaces.add(interfaces.getObjAt(index));
687 }
688
689 return directImplementedInterfaces;
690 }
691
692
693 public long getObjectSize() {
694 long bodySize = alignObjectOffset(getVtableLen() * getHeap().getOopSize())
695 + alignObjectOffset(getItableLen() * getHeap().getOopSize())
696 + (getStaticFieldSize() + getNonstaticOopMapSize()) * getHeap().getOopSize();
697 return alignObjectSize(headerSize + bodySize);
698 }
699
700 public Klass arrayKlassImpl(boolean orNull, int n) {
701 // FIXME: in reflective system this would need to change to
702 // actually allocate
703 if (getArrayKlasses() == null) { return null; }
704 ObjArrayKlass oak = (ObjArrayKlass) getArrayKlasses();
705 if (orNull) {
706 return oak.arrayKlassOrNull(n);
707 }
708 return oak.arrayKlass(n);
709 }
710
711 public Klass arrayKlassImpl(boolean orNull) {
712 return arrayKlassImpl(orNull, 1);
713 }
714
715 public String signature() {
716 return "L" + super.signature() + ";";
717 }
718
719 /** Convenience routine taking Strings; lookup is done in
720 SymbolTable. */
721 public Method findMethod(String name, String sig) {
722 SymbolTable syms = VM.getVM().getSymbolTable();
723 Symbol nameSym = syms.probe(name);
724 Symbol sigSym = syms.probe(sig);
725 if (nameSym == null || sigSym == null) {
726 return null;
727 }
728 return findMethod(nameSym, sigSym);
729 }
730
731 /** Find method in vtable. */
732 public Method findMethod(Symbol name, Symbol sig) {
733 return findMethod(getMethods(), name, sig);
734 }
735
736 /** Breakpoint support (see methods on methodOop for details) */
737 public BreakpointInfo getBreakpoints() {
738 Address addr = getHandle().getAddressAt(Oop.getHeaderSize() + breakpoints.getOffset());
739 return (BreakpointInfo) VMObjectFactory.newObject(BreakpointInfo.class, addr);
740 }
741
742 //----------------------------------------------------------------------
743 // Internals only below this point
744 //
745
746 private void visitField(OopVisitor visitor, FieldType type, int index) {
747 Field f = newField(index);
748 if (type.isOop()) {
749 visitor.doOop((OopField) f, false);
750 return;
751 }
752 if (type.isByte()) {
753 visitor.doByte((ByteField) f, false);
754 return;
755 }
756 if (type.isChar()) {
757 visitor.doChar((CharField) f, false);
758 return;
759 }
760 if (type.isDouble()) {
761 visitor.doDouble((DoubleField) f, false);
762 return;
763 }
764 if (type.isFloat()) {
765 visitor.doFloat((FloatField) f, false);
766 return;
767 }
768 if (type.isInt()) {
769 visitor.doInt((IntField) f, false);
770 return;
771 }
772 if (type.isLong()) {
773 visitor.doLong((LongField) f, false);
774 return;
775 }
776 if (type.isShort()) {
777 visitor.doShort((ShortField) f, false);
778 return;
779 }
780 if (type.isBoolean()) {
781 visitor.doBoolean((BooleanField) f, false);
782 return;
783 }
784 }
785
786 // Creates new field from index in fields TypeArray
787 private Field newField(int index) {
788 TypeArray fields = getFields();
789 short signatureIndex = fields.getShortAt(index + SIGNATURE_INDEX_OFFSET);
790 FieldType type = new FieldType((Symbol) getConstants().getObjAt(signatureIndex));
791 if (type.isOop()) {
792 if (VM.getVM().isCompressedOopsEnabled()) {
793 return new NarrowOopField(this, index);
794 } else {
795 return new OopField(this, index);
796 }
797 }
798 if (type.isByte()) {
799 return new ByteField(this, index);
800 }
801 if (type.isChar()) {
802 return new CharField(this, index);
803 }
804 if (type.isDouble()) {
805 return new DoubleField(this, index);
806 }
807 if (type.isFloat()) {
808 return new FloatField(this, index);
809 }
810 if (type.isInt()) {
811 return new IntField(this, index);
812 }
813 if (type.isLong()) {
814 return new LongField(this, index);
815 }
816 if (type.isShort()) {
817 return new ShortField(this, index);
818 }
819 if (type.isBoolean()) {
820 return new BooleanField(this, index);
821 }
822 throw new RuntimeException("Illegal field type at index " + index);
823 }
824
825 private static Method findMethod(ObjArray methods, Symbol name, Symbol signature) {
826 int len = (int) methods.getLength();
827 // methods are sorted, so do binary search
828 int l = 0;
829 int h = len - 1;
830 while (l <= h) {
831 int mid = (l + h) >> 1;
832 Method m = (Method) methods.getObjAt(mid);
833 int res = m.getName().fastCompare(name);
834 if (res == 0) {
835 // found matching name; do linear search to find matching signature
836 // first, quick check for common case
837 if (m.getSignature().equals(signature)) return m;
838 // search downwards through overloaded methods
839 int i;
840 for (i = mid - 1; i >= l; i--) {
841 Method m1 = (Method) methods.getObjAt(i);
842 if (!m1.getName().equals(name)) break;
843 if (m1.getSignature().equals(signature)) return m1;
844 }
845 // search upwards
846 for (i = mid + 1; i <= h; i++) {
847 Method m1 = (Method) methods.getObjAt(i);
848 if (!m1.getName().equals(name)) break;
849 if (m1.getSignature().equals(signature)) return m1;
850 }
851 // not found
852 if (Assert.ASSERTS_ENABLED) {
853 int index = linearSearch(methods, name, signature);
854 if (index != -1) {
855 throw new DebuggerException("binary search bug: should have found entry " + index);
856 }
857 }
858 return null;
859 } else if (res < 0) {
860 l = mid + 1;
861 } else {
862 h = mid - 1;
863 }
864 }
865 if (Assert.ASSERTS_ENABLED) {
866 int index = linearSearch(methods, name, signature);
867 if (index != -1) {
868 throw new DebuggerException("binary search bug: should have found entry " + index);
869 }
870 }
871 return null;
872 }
873
874 private static int linearSearch(ObjArray methods, Symbol name, Symbol signature) {
875 int len = (int) methods.getLength();
876 for (int index = 0; index < len; index++) {
877 Method m = (Method) methods.getObjAt(index);
878 if (m.getSignature().equals(signature) && m.getName().equals(name)) {
879 return index;
880 }
881 }
882 return -1;
883 }
884 }