0
|
1 /*
|
|
2 * Copyright 2002-2005 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.jdi;
|
|
26
|
|
27 import java.io.*;
|
|
28
|
|
29 import com.sun.jdi.*;
|
|
30
|
|
31 import sun.jvm.hotspot.oops.Instance;
|
|
32 import sun.jvm.hotspot.oops.InstanceKlass;
|
|
33 import sun.jvm.hotspot.oops.ArrayKlass;
|
|
34 import sun.jvm.hotspot.oops.JVMDIClassStatus;
|
|
35 import sun.jvm.hotspot.oops.Klass;
|
|
36 import sun.jvm.hotspot.oops.Oop;
|
|
37 import sun.jvm.hotspot.oops.Symbol;
|
|
38 import sun.jvm.hotspot.oops.DefaultHeapVisitor;
|
|
39 import sun.jvm.hotspot.utilities.Assert;
|
|
40
|
|
41 import java.util.*;
|
|
42 import java.lang.ref.SoftReference;
|
|
43
|
|
44 public abstract class ReferenceTypeImpl extends TypeImpl
|
|
45 implements ReferenceType {
|
|
46 protected Klass saKlass; // This can be an InstanceKlass or an ArrayKlass
|
|
47 protected Symbol typeNameSymbol; // This is used in vm.classesByName to speedup search
|
|
48 private int modifiers = -1;
|
|
49 private String signature = null;
|
|
50 private SoftReference sdeRef = null;
|
|
51 private SoftReference fieldsCache;
|
|
52 private SoftReference allFieldsCache;
|
|
53 private SoftReference methodsCache;
|
|
54 private SoftReference allMethodsCache;
|
|
55 private SoftReference nestedTypesCache;
|
|
56
|
|
57 /* to mark when no info available */
|
|
58 static final SDE NO_SDE_INFO_MARK = new SDE();
|
|
59
|
|
60 protected ReferenceTypeImpl(VirtualMachine aVm, sun.jvm.hotspot.oops.Klass klass) {
|
|
61 super(aVm);
|
|
62 saKlass = klass;
|
|
63 typeNameSymbol = saKlass.getName();
|
|
64 if (Assert.ASSERTS_ENABLED) {
|
|
65 Assert.that(typeNameSymbol != null, "null type name for a Klass");
|
|
66 }
|
|
67 }
|
|
68
|
|
69 Symbol typeNameAsSymbol() {
|
|
70 return typeNameSymbol;
|
|
71 }
|
|
72
|
|
73 Method getMethodMirror(sun.jvm.hotspot.oops.Method ref) {
|
|
74 // SA creates new Method objects when they are referenced which means
|
|
75 // that the incoming object might not be the same object as on our
|
|
76 // even though it is the same method. So do an address compare by
|
|
77 // calling equals rather than just reference compare.
|
|
78 Iterator it = methods().iterator();
|
|
79 while (it.hasNext()) {
|
|
80 MethodImpl method = (MethodImpl)it.next();
|
|
81 if (ref.equals(method.ref())) {
|
|
82 return method;
|
|
83 }
|
|
84 }
|
|
85 throw new IllegalArgumentException("Invalid method id: " + ref);
|
|
86 }
|
|
87
|
|
88 public boolean equals(Object obj) {
|
|
89 if ((obj != null) && (obj instanceof ReferenceTypeImpl)) {
|
|
90 ReferenceTypeImpl other = (ReferenceTypeImpl)obj;
|
|
91 return (ref().equals(other.ref())) &&
|
|
92 (vm.equals(other.virtualMachine()));
|
|
93 } else {
|
|
94 return false;
|
|
95 }
|
|
96 }
|
|
97
|
|
98 public int hashCode() {
|
|
99 return saKlass.hashCode();
|
|
100 }
|
|
101
|
|
102 public int compareTo(Object object) {
|
|
103 /*
|
|
104 * Note that it is critical that compareTo() == 0
|
|
105 * implies that equals() == true. Otherwise, TreeSet
|
|
106 * will collapse classes.
|
|
107 *
|
|
108 * (Classes of the same name loaded by different class loaders
|
|
109 * or in different VMs must not return 0).
|
|
110 */
|
|
111 ReferenceTypeImpl other = (ReferenceTypeImpl)object;
|
|
112 int comp = name().compareTo(other.name());
|
|
113 if (comp == 0) {
|
|
114 Oop rf1 = ref();
|
|
115 Oop rf2 = other.ref();
|
|
116 // optimize for typical case: refs equal and VMs equal
|
|
117 if (rf1.equals(rf2)) {
|
|
118 // sequenceNumbers are always positive
|
|
119 comp = vm.sequenceNumber -
|
|
120 ((VirtualMachineImpl)(other.virtualMachine())).sequenceNumber;
|
|
121 } else {
|
|
122 comp = rf1.getHandle().minus(rf2.getHandle()) < 0? -1 : 1;
|
|
123 }
|
|
124 }
|
|
125 return comp;
|
|
126 }
|
|
127
|
|
128 public String signature() {
|
|
129 if (signature == null) {
|
|
130 signature = saKlass.signature();
|
|
131 }
|
|
132 return signature;
|
|
133 }
|
|
134
|
|
135 // refer to JvmtiEnv::GetClassSignature.
|
|
136 // null is returned for array klasses.
|
|
137 public String genericSignature() {
|
|
138 if (saKlass instanceof ArrayKlass) {
|
|
139 return null;
|
|
140 } else {
|
|
141 Symbol genSig = ((InstanceKlass)saKlass).getGenericSignature();
|
|
142 return (genSig != null)? genSig.asString() : null;
|
|
143 }
|
|
144 }
|
|
145
|
|
146 public ClassLoaderReference classLoader() {
|
|
147 Instance xx = (Instance)(((InstanceKlass)saKlass).getClassLoader());
|
|
148 return (ClassLoaderReferenceImpl)vm.classLoaderMirror(xx);
|
|
149 }
|
|
150
|
|
151 public boolean isPublic() {
|
|
152 return((modifiers() & VMModifiers.PUBLIC) != 0);
|
|
153 }
|
|
154
|
|
155 public boolean isProtected() {
|
|
156 return((modifiers() & VMModifiers.PROTECTED) != 0);
|
|
157 }
|
|
158
|
|
159 public boolean isPrivate() {
|
|
160 return((modifiers() & VMModifiers.PRIVATE) != 0);
|
|
161 }
|
|
162
|
|
163 public boolean isPackagePrivate() {
|
|
164 return !isPublic() && !isPrivate() && !isProtected();
|
|
165 }
|
|
166
|
|
167 public boolean isAbstract() {
|
|
168 return((modifiers() & VMModifiers.ABSTRACT) != 0);
|
|
169 }
|
|
170
|
|
171 public boolean isFinal() {
|
|
172 return((modifiers() & VMModifiers.FINAL) != 0);
|
|
173 }
|
|
174
|
|
175 public boolean isStatic() {
|
|
176 return((modifiers() & VMModifiers.STATIC) != 0);
|
|
177 }
|
|
178
|
|
179 public boolean isPrepared() {
|
|
180 return (saKlass.getClassStatus() & JVMDIClassStatus.PREPARED) != 0;
|
|
181 }
|
|
182
|
|
183 final void checkPrepared() throws ClassNotPreparedException {
|
|
184 if (! isPrepared()) {
|
|
185 throw new ClassNotPreparedException();
|
|
186 }
|
|
187 }
|
|
188
|
|
189 public boolean isVerified() {
|
|
190 return (saKlass.getClassStatus() & JVMDIClassStatus.VERIFIED) != 0;
|
|
191 }
|
|
192
|
|
193 public boolean isInitialized() {
|
|
194 return (saKlass.getClassStatus() & JVMDIClassStatus.INITIALIZED) != 0;
|
|
195 }
|
|
196
|
|
197 public boolean failedToInitialize() {
|
|
198 return (saKlass.getClassStatus() & JVMDIClassStatus.ERROR) != 0;
|
|
199 }
|
|
200
|
|
201 private boolean isThrowableBacktraceField(sun.jvm.hotspot.oops.Field fld) {
|
|
202 // refer to JvmtiEnv::GetClassFields in jvmtiEnv.cpp.
|
|
203 // We want to filter out java.lang.Throwable.backtrace (see 4446677).
|
|
204 // It contains some methodOops that aren't quite real Objects.
|
|
205 if (fld.getFieldHolder().getName().equals(vm.javaLangThrowable()) &&
|
|
206 fld.getID().getName().equals("backtrace")) {
|
|
207 return true;
|
|
208 } else {
|
|
209 return false;
|
|
210 }
|
|
211 }
|
|
212
|
|
213 public final List fields() throws ClassNotPreparedException {
|
|
214 List fields = (fieldsCache != null)? (List) fieldsCache.get() : null;
|
|
215 if (fields == null) {
|
|
216 checkPrepared();
|
|
217 if (saKlass instanceof ArrayKlass) {
|
|
218 fields = new ArrayList(0);
|
|
219 } else {
|
|
220 // Get a list of the sa Field types
|
|
221 List saFields = ((InstanceKlass)saKlass).getImmediateFields();
|
|
222
|
|
223 // Create a list of our Field types
|
|
224 int len = saFields.size();
|
|
225 fields = new ArrayList(len);
|
|
226 for (int ii = 0; ii < len; ii++) {
|
|
227 sun.jvm.hotspot.oops.Field curField = (sun.jvm.hotspot.oops.Field)saFields.get(ii);
|
|
228 if (! isThrowableBacktraceField(curField)) {
|
|
229 fields.add(new FieldImpl(vm, this, curField));
|
|
230 }
|
|
231 }
|
|
232 }
|
|
233 fields = Collections.unmodifiableList(fields);
|
|
234 fieldsCache = new SoftReference(fields);
|
|
235 }
|
|
236 return fields;
|
|
237 }
|
|
238
|
|
239 public final List allFields() throws ClassNotPreparedException {
|
|
240 List allFields = (allFieldsCache != null)? (List) allFieldsCache.get() : null;
|
|
241 if (allFields == null) {
|
|
242 checkPrepared();
|
|
243 if (saKlass instanceof ArrayKlass) {
|
|
244 // is 'length' a field of array klasses? To maintain
|
|
245 // consistency with JVMDI-JDI we return 0 size.
|
|
246 allFields = new ArrayList(0);
|
|
247 } else {
|
|
248 List saFields;
|
|
249
|
|
250 // Get a list of the sa Field types
|
|
251 saFields = ((InstanceKlass)saKlass).getAllFields();
|
|
252
|
|
253 // Create a list of our Field types
|
|
254 int len = saFields.size();
|
|
255 allFields = new ArrayList(len);
|
|
256 for (int ii = 0; ii < len; ii++) {
|
|
257 sun.jvm.hotspot.oops.Field curField = (sun.jvm.hotspot.oops.Field)saFields.get(ii);
|
|
258 if (! isThrowableBacktraceField(curField)) {
|
|
259 allFields.add(new FieldImpl(vm, vm.referenceType(curField.getFieldHolder()), curField));
|
|
260 }
|
|
261 }
|
|
262 }
|
|
263 allFields = Collections.unmodifiableList(allFields);
|
|
264 allFieldsCache = new SoftReference(allFields);
|
|
265 }
|
|
266 return allFields;
|
|
267 }
|
|
268
|
|
269 abstract List inheritedTypes();
|
|
270
|
|
271 void addVisibleFields(List visibleList, Map visibleTable, List ambiguousNames) {
|
|
272 List list = visibleFields();
|
|
273 Iterator iter = list.iterator();
|
|
274 while (iter.hasNext()) {
|
|
275 Field field = (Field)iter.next();
|
|
276 String name = field.name();
|
|
277 if (!ambiguousNames.contains(name)) {
|
|
278 Field duplicate = (Field)visibleTable.get(name);
|
|
279 if (duplicate == null) {
|
|
280 visibleList.add(field);
|
|
281 visibleTable.put(name, field);
|
|
282 } else if (!field.equals(duplicate)) {
|
|
283 ambiguousNames.add(name);
|
|
284 visibleTable.remove(name);
|
|
285 visibleList.remove(duplicate);
|
|
286 } else {
|
|
287 // identical field from two branches; do nothing
|
|
288 }
|
|
289 }
|
|
290 }
|
|
291 }
|
|
292
|
|
293 public final List visibleFields() throws ClassNotPreparedException {
|
|
294 checkPrepared();
|
|
295 /*
|
|
296 * Maintain two different collections of visible fields. The
|
|
297 * list maintains a reasonable order for return. The
|
|
298 * hash map provides an efficient way to lookup visible fields
|
|
299 * by name, important for finding hidden or ambiguous fields.
|
|
300 */
|
|
301 List visibleList = new ArrayList();
|
|
302 Map visibleTable = new HashMap();
|
|
303
|
|
304 /* Track fields removed from above collection due to ambiguity */
|
|
305 List ambiguousNames = new ArrayList();
|
|
306
|
|
307 /* Add inherited, visible fields */
|
|
308 List types = inheritedTypes();
|
|
309 Iterator iter = types.iterator();
|
|
310 while (iter.hasNext()) {
|
|
311 /*
|
|
312 * TO DO: Be defensive and check for cyclic interface inheritance
|
|
313 */
|
|
314 ReferenceTypeImpl type = (ReferenceTypeImpl)iter.next();
|
|
315 type.addVisibleFields(visibleList, visibleTable, ambiguousNames);
|
|
316 }
|
|
317
|
|
318 /*
|
|
319 * Insert fields from this type, removing any inherited fields they
|
|
320 * hide.
|
|
321 */
|
|
322 List retList = new ArrayList(fields());
|
|
323 iter = retList.iterator();
|
|
324 while (iter.hasNext()) {
|
|
325 Field field = (Field)iter.next();
|
|
326 Field hidden = (Field)visibleTable.get(field.name());
|
|
327 if (hidden != null) {
|
|
328 visibleList.remove(hidden);
|
|
329 }
|
|
330 }
|
|
331 retList.addAll(visibleList);
|
|
332 return retList;
|
|
333 }
|
|
334
|
|
335 public final Field fieldByName(String fieldName) throws ClassNotPreparedException {
|
|
336 java.util.List searchList;
|
|
337 Field f;
|
|
338
|
|
339 // visibleFields calls checkPrepared
|
|
340 searchList = visibleFields();
|
|
341
|
|
342 for (int i=0; i<searchList.size(); i++) {
|
|
343 f = (Field)searchList.get(i);
|
|
344
|
|
345 if (f.name().equals(fieldName)) {
|
|
346 return f;
|
|
347 }
|
|
348 }
|
|
349 //throw new NoSuchFieldException("Field '" + fieldName + "' not found in " + name());
|
|
350 return null;
|
|
351 }
|
|
352
|
|
353 public final List methods() throws ClassNotPreparedException {
|
|
354 List methods = (methodsCache != null)? (List) methodsCache.get() : null;
|
|
355 if (methods == null) {
|
|
356 checkPrepared();
|
|
357 if (saKlass instanceof ArrayKlass) {
|
|
358 methods = new ArrayList(0);
|
|
359 } else {
|
|
360 List saMethods;
|
|
361 // Get a list of the SA Method types
|
|
362 saMethods = ((InstanceKlass)saKlass).getImmediateMethods();
|
|
363
|
|
364 // Create a list of our MethodImpl types
|
|
365 int len = saMethods.size();
|
|
366 methods = new ArrayList(len);
|
|
367 for (int ii = 0; ii < len; ii++) {
|
|
368 methods.add(MethodImpl.createMethodImpl(vm, this, (sun.jvm.hotspot.oops.Method)saMethods.get(ii)));
|
|
369 }
|
|
370 }
|
|
371 methods = Collections.unmodifiableList(methods);
|
|
372 methodsCache = new SoftReference(methods);
|
|
373 }
|
|
374 return methods;
|
|
375 }
|
|
376
|
|
377 abstract List getAllMethods();
|
|
378 public final List allMethods() throws ClassNotPreparedException {
|
|
379 List allMethods = (allMethodsCache != null)? (List) allMethodsCache.get() : null;
|
|
380 if (allMethods == null) {
|
|
381 checkPrepared();
|
|
382 allMethods = Collections.unmodifiableList(getAllMethods());
|
|
383 allMethodsCache = new SoftReference(allMethods);
|
|
384 }
|
|
385 return allMethods;
|
|
386 }
|
|
387
|
|
388 /*
|
|
389 * Utility method used by subclasses to build lists of visible
|
|
390 * methods.
|
|
391 */
|
|
392 void addToMethodMap(Map methodMap, List methodList) {
|
|
393 Iterator iter = methodList.iterator();
|
|
394 while (iter.hasNext()) {
|
|
395 Method method = (Method)iter.next();
|
|
396 methodMap.put(method.name().concat(method.signature()), method);
|
|
397 }
|
|
398 }
|
|
399
|
|
400 abstract void addVisibleMethods(Map methodMap);
|
|
401 public final List visibleMethods() throws ClassNotPreparedException {
|
|
402 checkPrepared();
|
|
403 /*
|
|
404 * Build a collection of all visible methods. The hash
|
|
405 * map allows us to do this efficiently by keying on the
|
|
406 * concatenation of name and signature.
|
|
407 */
|
|
408 //System.out.println("jj: RTI: Calling addVisibleMethods for:" + this);
|
|
409 Map map = new HashMap();
|
|
410 addVisibleMethods(map);
|
|
411
|
|
412 /*
|
|
413 * ... but the hash map destroys order. Methods should be
|
|
414 * returned in a sensible order, as they are in allMethods().
|
|
415 * So, start over with allMethods() and use the hash map
|
|
416 * to filter that ordered collection.
|
|
417 */
|
|
418 //System.out.println("jj: RTI: Calling allMethods for:" + this);
|
|
419
|
|
420 List list = new ArrayList(allMethods());
|
|
421 //System.out.println("jj: allMethods = " + jjstr(list));
|
|
422 //System.out.println("jj: map = " + map.toString());
|
|
423 //System.out.println("jj: map = " + jjstr(map.values()));
|
|
424 list.retainAll(map.values());
|
|
425 //System.out.println("jj: map = " + jjstr(list));
|
|
426 //System.exit(0);
|
|
427 return list;
|
|
428 }
|
|
429
|
|
430 static Object prev;
|
|
431
|
|
432 static public String jjstr(Collection cc) {
|
|
433 StringBuffer buf = new StringBuffer();
|
|
434 buf.append("[");
|
|
435 Iterator i = cc.iterator();
|
|
436 boolean hasNext = i.hasNext();
|
|
437 while (hasNext) {
|
|
438 Object o = i.next();
|
|
439 if (prev == null) {
|
|
440 prev = o;
|
|
441 } else {
|
|
442 System.out.println("prev == curr?" + prev.equals(o));
|
|
443 System.out.println("prev == curr?" + (prev == o));
|
|
444 }
|
|
445 buf.append( o + "@" + o.hashCode());
|
|
446 //buf.append( ((Object)o).toString());
|
|
447 hasNext = i.hasNext();
|
|
448 if (hasNext)
|
|
449 buf.append(", ");
|
|
450 }
|
|
451
|
|
452 buf.append("]");
|
|
453 return buf.toString();
|
|
454 }
|
|
455
|
|
456 public final List methodsByName(String name) throws ClassNotPreparedException {
|
|
457 // visibleMethods calls checkPrepared
|
|
458 List methods = visibleMethods();
|
|
459 ArrayList retList = new ArrayList(methods.size());
|
|
460 Iterator iter = methods.iterator();
|
|
461 while (iter.hasNext()) {
|
|
462 Method candidate = (Method)iter.next();
|
|
463 if (candidate.name().equals(name)) {
|
|
464 retList.add(candidate);
|
|
465 }
|
|
466 }
|
|
467 retList.trimToSize();
|
|
468 return retList;
|
|
469 }
|
|
470
|
|
471 public final List methodsByName(String name, String signature) throws ClassNotPreparedException {
|
|
472 // visibleMethods calls checkPrepared
|
|
473 List methods = visibleMethods();
|
|
474 ArrayList retList = new ArrayList(methods.size());
|
|
475 Iterator iter = methods.iterator();
|
|
476 while (iter.hasNext()) {
|
|
477 Method candidate = (Method)iter.next();
|
|
478 if (candidate.name().equals(name) &&
|
|
479 candidate.signature().equals(signature)) {
|
|
480 retList.add(candidate);
|
|
481 }
|
|
482 }
|
|
483 retList.trimToSize();
|
|
484 return retList;
|
|
485 }
|
|
486
|
|
487
|
|
488 List getInterfaces() {
|
|
489 List myInterfaces;
|
|
490 if (saKlass instanceof ArrayKlass) {
|
|
491 // Actually, JLS says arrays implement Cloneable and Serializable
|
|
492 // But, JVMDI-JDI just returns 0 interfaces for arrays. We follow
|
|
493 // the same for consistency.
|
|
494 myInterfaces = new ArrayList(0);
|
|
495 } else {
|
|
496 // Get a list of the sa InstanceKlass types
|
|
497 List saInterfaces = ((InstanceKlass)saKlass).getDirectImplementedInterfaces();
|
|
498
|
|
499 // Create a list of our InterfaceTypes
|
|
500 int len = saInterfaces.size();
|
|
501 myInterfaces = new ArrayList(len);
|
|
502 for (int ii = 0; ii < len; ii++) {
|
|
503 myInterfaces.add(new InterfaceTypeImpl(vm, (InstanceKlass)saInterfaces.get(ii)));
|
|
504 }
|
|
505 }
|
|
506 return myInterfaces;
|
|
507 }
|
|
508
|
|
509 public final List nestedTypes() {
|
|
510 List nestedTypes = (nestedTypesCache != null)? (List) nestedTypesCache.get() : null;
|
|
511 if (nestedTypes == null) {
|
|
512 if (saKlass instanceof ArrayKlass) {
|
|
513 nestedTypes = new ArrayList(0);
|
|
514 } else {
|
|
515 ClassLoaderReference cl = classLoader();
|
|
516 List classes = null;
|
|
517 if (cl != null) {
|
|
518 classes = cl.visibleClasses();
|
|
519 } else {
|
|
520 classes = vm.bootstrapClasses();
|
|
521 }
|
|
522 nestedTypes = new ArrayList();
|
|
523 Iterator iter = classes.iterator();
|
|
524 while (iter.hasNext()) {
|
|
525 ReferenceTypeImpl refType = (ReferenceTypeImpl)iter.next();
|
|
526 Symbol candidateName = refType.ref().getName();
|
|
527 if (((InstanceKlass)saKlass).isInnerOrLocalClassName(candidateName)) {
|
|
528 nestedTypes.add(refType);
|
|
529 }
|
|
530 }
|
|
531 }
|
|
532 nestedTypes = Collections.unmodifiableList(nestedTypes);
|
|
533 nestedTypesCache = new SoftReference(nestedTypes);
|
|
534 }
|
|
535 return nestedTypes;
|
|
536 }
|
|
537
|
|
538 public Value getValue(Field sig) {
|
|
539 List list = new ArrayList(1);
|
|
540 list.add(sig);
|
|
541 Map map = getValues(list);
|
|
542 return(Value)map.get(sig);
|
|
543 }
|
|
544
|
|
545 /**
|
|
546 * Returns a map of field values
|
|
547 */
|
|
548 public Map getValues(List theFields) {
|
|
549 //validateMirrors();
|
|
550 int size = theFields.size();
|
|
551 Map map = new HashMap(size);
|
|
552 for (int ii=0; ii<size; ii++) {
|
|
553 FieldImpl fieldImpl = (FieldImpl)theFields.get(ii);
|
|
554
|
|
555 validateFieldAccess(fieldImpl);
|
|
556 // Do more validation specific to ReferenceType field getting
|
|
557 if (!fieldImpl.isStatic()) {
|
|
558 throw new IllegalArgumentException(
|
|
559 "Attempt to use non-static field with ReferenceType: " +
|
|
560 fieldImpl.name());
|
|
561 }
|
|
562 map.put(fieldImpl, fieldImpl.getValue());
|
|
563 }
|
|
564 return map;
|
|
565 }
|
|
566
|
|
567 void validateFieldAccess(Field field) {
|
|
568 /*
|
|
569 * Field must be in this object's class, a superclass, or
|
|
570 * implemented interface
|
|
571 */
|
|
572 ReferenceTypeImpl declType = (ReferenceTypeImpl)field.declaringType();
|
|
573 if (!declType.isAssignableFrom(this)) {
|
|
574 throw new IllegalArgumentException("Invalid field");
|
|
575 }
|
|
576 }
|
|
577
|
|
578 public ClassObjectReference classObject() {
|
|
579 return vm.classObjectMirror(ref().getJavaMirror());
|
|
580 }
|
|
581
|
|
582 SDE.Stratum stratum(String stratumID) {
|
|
583 SDE sde = sourceDebugExtensionInfo();
|
|
584 if (!sde.isValid()) {
|
|
585 sde = NO_SDE_INFO_MARK;
|
|
586 }
|
|
587 return sde.stratum(stratumID);
|
|
588 }
|
|
589
|
|
590 public String sourceName() throws AbsentInformationException {
|
|
591 return (String)(sourceNames(vm.getDefaultStratum()).get(0));
|
|
592 }
|
|
593
|
|
594 public List sourceNames(String stratumID)
|
|
595 throws AbsentInformationException {
|
|
596 SDE.Stratum stratum = stratum(stratumID);
|
|
597 if (stratum.isJava()) {
|
|
598 List result = new ArrayList(1);
|
|
599 result.add(baseSourceName());
|
|
600 return result;
|
|
601 }
|
|
602 return stratum.sourceNames(this);
|
|
603 }
|
|
604
|
|
605 public List sourcePaths(String stratumID)
|
|
606 throws AbsentInformationException {
|
|
607 SDE.Stratum stratum = stratum(stratumID);
|
|
608 if (stratum.isJava()) {
|
|
609 List result = new ArrayList(1);
|
|
610 result.add(baseSourceDir() + baseSourceName());
|
|
611 return result;
|
|
612 }
|
|
613 return stratum.sourcePaths(this);
|
|
614 }
|
|
615
|
|
616 String baseSourceName() throws AbsentInformationException {
|
|
617 if (saKlass instanceof ArrayKlass) {
|
|
618 throw new AbsentInformationException();
|
|
619 }
|
|
620 Symbol sym = ((InstanceKlass)saKlass).getSourceFileName();
|
|
621 if (sym != null) {
|
|
622 return sym.asString();
|
|
623 } else {
|
|
624 throw new AbsentInformationException();
|
|
625 }
|
|
626 }
|
|
627
|
|
628 String baseSourcePath() throws AbsentInformationException {
|
|
629 return baseSourceDir() + baseSourceName();
|
|
630 }
|
|
631
|
|
632 String baseSourceDir() {
|
|
633 String typeName = name();
|
|
634 StringBuffer sb = new StringBuffer(typeName.length() + 10);
|
|
635 int index = 0;
|
|
636 int nextIndex;
|
|
637
|
|
638 while ((nextIndex = typeName.indexOf('.', index)) > 0) {
|
|
639 sb.append(typeName.substring(index, nextIndex));
|
|
640 sb.append(java.io.File.separatorChar);
|
|
641 index = nextIndex + 1;
|
|
642 }
|
|
643 return sb.toString();
|
|
644 }
|
|
645
|
|
646 public String sourceDebugExtension()
|
|
647 throws AbsentInformationException {
|
|
648 if (!vm.canGetSourceDebugExtension()) {
|
|
649 throw new UnsupportedOperationException();
|
|
650 }
|
|
651 SDE sde = sourceDebugExtensionInfo();
|
|
652 if (sde == NO_SDE_INFO_MARK) {
|
|
653 throw new AbsentInformationException();
|
|
654 }
|
|
655 return sde.sourceDebugExtension;
|
|
656 }
|
|
657
|
|
658 private SDE sourceDebugExtensionInfo() {
|
|
659 if (!vm.canGetSourceDebugExtension()) {
|
|
660 return NO_SDE_INFO_MARK;
|
|
661 }
|
|
662 SDE sde = null;
|
|
663 sde = (sdeRef == null) ? null : (SDE)sdeRef.get();
|
|
664 if (sde == null) {
|
|
665 String extension = null;
|
|
666 if (saKlass instanceof InstanceKlass) {
|
|
667 Symbol sdeSym = ((InstanceKlass)saKlass).getSourceDebugExtension();
|
|
668 extension = (sdeSym != null)? sdeSym.asString() : null;
|
|
669 }
|
|
670 if (extension == null) {
|
|
671 sde = NO_SDE_INFO_MARK;
|
|
672 } else {
|
|
673 sde = new SDE(extension);
|
|
674 }
|
|
675 sdeRef = new SoftReference(sde);
|
|
676 }
|
|
677 return sde;
|
|
678 }
|
|
679
|
|
680 public List availableStrata() {
|
|
681 SDE sde = sourceDebugExtensionInfo();
|
|
682 if (sde.isValid()) {
|
|
683 return sde.availableStrata();
|
|
684 } else {
|
|
685 List strata = new ArrayList();
|
|
686 strata.add(SDE.BASE_STRATUM_NAME);
|
|
687 return strata;
|
|
688 }
|
|
689 }
|
|
690
|
|
691 /**
|
|
692 * Always returns non-null stratumID
|
|
693 */
|
|
694 public String defaultStratum() {
|
|
695 SDE sdei = sourceDebugExtensionInfo();
|
|
696 if (sdei.isValid()) {
|
|
697 return sdei.defaultStratumId;
|
|
698 } else {
|
|
699 return SDE.BASE_STRATUM_NAME;
|
|
700 }
|
|
701 }
|
|
702
|
|
703 public final int modifiers() {
|
|
704 if (modifiers == -1) {
|
|
705 modifiers = getModifiers();
|
|
706 }
|
|
707 return modifiers;
|
|
708 }
|
|
709
|
|
710 // new method since 1.6.
|
|
711 // Real body will be supplied later.
|
|
712 public List instances(long maxInstances) {
|
|
713 if (!vm.canGetInstanceInfo()) {
|
|
714 throw new UnsupportedOperationException(
|
|
715 "target does not support getting instances");
|
|
716 }
|
|
717
|
|
718 if (maxInstances < 0) {
|
|
719 throw new IllegalArgumentException("maxInstances is less than zero: "
|
|
720 + maxInstances);
|
|
721 }
|
|
722
|
|
723 final List objects = new ArrayList(0);
|
|
724 if (isAbstract() || (this instanceof InterfaceType)) {
|
|
725 return objects;
|
|
726 }
|
|
727
|
|
728 final Klass givenKls = this.ref();
|
|
729 final long max = maxInstances;
|
|
730 vm.saObjectHeap().iterate(new DefaultHeapVisitor() {
|
|
731 private long instCount=0;
|
|
732 public boolean doObj(Oop oop) {
|
|
733 if (givenKls.equals(oop.getKlass())) {
|
|
734 objects.add(vm.objectMirror(oop));
|
|
735 instCount++;
|
|
736 }
|
|
737 if (max > 0 && instCount >= max) {
|
|
738 return true;
|
|
739 }
|
|
740 return false;
|
|
741 }
|
|
742 });
|
|
743 return objects;
|
|
744 }
|
|
745
|
|
746 int getModifiers() {
|
|
747 return (int) saKlass.getClassModifiers();
|
|
748 }
|
|
749
|
|
750 public List allLineLocations()
|
|
751 throws AbsentInformationException {
|
|
752 return allLineLocations(vm.getDefaultStratum(), null);
|
|
753 }
|
|
754
|
|
755 public List allLineLocations(String stratumID, String sourceName)
|
|
756 throws AbsentInformationException {
|
|
757 checkPrepared();
|
|
758 boolean someAbsent = false; // A method that should have info, didn't
|
|
759 SDE.Stratum stratum = stratum(stratumID);
|
|
760 List list = new ArrayList(); // location list
|
|
761
|
|
762 for (Iterator iter = methods().iterator(); iter.hasNext(); ) {
|
|
763 MethodImpl method = (MethodImpl)iter.next();
|
|
764 try {
|
|
765 list.addAll(
|
|
766 method.allLineLocations(stratum.id(), sourceName));
|
|
767 } catch(AbsentInformationException exc) {
|
|
768 someAbsent = true;
|
|
769 }
|
|
770 }
|
|
771
|
|
772 // If we retrieved no line info, and at least one of the methods
|
|
773 // should have had some (as determined by an
|
|
774 // AbsentInformationException being thrown) then we rethrow
|
|
775 // the AbsentInformationException.
|
|
776 if (someAbsent && list.size() == 0) {
|
|
777 throw new AbsentInformationException();
|
|
778 }
|
|
779 return list;
|
|
780 }
|
|
781
|
|
782 public List locationsOfLine(int lineNumber)
|
|
783 throws AbsentInformationException {
|
|
784 return locationsOfLine(vm.getDefaultStratum(),
|
|
785 null,
|
|
786 lineNumber);
|
|
787 }
|
|
788
|
|
789 public List locationsOfLine(String stratumID,
|
|
790 String sourceName,
|
|
791 int lineNumber)
|
|
792 throws AbsentInformationException {
|
|
793 checkPrepared();
|
|
794 // A method that should have info, didn't
|
|
795 boolean someAbsent = false;
|
|
796 // A method that should have info, did
|
|
797 boolean somePresent = false;
|
|
798 List methods = methods();
|
|
799 SDE.Stratum stratum = stratum(stratumID);
|
|
800
|
|
801 List list = new ArrayList();
|
|
802
|
|
803 Iterator iter = methods.iterator();
|
|
804 while(iter.hasNext()) {
|
|
805 MethodImpl method = (MethodImpl)iter.next();
|
|
806 // eliminate native and abstract to eliminate
|
|
807 // false positives
|
|
808 if (!method.isAbstract() &&
|
|
809 !method.isNative()) {
|
|
810 try {
|
|
811 list.addAll(
|
|
812 method.locationsOfLine(stratum.id(),
|
|
813 sourceName,
|
|
814 lineNumber));
|
|
815 somePresent = true;
|
|
816 } catch(AbsentInformationException exc) {
|
|
817 someAbsent = true;
|
|
818 }
|
|
819 }
|
|
820 }
|
|
821 if (someAbsent && !somePresent) {
|
|
822 throw new AbsentInformationException();
|
|
823 }
|
|
824 return list;
|
|
825 }
|
|
826
|
|
827 Klass ref() {
|
|
828 return saKlass;
|
|
829 }
|
|
830
|
|
831
|
|
832 /*
|
|
833 * Return true if an instance of this type
|
|
834 * can be assigned to a variable of the given type
|
|
835 */
|
|
836 abstract boolean isAssignableTo(ReferenceType type);
|
|
837
|
|
838 boolean isAssignableFrom(ReferenceType type) {
|
|
839 return ((ReferenceTypeImpl)type).isAssignableTo(this);
|
|
840 }
|
|
841
|
|
842 boolean isAssignableFrom(ObjectReference object) {
|
|
843 return object == null ||
|
|
844 isAssignableFrom(object.referenceType());
|
|
845 }
|
|
846
|
|
847 int indexOf(Method method) {
|
|
848 // Make sure they're all here - the obsolete method
|
|
849 // won't be found and so will have index -1
|
|
850 return methods().indexOf(method);
|
|
851 }
|
|
852
|
|
853 int indexOf(Field field) {
|
|
854 // Make sure they're all here
|
|
855 return fields().indexOf(field);
|
|
856 }
|
|
857
|
|
858 private static boolean isPrimitiveArray(String signature) {
|
|
859 int i = signature.lastIndexOf('[');
|
|
860 /*
|
|
861 * TO DO: Centralize JNI signature knowledge.
|
|
862 *
|
|
863 * Ref:
|
|
864 * jdk1.4/doc/guide/jpda/jdi/com/sun/jdi/doc-files/signature.html
|
|
865 */
|
|
866 boolean isPA;
|
|
867 if (i < 0) {
|
|
868 isPA = false;
|
|
869 } else {
|
|
870 char c = signature.charAt(i + 1);
|
|
871 isPA = (c != 'L');
|
|
872 }
|
|
873 return isPA;
|
|
874 }
|
|
875
|
|
876 Type findType(String signature) throws ClassNotLoadedException {
|
|
877 Type type;
|
|
878 if (signature.length() == 1) {
|
|
879 /* OTI FIX: Must be a primitive type or the void type */
|
|
880 char sig = signature.charAt(0);
|
|
881 if (sig == 'V') {
|
|
882 type = vm.theVoidType();
|
|
883 } else {
|
|
884 type = vm.primitiveTypeMirror(sig);
|
|
885 }
|
|
886 } else {
|
|
887 // Must be a reference type.
|
|
888 ClassLoaderReferenceImpl loader =
|
|
889 (ClassLoaderReferenceImpl)classLoader();
|
|
890 if ((loader == null) ||
|
|
891 (isPrimitiveArray(signature)) //Work around 4450091
|
|
892 ) {
|
|
893 // Caller wants type of boot class field
|
|
894 type = vm.findBootType(signature);
|
|
895 } else {
|
|
896 // Caller wants type of non-boot class field
|
|
897 type = loader.findType(signature);
|
|
898 }
|
|
899 }
|
|
900 return type;
|
|
901 }
|
|
902
|
|
903 String loaderString() {
|
|
904 if (classLoader() != null) {
|
|
905 return "loaded by " + classLoader().toString();
|
|
906 } else {
|
|
907 return "loaded by bootstrap loader";
|
|
908 }
|
|
909 }
|
|
910
|
|
911 long uniqueID() {
|
|
912 return vm.getAddressValue(ref());
|
|
913 }
|
|
914
|
|
915 // new method since 1.6
|
|
916 public int majorVersion() {
|
|
917 if (!vm.canGetClassFileVersion()) {
|
|
918 throw new UnsupportedOperationException("Cannot get class file version");
|
|
919 }
|
|
920 return (int)((InstanceKlass)saKlass).majorVersion();
|
|
921 }
|
|
922
|
|
923 // new method since 1.6
|
|
924 public int minorVersion() {
|
|
925 if (!vm.canGetClassFileVersion()) {
|
|
926 throw new UnsupportedOperationException("Cannot get class file version");
|
|
927 }
|
|
928 return (int)((InstanceKlass)saKlass).minorVersion();
|
|
929 }
|
|
930
|
|
931 // new method since 1.6
|
|
932 public int constantPoolCount() {
|
|
933 if (!vm.canGetConstantPool()) {
|
|
934 throw new UnsupportedOperationException("Cannot get constant pool");
|
|
935 }
|
|
936 if (saKlass instanceof ArrayKlass) {
|
|
937 return 0;
|
|
938 } else {
|
|
939 return (int)((InstanceKlass)saKlass).getConstants().getLength();
|
|
940 }
|
|
941 }
|
|
942
|
|
943 // new method since 1.6
|
|
944 public byte[] constantPool() {
|
|
945 if (!vm.canGetConstantPool()) {
|
|
946 throw new UnsupportedOperationException("Cannot get constant pool");
|
|
947 }
|
|
948 if (this instanceof ArrayType || this instanceof PrimitiveType) {
|
|
949 byte bytes[] = new byte[0];
|
|
950 return bytes;
|
|
951 } else {
|
|
952 ByteArrayOutputStream bs = new ByteArrayOutputStream();
|
|
953 try {
|
|
954 ((InstanceKlass)saKlass).getConstants().writeBytes(bs);
|
|
955 } catch (IOException ex) {
|
|
956 ex.printStackTrace();
|
|
957 byte bytes[] = new byte[0];
|
|
958 return bytes;
|
|
959 }
|
|
960 return bs.toByteArray();
|
|
961 }
|
|
962 }
|
|
963 }
|