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+
26+package com.sun.tools.jdi;
27+
28+import com.sun.jdi.*;
29+
30+import java.util.*;
31+import java.lang.ref.SoftReference;
32+
33+public abstract class ReferenceTypeImpl extends TypeImpl
34+implements 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+}