|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package com.sun.tools.jdi; |
|
|
|
import com.sun.jdi.*; |
|
|
|
import java.util.*; |
|
import java.lang.ref.SoftReference; |
|
|
|
public abstract class ReferenceTypeImpl extends TypeImpl |
|
implements ReferenceType { |
|
protected long ref; |
|
private String signature = null; |
|
private String genericSignature = null; |
|
private boolean genericSignatureGotten = false; |
|
private String baseSourceName = null; |
|
private String baseSourceDir = null; |
|
private String baseSourcePath = null; |
|
protected int modifiers = -1; |
|
private SoftReference<List<Field>> fieldsRef = null; |
|
private SoftReference<List<Method>> methodsRef = null; |
|
private SoftReference<SDE> sdeRef = null; |
|
|
|
private boolean isClassLoaderCached = false; |
|
private ClassLoaderReference classLoader = null; |
|
private ClassObjectReference classObject = null; |
|
|
|
private int status = 0; |
|
private boolean isPrepared = false; |
|
|
|
|
|
private boolean versionNumberGotten = false; |
|
private int majorVersion; |
|
private int minorVersion; |
|
|
|
private boolean constantPoolInfoGotten = false; |
|
private int constanPoolCount; |
|
private byte[] constantPoolBytes; |
|
private SoftReference<byte[]> constantPoolBytesRef = null; |
|
|
|
|
|
private static final String ABSENT_BASE_SOURCE_NAME = "**ABSENT_BASE_SOURCE_NAME**"; |
|
|
|
|
|
static final SDE NO_SDE_INFO_MARK = new SDE(); |
|
|
|
|
|
private static final int INITIALIZED_OR_FAILED = |
|
JDWP.ClassStatus.INITIALIZED | JDWP.ClassStatus.ERROR; |
|
|
|
|
|
protected ReferenceTypeImpl(VirtualMachine aVm, long aRef) { |
|
super(aVm); |
|
ref = aRef; |
|
genericSignatureGotten = false; |
|
} |
|
|
|
void noticeRedefineClass() { |
|
//Invalidate information previously fetched and cached. |
|
|
|
baseSourceName = null; |
|
baseSourcePath = null; |
|
modifiers = -1; |
|
fieldsRef = null; |
|
methodsRef = null; |
|
sdeRef = null; |
|
versionNumberGotten = false; |
|
constantPoolInfoGotten = false; |
|
} |
|
|
|
Method getMethodMirror(long ref) { |
|
if (ref == 0) { |
|
|
|
return new ObsoleteMethodImpl(vm, this); |
|
} |
|
// Fetch all methods for the class, check performance impact |
|
// Needs no synchronization now, since methods() returns |
|
|
|
Iterator<Method> it = methods().iterator(); |
|
while (it.hasNext()) { |
|
MethodImpl method = (MethodImpl)it.next(); |
|
if (method.ref() == ref) { |
|
return method; |
|
} |
|
} |
|
throw new IllegalArgumentException("Invalid method id: " + ref); |
|
} |
|
|
|
Field getFieldMirror(long ref) { |
|
// Fetch all fields for the class, check performance impact |
|
// Needs no synchronization now, since fields() returns |
|
|
|
Iterator<Field>it = fields().iterator(); |
|
while (it.hasNext()) { |
|
FieldImpl field = (FieldImpl)it.next(); |
|
if (field.ref() == ref) { |
|
return field; |
|
} |
|
} |
|
throw new IllegalArgumentException("Invalid field id: " + ref); |
|
} |
|
|
|
public boolean equals(Object obj) { |
|
if ((obj != null) && (obj instanceof ReferenceTypeImpl)) { |
|
ReferenceTypeImpl other = (ReferenceTypeImpl)obj; |
|
return (ref() == other.ref()) && |
|
(vm.equals(other.virtualMachine())); |
|
} else { |
|
return false; |
|
} |
|
} |
|
|
|
public int hashCode() { |
|
return(int)ref(); |
|
} |
|
|
|
public int compareTo(ReferenceType object) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
ReferenceTypeImpl other = (ReferenceTypeImpl)object; |
|
int comp = name().compareTo(other.name()); |
|
if (comp == 0) { |
|
long rf1 = ref(); |
|
long rf2 = other.ref(); |
|
|
|
if (rf1 == rf2) { |
|
|
|
comp = vm.sequenceNumber - |
|
((VirtualMachineImpl)(other.virtualMachine())).sequenceNumber; |
|
} else { |
|
comp = (rf1 < rf2)? -1 : 1; |
|
} |
|
} |
|
return comp; |
|
} |
|
|
|
public String signature() { |
|
if (signature == null) { |
|
// Does not need synchronization, since worst-case |
|
|
|
if (vm.canGet1_5LanguageFeatures()) { |
|
|
|
|
|
|
|
*/ |
|
genericSignature(); |
|
} else { |
|
try { |
|
signature = JDWP.ReferenceType.Signature. |
|
process(vm, this).signature; |
|
} catch (JDWPException exc) { |
|
throw exc.toJDIException(); |
|
} |
|
} |
|
} |
|
return signature; |
|
} |
|
|
|
public String genericSignature() { |
|
|
|
if (vm.canGet1_5LanguageFeatures() && !genericSignatureGotten) { |
|
// Does not need synchronization, since worst-case |
|
|
|
JDWP.ReferenceType.SignatureWithGeneric result; |
|
try { |
|
result = JDWP.ReferenceType.SignatureWithGeneric. |
|
process(vm, this); |
|
} catch (JDWPException exc) { |
|
throw exc.toJDIException(); |
|
} |
|
signature = result.signature; |
|
setGenericSignature(result.genericSignature); |
|
} |
|
return genericSignature; |
|
} |
|
|
|
public ClassLoaderReference classLoader() { |
|
if (!isClassLoaderCached) { |
|
// Does not need synchronization, since worst-case |
|
|
|
try { |
|
classLoader = (ClassLoaderReference) |
|
JDWP.ReferenceType.ClassLoader. |
|
process(vm, this).classLoader; |
|
isClassLoaderCached = true; |
|
} catch (JDWPException exc) { |
|
throw exc.toJDIException(); |
|
} |
|
} |
|
return classLoader; |
|
} |
|
|
|
public boolean isPublic() { |
|
if (modifiers == -1) |
|
getModifiers(); |
|
|
|
return((modifiers & VMModifiers.PUBLIC) > 0); |
|
} |
|
|
|
public boolean isProtected() { |
|
if (modifiers == -1) |
|
getModifiers(); |
|
|
|
return((modifiers & VMModifiers.PROTECTED) > 0); |
|
} |
|
|
|
public boolean isPrivate() { |
|
if (modifiers == -1) |
|
getModifiers(); |
|
|
|
return((modifiers & VMModifiers.PRIVATE) > 0); |
|
} |
|
|
|
public boolean isPackagePrivate() { |
|
return !isPublic() && !isPrivate() && !isProtected(); |
|
} |
|
|
|
public boolean isAbstract() { |
|
if (modifiers == -1) |
|
getModifiers(); |
|
|
|
return((modifiers & VMModifiers.ABSTRACT) > 0); |
|
} |
|
|
|
public boolean isFinal() { |
|
if (modifiers == -1) |
|
getModifiers(); |
|
|
|
return((modifiers & VMModifiers.FINAL) > 0); |
|
} |
|
|
|
public boolean isStatic() { |
|
if (modifiers == -1) |
|
getModifiers(); |
|
|
|
return((modifiers & VMModifiers.STATIC) > 0); |
|
} |
|
|
|
public boolean isPrepared() { |
|
// This ref type may have been prepared before we were getting |
|
// events, so get it once. After that, |
|
// this status flag is updated through the ClassPrepareEvent, |
|
|
|
if (status == 0) { |
|
updateStatus(); |
|
} |
|
return isPrepared; |
|
} |
|
|
|
public boolean isVerified() { |
|
|
|
if ((status & JDWP.ClassStatus.VERIFIED) == 0) { |
|
updateStatus(); |
|
} |
|
return (status & JDWP.ClassStatus.VERIFIED) != 0; |
|
} |
|
|
|
public boolean isInitialized() { |
|
// Once initialization succeeds or fails, it never resets, |
|
|
|
if ((status & INITIALIZED_OR_FAILED) == 0) { |
|
updateStatus(); |
|
} |
|
return (status & JDWP.ClassStatus.INITIALIZED) != 0; |
|
} |
|
|
|
public boolean failedToInitialize() { |
|
// Once initialization succeeds or fails, it never resets, |
|
|
|
if ((status & INITIALIZED_OR_FAILED) == 0) { |
|
updateStatus(); |
|
} |
|
return (status & JDWP.ClassStatus.ERROR) != 0; |
|
} |
|
|
|
public List<Field> fields() { |
|
List<Field> fields = (fieldsRef == null) ? null : fieldsRef.get(); |
|
if (fields == null) { |
|
if (vm.canGet1_5LanguageFeatures()) { |
|
JDWP.ReferenceType.FieldsWithGeneric.FieldInfo[] jdwpFields; |
|
try { |
|
jdwpFields = JDWP.ReferenceType.FieldsWithGeneric.process(vm, this).declared; |
|
} catch (JDWPException exc) { |
|
throw exc.toJDIException(); |
|
} |
|
fields = new ArrayList<Field>(jdwpFields.length); |
|
for (int i=0; i<jdwpFields.length; i++) { |
|
JDWP.ReferenceType.FieldsWithGeneric.FieldInfo fi |
|
= jdwpFields[i]; |
|
|
|
Field field = new FieldImpl(vm, this, fi.fieldID, |
|
fi.name, fi.signature, |
|
fi.genericSignature, |
|
fi.modBits); |
|
fields.add(field); |
|
} |
|
} else { |
|
JDWP.ReferenceType.Fields.FieldInfo[] jdwpFields; |
|
try { |
|
jdwpFields = JDWP.ReferenceType.Fields. |
|
process(vm, this).declared; |
|
} catch (JDWPException exc) { |
|
throw exc.toJDIException(); |
|
} |
|
fields = new ArrayList<Field>(jdwpFields.length); |
|
for (int i=0; i<jdwpFields.length; i++) { |
|
JDWP.ReferenceType.Fields.FieldInfo fi = jdwpFields[i]; |
|
|
|
Field field = new FieldImpl(vm, this, fi.fieldID, |
|
fi.name, fi.signature, |
|
null, |
|
fi.modBits); |
|
fields.add(field); |
|
} |
|
} |
|
|
|
fields = Collections.unmodifiableList(fields); |
|
fieldsRef = new SoftReference<List<Field>>(fields); |
|
} |
|
return fields; |
|
} |
|
|
|
abstract List<? extends ReferenceType> inheritedTypes(); |
|
|
|
void addVisibleFields(List<Field> visibleList, Map<String, Field> visibleTable, List<String> ambiguousNames) { |
|
for (Field field : visibleFields()) { |
|
String name = field.name(); |
|
if (!ambiguousNames.contains(name)) { |
|
Field duplicate = visibleTable.get(name); |
|
if (duplicate == null) { |
|
visibleList.add(field); |
|
visibleTable.put(name, field); |
|
} else if (!field.equals(duplicate)) { |
|
ambiguousNames.add(name); |
|
visibleTable.remove(name); |
|
visibleList.remove(duplicate); |
|
} else { |
|
// identical field from two branches; do nothing |
|
} |
|
} |
|
} |
|
} |
|
|
|
public List<Field> visibleFields() { |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
List<Field> visibleList = new ArrayList<Field>(); |
|
Map<String, Field> visibleTable = new HashMap<String, Field>(); |
|
|
|
|
|
List<String> ambiguousNames = new ArrayList<String>(); |
|
|
|
|
|
List<? extends ReferenceType> types = inheritedTypes(); |
|
Iterator<? extends ReferenceType> iter = types.iterator(); |
|
while (iter.hasNext()) { |
|
|
|
|
|
*/ |
|
ReferenceTypeImpl type = (ReferenceTypeImpl)iter.next(); |
|
type.addVisibleFields(visibleList, visibleTable, ambiguousNames); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
List<Field> retList = new ArrayList<Field>(fields()); |
|
for (Field field : retList) { |
|
Field hidden = visibleTable.get(field.name()); |
|
if (hidden != null) { |
|
visibleList.remove(hidden); |
|
} |
|
} |
|
retList.addAll(visibleList); |
|
return retList; |
|
} |
|
|
|
void addAllFields(List<Field> fieldList, Set<ReferenceType> typeSet) { |
|
|
|
if (!typeSet.contains(this)) { |
|
typeSet.add((ReferenceType)this); |
|
|
|
|
|
fieldList.addAll(fields()); |
|
|
|
|
|
List<? extends ReferenceType> types = inheritedTypes(); |
|
Iterator<? extends ReferenceType> iter = types.iterator(); |
|
while (iter.hasNext()) { |
|
ReferenceTypeImpl type = (ReferenceTypeImpl)iter.next(); |
|
type.addAllFields(fieldList, typeSet); |
|
} |
|
} |
|
} |
|
public List<Field> allFields() { |
|
List<Field> fieldList = new ArrayList<Field>(); |
|
Set<ReferenceType> typeSet = new HashSet<ReferenceType>(); |
|
addAllFields(fieldList, typeSet); |
|
return fieldList; |
|
} |
|
|
|
public Field fieldByName(String fieldName) { |
|
List<Field> searchList = visibleFields(); |
|
|
|
for (int i=0; i<searchList.size(); i++) { |
|
Field f = searchList.get(i); |
|
|
|
if (f.name().equals(fieldName)) { |
|
return f; |
|
} |
|
} |
|
|
|
return null; |
|
} |
|
|
|
public List<Method> methods() { |
|
List<Method> methods = (methodsRef == null) ? null : methodsRef.get(); |
|
if (methods == null) { |
|
if (!vm.canGet1_5LanguageFeatures()) { |
|
methods = methods1_4(); |
|
} else { |
|
JDWP.ReferenceType.MethodsWithGeneric.MethodInfo[] declared; |
|
try { |
|
declared = JDWP.ReferenceType.MethodsWithGeneric. |
|
process(vm, this).declared; |
|
} catch (JDWPException exc) { |
|
throw exc.toJDIException(); |
|
} |
|
methods = new ArrayList<Method>(declared.length); |
|
for (int i=0; i<declared.length; i++) { |
|
JDWP.ReferenceType.MethodsWithGeneric.MethodInfo |
|
mi = declared[i]; |
|
|
|
Method method = MethodImpl.createMethodImpl(vm, this, |
|
mi.methodID, |
|
mi.name, mi.signature, |
|
mi.genericSignature, |
|
mi.modBits); |
|
methods.add(method); |
|
} |
|
} |
|
methods = Collections.unmodifiableList(methods); |
|
methodsRef = new SoftReference<List<Method>>(methods); |
|
} |
|
return methods; |
|
} |
|
|
|
private List<Method> methods1_4() { |
|
List<Method> methods; |
|
JDWP.ReferenceType.Methods.MethodInfo[] declared; |
|
try { |
|
declared = JDWP.ReferenceType.Methods. |
|
process(vm, this).declared; |
|
} catch (JDWPException exc) { |
|
throw exc.toJDIException(); |
|
} |
|
methods = new ArrayList<Method>(declared.length); |
|
for (int i=0; i<declared.length; i++) { |
|
JDWP.ReferenceType.Methods.MethodInfo mi = declared[i]; |
|
|
|
Method method = MethodImpl.createMethodImpl(vm, this, |
|
mi.methodID, |
|
mi.name, mi.signature, |
|
null, |
|
mi.modBits); |
|
methods.add(method); |
|
} |
|
return methods; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
void addToMethodMap(Map<String, Method> methodMap, List<Method> methodList) { |
|
for (Method method : methodList) |
|
methodMap.put(method.name().concat(method.signature()), method); |
|
} |
|
|
|
abstract void addVisibleMethods(Map<String, Method> methodMap, Set<InterfaceType> seenInterfaces); |
|
|
|
public List<Method> visibleMethods() { |
|
|
|
|
|
|
|
|
|
*/ |
|
Map<String, Method> map = new HashMap<String, Method>(); |
|
addVisibleMethods(map, new HashSet<InterfaceType>()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
List<Method> list = allMethods(); |
|
list.retainAll(map.values()); |
|
return list; |
|
} |
|
|
|
abstract public List<Method> allMethods(); |
|
|
|
public List<Method> methodsByName(String name) { |
|
List<Method> methods = visibleMethods(); |
|
ArrayList<Method> retList = new ArrayList<Method>(methods.size()); |
|
for (Method candidate : methods) { |
|
if (candidate.name().equals(name)) { |
|
retList.add(candidate); |
|
} |
|
} |
|
retList.trimToSize(); |
|
return retList; |
|
} |
|
|
|
public List<Method> methodsByName(String name, String signature) { |
|
List<Method> methods = visibleMethods(); |
|
ArrayList<Method> retList = new ArrayList<Method>(methods.size()); |
|
for (Method candidate : methods) { |
|
if (candidate.name().equals(name) && |
|
candidate.signature().equals(signature)) { |
|
retList.add(candidate); |
|
} |
|
} |
|
retList.trimToSize(); |
|
return retList; |
|
} |
|
|
|
List<InterfaceType> getInterfaces() { |
|
InterfaceTypeImpl[] intfs; |
|
try { |
|
intfs = JDWP.ReferenceType.Interfaces. |
|
process(vm, this).interfaces; |
|
} catch (JDWPException exc) { |
|
throw exc.toJDIException(); |
|
} |
|
return Arrays.asList((InterfaceType[])intfs); |
|
} |
|
|
|
public List<ReferenceType> nestedTypes() { |
|
List<ReferenceType> all = vm.allClasses(); |
|
List<ReferenceType> nested = new ArrayList<ReferenceType>(); |
|
String outername = name(); |
|
int outerlen = outername.length(); |
|
Iterator<ReferenceType> iter = all.iterator(); |
|
while (iter.hasNext()) { |
|
ReferenceType refType = iter.next(); |
|
String name = refType.name(); |
|
int len = name.length(); |
|
|
|
if ( len > outerlen && name.startsWith(outername) ) { |
|
char c = name.charAt(outerlen); |
|
if ( c =='$' || c== '#' ) { |
|
nested.add(refType); |
|
} |
|
} |
|
} |
|
return nested; |
|
} |
|
|
|
public Value getValue(Field sig) { |
|
List<Field> list = new ArrayList<Field>(1); |
|
list.add(sig); |
|
Map<Field, Value> map = getValues(list); |
|
return map.get(sig); |
|
} |
|
|
|
|
|
void validateFieldAccess(Field field) { |
|
|
|
|
|
|
|
*/ |
|
ReferenceTypeImpl declType = (ReferenceTypeImpl)field.declaringType(); |
|
if (!declType.isAssignableFrom(this)) { |
|
throw new IllegalArgumentException("Invalid field"); |
|
} |
|
} |
|
|
|
void validateFieldSet(Field field) { |
|
validateFieldAccess(field); |
|
if (field.isFinal()) { |
|
throw new IllegalArgumentException("Cannot set value of final field"); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public Map<Field,Value> getValues(List<? extends Field> theFields) { |
|
validateMirrors(theFields); |
|
|
|
int size = theFields.size(); |
|
JDWP.ReferenceType.GetValues.Field[] queryFields = |
|
new JDWP.ReferenceType.GetValues.Field[size]; |
|
|
|
for (int i=0; i<size; i++) { |
|
FieldImpl field = (FieldImpl)theFields.get(i); |
|
|
|
validateFieldAccess(field); |
|
|
|
|
|
if (!field.isStatic()) { |
|
throw new IllegalArgumentException( |
|
"Attempt to use non-static field with ReferenceType"); |
|
} |
|
queryFields[i] = new JDWP.ReferenceType.GetValues.Field( |
|
field.ref()); |
|
} |
|
|
|
Map<Field, Value> map = new HashMap<Field, Value>(size); |
|
|
|
ValueImpl[] values; |
|
try { |
|
values = JDWP.ReferenceType.GetValues. |
|
process(vm, this, queryFields).values; |
|
} catch (JDWPException exc) { |
|
throw exc.toJDIException(); |
|
} |
|
|
|
if (size != values.length) { |
|
throw new InternalException( |
|
"Wrong number of values returned from target VM"); |
|
} |
|
for (int i=0; i<size; i++) { |
|
FieldImpl field = (FieldImpl)theFields.get(i); |
|
map.put(field, values[i]); |
|
} |
|
|
|
return map; |
|
} |
|
|
|
public ClassObjectReference classObject() { |
|
if (classObject == null) { |
|
// Are classObjects unique for an Object, or |
|
|
|
synchronized(this) { |
|
if (classObject == null) { |
|
try { |
|
classObject = JDWP.ReferenceType.ClassObject. |
|
process(vm, this).classObject; |
|
} catch (JDWPException exc) { |
|
throw exc.toJDIException(); |
|
} |
|
} |
|
} |
|
} |
|
return classObject; |
|
} |
|
|
|
SDE.Stratum stratum(String stratumID) { |
|
SDE sde = sourceDebugExtensionInfo(); |
|
if (!sde.isValid()) { |
|
sde = NO_SDE_INFO_MARK; |
|
} |
|
return sde.stratum(stratumID); |
|
} |
|
|
|
public String sourceName() throws AbsentInformationException { |
|
return sourceNames(vm.getDefaultStratum()).get(0); |
|
} |
|
|
|
public List<String> sourceNames(String stratumID) |
|
throws AbsentInformationException { |
|
SDE.Stratum stratum = stratum(stratumID); |
|
if (stratum.isJava()) { |
|
List<String> result = new ArrayList<String>(1); |
|
result.add(baseSourceName()); |
|
return result; |
|
} |
|
return stratum.sourceNames(this); |
|
} |
|
|
|
public List<String> sourcePaths(String stratumID) |
|
throws AbsentInformationException { |
|
SDE.Stratum stratum = stratum(stratumID); |
|
if (stratum.isJava()) { |
|
List<String> result = new ArrayList<String>(1); |
|
result.add(baseSourceDir() + baseSourceName()); |
|
return result; |
|
} |
|
return stratum.sourcePaths(this); |
|
} |
|
|
|
String baseSourceName() throws AbsentInformationException { |
|
String bsn = baseSourceName; |
|
if (bsn == null) { |
|
// Does not need synchronization, since worst-case |
|
|
|
try { |
|
bsn = JDWP.ReferenceType.SourceFile. |
|
process(vm, this).sourceFile; |
|
} catch (JDWPException exc) { |
|
if (exc.errorCode() == JDWP.Error.ABSENT_INFORMATION) { |
|
bsn = ABSENT_BASE_SOURCE_NAME; |
|
} else { |
|
throw exc.toJDIException(); |
|
} |
|
} |
|
baseSourceName = bsn; |
|
} |
|
if (bsn == ABSENT_BASE_SOURCE_NAME) { |
|
throw new AbsentInformationException(); |
|
} |
|
return bsn; |
|
} |
|
|
|
String baseSourcePath() throws AbsentInformationException { |
|
String bsp = baseSourcePath; |
|
if (bsp == null) { |
|
bsp = baseSourceDir() + baseSourceName(); |
|
baseSourcePath = bsp; |
|
} |
|
return bsp; |
|
} |
|
|
|
String baseSourceDir() { |
|
if (baseSourceDir == null) { |
|
String typeName = name(); |
|
StringBuffer sb = new StringBuffer(typeName.length() + 10); |
|
int index = 0; |
|
int nextIndex; |
|
|
|
while ((nextIndex = typeName.indexOf('.', index)) > 0) { |
|
sb.append(typeName.substring(index, nextIndex)); |
|
sb.append(java.io.File.separatorChar); |
|
index = nextIndex + 1; |
|
} |
|
baseSourceDir = sb.toString(); |
|
} |
|
return baseSourceDir; |
|
} |
|
|
|
public String sourceDebugExtension() |
|
throws AbsentInformationException { |
|
if (!vm.canGetSourceDebugExtension()) { |
|
throw new UnsupportedOperationException(); |
|
} |
|
SDE sde = sourceDebugExtensionInfo(); |
|
if (sde == NO_SDE_INFO_MARK) { |
|
throw new AbsentInformationException(); |
|
} |
|
return sde.sourceDebugExtension; |
|
} |
|
|
|
private SDE sourceDebugExtensionInfo() { |
|
if (!vm.canGetSourceDebugExtension()) { |
|
return NO_SDE_INFO_MARK; |
|
} |
|
SDE sde = (sdeRef == null) ? null : sdeRef.get(); |
|
if (sde == null) { |
|
String extension = null; |
|
try { |
|
extension = JDWP.ReferenceType.SourceDebugExtension. |
|
process(vm, this).extension; |
|
} catch (JDWPException exc) { |
|
if (exc.errorCode() != JDWP.Error.ABSENT_INFORMATION) { |
|
sdeRef = new SoftReference<SDE>(NO_SDE_INFO_MARK); |
|
throw exc.toJDIException(); |
|
} |
|
} |
|
if (extension == null) { |
|
sde = NO_SDE_INFO_MARK; |
|
} else { |
|
sde = new SDE(extension); |
|
} |
|
sdeRef = new SoftReference<SDE>(sde); |
|
} |
|
return sde; |
|
} |
|
|
|
public List<String> availableStrata() { |
|
SDE sde = sourceDebugExtensionInfo(); |
|
if (sde.isValid()) { |
|
return sde.availableStrata(); |
|
} else { |
|
List<String> strata = new ArrayList<String>(); |
|
strata.add(SDE.BASE_STRATUM_NAME); |
|
return strata; |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public String defaultStratum() { |
|
SDE sdei = sourceDebugExtensionInfo(); |
|
if (sdei.isValid()) { |
|
return sdei.defaultStratumId; |
|
} else { |
|
return SDE.BASE_STRATUM_NAME; |
|
} |
|
} |
|
|
|
public int modifiers() { |
|
if (modifiers == -1) |
|
getModifiers(); |
|
|
|
return modifiers; |
|
} |
|
|
|
public List<Location> allLineLocations() |
|
throws AbsentInformationException { |
|
return allLineLocations(vm.getDefaultStratum(), null); |
|
} |
|
|
|
public List<Location> allLineLocations(String stratumID, String sourceName) |
|
throws AbsentInformationException { |
|
boolean someAbsent = false; |
|
SDE.Stratum stratum = stratum(stratumID); |
|
List<Location> list = new ArrayList<Location>(); |
|
|
|
for (Iterator<Method> iter = methods().iterator(); iter.hasNext(); ) { |
|
MethodImpl method = (MethodImpl)iter.next(); |
|
try { |
|
list.addAll( |
|
method.allLineLocations(stratum, sourceName)); |
|
} catch(AbsentInformationException exc) { |
|
someAbsent = true; |
|
} |
|
} |
|
|
|
// If we retrieved no line info, and at least one of the methods |
|
// should have had some (as determined by an |
|
// AbsentInformationException being thrown) then we rethrow |
|
|
|
if (someAbsent && list.size() == 0) { |
|
throw new AbsentInformationException(); |
|
} |
|
return list; |
|
} |
|
|
|
public List<Location> locationsOfLine(int lineNumber) |
|
throws AbsentInformationException { |
|
return locationsOfLine(vm.getDefaultStratum(), |
|
null, |
|
lineNumber); |
|
} |
|
|
|
public List<Location> locationsOfLine(String stratumID, |
|
String sourceName, |
|
int lineNumber) |
|
throws AbsentInformationException { |
|
|
|
boolean someAbsent = false; |
|
|
|
boolean somePresent = false; |
|
List<Method> methods = methods(); |
|
SDE.Stratum stratum = stratum(stratumID); |
|
|
|
List<Location> list = new ArrayList<Location>(); |
|
|
|
Iterator<Method> iter = methods.iterator(); |
|
while(iter.hasNext()) { |
|
MethodImpl method = (MethodImpl)iter.next(); |
|
// eliminate native and abstract to eliminate |
|
|
|
if (!method.isAbstract() && |
|
!method.isNative()) { |
|
try { |
|
list.addAll( |
|
method.locationsOfLine(stratum, |
|
sourceName, |
|
lineNumber)); |
|
somePresent = true; |
|
} catch(AbsentInformationException exc) { |
|
someAbsent = true; |
|
} |
|
} |
|
} |
|
if (someAbsent && !somePresent) { |
|
throw new AbsentInformationException(); |
|
} |
|
return list; |
|
} |
|
|
|
public List<ObjectReference> instances(long maxInstances) { |
|
if (!vm.canGetInstanceInfo()) { |
|
throw new UnsupportedOperationException( |
|
"target does not support getting instances"); |
|
} |
|
|
|
if (maxInstances < 0) { |
|
throw new IllegalArgumentException("maxInstances is less than zero: " |
|
+ maxInstances); |
|
} |
|
int intMax = (maxInstances > Integer.MAX_VALUE)? |
|
Integer.MAX_VALUE: (int)maxInstances; |
|
// JDWP can't currently handle more than this (in mustang) |
|
|
|
try { |
|
return Arrays.asList( |
|
(ObjectReference[])JDWP.ReferenceType.Instances. |
|
process(vm, this, intMax).instances); |
|
} catch (JDWPException exc) { |
|
throw exc.toJDIException(); |
|
} |
|
} |
|
|
|
private void getClassFileVersion() { |
|
if (!vm.canGetClassFileVersion()) { |
|
throw new UnsupportedOperationException(); |
|
} |
|
JDWP.ReferenceType.ClassFileVersion classFileVersion; |
|
if (versionNumberGotten) { |
|
return; |
|
} else { |
|
try { |
|
classFileVersion = JDWP.ReferenceType.ClassFileVersion.process(vm, this); |
|
} catch (JDWPException exc) { |
|
if (exc.errorCode() == JDWP.Error.ABSENT_INFORMATION) { |
|
majorVersion = 0; |
|
minorVersion = 0; |
|
versionNumberGotten = true; |
|
return; |
|
} else { |
|
throw exc.toJDIException(); |
|
} |
|
} |
|
majorVersion = classFileVersion.majorVersion; |
|
minorVersion = classFileVersion.minorVersion; |
|
versionNumberGotten = true; |
|
} |
|
} |
|
|
|
public int majorVersion() { |
|
try { |
|
getClassFileVersion(); |
|
} catch (RuntimeException exc) { |
|
throw exc; |
|
} |
|
return majorVersion; |
|
} |
|
|
|
public int minorVersion() { |
|
try { |
|
getClassFileVersion(); |
|
} catch (RuntimeException exc) { |
|
throw exc; |
|
} |
|
return minorVersion; |
|
} |
|
|
|
private void getConstantPoolInfo() { |
|
JDWP.ReferenceType.ConstantPool jdwpCPool; |
|
if (!vm.canGetConstantPool()) { |
|
throw new UnsupportedOperationException(); |
|
} |
|
if (constantPoolInfoGotten) { |
|
return; |
|
} else { |
|
try { |
|
jdwpCPool = JDWP.ReferenceType.ConstantPool.process(vm, this); |
|
} catch (JDWPException exc) { |
|
if (exc.errorCode() == JDWP.Error.ABSENT_INFORMATION) { |
|
constanPoolCount = 0; |
|
constantPoolBytesRef = null; |
|
constantPoolInfoGotten = true; |
|
return; |
|
} else { |
|
throw exc.toJDIException(); |
|
} |
|
} |
|
byte[] cpbytes; |
|
constanPoolCount = jdwpCPool.count; |
|
cpbytes = jdwpCPool.bytes; |
|
constantPoolBytesRef = new SoftReference<byte[]>(cpbytes); |
|
constantPoolInfoGotten = true; |
|
} |
|
} |
|
|
|
public int constantPoolCount() { |
|
try { |
|
getConstantPoolInfo(); |
|
} catch (RuntimeException exc) { |
|
throw exc; |
|
} |
|
return constanPoolCount; |
|
} |
|
|
|
public byte[] constantPool() { |
|
try { |
|
getConstantPoolInfo(); |
|
} catch (RuntimeException exc) { |
|
throw exc; |
|
} |
|
if (constantPoolBytesRef != null) { |
|
byte[] cpbytes = constantPoolBytesRef.get(); |
|
|
|
|
|
|
|
|
|
*/ |
|
return cpbytes.clone(); |
|
} else { |
|
return null; |
|
} |
|
} |
|
|
|
// Does not need synchronization, since worst-case |
|
|
|
void getModifiers() { |
|
if (modifiers != -1) { |
|
return; |
|
} |
|
try { |
|
modifiers = JDWP.ReferenceType.Modifiers. |
|
process(vm, this).modBits; |
|
} catch (JDWPException exc) { |
|
throw exc.toJDIException(); |
|
} |
|
} |
|
|
|
void decodeStatus(int status) { |
|
this.status = status; |
|
if ((status & JDWP.ClassStatus.PREPARED) != 0) { |
|
isPrepared = true; |
|
} |
|
} |
|
|
|
void updateStatus() { |
|
try { |
|
decodeStatus(JDWP.ReferenceType.Status.process(vm, this).status); |
|
} catch (JDWPException exc) { |
|
throw exc.toJDIException(); |
|
} |
|
} |
|
|
|
void markPrepared() { |
|
isPrepared = true; |
|
} |
|
|
|
long ref() { |
|
return ref; |
|
} |
|
|
|
int indexOf(Method method) { |
|
// Make sure they're all here - the obsolete method |
|
|
|
return methods().indexOf(method); |
|
} |
|
|
|
int indexOf(Field field) { |
|
|
|
return fields().indexOf(field); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
abstract boolean isAssignableTo(ReferenceType type); |
|
|
|
boolean isAssignableFrom(ReferenceType type) { |
|
return ((ReferenceTypeImpl)type).isAssignableTo(this); |
|
} |
|
|
|
boolean isAssignableFrom(ObjectReference object) { |
|
return object == null || |
|
isAssignableFrom(object.referenceType()); |
|
} |
|
|
|
void setStatus(int status) { |
|
decodeStatus(status); |
|
} |
|
|
|
void setSignature(String signature) { |
|
this.signature = signature; |
|
} |
|
|
|
void setGenericSignature(String signature) { |
|
if (signature != null && signature.length() == 0) { |
|
this.genericSignature = null; |
|
} else{ |
|
this.genericSignature = signature; |
|
} |
|
this.genericSignatureGotten = true; |
|
} |
|
|
|
private static boolean isOneDimensionalPrimitiveArray(String signature) { |
|
int i = signature.lastIndexOf('['); |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
boolean isPA; |
|
if (i < 0 || signature.startsWith("[[")) { |
|
isPA = false; |
|
} else { |
|
char c = signature.charAt(i + 1); |
|
isPA = (c != 'L'); |
|
} |
|
return isPA; |
|
} |
|
|
|
Type findType(String signature) throws ClassNotLoadedException { |
|
Type type; |
|
if (signature.length() == 1) { |
|
|
|
char sig = signature.charAt(0); |
|
if (sig == 'V') { |
|
type = vm.theVoidType(); |
|
} else { |
|
type = vm.primitiveTypeMirror((byte)sig); |
|
} |
|
} else { |
|
|
|
ClassLoaderReferenceImpl loader = |
|
(ClassLoaderReferenceImpl)classLoader(); |
|
if ((loader == null) || |
|
(isOneDimensionalPrimitiveArray(signature)) |
|
) { |
|
|
|
type = vm.findBootType(signature); |
|
} else { |
|
|
|
type = loader.findType(signature); |
|
} |
|
} |
|
return type; |
|
} |
|
|
|
String loaderString() { |
|
if (classLoader() != null) { |
|
return "loaded by " + classLoader().toString(); |
|
} else { |
|
return "no class loader"; |
|
} |
|
} |
|
|
|
} |