Mercurial > hg > truffle
annotate agent/src/share/classes/sun/jvm/hotspot/jdi/ReferenceTypeImpl.java @ 2245:638119ce7cfd
7009309: JSR 292: compiler/6991596/Test6991596.java crashes on fastdebug JDK7/b122
Reviewed-by: kvn, never
author | twisti |
---|---|
date | Tue, 01 Feb 2011 03:38:44 -0800 |
parents | c18cbe5936b8 |
children | 37be97a58393 |
rev | line source |
---|---|
0 | 1 /* |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
2 * Copyright (c) 2002, 2005, Oracle and/or its affiliates. All rights reserved. |
0 | 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 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
21 * questions. |
0 | 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 } |