| /******************************************************************************* |
| * 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(); |
| } |
| } |
| |
| } |