blob: 2b0bfa7dcb1b4b4516e62ee7037de9aa4b353c79 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2015 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdi.internal;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket;
import org.eclipse.jdi.internal.jdwp.JdwpFrameID;
import org.eclipse.jdi.internal.jdwp.JdwpID;
import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket;
import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin;
import com.sun.jdi.AbsentInformationException;
import com.sun.jdi.ClassNotLoadedException;
import com.sun.jdi.InvalidStackFrameException;
import com.sun.jdi.InvalidTypeException;
import com.sun.jdi.LocalVariable;
import com.sun.jdi.Locatable;
import com.sun.jdi.Location;
import com.sun.jdi.ObjectReference;
import com.sun.jdi.StackFrame;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.VMMismatchException;
import com.sun.jdi.Value;
/**
* 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); //$NON-NLS-1$
fFrameID = ID;
fThread = thread;
fLocation = location;
}
/* (non-Javadoc)
* @see com.sun.jdi.StackFrame#getValue(com.sun.jdi.LocalVariable)
*/
@Override
public Value getValue(LocalVariable variable)
throws IllegalArgumentException, InvalidStackFrameException,
VMMismatchException {
ArrayList<LocalVariable> list = new ArrayList<>(1);
list.add(variable);
return getValues(list).get(variable);
}
/* (non-Javadoc)
* @see com.sun.jdi.StackFrame#getValues(java.util.List)
*/
@Override
public Map<LocalVariable, Value> getValues(List<? extends LocalVariable> variables) throws IllegalArgumentException,
InvalidStackFrameException, VMMismatchException {
// Note that this information should not be cached.
Map<LocalVariable, Value> map = new HashMap<>(variables.size());
// if the variable list is empty, nothing to do
if (variables.isEmpty()) {
return map;
}
/*
* 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); //$NON-NLS-1$
for (int i = 0; i < sizeAll; i++) {
if (!isThisValue[i]) {
LocalVariableImpl var = (LocalVariableImpl) variables
.get(i);
checkVM(var);
writeInt(var.slot(), "slot", outData); //$NON-NLS-1$
writeByte(var.tag(), "tag", JdwpID.tagMap(), outData); //$NON-NLS-1$
}
}
JdwpReplyPacket replyPacket = requestVM(
JdwpCommandPacket.SF_GET_VALUES, outBytes);
defaultReplyErrorHandler(replyPacket.errorCode());
DataInputStream replyData = replyPacket.dataInStream();
int nrOfElements = readInt("elements", replyData); //$NON-NLS-1$
if (nrOfElements != sizeNotThis)
throw new InternalError(
JDIMessages.StackFrameImpl_Retrieved_a_different_number_of_values_from_the_VM_than_requested_1);
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();
}
}
/* (non-Javadoc)
* @see com.sun.jdi.StackFrame#getArgumentValues()
*/
@Override
public List<Value> getArgumentValues() throws InvalidStackFrameException {
if (!thread().isSuspended()) {
throw new InvalidStackFrameException(
JDIMessages.StackFrameImpl_no_argument_values_available);
}
try {
List<LocalVariable> list = location().method().variables();
ArrayList<Value> ret = new ArrayList<>();
LocalVariable var = null;
for (Iterator<LocalVariable> iter = list.iterator(); iter.hasNext();) {
var = iter.next();
if (var.isArgument()) {
ret.add(getValue(var));
}
}
return ret;
} catch (AbsentInformationException e) {
JDIDebugPlugin.log(e);
return null;
}
}
/* (non-Javadoc)
* @see com.sun.jdi.StackFrame#location()
*/
@Override
public Location location() {
return fLocation;
}
/* (non-Javadoc)
* @see com.sun.jdi.StackFrame#setValue(com.sun.jdi.LocalVariable, com.sun.jdi.Value)
*/
@Override
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 //$NON-NLS-1$
checkVM(var);
writeInt(((LocalVariableImpl) var).slot(), "slot", outData); //$NON-NLS-1$
// check the type and the VM of the value, convert the value if
// needed.
ValueImpl checkedValue = ValueImpl.checkValue(value, var.type(),
virtualMachineImpl());
if (checkedValue != null) {
checkedValue.writeWithTag(this, outData);
} else {
ValueImpl.writeNullWithTag(this, outData);
}
JdwpReplyPacket replyPacket = requestVM(
JdwpCommandPacket.SF_SET_VALUES, outBytes);
switch (replyPacket.errorCode()) {
case JdwpReplyPacket.INVALID_CLASS:
throw new ClassNotLoadedException(var.typeName());
}
defaultReplyErrorHandler(replyPacket.errorCode());
} catch (IOException e) {
defaultIOExceptionHandler(e);
} finally {
handledJdwpRequest();
}
}
/* (non-Javadoc)
* @see com.sun.jdi.StackFrame#thisObject()
*/
@Override
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();
}
}
/* (non-Javadoc)
* @see com.sun.jdi.StackFrame#thread()
*/
@Override
public ThreadReference thread() {
return fThread;
}
/* (non-Javadoc)
* @see com.sun.jdi.StackFrame#visibleVariableByName(java.lang.String)
*/
@Override
public LocalVariable visibleVariableByName(String name)
throws AbsentInformationException {
Iterator<LocalVariable> iter = visibleVariables().iterator();
while (iter.hasNext()) {
LocalVariableImpl var = (LocalVariableImpl) iter.next();
if (var.name().equals(name)) {
return var;
}
}
return null;
}
/* (non-Javadoc)
* @see com.sun.jdi.StackFrame#visibleVariables()
*/
@Override
public List<LocalVariable> visibleVariables() throws AbsentInformationException {
List<LocalVariable> variables = fLocation.method().variables();
Iterator<LocalVariable> iter = variables.iterator();
List<LocalVariable> visibleVars = new ArrayList<>(variables.size());
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.
*/
@Override
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)
*/
@Override
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()); //$NON-NLS-1$
}
}
/**
* 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()); //$NON-NLS-1$
}
if (ID.isNull()) {
return null;
}
LocationImpl location = LocationImpl.read(target, in);
if (location == null) {
return null;
}
return new StackFrameImpl(vmImpl, ID, thread, location);
}
}