/******************************************************************************* * Copyright (c) 2000, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * 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.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket; import org.eclipse.jdi.internal.jdwp.JdwpID; import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket; import org.eclipse.jdi.internal.jdwp.JdwpThreadID; import org.eclipse.osgi.util.NLS; import com.sun.jdi.ClassNotLoadedException; import com.sun.jdi.IncompatibleThreadStateException; import com.sun.jdi.InternalException; import com.sun.jdi.InvalidStackFrameException; import com.sun.jdi.InvalidTypeException; import com.sun.jdi.NativeMethodException; import com.sun.jdi.ObjectCollectedException; import com.sun.jdi.ObjectReference; import com.sun.jdi.StackFrame; import com.sun.jdi.ThreadGroupReference; import com.sun.jdi.ThreadReference; import com.sun.jdi.VMCannotBeModifiedException; import com.sun.jdi.VMDisconnectedException; 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 ThreadReferenceImpl extends ObjectReferenceImpl implements ThreadReference, org.eclipse.jdi.hcr.ThreadReference { /** ThreadStatus Constants. */ public static final int JDWP_THREAD_STATUS_ZOMBIE = 0; public static final int JDWP_THREAD_STATUS_RUNNING = 1; public static final int JDWP_THREAD_STATUS_SLEEPING = 2; public static final int JDWP_THREAD_STATUS_MONITOR = 3; public static final int JDWP_THREAD_STATUS_WAIT = 4; /** SuspendStatus Constants. */ public static final int SUSPEND_STATUS_SUSPENDED = 0x01; /** Mapping of command codes to strings. */ private static Map<Integer, String> fgThreadStatusMap = null; /** Map with Strings for flag bits. */ private static String[] fgSuspendStatusStrings = null; /** JDWP Tag. */ protected static final byte tag = JdwpID.THREAD_TAG; /** Is thread currently at a breakpoint? */ private boolean fIsAtBreakpoint = false; /** * The cached thread group. A thread's thread group cannot be changed. */ private ThreadGroupReferenceImpl fThreadGroup = null; /** * Creates new ThreadReferenceImpl. */ public ThreadReferenceImpl(VirtualMachineImpl vmImpl, JdwpThreadID threadID) { super("ThreadReference", vmImpl, threadID); //$NON-NLS-1$ } /** * Sets at breakpoint flag. */ public void setIsAtBreakpoint() { fIsAtBreakpoint = true; } /** * Reset flags that can be set when event occurs. */ public void resetEventFlags() { fIsAtBreakpoint = false; } /** * @returns Value tag. */ @Override public byte getTag() { return tag; } /** * @returns Returns an ObjectReference for the monitor, if any, for which * this thread is currently waiting. */ @Override public ObjectReference currentContendedMonitor() throws IncompatibleThreadStateException { if (!virtualMachine().canGetCurrentContendedMonitor()) { throw new UnsupportedOperationException(); } // Note that this information should not be cached. initJdwpRequest(); try { JdwpReplyPacket replyPacket = requestVM( JdwpCommandPacket.TR_CURRENT_CONTENDED_MONITOR, this); switch (replyPacket.errorCode()) { case JdwpReplyPacket.INVALID_THREAD: throw new ObjectCollectedException(); case JdwpReplyPacket.THREAD_NOT_SUSPENDED: throw new IncompatibleThreadStateException( JDIMessages.ThreadReferenceImpl_Thread_was_not_suspended_1); } defaultReplyErrorHandler(replyPacket.errorCode()); DataInputStream replyData = replyPacket.dataInStream(); ObjectReference result = ObjectReferenceImpl.readObjectRefWithTag( this, replyData); return result; } catch (IOException e) { defaultIOExceptionHandler(e); return null; } finally { handledJdwpRequest(); } } /** * @see com.sun.jdi.ThreadReference#forceEarlyReturn(com.sun.jdi.Value) * @since 3.3 */ @Override public void forceEarlyReturn(Value value) throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException { if (!virtualMachineImpl().canBeModified()) { throw new VMCannotBeModifiedException( JDIMessages.ThreadReferenceImpl_vm_read_only); } initJdwpRequest(); ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream(); DataOutputStream dataOutStream = new DataOutputStream(byteOutStream); try { write(this, dataOutStream); if (value != null) { ((ValueImpl) value).writeWithTag((ValueImpl) value, dataOutStream); } else { ValueImpl.writeNullWithTag(this, dataOutStream); } JdwpReplyPacket reply = requestVM( JdwpCommandPacket.TR_FORCE_EARLY_RETURN, byteOutStream); switch (reply.errorCode()) { case JdwpReplyPacket.INVALID_THREAD: throw new ObjectCollectedException( JDIMessages.ThreadReferenceImpl_thread_object_invalid); case JdwpReplyPacket.INVALID_OBJECT: throw new ClassNotLoadedException( JDIMessages.ThreadReferenceImpl_thread_or_value_unknown); case JdwpReplyPacket.THREAD_NOT_SUSPENDED: case JdwpReplyPacket.THREAD_NOT_ALIVE: throw new IncompatibleThreadStateException( JDIMessages.ThreadReferenceImpl_thread_not_suspended); case JdwpReplyPacket.NOT_IMPLEMENTED: throw new UnsupportedOperationException( JDIMessages.ThreadReferenceImpl_no_force_early_return_on_threads); case JdwpReplyPacket.OPAQUE_FRAME: throw new NativeMethodException( JDIMessages.ThreadReferenceImpl_thread_cannot_force_native_method); case JdwpReplyPacket.NO_MORE_FRAMES: throw new InvalidStackFrameException( JDIMessages.ThreadReferenceImpl_thread_no_stackframes); case JdwpReplyPacket.TYPE_MISMATCH: throw new InvalidTypeException( JDIMessages.ThreadReferenceImpl_incapatible_return_type); case JdwpReplyPacket.VM_DEAD: throw new VMDisconnectedException(JDIMessages.vm_dead); } defaultReplyErrorHandler(reply.errorCode()); } catch (IOException e) { defaultIOExceptionHandler(e); } finally { handledJdwpRequest(); } } /** * @returns Returns the StackFrame at the given index in the thread's * current call stack. */ @Override public StackFrame frame(int index) throws IncompatibleThreadStateException { return frames(index, 1).get(0); } /** * @see com.sun.jdi.ThreadReference#frameCount() */ @Override public int frameCount() throws IncompatibleThreadStateException { // Note that this information should not be cached. initJdwpRequest(); try { JdwpReplyPacket replyPacket = requestVM( JdwpCommandPacket.TR_FRAME_COUNT, this); switch (replyPacket.errorCode()) { case JdwpReplyPacket.INVALID_THREAD: throw new ObjectCollectedException(); case JdwpReplyPacket.THREAD_NOT_SUSPENDED: throw new IncompatibleThreadStateException( JDIMessages.ThreadReferenceImpl_Thread_was_not_suspended_1); } defaultReplyErrorHandler(replyPacket.errorCode()); DataInputStream replyData = replyPacket.dataInStream(); int result = readInt("frame count", replyData); //$NON-NLS-1$ return result; } catch (IOException e) { defaultIOExceptionHandler(e); return 0; } finally { handledJdwpRequest(); } } /* (non-Javadoc) * @see com.sun.jdi.ThreadReference#frames() */ @Override public List<StackFrame> frames() throws IncompatibleThreadStateException { return frames(0, -1); } /* (non-Javadoc) * @see com.sun.jdi.ThreadReference#frames(int, int) */ @Override public List<StackFrame> frames(int start, int length) throws IndexOutOfBoundsException, IncompatibleThreadStateException { // Note that this information should not be cached. initJdwpRequest(); try { ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); DataOutputStream outData = new DataOutputStream(outBytes); write(this, outData); writeInt(start, "start", outData); //$NON-NLS-1$ writeInt(length, "length", outData); //$NON-NLS-1$ JdwpReplyPacket replyPacket = requestVM( JdwpCommandPacket.TR_FRAMES, outBytes); switch (replyPacket.errorCode()) { case JdwpReplyPacket.INVALID_THREAD: throw new ObjectCollectedException(); case JdwpReplyPacket.THREAD_NOT_SUSPENDED: throw new IncompatibleThreadStateException( JDIMessages.ThreadReferenceImpl_Thread_was_not_suspended_1); case JdwpReplyPacket.INVALID_INDEX: throw new IndexOutOfBoundsException( JDIMessages.ThreadReferenceImpl_Invalid_index_of_stack_frames_given_4); } defaultReplyErrorHandler(replyPacket.errorCode()); DataInputStream replyData = replyPacket.dataInStream(); int nrOfElements = readInt("elements", replyData); //$NON-NLS-1$ List<StackFrame> frames = new ArrayList<>(nrOfElements); for (int i = 0; i < nrOfElements; i++) { StackFrameImpl frame = StackFrameImpl.readWithLocation(this, this, replyData); if (frame == null) { continue; } frames.add(frame); } return frames; } catch (IOException e) { defaultIOExceptionHandler(e); return null; } finally { handledJdwpRequest(); } } /* (non-Javadoc) * @see com.sun.jdi.ThreadReference#interrupt() */ @Override public void interrupt() { // Note that this information should not be cached. initJdwpRequest(); try { requestVM(JdwpCommandPacket.TR_INTERRUPT, this); } finally { handledJdwpRequest(); } } /* (non-Javadoc) * @see com.sun.jdi.ThreadReference#isAtBreakpoint() */ @Override public boolean isAtBreakpoint() { return isSuspended() && fIsAtBreakpoint; } /* (non-Javadoc) * @see com.sun.jdi.ThreadReference#isSuspended() */ @Override public boolean isSuspended() { // Note that this information should not be cached. initJdwpRequest(); try { JdwpReplyPacket replyPacket = requestVM( JdwpCommandPacket.TR_STATUS, this); switch (replyPacket.errorCode()) { case JdwpReplyPacket.INVALID_THREAD: throw new ObjectCollectedException(); } defaultReplyErrorHandler(replyPacket.errorCode()); DataInputStream replyData = replyPacket.dataInStream(); // remove the thread status reply readInt("thread status", threadStatusMap(), replyData); //$NON-NLS-1$ int suspendStatus = readInt( "suspend status", suspendStatusStrings(), replyData); //$NON-NLS-1$ boolean result = suspendStatus == SUSPEND_STATUS_SUSPENDED; return result; } catch (IOException e) { defaultIOExceptionHandler(e); return false; } finally { handledJdwpRequest(); } } /* (non-Javadoc) * @see com.sun.jdi.ThreadReference#name() */ @Override public String name() { initJdwpRequest(); try { JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.TR_NAME, this); switch (replyPacket.errorCode()) { case JdwpReplyPacket.INVALID_THREAD: throw new ObjectCollectedException(); } defaultReplyErrorHandler(replyPacket.errorCode()); DataInputStream replyData = replyPacket.dataInStream(); return readString("name", replyData); //$NON-NLS-1$ } catch (IOException e) { defaultIOExceptionHandler(e); return null; } finally { handledJdwpRequest(); } } /* (non-Javadoc) * @see com.sun.jdi.ThreadReference#ownedMonitors() */ @Override public List<ObjectReference> ownedMonitors() throws IncompatibleThreadStateException { if (!virtualMachine().canGetOwnedMonitorInfo()) { throw new UnsupportedOperationException(); } // Note that this information should not be cached. initJdwpRequest(); try { JdwpReplyPacket replyPacket = requestVM( JdwpCommandPacket.TR_OWNED_MONITORS, this); switch (replyPacket.errorCode()) { case JdwpReplyPacket.INVALID_THREAD: throw new ObjectCollectedException(); case JdwpReplyPacket.THREAD_NOT_SUSPENDED: throw new IncompatibleThreadStateException( JDIMessages.ThreadReferenceImpl_Thread_was_not_suspended_5); } defaultReplyErrorHandler(replyPacket.errorCode()); DataInputStream replyData = replyPacket.dataInStream(); int nrOfMonitors = readInt("nr of monitors", replyData); //$NON-NLS-1$ List<ObjectReference> result = new ArrayList<>(nrOfMonitors); for (int i = 0; i < nrOfMonitors; i++) { result.add(ObjectReferenceImpl.readObjectRefWithTag(this, replyData)); } return result; } catch (IOException e) { defaultIOExceptionHandler(e); return null; } finally { handledJdwpRequest(); } } /* (non-Javadoc) * @see com.sun.jdi.ThreadReference#ownedMonitorsAndFrames() */ @Override public List<com.sun.jdi.MonitorInfo> ownedMonitorsAndFrames() throws IncompatibleThreadStateException { initJdwpRequest(); try { JdwpReplyPacket replyPacket = requestVM( JdwpCommandPacket.TR_OWNED_MONITOR_STACK_DEPTH, this); switch (replyPacket.errorCode()) { case JdwpReplyPacket.INVALID_THREAD: case JdwpReplyPacket.INVALID_OBJECT: throw new ObjectCollectedException( JDIMessages.ThreadReferenceImpl_thread_object_invalid); case JdwpReplyPacket.THREAD_NOT_SUSPENDED: throw new IncompatibleThreadStateException( JDIMessages.ThreadReferenceImpl_Thread_was_not_suspended_5); case JdwpReplyPacket.NOT_IMPLEMENTED: throw new UnsupportedOperationException( JDIMessages.ThreadReferenceImpl_no_force_early_return_on_threads); case JdwpReplyPacket.VM_DEAD: throw new VMDisconnectedException(JDIMessages.vm_dead); } defaultReplyErrorHandler(replyPacket.errorCode()); DataInputStream replyData = replyPacket.dataInStream(); int owned = readInt("owned monitors", replyData); //$NON-NLS-1$ List<com.sun.jdi.MonitorInfo> result = new ArrayList<>(owned); ObjectReference monitor = null; int depth = -1; for (int i = 0; i < owned; i++) { monitor = ObjectReferenceImpl.readObjectRefWithTag(this, replyData); depth = readInt("stack depth", replyData); //$NON-NLS-1$ result.add(new MonitorInfoImpl(this, depth, monitor, virtualMachineImpl())); } return result; } catch (IOException e) { defaultIOExceptionHandler(e); return null; } finally { handledJdwpRequest(); } } /** * Resumes this thread. * * @see com.sun.jdi.ThreadReference#resume() */ @Override public void resume() { initJdwpRequest(); try { JdwpReplyPacket replyPacket = requestVM( JdwpCommandPacket.TR_RESUME, this); switch (replyPacket.errorCode()) { case JdwpReplyPacket.INVALID_THREAD: throw new ObjectCollectedException(); } defaultReplyErrorHandler(replyPacket.errorCode()); resetEventFlags(); } finally { handledJdwpRequest(); } } /** * @return Returns the thread's status. */ @Override public int status() { // Note that this information should not be cached. initJdwpRequest(); try { JdwpReplyPacket replyPacket = requestVM( JdwpCommandPacket.TR_STATUS, this); switch (replyPacket.errorCode()) { case JdwpReplyPacket.ABSENT_INFORMATION: return THREAD_STATUS_UNKNOWN; case JdwpReplyPacket.INVALID_THREAD: return THREAD_STATUS_NOT_STARTED; } defaultReplyErrorHandler(replyPacket.errorCode()); DataInputStream replyData = replyPacket.dataInStream(); int threadStatus = readInt( "thread status", threadStatusMap(), replyData); //$NON-NLS-1$ readInt("suspend status", suspendStatusStrings(), replyData); //$NON-NLS-1$ switch (threadStatus) { case JDWP_THREAD_STATUS_ZOMBIE: return THREAD_STATUS_ZOMBIE; case JDWP_THREAD_STATUS_RUNNING: return THREAD_STATUS_RUNNING; case JDWP_THREAD_STATUS_SLEEPING: return THREAD_STATUS_SLEEPING; case JDWP_THREAD_STATUS_MONITOR: return THREAD_STATUS_MONITOR; case JDWP_THREAD_STATUS_WAIT: return THREAD_STATUS_WAIT; case -1: // see bug 30816 return THREAD_STATUS_UNKNOWN; } throw new InternalException( JDIMessages.ThreadReferenceImpl_Unknown_thread_status_received___6 + threadStatus); } catch (IOException e) { defaultIOExceptionHandler(e); return 0; } finally { handledJdwpRequest(); } } /** * Stops this thread with an asynchronous exception. * * @see com.sun.jdi.ThreadReference#stop(com.sun.jdi.ObjectReference) */ @Override public void stop(ObjectReference throwable) throws InvalidTypeException { checkVM(throwable); ObjectReferenceImpl throwableImpl = (ObjectReferenceImpl) throwable; initJdwpRequest(); try { ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); DataOutputStream outData = new DataOutputStream(outBytes); write(this, outData); throwableImpl.write(this, outData); JdwpReplyPacket replyPacket = requestVM(JdwpCommandPacket.TR_STOP, outBytes); switch (replyPacket.errorCode()) { case JdwpReplyPacket.INVALID_THREAD: throw new ObjectCollectedException(); case JdwpReplyPacket.INVALID_CLASS: throw new InvalidTypeException( JDIMessages.ThreadReferenceImpl_Stop_argument_not_an_instance_of_java_lang_Throwable_in_the_target_VM_7); } defaultReplyErrorHandler(replyPacket.errorCode()); } catch (IOException e) { defaultIOExceptionHandler(e); } finally { handledJdwpRequest(); } } /** * Suspends this thread. * * @see com.sun.jdi.ThreadReference#suspend() */ @Override public void suspend() { initJdwpRequest(); try { JdwpReplyPacket replyPacket = requestVM( JdwpCommandPacket.TR_SUSPEND, this); switch (replyPacket.errorCode()) { case JdwpReplyPacket.INVALID_THREAD: throw new ObjectCollectedException(); } defaultReplyErrorHandler(replyPacket.errorCode()); } finally { handledJdwpRequest(); } } /** * @return Returns the number of pending suspends for this thread. */ @Override public int suspendCount() { // Note that this information should not be cached. initJdwpRequest(); try { JdwpReplyPacket replyPacket = requestVM( JdwpCommandPacket.TR_SUSPEND_COUNT, this); defaultReplyErrorHandler(replyPacket.errorCode()); DataInputStream replyData = replyPacket.dataInStream(); int result = readInt("suspend count", replyData); //$NON-NLS-1$ return result; } catch (IOException e) { defaultIOExceptionHandler(e); return 0; } finally { handledJdwpRequest(); } } /** * @return Returns this thread's thread group. */ @Override public ThreadGroupReference threadGroup() { if (fThreadGroup != null) { return fThreadGroup; } initJdwpRequest(); try { JdwpReplyPacket replyPacket = requestVM( JdwpCommandPacket.TR_THREAD_GROUP, this); switch (replyPacket.errorCode()) { case JdwpReplyPacket.INVALID_THREAD: throw new ObjectCollectedException(); } defaultReplyErrorHandler(replyPacket.errorCode()); DataInputStream replyData = replyPacket.dataInStream(); fThreadGroup = ThreadGroupReferenceImpl.read(this, replyData); return fThreadGroup; } catch (IOException e) { defaultIOExceptionHandler(e); return null; } finally { handledJdwpRequest(); } } /** * Simulate the execution of a return instruction instead of executing the * next byte code in a method. * * @return Returns whether any finally or synchronized blocks are enclosing * the current instruction. */ @Override public boolean doReturn(Value returnValue, boolean triggerFinallyAndSynchronized) throws org.eclipse.jdi.hcr.OperationRefusedException { virtualMachineImpl().checkHCRSupported(); ValueImpl valueImpl; if (returnValue != null) { // null is used if no value is returned. checkVM(returnValue); valueImpl = (ValueImpl) returnValue; } else { try { TypeImpl returnType = (TypeImpl) frame(0).location().method() .returnType(); valueImpl = (ValueImpl) returnType.createNullValue(); } catch (IncompatibleThreadStateException e) { throw new org.eclipse.jdi.hcr.OperationRefusedException( e.toString()); } catch (ClassNotLoadedException e) { throw new org.eclipse.jdi.hcr.OperationRefusedException( e.toString()); } } // Note that this information should not be cached. initJdwpRequest(); try { ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); DataOutputStream outData = new DataOutputStream(outBytes); write(this, outData); valueImpl.writeWithTag(this, outData); writeBoolean(triggerFinallyAndSynchronized, "trigger finaly+sync", outData); //$NON-NLS-1$ JdwpReplyPacket replyPacket = requestVM( JdwpCommandPacket.HCR_DO_RETURN, outBytes); switch (replyPacket.errorCode()) { case JdwpReplyPacket.INVALID_THREAD: throw new ObjectCollectedException(); } defaultReplyErrorHandler(replyPacket.errorCode()); DataInputStream replyData = replyPacket.dataInStream(); boolean result = readBoolean("is enclosed", replyData); //$NON-NLS-1$ return result; } catch (IOException e) { defaultIOExceptionHandler(e); return false; } finally { handledJdwpRequest(); } } /** * @return Returns description of Mirror object. */ @Override public String toString() { try { return NLS.bind(JDIMessages.ThreadReferenceImpl_8, new String[] { type().toString(), name(), getObjectID().toString() }); } catch (ObjectCollectedException e) { return JDIMessages.ThreadReferenceImpl__Garbage_Collected__ThreadReference__9 + idString(); } catch (Exception e) { return fDescription; } } /** * @return Reads JDWP representation and returns new instance. */ public static ThreadReferenceImpl read(MirrorImpl target, DataInputStream in) throws IOException { VirtualMachineImpl vmImpl = target.virtualMachineImpl(); JdwpThreadID ID = new JdwpThreadID(vmImpl); ID.read(in); if (target.fVerboseWriter != null) target.fVerboseWriter.println("threadReference", ID.value()); //$NON-NLS-1$ if (ID.isNull()) return null; ThreadReferenceImpl mirror = (ThreadReferenceImpl) vmImpl .getCachedMirror(ID); if (mirror == null) { mirror = new ThreadReferenceImpl(vmImpl, ID); vmImpl.addCachedMirror(mirror); } return mirror; } /** * Retrieves constant mappings. */ public static void getConstantMaps() { if (fgThreadStatusMap != null) { return; } Field[] fields = ThreadReferenceImpl.class.getDeclaredFields(); fgThreadStatusMap = new HashMap<>(); fgSuspendStatusStrings = new String[32]; // Int for (Field field : fields) { if ((field.getModifiers() & Modifier.PUBLIC) == 0 || (field.getModifiers() & Modifier.STATIC) == 0 || (field.getModifiers() & Modifier.FINAL) == 0) continue; try { String name = field.getName(); int value = field.getInt(null); Integer intValue = new Integer(value); if (name.startsWith("JDWP_THREAD_STATUS_")) { //$NON-NLS-1$ name = name.substring(19); fgThreadStatusMap.put(intValue, name); } else if (name.startsWith("SUSPEND_STATUS_")) { //$NON-NLS-1$ name = name.substring(15); for (int j = 0; j < fgSuspendStatusStrings.length; j++) { if ((1 << j & value) != 0) { fgSuspendStatusStrings[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 Map<Integer, String> threadStatusMap() { getConstantMaps(); return fgThreadStatusMap; } /** * @return Returns a map with string representations of tags. */ public static String[] suspendStatusStrings() { getConstantMaps(); return fgSuspendStatusStrings; } /** * @see ThreadReference#popFrames(StackFrame) */ @Override public void popFrames(StackFrame frameToPop) throws IncompatibleThreadStateException { if (!isSuspended()) { throw new IncompatibleThreadStateException(); } if (!virtualMachineImpl().canPopFrames()) { throw new UnsupportedOperationException(); } StackFrameImpl frame = (StackFrameImpl) frameToPop; initJdwpRequest(); try { ByteArrayOutputStream outBytes = new ByteArrayOutputStream(); DataOutputStream outData = new DataOutputStream(outBytes); frame.writeWithThread(frame, outData); JdwpReplyPacket replyPacket = requestVM( JdwpCommandPacket.SF_POP_FRAME, outBytes); switch (replyPacket.errorCode()) { case JdwpReplyPacket.INVALID_THREAD: throw new InvalidStackFrameException(); case JdwpReplyPacket.INVALID_FRAMEID: throw new InvalidStackFrameException( JDIMessages.ThreadReferenceImpl_Unable_to_pop_the_requested_stack_frame_from_the_call_stack__Reasons_include__The_frame_id_was_invalid__The_thread_was_resumed__10); case JdwpReplyPacket.THREAD_NOT_SUSPENDED: throw new IncompatibleThreadStateException( JDIMessages.ThreadReferenceImpl_Unable_to_pop_the_requested_stack_frame__The_requested_stack_frame_is_not_suspended_11); case JdwpReplyPacket.NO_MORE_FRAMES: throw new InvalidStackFrameException( JDIMessages.ThreadReferenceImpl_Unable_to_pop_the_requested_stack_frame_from_the_call_stack__Reasons_include__The_requested_frame_was_the_last_frame_on_the_call_stack__The_requested_frame_was_the_last_frame_above_a_native_frame__12); default: defaultReplyErrorHandler(replyPacket.errorCode()); } } catch (IOException ioe) { defaultIOExceptionHandler(ioe); } finally { handledJdwpRequest(); } } }