001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdi.internal;
011:
012: import java.io.ByteArrayOutputStream;
013: import java.io.DataInputStream;
014: import java.io.DataOutputStream;
015: import java.io.IOException;
016: import java.util.ArrayList;
017: import java.util.HashMap;
018: import java.util.Iterator;
019: import java.util.List;
020: import java.util.Map;
021:
022: import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket;
023: import org.eclipse.jdi.internal.jdwp.JdwpFrameID;
024: import org.eclipse.jdi.internal.jdwp.JdwpID;
025: import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket;
026: import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin;
027:
028: import com.sun.jdi.AbsentInformationException;
029: import com.sun.jdi.ClassNotLoadedException;
030: import com.sun.jdi.InvalidStackFrameException;
031: import com.sun.jdi.InvalidTypeException;
032: import com.sun.jdi.LocalVariable;
033: import com.sun.jdi.Locatable;
034: import com.sun.jdi.Location;
035: import com.sun.jdi.ObjectReference;
036: import com.sun.jdi.StackFrame;
037: import com.sun.jdi.ThreadReference;
038: import com.sun.jdi.VMMismatchException;
039: import com.sun.jdi.Value;
040:
041: /**
042: * this class implements the corresponding interfaces
043: * declared by the JDI specification. See the com.sun.jdi package
044: * for more information.
045: *
046: */
047: public class StackFrameImpl extends MirrorImpl implements StackFrame,
048: Locatable {
049: /** FrameID that corresponds to this reference. */
050: private JdwpFrameID fFrameID;
051: /** Thread under which this frame's method is running. */
052: private ThreadReferenceImpl fThread;
053: /** Location of the current instruction in the frame. */
054: private LocationImpl fLocation;
055:
056: /**
057: * Creates new StackFrameImpl.
058: */
059: public StackFrameImpl(VirtualMachineImpl vmImpl, JdwpFrameID ID,
060: ThreadReferenceImpl thread, LocationImpl location) {
061: super ("StackFrame", vmImpl); //$NON-NLS-1$
062: fFrameID = ID;
063: fThread = thread;
064: fLocation = location;
065: }
066:
067: /**
068: * @return Returns the Value of a LocalVariable in this frame.
069: */
070: public Value getValue(LocalVariable variable)
071: throws IllegalArgumentException,
072: InvalidStackFrameException, VMMismatchException {
073: ArrayList list = new ArrayList(1);
074: list.add(variable);
075: return (ValueImpl) getValues(list).get(variable);
076: }
077:
078: /**
079: * @return Returns the values of multiple local variables in this frame.
080: */
081: public Map getValues(List variables)
082: throws IllegalArgumentException,
083: InvalidStackFrameException, VMMismatchException {
084: // Note that this information should not be cached.
085: Map map = new HashMap(variables.size());
086: // if the variable list is empty, nothing to do
087: if (variables.isEmpty()) {
088: return map;
089: }
090: /*
091: * If 'this' is requested, we have to use a special JDWP request.
092: * Therefore, we remember the positions in the list of requests for 'this'.
093: */
094: int sizeAll = variables.size();
095: int sizeThis = 0;
096: boolean[] isThisValue = new boolean[sizeAll];
097: for (int i = 0; i < sizeAll; i++) {
098: LocalVariableImpl var = (LocalVariableImpl) variables
099: .get(i);
100: isThisValue[i] = var.isThis();
101: if (isThisValue[i]) {
102: sizeThis++;
103: }
104: }
105: int sizeNotThis = sizeAll - sizeThis;
106:
107: if (sizeThis > 0) {
108: Value this Value = this Object();
109: for (int i = 0; i < sizeAll; i++) {
110: if (isThisValue[i]) {
111: map.put(variables.get(i), this Value);
112: }
113: }
114: }
115:
116: // If only 'this' was requested, we're finished.
117: if (sizeNotThis == 0) {
118: return map;
119: }
120:
121: // Request values for local variables other than 'this'.
122: initJdwpRequest();
123: try {
124: ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
125: DataOutputStream outData = new DataOutputStream(outBytes);
126: writeWithThread(this , outData);
127: writeInt(sizeNotThis, "size", outData); //$NON-NLS-1$
128: for (int i = 0; i < sizeAll; i++) {
129: if (!isThisValue[i]) {
130: LocalVariableImpl var = (LocalVariableImpl) variables
131: .get(i);
132: checkVM(var);
133: writeInt(var.slot(), "slot", outData); //$NON-NLS-1$
134: writeByte(var.tag(),
135: "tag", JdwpID.tagMap(), outData); //$NON-NLS-1$
136: }
137: }
138: JdwpReplyPacket replyPacket = requestVM(
139: JdwpCommandPacket.SF_GET_VALUES, outBytes);
140: defaultReplyErrorHandler(replyPacket.errorCode());
141:
142: DataInputStream replyData = replyPacket.dataInStream();
143: int nrOfElements = readInt("elements", replyData); //$NON-NLS-1$
144: if (nrOfElements != sizeNotThis)
145: throw new InternalError(
146: JDIMessages.StackFrameImpl_Retrieved_a_different_number_of_values_from_the_VM_than_requested_1);
147:
148: for (int i = 0, j = 0; i < sizeAll; i++) {
149: if (!isThisValue[i])
150: map.put(variables.get(j++), ValueImpl.readWithTag(
151: this , replyData));
152: }
153: return map;
154: } catch (IOException e) {
155: defaultIOExceptionHandler(e);
156: return null;
157: } finally {
158: handledJdwpRequest();
159: }
160: }
161:
162: /**
163: * @see com.sun.jdi.StackFrame#getArgumentValues()
164: * @since 3.3
165: */
166: public List getArgumentValues() throws InvalidStackFrameException {
167: if (!thread().isSuspended()) {
168: throw new InvalidStackFrameException(
169: JDIMessages.StackFrameImpl_no_argument_values_available);
170: }
171: try {
172: List list = location().method().variables();
173: ArrayList ret = new ArrayList();
174: LocalVariable var = null;
175: for (Iterator iter = list.iterator(); iter.hasNext();) {
176: var = (LocalVariable) iter.next();
177: if (var.isArgument()) {
178: ret.add(getValue(var));
179: }
180: }
181: return ret;
182: } catch (AbsentInformationException e) {
183: JDIDebugPlugin.log(e);
184: return null;
185: }
186: }
187:
188: /**
189: * @return Returns the Location of the current instruction in the frame.
190: */
191: public Location location() {
192: return fLocation;
193: }
194:
195: /**
196: * Sets the Value of a LocalVariable in this frame.
197: */
198: public void setValue(LocalVariable var, Value value)
199: throws InvalidTypeException, ClassNotLoadedException {
200: // Note that this information should not be cached.
201: initJdwpRequest();
202: try {
203: ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
204: DataOutputStream outData = new DataOutputStream(outBytes);
205: ((ThreadReferenceImpl) thread()).write(this , outData);
206: write(this , outData);
207: writeInt(1, "size", outData); // We only set one field //$NON-NLS-1$
208: checkVM(var);
209: writeInt(((LocalVariableImpl) var).slot(), "slot", outData); //$NON-NLS-1$
210:
211: // check the type and the vm of the value, convert the value if needed.
212: ValueImpl checkedValue = ValueImpl.checkValue(value, var
213: .type(), virtualMachineImpl());
214:
215: if (checkedValue != null) {
216: checkedValue.writeWithTag(this , outData);
217: } else {
218: ValueImpl.writeNullWithTag(this , outData);
219: }
220:
221: JdwpReplyPacket replyPacket = requestVM(
222: JdwpCommandPacket.SF_SET_VALUES, outBytes);
223: switch (replyPacket.errorCode()) {
224: case JdwpReplyPacket.INVALID_CLASS:
225: throw new ClassNotLoadedException(var.typeName());
226: }
227: defaultReplyErrorHandler(replyPacket.errorCode());
228: } catch (IOException e) {
229: defaultIOExceptionHandler(e);
230: } finally {
231: handledJdwpRequest();
232: }
233: }
234:
235: /**
236: * @return Returns the value of 'this' for the current frame.
237: */
238: public ObjectReference this Object()
239: throws InvalidStackFrameException {
240: // Note that this information should not be cached.
241: initJdwpRequest();
242: try {
243: ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
244: DataOutputStream outData = new DataOutputStream(outBytes);
245: writeWithThread(this , outData);
246:
247: JdwpReplyPacket replyPacket = requestVM(
248: JdwpCommandPacket.SF_THIS_OBJECT, outBytes);
249: defaultReplyErrorHandler(replyPacket.errorCode());
250:
251: DataInputStream replyData = replyPacket.dataInStream();
252: ObjectReference result = ObjectReferenceImpl
253: .readObjectRefWithTag(this , replyData);
254: return result;
255: } catch (IOException e) {
256: defaultIOExceptionHandler(e);
257: return null;
258: } finally {
259: handledJdwpRequest();
260: }
261: }
262:
263: /**
264: * @return Returns the thread under which this frame's method is running.
265: */
266: public ThreadReference thread() {
267: return fThread;
268: }
269:
270: /**
271: * @return Returns a LocalVariable that matches the given name and is visible at the current frame location.
272: */
273: public LocalVariable visibleVariableByName(String name)
274: throws AbsentInformationException {
275: Iterator iter = visibleVariables().iterator();
276: while (iter.hasNext()) {
277: LocalVariableImpl var = (LocalVariableImpl) iter.next();
278: if (var.name().equals(name)) {
279: return var;
280: }
281: }
282:
283: return null;
284: }
285:
286: /**
287: * @return Returns the values of multiple local variables in this frame.
288: */
289: public List visibleVariables() throws AbsentInformationException {
290: List variables = fLocation.method().variables();
291: Iterator iter = variables.iterator();
292: List visibleVars = new ArrayList(variables.size());
293: while (iter.hasNext()) {
294: LocalVariableImpl var = (LocalVariableImpl) iter.next();
295: // Only return local variables other than the this pointer.
296: if (var.isVisible(this ) && !var.isThis()) {
297: visibleVars.add(var);
298: }
299: }
300: return visibleVars;
301: }
302:
303: /**
304: * @return Returns the hash code value.
305: */
306: public int hashCode() {
307: return fThread.hashCode() + fFrameID.hashCode();
308: }
309:
310: /**
311: * @return Returns true if two mirrors refer to the same entity in the target VM.
312: * @see java.lang.Object#equals(Object)
313: */
314: public boolean equals(Object object) {
315: return object != null
316: && object.getClass().equals(this .getClass())
317: && fThread.equals(((StackFrameImpl) object).fThread)
318: && fFrameID.equals(((StackFrameImpl) object).fFrameID);
319: }
320:
321: /**
322: * Writes JDWP representation.
323: */
324: public void write(MirrorImpl target, DataOutputStream out)
325: throws IOException {
326: fFrameID.write(out);
327: if (target.fVerboseWriter != null) {
328: target.fVerboseWriter.println(
329: "stackFrame", fFrameID.value()); //$NON-NLS-1$
330: }
331: }
332:
333: /**
334: * Writes JDWP representation.
335: */
336: public void writeWithThread(MirrorImpl target, DataOutputStream out)
337: throws IOException {
338: fThread.write(target, out);
339: write(target, out);
340: }
341:
342: /**
343: * @return Reads JDWP representation and returns new instance.
344: */
345: public static StackFrameImpl readWithLocation(MirrorImpl target,
346: ThreadReferenceImpl thread, DataInputStream in)
347: throws IOException {
348: VirtualMachineImpl vmImpl = target.virtualMachineImpl();
349: JdwpFrameID ID = new JdwpFrameID(vmImpl);
350: ID.read(in);
351: if (target.fVerboseWriter != null) {
352: target.fVerboseWriter.println("stackFrame", ID.value()); //$NON-NLS-1$
353: }
354:
355: if (ID.isNull()) {
356: return null;
357: }
358: LocationImpl location = LocationImpl.read(target, in);
359: if (location == null) {
360: return null;
361: }
362:
363: return new StackFrameImpl(vmImpl, ID, thread, location);
364: }
365: }
|