blob: 7bf1d5653008581be85fd46f611405246bacc887 [file] [log] [blame]
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 class StackFrameImpl extends MirrorImpl implements StackFrame, Locatable {
/** FrameID that corresponds to this reference. */
private JdwpFrameID fFrameID;
/** Thread under which this frame's method is running. */
private ThreadReferenceImpl fThread;
/** Location of the current instruction in the frame. */
private LocationImpl fLocation;
/**
* Creates new StackFrameImpl.
*/
public StackFrameImpl(VirtualMachineImpl vmImpl, JdwpFrameID ID, ThreadReferenceImpl thread, LocationImpl location) {
super("StackFrame", vmImpl);
fFrameID = ID;
fThread = thread;
fLocation = location;
}
/**
* @return Returns the Value of a LocalVariable in this frame.
*/
public Value getValue(LocalVariable variable) throws IllegalArgumentException, InvalidStackFrameException, VMMismatchException {
ArrayList list = new ArrayList(1);
list.add(variable);
return (ValueImpl)getValues(list).get(variable);
}
/**
* @return Returns the values of multiple local variables in this frame.
*/
public Map getValues(List variables) throws IllegalArgumentException, InvalidStackFrameException, VMMismatchException {
// Note that this information should not be cached.
HashMap map = new HashMap();
/*
* If 'this' is requested, we have to use a special JDWP request.
* Therefore, we remember the positions in the list of requests for 'this'.
*/
int sizeAll = variables.size();
int sizeThis = 0;
boolean[] isThisValue = new boolean[sizeAll];
for (int i = 0; i < sizeAll; i++) {
LocalVariableImpl var = (LocalVariableImpl)variables.get(i);
isThisValue[i] = var.isThis();
if (isThisValue[i])
sizeThis++;
}
int sizeNotThis = sizeAll - sizeThis;
if (sizeThis > 0) {
Value thisValue = thisObject();
for (int i = 0; i < sizeAll; i++) {
if (isThisValue[i])
map.put(variables.get(i), thisValue);
}
}
// If only 'this' was requested, we're finished.
if (sizeNotThis == 0)
return map;
// Request values for local variables other than 'this'.
initJdwpRequest();
try {
ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
DataOutputStream outData = new DataOutputStream(outBytes);
writeWithThread(this, outData);
writeInt(sizeNotThis, "size", outData);
for (int i = 0; i < sizeNotThis; i++) {
LocalVariableImpl var = (LocalVariableImpl)variables.get(i);
checkVM(var);
writeInt(var.slot(), "slot", outData);
writeByte(var.tag(), "tag", JdwpID.tagMap(), outData);
}
JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.SF_GET_VALUES, outBytes);
defaultReplyErrorHandler(replyPacket.errorCode());
DataInputStream replyData = replyPacket.dataInStream();
int nrOfElements = readInt("elements", replyData);
if (nrOfElements != sizeNotThis)
throw new InternalError("Retrieved a different number of values from the VM than requested.");
for (int i = 0, j = 0; i < sizeAll; i++) {
if (!isThisValue[i])
map.put(variables.get(j++), ValueImpl.readWithTag(this, replyData));
}
return map;
} catch (IOException e) {
defaultIOExceptionHandler(e);
return null;
} finally {
handledJdwpRequest();
}
}
/**
* @return Returns the Location of the current instruction in the frame.
*/
public Location location() {
return fLocation;
}
/**
* Sets the Value of a LocalVariable in this frame.
*/
public void setValue(LocalVariable var, Value value) throws InvalidTypeException, ClassNotLoadedException {
// Note that this information should not be cached.
initJdwpRequest();
try {
ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
DataOutputStream outData = new DataOutputStream(outBytes);
((ThreadReferenceImpl)thread()).write(this, outData);
write(this, outData);
writeInt(1, "size", outData); // We only set one field
checkVM(var);
writeInt(((LocalVariableImpl)var).slot(), "slot", outData);
if (value != null) {
checkVM(value);
((ValueImpl)value).writeWithTag(this, outData);
} else {
ValueImpl.writeNullWithTag(this, outData);
}
JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.SF_SET_VALUES, outBytes);
switch (replyPacket.errorCode()) {
case JdwpReplyPacket.TYPE_MISMATCH:
throw new InvalidTypeException();
case JdwpReplyPacket.INVALID_CLASS:
throw new ClassNotLoadedException(var.typeName());
}
defaultReplyErrorHandler(replyPacket.errorCode());
} catch (IOException e) {
defaultIOExceptionHandler(e);
} finally {
handledJdwpRequest();
}
}
/**
* @return Returns the value of 'this' for the current frame.
*/
public ObjectReference thisObject() throws InvalidStackFrameException {
// Note that this information should not be cached.
initJdwpRequest();
try {
ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
DataOutputStream outData = new DataOutputStream(outBytes);
writeWithThread(this, outData);
JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.SF_THIS_OBJECT, outBytes);
defaultReplyErrorHandler(replyPacket.errorCode());
DataInputStream replyData = replyPacket.dataInStream();
ObjectReference result = ObjectReferenceImpl.readObjectRefWithTag(this, replyData);
return result;
} catch (IOException e) {
defaultIOExceptionHandler(e);
return null;
} finally {
handledJdwpRequest();
}
}
/**
* @return Returns the thread under which this frame's method is running.
*/
public com.sun.jdi.ThreadReference thread() {
return fThread;
}
/**
* @return Returns a LocalVariable that matches the given name and is visible at the current frame location.
*/
public LocalVariable visibleVariableByName(String name) throws AbsentInformationException {
Iterator iter = visibleVariables().iterator();
while (iter.hasNext()) {
LocalVariableImpl var = (LocalVariableImpl)iter.next();
if (var.name().equals(name))
return var;
}
return null;
}
/**
* @return Returns the values of multiple local variables in this frame.
*/
public List visibleVariables() throws AbsentInformationException {
Iterator iter = fLocation.method().variables().iterator();
Vector visibleVars = new Vector();
while (iter.hasNext()) {
LocalVariableImpl var = (LocalVariableImpl)iter.next();
// Only return local variables other than the this pointer.
if (var.isVisible(this) && !var.isThis())
visibleVars.add(var);
}
return visibleVars;
}
/**
* @return Returns the hash code value.
*/
public int hashCode() {
return fThread.hashCode() + fFrameID.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()) && fThread.equals(((StackFrameImpl)object).fThread) && fFrameID.equals(((StackFrameImpl)object).fFrameID);
}
/**
* Writes JDWP representation.
*/
public void write(MirrorImpl target, DataOutputStream out) throws IOException {
fFrameID.write(out);
if (target.fVerboseWriter != null)
target.fVerboseWriter.println("stackFrame", fFrameID.value());
}
/**
* Writes JDWP representation.
*/
public void writeWithThread(MirrorImpl target, DataOutputStream out) throws IOException {
fThread.write(target, out);
write(target, out);
}
/**
* @return Reads JDWP representation and returns new instance.
*/
public static StackFrameImpl readWithLocation(MirrorImpl target, ThreadReferenceImpl thread, DataInputStream in) throws IOException {
VirtualMachineImpl vmImpl = target.virtualMachineImpl();
JdwpFrameID ID = new JdwpFrameID(vmImpl);
ID.read(in);
if (target.fVerboseWriter != null)
target.fVerboseWriter.println("stackFrame", ID.value());
if (ID.isNull())
return null;
LocationImpl location = LocationImpl.read(target, in);
if (location == null)
return null;
return new StackFrameImpl(vmImpl, ID, thread, location);
}
}