History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/com/sun/tools/jdi/ReferenceTypeImpl.java (1 of 18352 files). Show all

Unified · Split

java/pkg/com/sun/tools/jdi/ReferenceTypeImpl.java+1170−0
@@ -0,0 +1,1170 @@
1/*
2 * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.tools.jdi;
27
28import com.sun.jdi.*;
29
30import java.util.*;
31import java.lang.ref.SoftReference;
32
33public abstract class ReferenceTypeImpl extends TypeImpl
34implements ReferenceType {
35 protected long ref;
36 private String signature = null;
37 private String genericSignature = null;
38 private boolean genericSignatureGotten = false;
39 private String baseSourceName = null;
40 private String baseSourceDir = null;
41 private String baseSourcePath = null;
42 protected int modifiers = -1;
43 private SoftReference<List<Field>> fieldsRef = null;
44 private SoftReference<List<Method>> methodsRef = null;
45 private SoftReference<SDE> sdeRef = null;
46
47 private boolean isClassLoaderCached = false;
48 private ClassLoaderReference classLoader = null;
49 private ClassObjectReference classObject = null;
50
51 private int status = 0;
52 private boolean isPrepared = false;
53
54
55 private boolean versionNumberGotten = false;
56 private int majorVersion;
57 private int minorVersion;
58
59 private boolean constantPoolInfoGotten = false;
60 private int constanPoolCount;
61 private byte[] constantPoolBytes;
62 private SoftReference<byte[]> constantPoolBytesRef = null;
63
64 /* to mark a SourceFile request that returned a genuine JDWP.Error.ABSENT_INFORMATION */
65 private static final String ABSENT_BASE_SOURCE_NAME = "**ABSENT_BASE_SOURCE_NAME**";
66
67 /* to mark when no info available */
68 static final SDE NO_SDE_INFO_MARK = new SDE();
69
70 // bits set when initialization was attempted (succeeded or failed)
71 private static final int INITIALIZED_OR_FAILED =
72 JDWP.ClassStatus.INITIALIZED | JDWP.ClassStatus.ERROR;
73
74
75 protected ReferenceTypeImpl(VirtualMachine aVm, long aRef) {
76 super(aVm);
77 ref = aRef;
78 genericSignatureGotten = false;
79 }
80
81 void noticeRedefineClass() {
82 //Invalidate information previously fetched and cached.
83 //These will be refreshed later on demand.
84 baseSourceName = null;
85 baseSourcePath = null;
86 modifiers = -1;
87 fieldsRef = null;
88 methodsRef = null;
89 sdeRef = null;
90 versionNumberGotten = false;
91 constantPoolInfoGotten = false;
92 }
93
94 Method getMethodMirror(long ref) {
95 if (ref == 0) {
96 // obsolete method
97 return new ObsoleteMethodImpl(vm, this);
98 }
99 // Fetch all methods for the class, check performance impact
100 // Needs no synchronization now, since methods() returns
101 // unmodifiable local data
102 Iterator it = methods().iterator();
103 while (it.hasNext()) {
104 MethodImpl method = (MethodImpl)it.next();
105 if (method.ref() == ref) {
106 return method;
107 }
108 }
109 throw new IllegalArgumentException("Invalid method id: " + ref);
110 }
111
112 Field getFieldMirror(long ref) {
113 // Fetch all fields for the class, check performance impact
114 // Needs no synchronization now, since fields() returns
115 // unmodifiable local data
116 Iterator it = fields().iterator();
117 while (it.hasNext()) {
118 FieldImpl field = (FieldImpl)it.next();
119 if (field.ref() == ref) {
120 return field;
121 }
122 }
123 throw new IllegalArgumentException("Invalid field id: " + ref);
124 }
125
126 public boolean equals(Object obj) {
127 if ((obj != null) && (obj instanceof ReferenceTypeImpl)) {
128 ReferenceTypeImpl other = (ReferenceTypeImpl)obj;
129 return (ref() == other.ref()) &&
130 (vm.equals(other.virtualMachine()));
131 } else {
132 return false;
133 }
134 }
135
136 public int hashCode() {
137 return(int)ref();
138 }
139
140 public int compareTo(ReferenceType object) {
141 /*
142 * Note that it is critical that compareTo() == 0
143 * implies that equals() == true. Otherwise, TreeSet
144 * will collapse classes.
145 *
146 * (Classes of the same name loaded by different class loaders
147 * or in different VMs must not return 0).
148 */
149 ReferenceTypeImpl other = (ReferenceTypeImpl)object;
150 int comp = name().compareTo(other.name());
151 if (comp == 0) {
152 long rf1 = ref();
153 long rf2 = other.ref();
154 // optimize for typical case: refs equal and VMs equal
155 if (rf1 == rf2) {
156 // sequenceNumbers are always positive
157 comp = vm.sequenceNumber -
158 ((VirtualMachineImpl)(other.virtualMachine())).sequenceNumber;
159 } else {
160 comp = (rf1 < rf2)? -1 : 1;
161 }
162 }
163 return comp;
164 }
165
166 public String signature() {
167 if (signature == null) {
168 // Does not need synchronization, since worst-case
169 // static info is fetched twice
170 if (vm.canGet1_5LanguageFeatures()) {
171 /*
172 * we might as well get both the signature and the
173 * generic signature.
174 */
175 genericSignature();
176 } else {
177 try {
178 signature = JDWP.ReferenceType.Signature.
179 process(vm, this).signature;
180 } catch (JDWPException exc) {
181 throw exc.toJDIException();
182 }
183 }
184 }
185 return signature;
186 }
187
188 public String genericSignature() {
189 // This gets both the signature and the generic signature
190 if (vm.canGet1_5LanguageFeatures() && !genericSignatureGotten) {
191 // Does not need synchronization, since worst-case
192 // static info is fetched twice
193 JDWP.ReferenceType.SignatureWithGeneric result;
194 try {
195 result = JDWP.ReferenceType.SignatureWithGeneric.
196 process(vm, this);
197 } catch (JDWPException exc) {
198 throw exc.toJDIException();
199 }
200 signature = result.signature;
201 setGenericSignature(result.genericSignature);
202 }
203 return genericSignature;
204 }
205
206 public ClassLoaderReference classLoader() {
207 if (!isClassLoaderCached) {
208 // Does not need synchronization, since worst-case
209 // static info is fetched twice
210 try {
211 classLoader = (ClassLoaderReference)
212 JDWP.ReferenceType.ClassLoader.
213 process(vm, this).classLoader;
214 isClassLoaderCached = true;
215 } catch (JDWPException exc) {
216 throw exc.toJDIException();
217 }
218 }
219 return classLoader;
220 }
221
222 public boolean isPublic() {
223 if (modifiers == -1)
224 getModifiers();
225
226 return((modifiers & VMModifiers.PUBLIC) > 0);
227 }
228
229 public boolean isProtected() {
230 if (modifiers == -1)
231 getModifiers();
232
233 return((modifiers & VMModifiers.PROTECTED) > 0);
234 }
235
236 public boolean isPrivate() {
237 if (modifiers == -1)
238 getModifiers();
239
240 return((modifiers & VMModifiers.PRIVATE) > 0);
241 }
242
243 public boolean isPackagePrivate() {
244 return !isPublic() && !isPrivate() && !isProtected();
245 }
246
247 public boolean isAbstract() {
248 if (modifiers == -1)
249 getModifiers();
250
251 return((modifiers & VMModifiers.ABSTRACT) > 0);
252 }
253
254 public boolean isFinal() {
255 if (modifiers == -1)
256 getModifiers();
257
258 return((modifiers & VMModifiers.FINAL) > 0);
259 }
260
261 public boolean isStatic() {
262 if (modifiers == -1)
263 getModifiers();
264
265 return((modifiers & VMModifiers.STATIC) > 0);
266 }
267
268 public boolean isPrepared() {
269 // This ref type may have been prepared before we were getting
270 // events, so get it once. After that,
271 // this status flag is updated through the ClassPrepareEvent,
272 // there is no need for the expense of a JDWP query.
273 if (status == 0) {
274 updateStatus();
275 }
276 return isPrepared;
277 }
278
279 public boolean isVerified() {
280 // Once true, it never resets, so we don't need to update
281 if ((status & JDWP.ClassStatus.VERIFIED) == 0) {
282 updateStatus();
283 }
284 return (status & JDWP.ClassStatus.VERIFIED) != 0;
285 }
286
287 public boolean isInitialized() {
288 // Once initialization succeeds or fails, it never resets,
289 // so we don't need to update
290 if ((status & INITIALIZED_OR_FAILED) == 0) {
291 updateStatus();
292 }
293 return (status & JDWP.ClassStatus.INITIALIZED) != 0;
294 }
295
296 public boolean failedToInitialize() {
297 // Once initialization succeeds or fails, it never resets,
298 // so we don't need to update
299 if ((status & INITIALIZED_OR_FAILED) == 0) {
300 updateStatus();
301 }
302 return (status & JDWP.ClassStatus.ERROR) != 0;
303 }
304
305 public List<Field> fields() {
306 List<Field> fields = (fieldsRef == null) ? null : fieldsRef.get();
307 if (fields == null) {
308 if (vm.canGet1_5LanguageFeatures()) {
309 JDWP.ReferenceType.FieldsWithGeneric.FieldInfo[] jdwpFields;
310 try {
311 jdwpFields = JDWP.ReferenceType.FieldsWithGeneric.process(vm, this).declared;
312 } catch (JDWPException exc) {
313 throw exc.toJDIException();
314 }
315 fields = new ArrayList<Field>(jdwpFields.length);
316 for (int i=0; i<jdwpFields.length; i++) {
317 JDWP.ReferenceType.FieldsWithGeneric.FieldInfo fi
318 = jdwpFields[i];
319
320 Field field = new FieldImpl(vm, this, fi.fieldID,
321 fi.name, fi.signature,
322 fi.genericSignature,
323 fi.modBits);
324 fields.add(field);
325 }
326 } else {
327 JDWP.ReferenceType.Fields.FieldInfo[] jdwpFields;
328 try {
329 jdwpFields = JDWP.ReferenceType.Fields.
330 process(vm, this).declared;
331 } catch (JDWPException exc) {
332 throw exc.toJDIException();
333 }
334 fields = new ArrayList<Field>(jdwpFields.length);
335 for (int i=0; i<jdwpFields.length; i++) {
336 JDWP.ReferenceType.Fields.FieldInfo fi = jdwpFields[i];
337
338 Field field = new FieldImpl(vm, this, fi.fieldID,
339 fi.name, fi.signature,
340 null,
341 fi.modBits);
342 fields.add(field);
343 }
344 }
345
346 fields = Collections.unmodifiableList(fields);
347 fieldsRef = new SoftReference<List<Field>>(fields);
348 }
349 return fields;
350 }
351
352 abstract List<? extends ReferenceType> inheritedTypes();
353
354 void addVisibleFields(List<Field> visibleList, Map<String, Field> visibleTable, List<String> ambiguousNames) {
355 for (Field field : visibleFields()) {
356 String name = field.name();
357 if (!ambiguousNames.contains(name)) {
358 Field duplicate = visibleTable.get(name);
359 if (duplicate == null) {
360 visibleList.add(field);
361 visibleTable.put(name, field);
362 } else if (!field.equals(duplicate)) {
363 ambiguousNames.add(name);
364 visibleTable.remove(name);
365 visibleList.remove(duplicate);
366 } else {
367 // identical field from two branches; do nothing
368 }
369 }
370 }
371 }
372
373 public List<Field> visibleFields() {
374 /*
375 * Maintain two different collections of visible fields. The
376 * list maintains a reasonable order for return. The
377 * hash map provides an efficient way to lookup visible fields
378 * by name, important for finding hidden or ambiguous fields.
379 */
380 List<Field> visibleList = new ArrayList<Field>();
381 Map<String, Field> visibleTable = new HashMap<String, Field>();
382
383 /* Track fields removed from above collection due to ambiguity */
384 List<String> ambiguousNames = new ArrayList<String>();
385
386 /* Add inherited, visible fields */
387 List<? extends ReferenceType> types = inheritedTypes();
388 Iterator iter = types.iterator();
389 while (iter.hasNext()) {
390 /*
391 * TO DO: Be defensive and check for cyclic interface inheritance
392 */
393 ReferenceTypeImpl type = (ReferenceTypeImpl)iter.next();
394 type.addVisibleFields(visibleList, visibleTable, ambiguousNames);
395 }
396
397 /*
398 * Insert fields from this type, removing any inherited fields they
399 * hide.
400 */
401 List<Field> retList = new ArrayList<Field>(fields());
402 for (Field field : retList) {
403 Field hidden = visibleTable.get(field.name());
404 if (hidden != null) {
405 visibleList.remove(hidden);
406 }
407 }
408 retList.addAll(visibleList);
409 return retList;
410 }
411
412 void addAllFields(List<Field> fieldList, Set<ReferenceType> typeSet) {
413 /* Continue the recursion only if this type is new */
414 if (!typeSet.contains(this)) {
415 typeSet.add((ReferenceType)this);
416
417 /* Add local fields */
418 fieldList.addAll(fields());
419
420 /* Add inherited fields */
421 List<? extends ReferenceType> types = inheritedTypes();
422 Iterator iter = types.iterator();
423 while (iter.hasNext()) {
424 ReferenceTypeImpl type = (ReferenceTypeImpl)iter.next();
425 type.addAllFields(fieldList, typeSet);
426 }
427 }
428 }
429 public List<Field> allFields() {
430 List<Field> fieldList = new ArrayList<Field>();
431 Set<ReferenceType> typeSet = new HashSet<ReferenceType>();
432 addAllFields(fieldList, typeSet);
433 return fieldList;
434 }
435
436 public Field fieldByName(String fieldName) {
437 java.util.List searchList;
438 Field f;
439
440 searchList = visibleFields();
441
442 for (int i=0; i<searchList.size(); i++) {
443 f = (Field)searchList.get(i);
444
445 if (f.name().equals(fieldName)) {
446 return f;
447 }
448 }
449 //throw new NoSuchFieldException("Field '" + fieldName + "' not found in " + name());
450 return null;
451 }
452
453 public List<Method> methods() {
454 List<Method> methods = (methodsRef == null) ? null : methodsRef.get();
455 if (methods == null) {
456 if (!vm.canGet1_5LanguageFeatures()) {
457 methods = methods1_4();
458 } else {
459 JDWP.ReferenceType.MethodsWithGeneric.MethodInfo[] declared;
460 try {
461 declared = JDWP.ReferenceType.MethodsWithGeneric.
462 process(vm, this).declared;
463 } catch (JDWPException exc) {
464 throw exc.toJDIException();
465 }
466 methods = new ArrayList<Method>(declared.length);
467 for (int i=0; i<declared.length; i++) {
468 JDWP.ReferenceType.MethodsWithGeneric.MethodInfo
469 mi = declared[i];
470
471 Method method = MethodImpl.createMethodImpl(vm, this,
472 mi.methodID,
473 mi.name, mi.signature,
474 mi.genericSignature,
475 mi.modBits);
476 methods.add(method);
477 }
478 }
479 methods = Collections.unmodifiableList(methods);
480 methodsRef = new SoftReference<List<Method>>(methods);
481 }
482 return methods;
483 }
484
485 private List<Method> methods1_4() {
486 List<Method> methods;
487 JDWP.ReferenceType.Methods.MethodInfo[] declared;
488 try {
489 declared = JDWP.ReferenceType.Methods.
490 process(vm, this).declared;
491 } catch (JDWPException exc) {
492 throw exc.toJDIException();
493 }
494 methods = new ArrayList<Method>(declared.length);
495 for (int i=0; i<declared.length; i++) {
496 JDWP.ReferenceType.Methods.MethodInfo mi = declared[i];
497
498 Method method = MethodImpl.createMethodImpl(vm, this,
499 mi.methodID,
500 mi.name, mi.signature,
501 null,
502 mi.modBits);
503 methods.add(method);
504 }
505 return methods;
506 }
507
508 /*
509 * Utility method used by subclasses to build lists of visible
510 * methods.
511 */
512 void addToMethodMap(Map<String, Method> methodMap, List<Method> methodList) {
513 for (Method method : methodList)
514 methodMap.put(method.name().concat(method.signature()), method);
515 }
516
517 abstract void addVisibleMethods(Map<String, Method> methodMap);
518
519 public List<Method> visibleMethods() {
520 /*
521 * Build a collection of all visible methods. The hash
522 * map allows us to do this efficiently by keying on the
523 * concatenation of name and signature.
524 */
525 Map<String, Method> map = new HashMap<String, Method>();
526 addVisibleMethods(map);
527
528 /*
529 * ... but the hash map destroys order. Methods should be
530 * returned in a sensible order, as they are in allMethods().
531 * So, start over with allMethods() and use the hash map
532 * to filter that ordered collection.
533 */
534 List<Method> list = allMethods();
535 list.retainAll(map.values());
536 return list;
537 }
538
539 abstract public List<Method> allMethods();
540
541 public List<Method> methodsByName(String name) {
542 List<Method> methods = visibleMethods();
543 ArrayList<Method> retList = new ArrayList<Method>(methods.size());
544 for (Method candidate : methods) {
545 if (candidate.name().equals(name)) {
546 retList.add(candidate);
547 }
548 }
549 retList.trimToSize();
550 return retList;
551 }
552
553 public List<Method> methodsByName(String name, String signature) {
554 List<Method> methods = visibleMethods();
555 ArrayList<Method> retList = new ArrayList<Method>(methods.size());
556 for (Method candidate : methods) {
557 if (candidate.name().equals(name) &&
558 candidate.signature().equals(signature)) {
559 retList.add(candidate);
560 }
561 }
562 retList.trimToSize();
563 return retList;
564 }
565
566 List<InterfaceType> getInterfaces() {
567 InterfaceTypeImpl[] intfs;
568 try {
569 intfs = JDWP.ReferenceType.Interfaces.
570 process(vm, this).interfaces;
571 } catch (JDWPException exc) {
572 throw exc.toJDIException();
573 }
574 return Arrays.asList((InterfaceType[])intfs);
575 }
576
577 public List<ReferenceType> nestedTypes() {
578 List all = vm.allClasses();
579 List<ReferenceType> nested = new ArrayList<ReferenceType>();
580 String outername = name();
581 int outerlen = outername.length();
582 Iterator iter = all.iterator();
583 while (iter.hasNext()) {
584 ReferenceType refType = (ReferenceType)iter.next();
585 String name = refType.name();
586 int len = name.length();
587 /* The separator is historically '$' but could also be '#' */
588 if ( len > outerlen && name.startsWith(outername) ) {
589 char c = name.charAt(outerlen);
590 if ( c =='$' || c== '#' ) {
591 nested.add(refType);
592 }
593 }
594 }
595 return nested;
596 }
597
598 public Value getValue(Field sig) {
599 List<Field> list = new ArrayList<Field>(1);
600 list.add(sig);
601 Map map = getValues(list);
602 return(Value)map.get(sig);
603 }
604
605
606 void validateFieldAccess(Field field) {
607 /*
608 * Field must be in this object's class, a superclass, or
609 * implemented interface
610 */
611 ReferenceTypeImpl declType = (ReferenceTypeImpl)field.declaringType();
612 if (!declType.isAssignableFrom(this)) {
613 throw new IllegalArgumentException("Invalid field");
614 }
615 }
616
617 void validateFieldSet(Field field) {
618 validateFieldAccess(field);
619 if (field.isFinal()) {
620 throw new IllegalArgumentException("Cannot set value of final field");
621 }
622 }
623
624 /**
625 * Returns a map of field values
626 */
627 public Map<Field,Value> getValues(List<? extends Field> theFields) {
628 validateMirrors(theFields);
629
630 int size = theFields.size();
631 JDWP.ReferenceType.GetValues.Field[] queryFields =
632 new JDWP.ReferenceType.GetValues.Field[size];
633
634 for (int i=0; i<size; i++) {
635 FieldImpl field = (FieldImpl)theFields.get(i);
636
637 validateFieldAccess(field);
638
639 // Do more validation specific to ReferenceType field getting
640 if (!field.isStatic()) {
641 throw new IllegalArgumentException(
642 "Attempt to use non-static field with ReferenceType");
643 }
644 queryFields[i] = new JDWP.ReferenceType.GetValues.Field(
645 field.ref());
646 }
647
648 Map<Field, Value> map = new HashMap<Field, Value>(size);
649
650 ValueImpl[] values;
651 try {
652 values = JDWP.ReferenceType.GetValues.
653 process(vm, this, queryFields).values;
654 } catch (JDWPException exc) {
655 throw exc.toJDIException();
656 }
657
658 if (size != values.length) {
659 throw new InternalException(
660 "Wrong number of values returned from target VM");
661 }
662 for (int i=0; i<size; i++) {
663 FieldImpl field = (FieldImpl)theFields.get(i);
664 map.put(field, values[i]);
665 }
666
667 return map;
668 }
669
670 public ClassObjectReference classObject() {
671 if (classObject == null) {
672 // Are classObjects unique for an Object, or
673 // created each time? Is this spec'ed?
674 synchronized(this) {
675 if (classObject == null) {
676 try {
677 classObject = JDWP.ReferenceType.ClassObject.
678 process(vm, this).classObject;
679 } catch (JDWPException exc) {
680 throw exc.toJDIException();
681 }
682 }
683 }
684 }
685 return classObject;
686 }
687
688 SDE.Stratum stratum(String stratumID) {
689 SDE sde = sourceDebugExtensionInfo();
690 if (!sde.isValid()) {
691 sde = NO_SDE_INFO_MARK;
692 }
693 return sde.stratum(stratumID);
694 }
695
696 public String sourceName() throws AbsentInformationException {
697 return sourceNames(vm.getDefaultStratum()).get(0);
698 }
699
700 public List<String> sourceNames(String stratumID)
701 throws AbsentInformationException {
702 SDE.Stratum stratum = stratum(stratumID);
703 if (stratum.isJava()) {
704 List<String> result = new ArrayList<String>(1);
705 result.add(baseSourceName());
706 return result;
707 }
708 return stratum.sourceNames(this);
709 }
710
711 public List<String> sourcePaths(String stratumID)
712 throws AbsentInformationException {
713 SDE.Stratum stratum = stratum(stratumID);
714 if (stratum.isJava()) {
715 List<String> result = new ArrayList<String>(1);
716 result.add(baseSourceDir() + baseSourceName());
717 return result;
718 }
719 return stratum.sourcePaths(this);
720 }
721
722 String baseSourceName() throws AbsentInformationException {
723 String bsn = baseSourceName;
724 if (bsn == null) {
725 // Does not need synchronization, since worst-case
726 // static info is fetched twice
727 try {
728 bsn = JDWP.ReferenceType.SourceFile.
729 process(vm, this).sourceFile;
730 } catch (JDWPException exc) {
731 if (exc.errorCode() == JDWP.Error.ABSENT_INFORMATION) {
732 bsn = ABSENT_BASE_SOURCE_NAME;
733 } else {
734 throw exc.toJDIException();
735 }
736 }
737 baseSourceName = bsn;
738 }
739 if (bsn == ABSENT_BASE_SOURCE_NAME) {
740 throw new AbsentInformationException();
741 }
742 return bsn;
743 }
744
745 String baseSourcePath() throws AbsentInformationException {
746 String bsp = baseSourcePath;
747 if (bsp == null) {
748 bsp = baseSourceDir() + baseSourceName();
749 baseSourcePath = bsp;
750 }
751 return bsp;
752 }
753
754 String baseSourceDir() {
755 if (baseSourceDir == null) {
756 String typeName = name();
757 StringBuffer sb = new StringBuffer(typeName.length() + 10);
758 int index = 0;
759 int nextIndex;
760
761 while ((nextIndex = typeName.indexOf('.', index)) > 0) {
762 sb.append(typeName.substring(index, nextIndex));
763 sb.append(java.io.File.separatorChar);
764 index = nextIndex + 1;
765 }
766 baseSourceDir = sb.toString();
767 }
768 return baseSourceDir;
769 }
770
771 public String sourceDebugExtension()
772 throws AbsentInformationException {
773 if (!vm.canGetSourceDebugExtension()) {
774 throw new UnsupportedOperationException();
775 }
776 SDE sde = sourceDebugExtensionInfo();
777 if (sde == NO_SDE_INFO_MARK) {
778 throw new AbsentInformationException();
779 }
780 return sde.sourceDebugExtension;
781 }
782
783 private SDE sourceDebugExtensionInfo() {
784 if (!vm.canGetSourceDebugExtension()) {
785 return NO_SDE_INFO_MARK;
786 }
787 SDE sde = (sdeRef == null) ? null : sdeRef.get();
788 if (sde == null) {
789 String extension = null;
790 try {
791 extension = JDWP.ReferenceType.SourceDebugExtension.
792 process(vm, this).extension;
793 } catch (JDWPException exc) {
794 if (exc.errorCode() != JDWP.Error.ABSENT_INFORMATION) {
795 sdeRef = new SoftReference<SDE>(NO_SDE_INFO_MARK);
796 throw exc.toJDIException();
797 }
798 }
799 if (extension == null) {
800 sde = NO_SDE_INFO_MARK;
801 } else {
802 sde = new SDE(extension);
803 }
804 sdeRef = new SoftReference<SDE>(sde);
805 }
806 return sde;
807 }
808
809 public List<String> availableStrata() {
810 SDE sde = sourceDebugExtensionInfo();
811 if (sde.isValid()) {
812 return sde.availableStrata();
813 } else {
814 List<String> strata = new ArrayList<String>();
815 strata.add(SDE.BASE_STRATUM_NAME);
816 return strata;
817 }
818 }
819
820 /**
821 * Always returns non-null stratumID
822 */
823 public String defaultStratum() {
824 SDE sdei = sourceDebugExtensionInfo();
825 if (sdei.isValid()) {
826 return sdei.defaultStratumId;
827 } else {
828 return SDE.BASE_STRATUM_NAME;
829 }
830 }
831
832 public int modifiers() {
833 if (modifiers == -1)
834 getModifiers();
835
836 return modifiers;
837 }
838
839 public List<Location> allLineLocations()
840 throws AbsentInformationException {
841 return allLineLocations(vm.getDefaultStratum(), null);
842 }
843
844 public List<Location> allLineLocations(String stratumID, String sourceName)
845 throws AbsentInformationException {
846 boolean someAbsent = false; // A method that should have info, didn't
847 SDE.Stratum stratum = stratum(stratumID);
848 List<Location> list = new ArrayList<Location>(); // location list
849
850 for (Iterator iter = methods().iterator(); iter.hasNext(); ) {
851 MethodImpl method = (MethodImpl)iter.next();
852 try {
853 list.addAll(
854 method.allLineLocations(stratum, sourceName));
855 } catch(AbsentInformationException exc) {
856 someAbsent = true;
857 }
858 }
859
860 // If we retrieved no line info, and at least one of the methods
861 // should have had some (as determined by an
862 // AbsentInformationException being thrown) then we rethrow
863 // the AbsentInformationException.
864 if (someAbsent && list.size() == 0) {
865 throw new AbsentInformationException();
866 }
867 return list;
868 }
869
870 public List<Location> locationsOfLine(int lineNumber)
871 throws AbsentInformationException {
872 return locationsOfLine(vm.getDefaultStratum(),
873 null,
874 lineNumber);
875 }
876
877 public List<Location> locationsOfLine(String stratumID,
878 String sourceName,
879 int lineNumber)
880 throws AbsentInformationException {
881 // A method that should have info, didn't
882 boolean someAbsent = false;
883 // A method that should have info, did
884 boolean somePresent = false;
885 List<Method> methods = methods();
886 SDE.Stratum stratum = stratum(stratumID);
887
888 List<Location> list = new ArrayList<Location>();
889
890 Iterator iter = methods.iterator();
891 while(iter.hasNext()) {
892 MethodImpl method = (MethodImpl)iter.next();
893 // eliminate native and abstract to eliminate
894 // false positives
895 if (!method.isAbstract() &&
896 !method.isNative()) {
897 try {
898 list.addAll(
899 method.locationsOfLine(stratum,
900 sourceName,
901 lineNumber));
902 somePresent = true;
903 } catch(AbsentInformationException exc) {
904 someAbsent = true;
905 }
906 }
907 }
908 if (someAbsent && !somePresent) {
909 throw new AbsentInformationException();
910 }
911 return list;
912 }
913
914 public List<ObjectReference> instances(long maxInstances) {
915 if (!vm.canGetInstanceInfo()) {
916 throw new UnsupportedOperationException(
917 "target does not support getting instances");
918 }
919
920 if (maxInstances < 0) {
921 throw new IllegalArgumentException("maxInstances is less than zero: "
922 + maxInstances);
923 }
924 int intMax = (maxInstances > Integer.MAX_VALUE)?
925 Integer.MAX_VALUE: (int)maxInstances;
926 // JDWP can't currently handle more than this (in mustang)
927
928 try {
929 return Arrays.asList(
930 (ObjectReference[])JDWP.ReferenceType.Instances.
931 process(vm, this, intMax).instances);
932 } catch (JDWPException exc) {
933 throw exc.toJDIException();
934 }
935 }
936
937 private void getClassFileVersion() {
938 if (!vm.canGetClassFileVersion()) {
939 throw new UnsupportedOperationException();
940 }
941 JDWP.ReferenceType.ClassFileVersion classFileVersion;
942 if (versionNumberGotten) {
943 return;
944 } else {
945 try {
946 classFileVersion = JDWP.ReferenceType.ClassFileVersion.process(vm, this);
947 } catch (JDWPException exc) {
948 if (exc.errorCode() == JDWP.Error.ABSENT_INFORMATION) {
949 majorVersion = 0;
950 minorVersion = 0;
951 versionNumberGotten = true;
952 return;
953 } else {
954 throw exc.toJDIException();
955 }
956 }
957 majorVersion = classFileVersion.majorVersion;
958 minorVersion = classFileVersion.minorVersion;
959 versionNumberGotten = true;
960 }
961 }
962
963 public int majorVersion() {
964 try {
965 getClassFileVersion();
966 } catch (RuntimeException exc) {
967 throw exc;
968 }
969 return majorVersion;
970 }
971
972 public int minorVersion() {
973 try {
974 getClassFileVersion();
975 } catch (RuntimeException exc) {
976 throw exc;
977 }
978 return minorVersion;
979 }
980
981 private void getConstantPoolInfo() {
982 JDWP.ReferenceType.ConstantPool jdwpCPool;
983 if (!vm.canGetConstantPool()) {
984 throw new UnsupportedOperationException();
985 }
986 if (constantPoolInfoGotten) {
987 return;
988 } else {
989 try {
990 jdwpCPool = JDWP.ReferenceType.ConstantPool.process(vm, this);
991 } catch (JDWPException exc) {
992 if (exc.errorCode() == JDWP.Error.ABSENT_INFORMATION) {
993 constanPoolCount = 0;
994 constantPoolBytesRef = null;
995 constantPoolInfoGotten = true;
996 return;
997 } else {
998 throw exc.toJDIException();
999 }
1000 }
1001 byte[] cpbytes;
1002 constanPoolCount = jdwpCPool.count;
1003 cpbytes = jdwpCPool.bytes;
1004 constantPoolBytesRef = new SoftReference<byte[]>(cpbytes);
1005 constantPoolInfoGotten = true;
1006 }
1007 }
1008
1009 public int constantPoolCount() {
1010 try {
1011 getConstantPoolInfo();
1012 } catch (RuntimeException exc) {
1013 throw exc;
1014 }
1015 return constanPoolCount;
1016 }
1017
1018 public byte[] constantPool() {
1019 try {
1020 getConstantPoolInfo();
1021 } catch (RuntimeException exc) {
1022 throw exc;
1023 }
1024 if (constantPoolBytesRef != null) {
1025 byte[] cpbytes = constantPoolBytesRef.get();
1026 /*
1027 * Arrays are always modifiable, so it is a little unsafe
1028 * to return the cached bytecodes directly; instead, we
1029 * make a clone at the cost of using more memory.
1030 */
1031 return cpbytes.clone();
1032 } else {
1033 return null;
1034 }
1035 }
1036
1037 // Does not need synchronization, since worst-case
1038 // static info is fetched twice
1039 void getModifiers() {
1040 if (modifiers != -1) {
1041 return;
1042 }
1043 try {
1044 modifiers = JDWP.ReferenceType.Modifiers.
1045 process(vm, this).modBits;
1046 } catch (JDWPException exc) {
1047 throw exc.toJDIException();
1048 }
1049 }
1050
1051 void decodeStatus(int status) {
1052 this.status = status;
1053 if ((status & JDWP.ClassStatus.PREPARED) != 0) {
1054 isPrepared = true;
1055 }
1056 }
1057
1058 void updateStatus() {
1059 try {
1060 decodeStatus(JDWP.ReferenceType.Status.process(vm, this).status);
1061 } catch (JDWPException exc) {
1062 throw exc.toJDIException();
1063 }
1064 }
1065
1066 void markPrepared() {
1067 isPrepared = true;
1068 }
1069
1070 long ref() {
1071 return ref;
1072 }
1073
1074 int indexOf(Method method) {
1075 // Make sure they're all here - the obsolete method
1076 // won't be found and so will have index -1
1077 return methods().indexOf(method);
1078 }
1079
1080 int indexOf(Field field) {
1081 // Make sure they're all here
1082 return fields().indexOf(field);
1083 }
1084
1085 /*
1086 * Return true if an instance of this type
1087 * can be assigned to a variable of the given type
1088 */
1089 abstract boolean isAssignableTo(ReferenceType type);
1090
1091 boolean isAssignableFrom(ReferenceType type) {
1092 return ((ReferenceTypeImpl)type).isAssignableTo(this);
1093 }
1094
1095 boolean isAssignableFrom(ObjectReference object) {
1096 return object == null ||
1097 isAssignableFrom(object.referenceType());
1098 }
1099
1100 void setStatus(int status) {
1101 decodeStatus(status);
1102 }
1103
1104 void setSignature(String signature) {
1105 this.signature = signature;
1106 }
1107
1108 void setGenericSignature(String signature) {
1109 if (signature != null && signature.length() == 0) {
1110 this.genericSignature = null;
1111 } else{
1112 this.genericSignature = signature;
1113 }
1114 this.genericSignatureGotten = true;
1115 }
1116
1117 private static boolean isPrimitiveArray(String signature) {
1118 int i = signature.lastIndexOf('[');
1119 /*
1120 * TO DO: Centralize JNI signature knowledge.
1121 *
1122 * Ref:
1123 * jdk1.4/doc/guide/jpda/jdi/com/sun/jdi/doc-files/signature.html
1124 */
1125 boolean isPA;
1126 if (i < 0) {
1127 isPA = false;
1128 } else {
1129 char c = signature.charAt(i + 1);
1130 isPA = (c != 'L');
1131 }
1132 return isPA;
1133 }
1134
1135 Type findType(String signature) throws ClassNotLoadedException {
1136 Type type;
1137 if (signature.length() == 1) {
1138 /* OTI FIX: Must be a primitive type or the void type */
1139 char sig = signature.charAt(0);
1140 if (sig == 'V') {
1141 type = vm.theVoidType();
1142 } else {
1143 type = vm.primitiveTypeMirror((byte)sig);
1144 }
1145 } else {
1146 // Must be a reference type.
1147 ClassLoaderReferenceImpl loader =
1148 (ClassLoaderReferenceImpl)classLoader();
1149 if ((loader == null) ||
1150 (isPrimitiveArray(signature)) //Work around 4450091
1151 ) {
1152 // Caller wants type of boot class field
1153 type = vm.findBootType(signature);
1154 } else {
1155 // Caller wants type of non-boot class field
1156 type = loader.findType(signature);
1157 }
1158 }
1159 return type;
1160 }
1161
1162 String loaderString() {
1163 if (classLoader() != null) {
1164 return "loaded by " + classLoader().toString();
1165 } else {
1166 return "no class loader";
1167 }
1168 }
1169
1170}