package org.eclipse.jdi.internal; | |
/* | |
* (c) Copyright IBM Corp. 2000, 2001. | |
* All Rights Reserved. | |
*/ | |
import com.sun.jdi.*; | |
import com.sun.jdi.connect.*; | |
import com.sun.jdi.event.*; | |
import com.sun.jdi.request.*; | |
import org.eclipse.jdi.internal.connect.*; | |
import org.eclipse.jdi.internal.request.*; | |
import org.eclipse.jdi.internal.event.*; | |
import org.eclipse.jdi.internal.jdwp.*; | |
import org.eclipse.jdi.internal.spy.*; | |
import java.util.*; | |
import java.io.*; | |
/** | |
* this class implements the corresponding interfaces | |
* declared by the JDI specification. See the com.sun.jdi package | |
* for more information. | |
* | |
*/ | |
public abstract class ReferenceTypeImpl extends TypeImpl implements ReferenceType, org.eclipse.jdi.hcr.ReferenceType { | |
/** ClassStatus Constants. */ | |
public static final int JDWP_CLASS_STATUS_VERIFIED = 1; | |
public static final int JDWP_CLASS_STATUS_PREPARED = 2; | |
public static final int JDWP_CLASS_STATUS_INITIALIZED = 4; | |
public static final int JDWP_CLASS_STATUS_ERROR = 8; | |
/** Mapping of command codes to strings. */ | |
private static Vector fClassStatusVector = null; | |
/** ReferenceTypeID that corresponds to this reference. */ | |
private JdwpReferenceTypeID fReferenceTypeID; | |
/** The following are the stored results of JDWP calls. */ | |
protected List fInterfaces = null; | |
private List fMethods = null; | |
private List fFields = null; | |
private List fAllMethods = null; | |
private List fVisibleMethods = null; | |
private List fAllFields = null; | |
private List fVisibleFields = null; | |
private List fAllInterfaces = null; | |
private List fAllLineLocations = null; | |
private String fSourcename = null; | |
private int fModifierBits = -1; | |
private ClassLoaderReferenceImpl fClassLoader = null; | |
private ClassObjectReferenceImpl fClassObject = null; | |
private boolean fGotClassFileVersion = false; // HCR addition. | |
private int fClassFileVersion; // HCR addition. | |
private boolean fIsHCREligible; // HCR addition. | |
private boolean fIsVersionKnown; // HCR addition. | |
/** | |
* Creates new instance. | |
*/ | |
protected ReferenceTypeImpl(String description, VirtualMachineImpl vmImpl, JdwpReferenceTypeID referenceTypeID) { | |
super(description, vmImpl); | |
fReferenceTypeID = referenceTypeID; | |
} | |
/** | |
* Creates new instance. | |
*/ | |
protected ReferenceTypeImpl(String description, VirtualMachineImpl vmImpl, JdwpReferenceTypeID referenceTypeID, String signature) { | |
super(description, vmImpl); | |
fReferenceTypeID = referenceTypeID; | |
setSignature(signature); | |
} | |
/** | |
* @return Returns type tag. | |
*/ | |
public abstract byte typeTag(); | |
/** | |
* Flushes all stored Jdwp results. | |
*/ | |
public void flushStoredJdwpResults() { | |
Iterator iter; | |
// Flush Methods. | |
if (fMethods != null) { | |
iter = fMethods.iterator(); | |
while (iter.hasNext()) { | |
MethodImpl method = (MethodImpl)iter.next(); | |
method.flushStoredJdwpResults(); | |
} | |
fMethods = null; | |
} | |
// Flush Fields. | |
if (fFields != null) { | |
iter = fFields.iterator(); | |
while (iter.hasNext()) { | |
FieldImpl field = (FieldImpl)iter.next(); | |
field.flushStoredJdwpResults(); | |
} | |
fFields = null; | |
} | |
fInterfaces = null; | |
fAllMethods = null; | |
fVisibleMethods = null; | |
fAllFields = null; | |
fVisibleFields = null; | |
fAllInterfaces = null; | |
fAllLineLocations = null; | |
fSourcename = null; | |
fModifierBits = -1; | |
fClassLoader = null; | |
fClassObject = null; | |
fGotClassFileVersion = false; | |
// The following cached results are stored higher up in the class hierarchy. | |
fSignature = null; | |
fSourcename = null; | |
} | |
/** | |
* @return Returns Jdwp Reference ID. | |
*/ | |
public JdwpReferenceTypeID getRefTypeID() { | |
return fReferenceTypeID; | |
} | |
/** | |
* @return Returns modifier bits. | |
*/ | |
public int modifiers() { | |
if (fModifierBits != -1) | |
return fModifierBits; | |
initJdwpRequest(); | |
try { | |
JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.RT_MODIFIERS, this); | |
defaultReplyErrorHandler(replyPacket.errorCode()); | |
DataInputStream replyData = replyPacket.dataInStream(); | |
fModifierBits = readInt("modifiers", AccessibleImpl.modifierVector(), replyData); | |
return fModifierBits; | |
} catch (IOException e) { | |
defaultIOExceptionHandler(e); | |
return 0; | |
} finally { | |
handledJdwpRequest(); | |
} | |
} | |
/** | |
* Add methods to a set of methods if they are not overriden, add new names+signature combinations to set of names+signature combinations. | |
*/ | |
private void addVisibleMethods(List newMethods, HashSet nameAndSignatures, Vector resultMethods) { | |
Iterator iter = newMethods.iterator(); | |
MethodImpl method; | |
while (iter.hasNext()) { | |
method = (MethodImpl)iter.next(); | |
String nameAndSignature = method.name() + method.signature(); | |
if (!nameAndSignatures.contains(nameAndSignature)) { | |
resultMethods.add(method); | |
nameAndSignatures.add(nameAndSignature); | |
} | |
} | |
} | |
/** | |
* @return Returns a list containing each unhidden and unambiguous Method in this type. | |
*/ | |
public List visibleMethods() { | |
if (fVisibleMethods != null) | |
return fVisibleMethods; | |
/* Recursion: | |
* The methods of its own (own methods() command); | |
* All methods of the interfaces it implements; | |
* If it is a class, all methods of it's superclass. | |
*/ | |
// The name+signature combinations of methods are maintained in a set, to avoid including methods that have been overriden. | |
HashSet namesAndSignatures = new HashSet(); | |
// The methods of its own (own methods() command). | |
Vector visibleMethods = new Vector(); | |
addVisibleMethods(methods(), namesAndSignatures, visibleMethods); | |
// All methods of the interfaces it implements. | |
Iterator interfaces = interfaces().iterator(); | |
InterfaceTypeImpl inter; | |
while (interfaces.hasNext()) { | |
inter = (InterfaceTypeImpl)interfaces.next(); | |
addVisibleMethods(inter.visibleMethods(), namesAndSignatures, visibleMethods); | |
} | |
// If it is a class, all methods of it's superclass. | |
if (this instanceof ClassType) { | |
ClassType superclass = ((ClassType)this).superclass(); | |
if (superclass != null) | |
addVisibleMethods(superclass.visibleMethods(), namesAndSignatures, visibleMethods); | |
} | |
fVisibleMethods = visibleMethods; | |
return fVisibleMethods; | |
} | |
/** | |
* @return Returns a list containing each Method declared in this type, and its superclasses, implemented interfaces, and/or superinterfaces. | |
*/ | |
public List allMethods() { | |
if (fAllMethods != null) | |
return fAllMethods; | |
/* Recursion: | |
* The methods of its own (own methods() command); | |
* All methods of the interfaces it implements; | |
* If it is a class, all methods of it's superclass. | |
*/ | |
// The name+signature combinations of methods are maintained in a set. | |
HashSet resultSet = new HashSet(); | |
// The methods of its own (own methods() command). | |
resultSet.addAll(methods()); | |
// All methods of the interfaces it implements. | |
Iterator interfaces = interfaces().iterator(); | |
InterfaceTypeImpl inter; | |
while (interfaces.hasNext()) { | |
inter = (InterfaceTypeImpl)interfaces.next(); | |
resultSet.addAll(inter.allMethods()); | |
} | |
// If it is a class, all methods of it's superclass. | |
if (this instanceof ClassType) { | |
ClassType superclass = ((ClassType)this).superclass(); | |
if (superclass != null) | |
resultSet.addAll(superclass.allMethods()); | |
} | |
fAllMethods = new ArrayList(resultSet); | |
return fAllMethods; | |
} | |
/** | |
* @return Returns the interfaces declared as implemented by this class. Interfaces indirectly implemented (extended by the implemented interface or implemented by a superclass) are not included. | |
*/ | |
public List interfaces() { | |
if (fInterfaces != null) | |
return fInterfaces; | |
initJdwpRequest(); | |
try { | |
JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.RT_INTERFACES, this); | |
defaultReplyErrorHandler(replyPacket.errorCode()); | |
DataInputStream replyData = replyPacket.dataInStream(); | |
Vector elements = new Vector(); | |
int nrOfElements = readInt("elements", replyData); | |
for (int i = 0; i < nrOfElements; i++) { | |
InterfaceTypeImpl ref = InterfaceTypeImpl.read(this, replyData); | |
if (ref == null) | |
continue; | |
elements.add(ref); | |
} | |
fInterfaces = elements; | |
return elements; | |
} catch (IOException e) { | |
defaultIOExceptionHandler(e); | |
return null; | |
} finally { | |
handledJdwpRequest(); | |
} | |
} | |
/** | |
* @return Returns the interfaces declared as implemented by this class. Interfaces indirectly implemented (extended by the implemented interface or implemented by a superclass) are not included. | |
*/ | |
public List allInterfaces() { | |
if (fAllInterfaces != null) | |
return fAllInterfaces; | |
/* Recursion: | |
* The interfaces that it directly implements; | |
* All interfaces that are implemented by its interfaces; | |
* If it is a class, all interfaces that are implemented by its superclass. | |
*/ | |
// The interfaces are maintained in a set, to avoid duplicates. | |
// The interfaces of its own (own interfaces() command) are first inserted. | |
HashSet allInterfacesSet = new HashSet(interfaces()); | |
// All interfaces of the interfaces it implements. | |
Iterator interfaces = interfaces().iterator(); | |
InterfaceTypeImpl inter; | |
while (interfaces.hasNext()) { | |
inter = (InterfaceTypeImpl)interfaces.next(); | |
allInterfacesSet.addAll(inter.allInterfaces()); | |
} | |
// If it is a class, all interfaces of it's superclass. | |
if (this instanceof ClassType) { | |
ClassType superclass = ((ClassType)this).superclass(); | |
if (superclass != null) | |
allInterfacesSet.addAll(superclass.allInterfaces()); | |
} | |
fAllInterfaces = new ArrayList(allInterfacesSet); | |
return fAllInterfaces; | |
} | |
/** | |
* Add fields to a set of fields if they are not overriden, add new fieldnames to set of fieldnames. | |
*/ | |
private void addVisibleFields(List newFields, HashSet names, Vector resultFields) { | |
Iterator iter = newFields.iterator(); | |
FieldImpl field; | |
while (iter.hasNext()) { | |
field = (FieldImpl)iter.next(); | |
String name = field.name(); | |
if (!names.contains(name)) { | |
resultFields.add(field); | |
names.add(name); | |
} | |
} | |
} | |
/** | |
* @return Returns a list containing each unhidden and unambiguous Field in this type. | |
*/ | |
public List visibleFields() { | |
if (fVisibleFields != null) | |
return fVisibleFields; | |
/* Recursion: | |
* The fields of its own (own fields() command); | |
* All fields of the interfaces it implements; | |
* If it is a class, all fields of it's superclass. | |
*/ | |
// The names of fields are maintained in a set, to avoid including fields that have been overriden. | |
HashSet fieldNames = new HashSet(); | |
// The fields of its own (own fields() command). | |
Vector visibleFields = new Vector(); | |
addVisibleFields(fields(), fieldNames, visibleFields); | |
// All fields of the interfaces it implements. | |
Iterator interfaces = interfaces().iterator(); | |
InterfaceTypeImpl inter; | |
while (interfaces.hasNext()) { | |
inter = (InterfaceTypeImpl)interfaces.next(); | |
addVisibleFields(inter.visibleFields(), fieldNames, visibleFields); | |
} | |
// If it is a class, all fields of it's superclass. | |
if (this instanceof ClassType) { | |
ClassType superclass = ((ClassType)this).superclass(); | |
if (superclass != null) | |
addVisibleFields(superclass.visibleFields(), fieldNames, visibleFields); | |
} | |
fVisibleFields = visibleFields; | |
return fVisibleFields; | |
} | |
/** | |
* @return Returns a list containing each Field declared in this type, and its superclasses, implemented interfaces, and/or superinterfaces. | |
*/ | |
public List allFields() { | |
if (fAllFields != null) | |
return fAllFields; | |
/* Recursion: | |
* The fields of its own (own fields() command); | |
* All fields of the interfaces it implements; | |
* If it is a class, all fields of it's superclass. | |
*/ | |
// The names of fields are maintained in a set, to avoid including fields that have been inherited double. | |
HashSet resultSet = new HashSet(); | |
// The fields of its own (own fields() command). | |
resultSet.addAll(fields()); | |
// All fields of the interfaces it implements. | |
Iterator interfaces = interfaces().iterator(); | |
InterfaceTypeImpl inter; | |
while (interfaces.hasNext()) { | |
inter = (InterfaceTypeImpl)interfaces.next(); | |
resultSet.addAll(inter.allFields()); | |
} | |
// If it is a class, all fields of it's superclass. | |
if (this instanceof ClassType) { | |
ClassType superclass = ((ClassType)this).superclass(); | |
if (superclass != null) | |
resultSet.addAll(superclass.allFields()); | |
} | |
fAllFields = new ArrayList(resultSet); | |
return fAllFields; | |
} | |
/** | |
* @return Returns the classloader object which loaded the class corresponding to this type. | |
*/ | |
public ClassLoaderReference classLoader() { | |
if (fClassLoader != null) | |
return fClassLoader; | |
initJdwpRequest(); | |
try { | |
JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.RT_CLASS_LOADER, this); | |
defaultReplyErrorHandler(replyPacket.errorCode()); | |
DataInputStream replyData = replyPacket.dataInStream(); | |
fClassLoader = ClassLoaderReferenceImpl.read(this, replyData); | |
return fClassLoader; | |
} catch (IOException e) { | |
defaultIOExceptionHandler(e); | |
return null; | |
} finally { | |
handledJdwpRequest(); | |
} | |
} | |
/** | |
* @return Returns the class object that corresponds to this type in the target VM. | |
*/ | |
public ClassObjectReference classObject() { | |
if (fClassObject != null) | |
return fClassObject; | |
initJdwpRequest(); | |
try { | |
JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.RT_CLASS_OBJECT, this); | |
defaultReplyErrorHandler(replyPacket.errorCode()); | |
DataInputStream replyData = replyPacket.dataInStream(); | |
fClassObject = ClassObjectReferenceImpl.read(this, replyData); | |
return fClassObject; | |
} catch (IOException e) { | |
defaultIOExceptionHandler(e); | |
return null; | |
} finally { | |
handledJdwpRequest(); | |
} | |
} | |
/** | |
* @return Returns status of class/interface. | |
*/ | |
protected int status() { | |
// Note that this information should not be cached. | |
initJdwpRequest(); | |
try { | |
JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.RT_STATUS, this); | |
defaultReplyErrorHandler(replyPacket.errorCode()); | |
DataInputStream replyData = replyPacket.dataInStream(); | |
int status = readInt("status", classStatusVector(), replyData); | |
return status; | |
} catch (IOException e) { | |
defaultIOExceptionHandler(e); | |
return 0; | |
} finally { | |
handledJdwpRequest(); | |
} | |
} | |
/** | |
* @return Returns true if initialization failed for this class. | |
*/ | |
public boolean failedToInitialize() { | |
return (status() & JDWP_CLASS_STATUS_ERROR) != 0; | |
} | |
/** | |
* @return Returns true if this type has been initialized. | |
*/ | |
public boolean isInitialized() { | |
return (status() & JDWP_CLASS_STATUS_INITIALIZED) != 0; | |
} | |
/** | |
* @return Returns true if this type has been prepared. | |
*/ | |
public boolean isPrepared() { | |
return (status() & JDWP_CLASS_STATUS_PREPARED) != 0; | |
} | |
/** | |
* @return Returns true if this type has been verified. | |
*/ | |
public boolean isVerified() { | |
return (status() & JDWP_CLASS_STATUS_VERIFIED) != 0; | |
} | |
/** | |
* @return Returns the visible Field with the given non-ambiguous name. | |
*/ | |
public Field fieldByName(String name) { | |
Iterator iter = visibleFields().iterator(); | |
while (iter.hasNext()) { | |
FieldImpl field = (FieldImpl)iter.next(); | |
if (field.name().equals(name)) | |
return field; | |
} | |
return null; | |
} | |
/** | |
* @return Returns a list containing each Field declared in this type. | |
*/ | |
public List fields() { | |
if (fFields != null) | |
return fFields; | |
// Note: Fields are returned in the order they occur in the class file, therefore their | |
// order in this list can be used for comparisons. | |
initJdwpRequest(); | |
try { | |
JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.RT_FIELDS, this); | |
defaultReplyErrorHandler(replyPacket.errorCode()); | |
DataInputStream replyData = replyPacket.dataInStream(); | |
Vector elements = new Vector(); | |
int nrOfElements = readInt("elements", replyData); | |
for (int i = 0; i < nrOfElements; i++) { | |
FieldImpl elt = FieldImpl.readWithNameSignatureModifiers(this, this, replyData); | |
if (elt == null) | |
continue; | |
elements.add(elt); | |
} | |
fFields = elements; | |
return elements; | |
} catch (IOException e) { | |
defaultIOExceptionHandler(e); | |
return null; | |
} finally { | |
handledJdwpRequest(); | |
} | |
} | |
/** | |
* @return Returns FieldImpl of a field in the reference specified by a given fieldID, or null if not found. | |
*/ | |
public FieldImpl findField(JdwpFieldID fieldID) { | |
Iterator iter = allFields().iterator(); | |
while(iter.hasNext()) { | |
FieldImpl field = (FieldImpl)iter.next(); | |
if (field.getFieldID().equals(fieldID)) | |
return field; | |
} | |
return null; | |
} | |
/** | |
* @return Returns MethodImpl of a method in the reference specified by a given methodID, or null if not found. | |
*/ | |
public MethodImpl findMethod(JdwpMethodID methodID) { | |
Iterator iter = allMethods().iterator(); | |
while(iter.hasNext()) { | |
MethodImpl method = (MethodImpl)iter.next(); | |
if (method.getMethodID().equals(methodID)) | |
return method; | |
} | |
return null; | |
} | |
/** | |
* @return Returns the Value of a given static Field in this type. | |
*/ | |
public Value getValue(Field field) { | |
ArrayList list = new ArrayList(1); | |
list.add(field); | |
return (ValueImpl)getValues(list).get(field); | |
} | |
/** | |
* @return a Map of the requested static Field objects with their Value. | |
*/ | |
public Map getValues(List fields) { | |
// Note that this information should not be cached. | |
initJdwpRequest(); | |
try { | |
ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); | |
DataOutputStream outData = new DataOutputStream(outBytes); | |
int fieldsSize = fields.size(); | |
write(this, outData); | |
writeInt(fieldsSize, "size", outData); | |
for (int i = 0; i < fieldsSize; i++) { | |
FieldImpl field = (FieldImpl)fields.get(i); | |
checkVM(field); | |
field.getFieldID().write(outData); | |
} | |
JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.RT_GET_VALUES, outBytes); | |
defaultReplyErrorHandler(replyPacket.errorCode()); | |
DataInputStream replyData = replyPacket.dataInStream(); | |
HashMap map = new HashMap(); | |
int nrOfElements = readInt("elements", replyData); | |
if (nrOfElements != fieldsSize) | |
throw new InternalError("Retrieved a different number of values from the VM than requested."); | |
for (int i = 0; i < nrOfElements; i++) { | |
map.put(fields.get(i), ValueImpl.readWithTag(this, replyData)); | |
} | |
return map; | |
} catch (IOException e) { | |
defaultIOExceptionHandler(e); | |
return null; | |
} finally { | |
handledJdwpRequest(); | |
} | |
} | |
/** | |
* @return Returns the hash code value. | |
*/ | |
public int hashCode() { | |
return fReferenceTypeID.hashCode(); | |
} | |
/** | |
* @return Returns true if two mirrors refer to the same entity in the target VM. | |
* @see java.lang.Object#equals(Object) | |
*/ | |
public boolean equals(Object object) { | |
return object != null | |
&& object.getClass().equals(this.getClass()) | |
&& fReferenceTypeID.equals(((ReferenceTypeImpl)object).fReferenceTypeID) | |
&& virtualMachine().equals(((MirrorImpl)object).virtualMachine()); | |
} | |
/** | |
* @return Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object. | |
*/ | |
public int compareTo(Object object) { | |
if (object == null || !object.getClass().equals(this.getClass())) | |
throw new ClassCastException("Can't compare reference type to given object."); | |
return name().compareTo(((ReferenceType)object).name()); | |
} | |
/** | |
* @return Returns true if the type was declared abstract. | |
*/ | |
public boolean isAbstract() { | |
return (modifiers() & MODIFIER_ACC_ABSTRACT) != 0; | |
} | |
/** | |
* @return Returns true if the type was declared final. | |
*/ | |
public boolean isFinal() { | |
return (modifiers() & MODIFIER_ACC_FINAL) != 0; | |
} | |
/** | |
* @return Returns true if the type was declared static. | |
*/ | |
public boolean isStatic() { | |
return (modifiers() & MODIFIER_ACC_STATIC) != 0; | |
} | |
/** | |
* @return Returns a List filled with all Location objects that map to the given line number. | |
*/ | |
public List locationsOfLine(int line) throws AbsentInformationException { | |
Iterator allMethods = methods().iterator(); | |
List locations; | |
while (allMethods.hasNext()) { | |
MethodImpl method = (MethodImpl)allMethods.next(); | |
try { | |
locations = method.locationsOfLine(line); | |
} catch (AbsentInformationException e) { | |
continue; | |
} catch (InvalidLineNumberException e) { | |
continue; | |
} | |
return locations; | |
} | |
throw new InvalidLineNumberException("No executable code at line " + line + "."); | |
} | |
/** | |
* @return Returns a list containing each Method declared directly in this type. | |
*/ | |
public List methods() { | |
// Note that ArrayReference overwrites this method by returning an empty list. | |
if (fMethods != null) | |
return fMethods; | |
// Note: Methods are returned in the order they occur in the class file, therefore their | |
// order in this list can be used for comparisons. | |
initJdwpRequest(); | |
try { | |
JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.RT_METHODS, this); | |
defaultReplyErrorHandler(replyPacket.errorCode()); | |
DataInputStream replyData = replyPacket.dataInStream(); | |
Vector elements = new Vector(); | |
int nrOfElements = readInt("elements", replyData); | |
for (int i = 0; i < nrOfElements; i++) { | |
MethodImpl elt = MethodImpl.readWithNameSignatureModifiers(this, this, replyData); | |
if (elt == null) | |
continue; | |
elements.add(elt); | |
} | |
fMethods = elements; | |
return elements; | |
} catch (IOException e) { | |
defaultIOExceptionHandler(e); | |
return null; | |
} finally { | |
handledJdwpRequest(); | |
} | |
} | |
/** | |
* @return Returns a List containing each visible Method that has the given name. | |
*/ | |
public List methodsByName(String name) { | |
Vector elements = new Vector(); | |
Iterator iter = visibleMethods().iterator(); | |
while (iter.hasNext()) { | |
MethodImpl method = (MethodImpl)iter.next(); | |
if (method.name().equals(name)) | |
elements.add(method); | |
} | |
return elements; | |
} | |
/** | |
* @return Returns a List containing each visible Method that has the given name and signature. | |
*/ | |
public List methodsByName(String name, String signature) { | |
Vector elements = new Vector(); | |
Iterator iter = visibleMethods().iterator(); | |
while (iter.hasNext()) { | |
MethodImpl method = (MethodImpl)iter.next(); | |
if (method.name().equals(name) && method.signature().equals(signature)) | |
elements.add(method); | |
} | |
return elements; | |
} | |
/** | |
* @return Returns the fully qualified name of this type. | |
*/ | |
public String name() { | |
// Make sure that we know the signature, from which the name is derived. | |
if (fName == null) | |
setName(signatureToName(signature())); | |
return fName; | |
} | |
/** | |
* @return Returns the JNI-style signature for this type. | |
*/ | |
public String signature() { | |
if (fSignature != null) | |
return fSignature; | |
initJdwpRequest(); | |
try { | |
JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.RT_SIGNATURE, this); | |
defaultReplyErrorHandler(replyPacket.errorCode()); | |
DataInputStream replyData = replyPacket.dataInStream(); | |
setSignature(readString("signature", replyData)); | |
return fSignature; | |
} catch (IOException e) { | |
defaultIOExceptionHandler(e); | |
return null; | |
} finally { | |
handledJdwpRequest(); | |
} | |
} | |
/** | |
* @return Returns a List containing each ReferenceType declared within this type. | |
*/ | |
public List nestedTypes() { | |
// Note that the VM gives an empty reply on RT_NESTED_TYPES, therefore we search for the | |
// nested types in the loaded types. | |
Vector result = new Vector(); | |
Enumeration enum = virtualMachineImpl().allRefTypesEnum(); | |
while (enum.hasMoreElements()) { | |
try { | |
ReferenceTypeImpl refType = (ReferenceTypeImpl)enum.nextElement(); | |
String refName = refType.name(); | |
if (refName.length() > name().length() && refName.startsWith(name()) && refName.charAt(name().length()) == '$') | |
result.add(refType); | |
} catch (ClassNotPreparedException e) { | |
continue; | |
} | |
} | |
return result; | |
} | |
/** | |
* @return Returns an identifing name for the source corresponding to the declaration of this type. | |
*/ | |
public String sourceName() throws AbsentInformationException { | |
if (fSourcename != null) | |
return fSourcename; | |
initJdwpRequest(); | |
try { | |
JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.RT_SOURCE_FILE, this); | |
if (replyPacket.errorCode() == JdwpReplyPacket.ABSENT_INFORMATION) | |
throw new AbsentInformationException("Source name is not known."); | |
else | |
defaultReplyErrorHandler(replyPacket.errorCode()); | |
DataInputStream replyData = replyPacket.dataInStream(); | |
fSourcename = readString("source name", replyData); | |
return fSourcename; | |
} catch (IOException e) { | |
defaultIOExceptionHandler(e); | |
return null; | |
} finally { | |
handledJdwpRequest(); | |
} | |
} | |
/** | |
* @return Returns the CRC-32 of the given reference type, undefined if unknown. | |
*/ | |
public int getClassFileVersion() { | |
virtualMachineImpl().checkHCRSupported(); | |
if (fGotClassFileVersion) | |
return fClassFileVersion; | |
initJdwpRequest(); | |
try { | |
JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.HCR_GET_CLASS_VERSION, this); | |
defaultReplyErrorHandler(replyPacket.errorCode()); | |
DataInputStream replyData = replyPacket.dataInStream(); | |
fIsHCREligible = readBoolean("HCR eligible", replyData); | |
fIsVersionKnown = readBoolean("version known", replyData); | |
fClassFileVersion = readInt("class file version", replyData); | |
fGotClassFileVersion = true; | |
return fClassFileVersion; | |
} catch (IOException e) { | |
defaultIOExceptionHandler(e); | |
return 0; | |
} finally { | |
handledJdwpRequest(); | |
} | |
} | |
/** | |
* @return Returns whether the CRC-32 of the given reference type is known. | |
*/ | |
public boolean isVersionKnown() { | |
getClassFileVersion(); | |
return fIsVersionKnown; | |
} | |
/** | |
* @return Returns whether the reference type is HCR-eligible. | |
*/ | |
public boolean isHCREligible() { | |
getClassFileVersion(); | |
return fIsHCREligible; | |
} | |
/** | |
* Writes JDWP representation. | |
*/ | |
public void write(MirrorImpl target, DataOutputStream out) throws IOException { | |
fReferenceTypeID.write(out); | |
if (target.fVerboseWriter != null) | |
target.fVerboseWriter.println("referenceType", fReferenceTypeID.value()); | |
} | |
/** | |
* Writes representation of null referenceType. | |
*/ | |
public static void writeNull(MirrorImpl target, DataOutputStream out) throws IOException { | |
// create null id | |
JdwpReferenceTypeID ID = new JdwpReferenceTypeID(target.virtualMachineImpl()); | |
ID.write(out); | |
if (target.fVerboseWriter != null) | |
target.fVerboseWriter.println("referenceType", ID.value()); | |
} | |
/** | |
* Writes JDWP representation. | |
*/ | |
public void writeWithTag(MirrorImpl target, DataOutputStream out) throws IOException { | |
target.writeByte(typeTag(), "type tag", JdwpID.typeTagMap(), out); | |
write(target, out); | |
} | |
/** | |
* @return Reads JDWP representation and returns new or cached instance. | |
*/ | |
public static ReferenceTypeImpl readWithTypeTag(MirrorImpl target, DataInputStream in) throws IOException { | |
byte typeTag = target.readByte("type tag", JdwpID.typeTagMap(), in); | |
switch (typeTag) { | |
case 0: | |
return null; | |
case ArrayTypeImpl.typeTag: | |
return ArrayTypeImpl.read(target, in); | |
case ClassTypeImpl.typeTag: | |
return ClassTypeImpl.read(target, in); | |
case InterfaceTypeImpl.typeTag: | |
return InterfaceTypeImpl.read(target, in); | |
} | |
throw new InternalException("Invalid ReferenceTypeID tag encountered: " + typeTag); | |
} | |
/** | |
* @return Returns the Location objects for each executable source line in this reference type. | |
*/ | |
public List allLineLocations() throws AbsentInformationException { | |
if (fAllLineLocations != null) | |
return fAllLineLocations; | |
Iterator allMethods = methods().iterator(); | |
Vector locations = new Vector(); | |
while (allMethods.hasNext()) { | |
MethodImpl method = (MethodImpl)allMethods.next(); | |
locations.addAll(method.allLineLocations()); | |
} | |
fAllLineLocations = locations; | |
return fAllLineLocations; | |
} | |
/** | |
* @return Reads JDWP representation and returns new or cached instance. | |
*/ | |
public static ReferenceTypeImpl readWithTypeTagAndSignature(MirrorImpl target, DataInputStream in) throws IOException { | |
byte typeTag = target.readByte("type tag", JdwpID.typeTagMap(), in); | |
switch (typeTag) { | |
case 0: | |
return null; | |
case ArrayTypeImpl.typeTag: | |
return ArrayTypeImpl.readWithSignature(target, in); | |
case ClassTypeImpl.typeTag: | |
return ClassTypeImpl.readWithSignature(target, in); | |
case InterfaceTypeImpl.typeTag: | |
return InterfaceTypeImpl.readWithSignature(target, in); | |
} | |
throw new InternalException("Invalid ReferenceTypeID tag encountered: " + typeTag); | |
} | |
/** | |
* @return Returns new instance based on signature and classLoader. | |
* @throws ClassNotLoadedException when the ReferenceType has not been loaded by the specified class loader. | |
*/ | |
public static TypeImpl create(VirtualMachineImpl vmImpl, String signature, ClassLoaderReference classLoader) throws ClassNotLoadedException { | |
Iterator iter = vmImpl.classesBySignature(signature).iterator(); | |
ReferenceTypeImpl refTypeBootstrap = null; | |
while (iter.hasNext()) { | |
ReferenceTypeImpl type = (ReferenceTypeImpl)iter.next(); | |
if (type.classLoader() == null) { // bootstrap classloader | |
if (classLoader == null) | |
return type; | |
else | |
refTypeBootstrap = type; | |
} | |
if (classLoader != null && classLoader.equals(type.classLoader())) | |
return (ReferenceTypeImpl)type; | |
} | |
// If no ReferenceType is found with the specified classloader, but there is one with the | |
// bootstrap classloader, the latter is returned. | |
if (refTypeBootstrap != null) | |
return refTypeBootstrap; | |
throw new ClassNotLoadedException(TypeImpl.classSignatureToName(signature), "Type has not been loaded."); | |
} | |
/** | |
* Retrieves constant mappings. | |
*/ | |
public static void getConstantMaps() { | |
if (fClassStatusVector != null) | |
return; | |
java.lang.reflect.Field[] fields = ReferenceTypeImpl.class.getDeclaredFields(); | |
fClassStatusVector = new Vector(); | |
fClassStatusVector.setSize(32); // Integer | |
for (int i = 0; i < fields.length; i++) { | |
java.lang.reflect.Field field = fields[i]; | |
if ((field.getModifiers() & java.lang.reflect.Modifier.PUBLIC) == 0 || (field.getModifiers() & java.lang.reflect.Modifier.STATIC) == 0 || (field.getModifiers() & java.lang.reflect.Modifier.FINAL) == 0) | |
continue; | |
String name = field.getName(); | |
if (!name.startsWith("JDWP_CLASS_STATUS_")) | |
continue; | |
name = name.substring(18); | |
try { | |
int value = field.getInt(null); | |
for (int j = 0; j < fClassStatusVector.size(); j++) { | |
if ((1 << j & value) != 0) { | |
fClassStatusVector.set(j, name); | |
break; | |
} | |
} | |
} catch (IllegalAccessException e) { | |
// Will not occur for own class. | |
} catch (IllegalArgumentException e) { | |
// Should not occur. | |
// We should take care that all public static final constants | |
// in this class are numbers that are convertible to int. | |
} | |
} | |
} | |
/** | |
* @return Returns a map with string representations of tags. | |
*/ | |
public static Vector classStatusVector() { | |
getConstantMaps(); | |
return fClassStatusVector; | |
} | |
} |