0
|
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
|
|
471 FieldType type = new FieldType((Symbol) getConstants().getObjAt(signatureIndex));
|
|
472 AccessFlags access = new AccessFlags(accessFlags);
|
|
473 if (access.isStatic()) {
|
|
474 visitField(visitor, type, index);
|
|
475 }
|
|
476 }
|
|
477 }
|
|
478
|
|
479 public Klass getJavaSuper() {
|
|
480 return getSuper();
|
|
481 }
|
|
482
|
|
483 public void iterateNonStaticFields(OopVisitor visitor) {
|
|
484 if (getSuper() != null) {
|
|
485 ((InstanceKlass) getSuper()).iterateNonStaticFields(visitor);
|
|
486 }
|
|
487 TypeArray fields = getFields();
|
|
488
|
|
489 int length = (int) fields.getLength();
|
|
490 for (int index = 0; index < length; index += NEXT_OFFSET) {
|
|
491 short accessFlags = fields.getShortAt(index + ACCESS_FLAGS_OFFSET);
|
|
492 short signatureIndex = fields.getShortAt(index + SIGNATURE_INDEX_OFFSET);
|
|
493
|
|
494 FieldType type = new FieldType((Symbol) getConstants().getObjAt(signatureIndex));
|
|
495 AccessFlags access = new AccessFlags(accessFlags);
|
|
496 if (!access.isStatic()) {
|
|
497 visitField(visitor, type, index);
|
|
498 }
|
|
499 }
|
|
500 }
|
|
501
|
|
502 /** Field access by name. */
|
|
503 public Field findLocalField(Symbol name, Symbol sig) {
|
|
504 TypeArray fields = getFields();
|
|
505 int n = (int) fields.getLength();
|
|
506 ConstantPool cp = getConstants();
|
|
507 for (int i = 0; i < n; i += NEXT_OFFSET) {
|
|
508 int nameIndex = fields.getShortAt(i + NAME_INDEX_OFFSET);
|
|
509 int sigIndex = fields.getShortAt(i + SIGNATURE_INDEX_OFFSET);
|
|
510 Symbol f_name = cp.getSymbolAt(nameIndex);
|
|
511 Symbol f_sig = cp.getSymbolAt(sigIndex);
|
|
512 if (name.equals(f_name) && sig.equals(f_sig)) {
|
|
513 return newField(i);
|
|
514 }
|
|
515 }
|
|
516
|
|
517 return null;
|
|
518 }
|
|
519
|
|
520 /** Find field in direct superinterfaces. */
|
|
521 public Field findInterfaceField(Symbol name, Symbol sig) {
|
|
522 ObjArray interfaces = getLocalInterfaces();
|
|
523 int n = (int) interfaces.getLength();
|
|
524 for (int i = 0; i < n; i++) {
|
|
525 InstanceKlass intf1 = (InstanceKlass) interfaces.getObjAt(i);
|
|
526 if (Assert.ASSERTS_ENABLED) {
|
|
527 Assert.that(intf1.isInterface(), "just checking type");
|
|
528 }
|
|
529 // search for field in current interface
|
|
530 Field f = intf1.findLocalField(name, sig);
|
|
531 if (f != null) {
|
|
532 if (Assert.ASSERTS_ENABLED) {
|
|
533 Assert.that(f.getAccessFlagsObj().isStatic(), "interface field must be static");
|
|
534 }
|
|
535 return f;
|
|
536 }
|
|
537 // search for field in direct superinterfaces
|
|
538 f = intf1.findInterfaceField(name, sig);
|
|
539 if (f != null) return f;
|
|
540 }
|
|
541 // otherwise field lookup fails
|
|
542 return null;
|
|
543 }
|
|
544
|
|
545 /** Find field according to JVM spec 5.4.3.2, returns the klass in
|
|
546 which the field is defined. */
|
|
547 public Field findField(Symbol name, Symbol sig) {
|
|
548 // search order according to newest JVM spec (5.4.3.2, p.167).
|
|
549 // 1) search for field in current klass
|
|
550 Field f = findLocalField(name, sig);
|
|
551 if (f != null) return f;
|
|
552
|
|
553 // 2) search for field recursively in direct superinterfaces
|
|
554 f = findInterfaceField(name, sig);
|
|
555 if (f != null) return f;
|
|
556
|
|
557 // 3) apply field lookup recursively if superclass exists
|
|
558 InstanceKlass supr = (InstanceKlass) getSuper();
|
|
559 if (supr != null) return supr.findField(name, sig);
|
|
560
|
|
561 // 4) otherwise field lookup fails
|
|
562 return null;
|
|
563 }
|
|
564
|
|
565 /** Find field according to JVM spec 5.4.3.2, returns the klass in
|
|
566 which the field is defined (convenience routine) */
|
|
567 public Field findField(String name, String sig) {
|
|
568 SymbolTable symbols = VM.getVM().getSymbolTable();
|
|
569 Symbol nameSym = symbols.probe(name);
|
|
570 Symbol sigSym = symbols.probe(sig);
|
|
571 if (nameSym == null || sigSym == null) {
|
|
572 return null;
|
|
573 }
|
|
574 return findField(nameSym, sigSym);
|
|
575 }
|
|
576
|
|
577 /** Find field according to JVM spec 5.4.3.2, returns the klass in
|
|
578 which the field is defined (retained only for backward
|
|
579 compatibility with jdbx) */
|
|
580 public Field findFieldDbg(String name, String sig) {
|
|
581 return findField(name, sig);
|
|
582 }
|
|
583
|
|
584 /** Get field by its index in the fields array. Only designed for
|
|
585 use in a debugging system. */
|
|
586 public Field getFieldByIndex(int fieldArrayIndex) {
|
|
587 return newField(fieldArrayIndex);
|
|
588 }
|
|
589
|
|
590
|
|
591 /** Return a List of SA Fields for the fields declared in this class.
|
|
592 Inherited fields are not included.
|
|
593 Return an empty list if there are no fields declared in this class.
|
|
594 Only designed for use in a debugging system. */
|
|
595 public List getImmediateFields() {
|
|
596 // A list of Fields for each field declared in this class/interface,
|
|
597 // not including inherited fields.
|
|
598 TypeArray fields = getFields();
|
|
599
|
|
600 int length = (int) fields.getLength();
|
|
601 List immediateFields = new ArrayList(length / NEXT_OFFSET);
|
|
602 for (int index = 0; index < length; index += NEXT_OFFSET) {
|
|
603 immediateFields.add(getFieldByIndex(index));
|
|
604 }
|
|
605
|
|
606 return immediateFields;
|
|
607 }
|
|
608
|
|
609 /** Return a List of SA Fields for all the java fields in this class,
|
|
610 including all inherited fields. This includes hidden
|
|
611 fields. Thus the returned list can contain fields with
|
|
612 the same name.
|
|
613 Return an empty list if there are no fields.
|
|
614 Only designed for use in a debugging system. */
|
|
615 public List getAllFields() {
|
|
616 // Contains a Field for each field in this class, including immediate
|
|
617 // fields and inherited fields.
|
|
618 List allFields = getImmediateFields();
|
|
619
|
|
620 // transitiveInterfaces contains all interfaces implemented
|
|
621 // by this class and its superclass chain with no duplicates.
|
|
622
|
|
623 ObjArray interfaces = getTransitiveInterfaces();
|
|
624 int n = (int) interfaces.getLength();
|
|
625 for (int i = 0; i < n; i++) {
|
|
626 InstanceKlass intf1 = (InstanceKlass) interfaces.getObjAt(i);
|
|
627 if (Assert.ASSERTS_ENABLED) {
|
|
628 Assert.that(intf1.isInterface(), "just checking type");
|
|
629 }
|
|
630 allFields.addAll(intf1.getImmediateFields());
|
|
631 }
|
|
632
|
|
633 // Get all fields in the superclass, recursively. But, don't
|
|
634 // include fields in interfaces implemented by superclasses;
|
|
635 // we already have all those.
|
|
636 if (!isInterface()) {
|
|
637 InstanceKlass supr;
|
|
638 if ( (supr = (InstanceKlass) getSuper()) != null) {
|
|
639 allFields.addAll(supr.getImmediateFields());
|
|
640 }
|
|
641 }
|
|
642
|
|
643 return allFields;
|
|
644 }
|
|
645
|
|
646
|
|
647 /** Return a List of SA Methods declared directly in this class/interface.
|
|
648 Return an empty list if there are none, or if this isn't a class/
|
|
649 interface.
|
|
650 */
|
|
651 public List getImmediateMethods() {
|
|
652 // Contains a Method for each method declared in this class/interface
|
|
653 // not including inherited methods.
|
|
654
|
|
655 ObjArray methods = getMethods();
|
|
656 int length = (int)methods.getLength();
|
|
657 Object[] tmp = new Object[length];
|
|
658
|
|
659 TypeArray methodOrdering = getMethodOrdering();
|
|
660 if (methodOrdering.getLength() != length) {
|
|
661 // no ordering info present
|
|
662 for (int index = 0; index < length; index++) {
|
|
663 tmp[index] = methods.getObjAt(index);
|
|
664 }
|
|
665 } else {
|
|
666 for (int index = 0; index < length; index++) {
|
|
667 int originalIndex = getMethodOrdering().getIntAt(index);
|
|
668 tmp[originalIndex] = methods.getObjAt(index);
|
|
669 }
|
|
670 }
|
|
671
|
|
672 return Arrays.asList(tmp);
|
|
673 }
|
|
674
|
|
675 /** Return a List containing an SA InstanceKlass for each
|
|
676 interface named in this class's 'implements' clause.
|
|
677 */
|
|
678 public List getDirectImplementedInterfaces() {
|
|
679 // Contains an InstanceKlass for each interface in this classes
|
|
680 // 'implements' clause.
|
|
681
|
|
682 ObjArray interfaces = getLocalInterfaces();
|
|
683 int length = (int) interfaces.getLength();
|
|
684 List directImplementedInterfaces = new ArrayList(length);
|
|
685
|
|
686 for (int index = 0; index < length; index ++) {
|
|
687 directImplementedInterfaces.add(interfaces.getObjAt(index));
|
|
688 }
|
|
689
|
|
690 return directImplementedInterfaces;
|
|
691 }
|
|
692
|
|
693
|
|
694 public long getObjectSize() {
|
|
695 long bodySize = alignObjectOffset(getVtableLen() * getHeap().getOopSize())
|
|
696 + alignObjectOffset(getItableLen() * getHeap().getOopSize())
|
|
697 + (getStaticFieldSize() + getNonstaticOopMapSize()) * getHeap().getOopSize();
|
|
698 return alignObjectSize(headerSize + bodySize);
|
|
699 }
|
|
700
|
|
701 public Klass arrayKlassImpl(boolean orNull, int n) {
|
|
702 // FIXME: in reflective system this would need to change to
|
|
703 // actually allocate
|
|
704 if (getArrayKlasses() == null) { return null; }
|
|
705 ObjArrayKlass oak = (ObjArrayKlass) getArrayKlasses();
|
|
706 if (orNull) {
|
|
707 return oak.arrayKlassOrNull(n);
|
|
708 }
|
|
709 return oak.arrayKlass(n);
|
|
710 }
|
|
711
|
|
712 public Klass arrayKlassImpl(boolean orNull) {
|
|
713 return arrayKlassImpl(orNull, 1);
|
|
714 }
|
|
715
|
|
716 public String signature() {
|
|
717 return "L" + super.signature() + ";";
|
|
718 }
|
|
719
|
|
720 /** Convenience routine taking Strings; lookup is done in
|
|
721 SymbolTable. */
|
|
722 public Method findMethod(String name, String sig) {
|
|
723 SymbolTable syms = VM.getVM().getSymbolTable();
|
|
724 Symbol nameSym = syms.probe(name);
|
|
725 Symbol sigSym = syms.probe(sig);
|
|
726 if (nameSym == null || sigSym == null) {
|
|
727 return null;
|
|
728 }
|
|
729 return findMethod(nameSym, sigSym);
|
|
730 }
|
|
731
|
|
732 /** Find method in vtable. */
|
|
733 public Method findMethod(Symbol name, Symbol sig) {
|
|
734 return findMethod(getMethods(), name, sig);
|
|
735 }
|
|
736
|
|
737 /** Breakpoint support (see methods on methodOop for details) */
|
|
738 public BreakpointInfo getBreakpoints() {
|
|
739 Address addr = getHandle().getAddressAt(Oop.getHeaderSize() + breakpoints.getOffset());
|
|
740 return (BreakpointInfo) VMObjectFactory.newObject(BreakpointInfo.class, addr);
|
|
741 }
|
|
742
|
|
743 //----------------------------------------------------------------------
|
|
744 // Internals only below this point
|
|
745 //
|
|
746
|
|
747 private void visitField(OopVisitor visitor, FieldType type, int index) {
|
|
748 Field f = newField(index);
|
|
749 if (type.isOop()) {
|
|
750 visitor.doOop((OopField) f, false);
|
|
751 return;
|
|
752 }
|
|
753 if (type.isByte()) {
|
|
754 visitor.doByte((ByteField) f, false);
|
|
755 return;
|
|
756 }
|
|
757 if (type.isChar()) {
|
|
758 visitor.doChar((CharField) f, false);
|
|
759 return;
|
|
760 }
|
|
761 if (type.isDouble()) {
|
|
762 visitor.doDouble((DoubleField) f, false);
|
|
763 return;
|
|
764 }
|
|
765 if (type.isFloat()) {
|
|
766 visitor.doFloat((FloatField) f, false);
|
|
767 return;
|
|
768 }
|
|
769 if (type.isInt()) {
|
|
770 visitor.doInt((IntField) f, false);
|
|
771 return;
|
|
772 }
|
|
773 if (type.isLong()) {
|
|
774 visitor.doLong((LongField) f, false);
|
|
775 return;
|
|
776 }
|
|
777 if (type.isShort()) {
|
|
778 visitor.doShort((ShortField) f, false);
|
|
779 return;
|
|
780 }
|
|
781 if (type.isBoolean()) {
|
|
782 visitor.doBoolean((BooleanField) f, false);
|
|
783 return;
|
|
784 }
|
|
785 }
|
|
786
|
|
787 // Creates new field from index in fields TypeArray
|
|
788 private Field newField(int index) {
|
|
789 TypeArray fields = getFields();
|
|
790 short signatureIndex = fields.getShortAt(index + SIGNATURE_INDEX_OFFSET);
|
|
791 FieldType type = new FieldType((Symbol) getConstants().getObjAt(signatureIndex));
|
|
792 if (type.isOop()) {
|
|
793 return new OopField(this, index);
|
|
794 }
|
|
795 if (type.isByte()) {
|
|
796 return new ByteField(this, index);
|
|
797 }
|
|
798 if (type.isChar()) {
|
|
799 return new CharField(this, index);
|
|
800 }
|
|
801 if (type.isDouble()) {
|
|
802 return new DoubleField(this, index);
|
|
803 }
|
|
804 if (type.isFloat()) {
|
|
805 return new FloatField(this, index);
|
|
806 }
|
|
807 if (type.isInt()) {
|
|
808 return new IntField(this, index);
|
|
809 }
|
|
810 if (type.isLong()) {
|
|
811 return new LongField(this, index);
|
|
812 }
|
|
813 if (type.isShort()) {
|
|
814 return new ShortField(this, index);
|
|
815 }
|
|
816 if (type.isBoolean()) {
|
|
817 return new BooleanField(this, index);
|
|
818 }
|
|
819 throw new RuntimeException("Illegal field type at index " + index);
|
|
820 }
|
|
821
|
|
822 private static Method findMethod(ObjArray methods, Symbol name, Symbol signature) {
|
|
823 int len = (int) methods.getLength();
|
|
824 // methods are sorted, so do binary search
|
|
825 int l = 0;
|
|
826 int h = len - 1;
|
|
827 while (l <= h) {
|
|
828 int mid = (l + h) >> 1;
|
|
829 Method m = (Method) methods.getObjAt(mid);
|
|
830 int res = m.getName().fastCompare(name);
|
|
831 if (res == 0) {
|
|
832 // found matching name; do linear search to find matching signature
|
|
833 // first, quick check for common case
|
|
834 if (m.getSignature().equals(signature)) return m;
|
|
835 // search downwards through overloaded methods
|
|
836 int i;
|
|
837 for (i = mid - 1; i >= l; i--) {
|
|
838 Method m1 = (Method) methods.getObjAt(i);
|
|
839 if (!m1.getName().equals(name)) break;
|
|
840 if (m1.getSignature().equals(signature)) return m1;
|
|
841 }
|
|
842 // search upwards
|
|
843 for (i = mid + 1; i <= h; i++) {
|
|
844 Method m1 = (Method) methods.getObjAt(i);
|
|
845 if (!m1.getName().equals(name)) break;
|
|
846 if (m1.getSignature().equals(signature)) return m1;
|
|
847 }
|
|
848 // not found
|
|
849 if (Assert.ASSERTS_ENABLED) {
|
|
850 int index = linearSearch(methods, name, signature);
|
|
851 if (index != -1) {
|
|
852 throw new DebuggerException("binary search bug: should have found entry " + index);
|
|
853 }
|
|
854 }
|
|
855 return null;
|
|
856 } else if (res < 0) {
|
|
857 l = mid + 1;
|
|
858 } else {
|
|
859 h = mid - 1;
|
|
860 }
|
|
861 }
|
|
862 if (Assert.ASSERTS_ENABLED) {
|
|
863 int index = linearSearch(methods, name, signature);
|
|
864 if (index != -1) {
|
|
865 throw new DebuggerException("binary search bug: should have found entry " + index);
|
|
866 }
|
|
867 }
|
|
868 return null;
|
|
869 }
|
|
870
|
|
871 private static int linearSearch(ObjArray methods, Symbol name, Symbol signature) {
|
|
872 int len = (int) methods.getLength();
|
|
873 for (int index = 0; index < len; index++) {
|
|
874 Method m = (Method) methods.getObjAt(index);
|
|
875 if (m.getSignature().equals(signature) && m.getName().equals(name)) {
|
|
876 return index;
|
|
877 }
|
|
878 }
|
|
879 return -1;
|
|
880 }
|
|
881 }
|