blob: 8cb02c1ce59671347f7f07c9087332de86664af3 [file] [log] [blame]
package org.eclipse.jdt.internal.debug.core;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
import java.util.*;
import org.eclipse.core.resources.IMarker;
import org.eclipse.debug.core.*;
import org.eclipse.debug.core.model.*;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.eval.IEvaluationContext;
import org.eclipse.jdt.debug.core.IJavaEvaluationListener;
import org.eclipse.jdt.debug.core.IJavaThread;
import com.sun.jdi.*;
import com.sun.jdi.event.*;
import com.sun.jdi.request.*;
/**
* Proxy to a thread reference on the target.
*/
public class JDIThread extends JDIDebugElement implements IJavaThread, ITimeoutListener {
// Resource String keys
private static final String PREFIX= "jdi_thread.";
private static final String ERROR= PREFIX + "error.";
private static final String ERROR_GET_NAME= ERROR + "get_name";
private static final String ERROR_GET_PRIORITY= ERROR + "get_priority";
private static final String ERROR_GET_THREAD_GROUP= ERROR + "get_thread_group";
private static final String ERROR_GET_THREAD_GROUP_NAME= ERROR + "get_thread_group_name";
private static final String ERROR_DROPPING_FRAME= ERROR + "dropping_frame";
private static final String ERROR_CREATING_STEP_REQUEST= ERROR + "creating_step_request";
private static final String ERROR_INVOKING_METHOD= ERROR + "invoking_method";
private static final String ERROR_RESUME= ERROR + "resume";
private static final String ERROR_STEP= ERROR + "step";
private static final String ERROR_SUSPEND= ERROR + "suspend";
private static final String ERROR_TERMINATE= ERROR + "terminate";
private static final String CANT_TERMINATE= ERROR + "cant_terminate";
protected static final String IN_EVALUATION= ERROR + "in_evaluation";
protected static final String NO_BUILT_STATE= ERROR + "no_built_state";
protected static final String INVALID_EVALUATION_LOCATION= ERROR + "invalid_evaluation_location";
protected static final String MAIN_THREAD_GROUP = "main";
/**
* Underlying thread.
*/
protected ThreadReference fThread;
/**
* Underlying thread group.
*/
protected ThreadGroupReference fThreadGroup;
/**
* Whether children need to be refreshed. Set to
* to true after a step has started.
*/
protected boolean fRefreshChildren = true;
/**
* Step request used to step in this thread (only one is allowed per
* thread).
*/
protected StepRequest fStepRequest= null;
/**
* Whether running.
*/
protected boolean fRunning;
/**
* Whether stepping.
*/
protected boolean fStepping;
protected int fStepCount= 0;
/**
* Whether suspended by an event in the VM such as a
* breakpoint or step, or via an explicit user
* request to suspend.
*/
protected boolean fEventSuspend = false;
/**
* The destination stack frame when stepping
* in the non-top stack frame, or <code>null</code>
* when stepping in the top stack frame.
*/
protected IStackFrame fDestinationFrame;
/**
* Step timer. During a long running step, children are disposed.
*/
protected Timer fTimer;
/**
* Whether terminated.
*/
protected boolean fTerminated;
/**
* Whether this thread is a system thread.
*/
protected boolean fIsSystemThread;
/**
* The breakpoint that caused the last suspend, or
* <code>null</code> if none.
*/
protected IMarker fCurrentBreakpoint;
/**
* The cached named of the underlying thread.
*/
protected String fName= null;
/**
* Whether this thread is doing a "drop to frame".
*/
protected boolean fDropping= false;
/**
* Whether this thread is doing a "reenter top frame"
*/
protected boolean fReentering= false;
/**
* A count of the number of frames remaining to drop
*/
protected int fFramesToDrop= 0;
/**
* Whether this thread is currently performing
* an evaluation (invoke method). Nested method
* invocations cannot be performed.
*/
protected boolean fInEvaluation = false;
protected boolean fEvaluationAborted = false;
/**
* Creates a new thread on the underlying thread reference.
*/
public JDIThread(JDIDebugTarget target, ThreadReference thread) {
super(target);
fThread= thread;
initialize();
}
/**
* Initializes this thread on creation
*/
protected void initialize() {
// system thread
try {
determineIfSystemThread();
} catch (DebugException e) {
internalError(e);
}
// state
fTerminated= false;
fStepping= false;
try {
fRunning= !getUnderlyingThread().isSuspended();
} catch (VMDisconnectedException e) {
fTerminated = true;
fRunning = false;
} catch (RuntimeException e) {
internalError(e);
fRunning= false;
}
}
/**
* @see IDebugElement
*/
public int getElementType() {
return THREAD;
}
/**
* @see IDebugElement
*/
public IThread getThread() {
return this;
}
/**
* @see IJavaThread
*/
public IMarker getBreakpoint() {
if (fCurrentBreakpoint != null && !fCurrentBreakpoint.exists()) {
fCurrentBreakpoint= null;
}
return fCurrentBreakpoint;
}
/**
* @see ISuspendResume
*/
public boolean canResume() {
return isSuspended();
}
/**
* @see ISuspendResume
*/
public boolean canSuspend() {
return !isSuspended();
}
/**
* @see ITerminate
*/
public boolean canTerminate() {
ObjectReference threadDeath= ((JDIDebugTarget) getDebugTarget()).getThreadDeathInstance();
return threadDeath != null && !isSystemThread() && !isTerminated();
}
/**
* @see IStep
*/
public boolean canStepInto() {
return isSuspended() && !isStepping();
}
/**
* @see IStep
*/
public boolean canStepOver() {
return isSuspended() && !isStepping();
}
/**
* @see IStep
*/
public boolean canStepReturn() {
return isSuspended() && !isStepping();
}
/**
* Determines and sets whether this thread represents a system thread.
*/
protected void determineIfSystemThread() throws DebugException {
fIsSystemThread= false;
ThreadGroupReference tgr= getUnderlyingThreadGroup();
fIsSystemThread = tgr != null;
while (tgr != null) {
String tgn= null;
try {
tgn= tgr.name();
tgr= tgr.parent();
} catch (VMDisconnectedException e) {
break;
} catch (UnsupportedOperationException e) {
fIsSystemThread = false;
break;
} catch (RuntimeException e) {
targetRequestFailed(ERROR_GET_THREAD_GROUP_NAME, e);
}
if (tgn != null && tgn.equals(MAIN_THREAD_GROUP)) {
fIsSystemThread= false;
break;
}
}
}
protected void enableStepRequest(int type) throws DebugException {
EventRequestManager erm= getEventRequestManager();
try {
if (fStepRequest != null)
erm.deleteEventRequest(fStepRequest);
fStepRequest= erm.createStepRequest(fThread, StepRequest.STEP_LINE, type);
fStepRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
fStepRequest.addCountFilter(1);
fStepRequest.enable();
} catch (VMDisconnectedException e) {
} catch (RuntimeException e) {
targetRequestFailed(ERROR_CREATING_STEP_REQUEST, e);
}
}
/**
* @see IDebugElement
*/
public boolean hasChildren() {
return isSuspended();
}
/**
* @see IDebugElement
*/
protected List getChildren0() throws DebugException {
if (isSuspended()) {
if (isTerminated()) {
fChildren = Collections.EMPTY_LIST;
return fChildren;
}
if (fRefreshChildren) {
if (fChildren == null || fChildren.isEmpty()) {
fChildren = createAllStackFrames();
} else {
// compute new or removed stack frames
List frames= getUnderlyingFrames();
int offset= 0, length= frames.size();
if (length > fChildren.size()) {
// compute new children
offset= length - fChildren.size();
for (int i= offset - 1; i >= 0; i--) {
JDIStackFrame newStackFrame= new JDIStackFrame(this, (StackFrame) frames.get(i));
// addChild appends - we need a stack, so insert manually
fChildren.add(0, newStackFrame);
}
length= fChildren.size() - offset;
} else
if (length < fChildren.size()) {
// compute removed children
int removed= fChildren.size() - length;
for (int i= 0; i < removed; i++) {
fChildren.remove(0);
}
} else {
if (frames.isEmpty()) {
fChildren = Collections.EMPTY_LIST;
return fChildren;
} else {
// same number of stack frames - if the TOS is different, remove/replace all stack frames
Method oldMethod= ((JDIStackFrame) fChildren.get(0)).getUnderlyingMethod();
if (oldMethod == null) {
fChildren = createAllStackFrames();
return fChildren;
}
StackFrame newTOS= (StackFrame) frames.get(0);
Method newMethod= getUnderlyingMethod(newTOS);
if (newMethod == null) {
fChildren = createAllStackFrames();
return fChildren;
}
if (!oldMethod.equals(newMethod)) {
// remove & replace all stack frames
fChildren= createAllStackFrames();
// no stack frames to update
offset= fChildren.size();
}
}
}
// update existing frames
if (offset < fChildren.size()) {
updateStackFrames(frames, offset, fChildren, length);
}
}
fRefreshChildren = false;
}
} else
return Collections.EMPTY_LIST;
return fChildren;
}
/**
* Helper method for #getChildren0 to create new children for all frames
*/
protected List createAllStackFrames() throws DebugException {
List frames= getUnderlyingFrames();
if (frames == null) {
return new ArrayList(0);
}
List list= new ArrayList(frames.size());
Iterator iter= frames.iterator();
while (iter.hasNext()) {
JDIStackFrame newStackFrame= new JDIStackFrame(this, (StackFrame) iter.next());
list.add(newStackFrame);
}
return list;
}
/**
* Helper method for #getChildren to retrieve stack frames for this thread
*
* @see com.sun.jdi.ThreadReference
*/
protected List getUnderlyingFrames() throws DebugException {
List frames= null;
try {
frames= fThread.frames();
} catch (IncompatibleThreadStateException e) {
targetRequestFailed(ERROR_GET_CHILDREN, e);
} catch (VMDisconnectedException e) {
return Collections.EMPTY_LIST;
} catch (RuntimeException e) {
targetRequestFailed(ERROR_GET_CHILDREN, e);
}
return frames;
}
/**
* Helper method for #getChildren to retrieve the method for a stack frame
*/
protected Method getUnderlyingMethod(StackFrame frame) throws DebugException {
Method method= null;
try {
method= frame.location().method();
} catch (VMDisconnectedException e) {
return null;
} catch (RuntimeException e) {
targetRequestFailed(ERROR_GET_CHILDREN, e);
}
return method;
}
/**
* Invokes a method in this thread, and returns the result. Only one receiver may
* be specified - either a class or an object, the other must be <code>null</code>.
*/
protected Value invokeMethod(ClassType receiverClass, ObjectReference receiverObject, Method method, List args) throws DebugException {
if (fInEvaluation) {
requestFailed(IN_EVALUATION, null);
}
Value result= null;
int timeout= getRequestTimeout();
try {
// set the request timeout to be infinite
setRequestTimeout(Integer.MAX_VALUE);
setRunning(true);
fInEvaluation = true;
if (receiverClass == null) {
result= receiverObject.invokeMethod(fThread, method, args, ClassType.INVOKE_SINGLE_THREADED);
} else {
result= receiverClass.invokeMethod(fThread, method, args, ClassType.INVOKE_SINGLE_THREADED);
}
} catch (InvalidTypeException e) {
invokeFailed(e, timeout);
} catch (ClassNotLoadedException e) {
invokeFailed(e, timeout);
} catch (IncompatibleThreadStateException e) {
invokeFailed(e, timeout);
} catch (InvocationException e) {
invokeFailed(e, timeout);
} catch (RuntimeException e) {
invokeFailed(e, timeout);
}
invokeComplete(timeout);
if (fEvaluationAborted) {
fEvaluationAborted = false;
resume();
}
return result;
}
/**
* Called by JDIValue when an evaluation of
* #toString times out. Causes this thread to
* be automatically resumed when it returns from
* its evaluation - see <code>invokeMethod</code>.
*/
protected void abortEvaluation() {
fEvaluationAborted = true;
}
/**
* Invokes a method in this thread, creating a new instance of the given
* class using the specified constructor, and returns the result.
*/
protected ObjectReference newInstance(ClassType receiverClass, Method constructor, List args) throws DebugException {
if (fInEvaluation) {
requestFailed(IN_EVALUATION, null);
}
ObjectReference result= null;
int timeout= getRequestTimeout();
try {
// set the request timeout to be infinite
setRequestTimeout(Integer.MAX_VALUE);
setRunning(true);
fInEvaluation = true;
result= receiverClass.newInstance(fThread, constructor, args, ClassType.INVOKE_SINGLE_THREADED);
} catch (InvalidTypeException e) {
invokeFailed(e, timeout);
} catch (ClassNotLoadedException e) {
invokeFailed(e, timeout);
} catch (IncompatibleThreadStateException e) {
invokeFailed(e, timeout);
} catch (InvocationException e) {
invokeFailed(e, timeout);
} catch (RuntimeException e) {
invokeFailed(e, timeout);
}
invokeComplete(timeout);
return result;
}
/**
* An invocation failed. Restore the JDI timeout value and
* handle the exception.
*/
protected void invokeFailed(Throwable e, int restoreTimeout) throws DebugException {
invokeComplete(restoreTimeout);
targetRequestFailed(ERROR_INVOKING_METHOD, e);
}
/**
* Update state when invocation is complete. Restore
* the orginal timeout value for JDI requests.
*/
protected void invokeComplete(int restoreTimeout) {
setRunning(false);
fInEvaluation = false;
setRequestTimeout(restoreTimeout);
}
/**
* Sets the timeout interval for jdi requests in milliseconds
*/
protected void setRequestTimeout(int timeout) {
VirtualMachine vm = getVM();
if (vm instanceof org.eclipse.jdi.VirtualMachine) {
((org.eclipse.jdi.VirtualMachine) vm).setRequestTimeout(timeout);
}
}
/**
* Returns the timeout interval for jdi requests in millieseconds,
* or -1 if not supported
*/
protected int getRequestTimeout() {
VirtualMachine vm = getVM();
if (vm instanceof org.eclipse.jdi.VirtualMachine) {
return ((org.eclipse.jdi.VirtualMachine) vm).getRequestTimeout();
}
return -1;
}
/**
* @see IDebugElement
*/
public String getName() throws DebugException {
if (fName == null) {
try {
fName = getUnderlyingThread().name();
} catch (VMDisconnectedException e) {
fName = getUnknownMessage();
} catch (RuntimeException e) {
targetRequestFailed(ERROR_GET_NAME, e);
}
}
return fName;
}
/**
* @see IThread
*/
public int getPriority() throws DebugException {
// to get the priority, we must get the value from the "priority" field
Field p= null;
try {
p= getUnderlyingThread().referenceType().fieldByName("priority");
if (p == null) {
requestFailed(ERROR_GET_PRIORITY, null);
}
Value v= getUnderlyingThread().getValue(p);
if (v instanceof IntegerValue) {
return ((IntegerValue)v).value();
} else {
requestFailed(ERROR_GET_PRIORITY, null);
}
} catch (VMDisconnectedException e) {
} catch (RuntimeException e) {
targetRequestFailed(ERROR_GET_PRIORITY, e);
}
return -1;
}
/**
* @see IThread
*/
public IStackFrame getTopStackFrame() throws DebugException {
if (isSuspended()) {
List c= getChildren0();
if (c.isEmpty()) {
return null;
} else {
return (IStackFrame) c.get(0);
}
} else {
return null;
}
}
/**
* Suspend the thread based on a breakpoint or watchpoint event
*/
protected void handleLocatableEvent(LocatableEvent event) {
abortDropAndStep();
fCurrentBreakpoint= (IMarker) event.request().getProperty(IDebugConstants.BREAKPOINT_MARKER);
setRunning(false, DebugEvent.BREAKPOINT);
((JDIDebugTarget) getDebugTarget()).expireHitCount(event);
}
/**
* Suspend the thread based on an exception event
*/
protected void handleException(ExceptionEvent event) {
abortDropAndStep();
fCurrentBreakpoint= (IMarker) event.request().getProperty(IDebugConstants.BREAKPOINT_MARKER);
setRunning(false, DebugEvent.BREAKPOINT);
}
/**
* Suspend the thread based on the method entry event
*/
protected void handleSuspendMethodEntry(IMarker breakpoint) {
abortDropAndStep();
fCurrentBreakpoint= breakpoint;
setRunning(false, DebugEvent.BREAKPOINT);
}
protected void handleStep(StepEvent event) {
fRunning = false;
if (fDestinationFrame != null) {
try {
if (getTopStackFrame().equals(fDestinationFrame)) {
fDestinationFrame = null;
} else if (getChildren0().indexOf(fDestinationFrame) == -1) {
fDestinationFrame = null;
} else {
if (hasPendingEvents()) {
fDestinationFrame = null;
} else {
stepReturn0();
fRunning = true;
fStepCount--;
return;
}
}
} catch (DebugException e) {
abortDropAndStep();
internalError(e);
}
} else if (fDropping) {
fFramesToDrop--;
fDropping= fFramesToDrop > 0;
if (fDropping) {
try {
dropTopFrame();
} catch (DebugException e) {
abortDropAndStep();
internalError(e);
}
} else {
try {
reenterTopFrame();
} catch (DebugException e) {
abortDropAndStep();
internalError(e);
}
}
} else if (fReentering) {
fReentering= false;
try {
stepInto0();
} catch (DebugException e) {
abortDropAndStep();
internalError(e);
}
}
fRunning = true;
setRunning(false, DebugEvent.STEP_END);
}
/**
* @see IStep
*/
public boolean isStepping() {
return fStepping;
}
/**
* @see IStep
*/
public boolean isSuspended() {
return !fRunning && !fTerminated;
}
/**
* @see IJavaThread
*/
public boolean isSystemThread() {
return fIsSystemThread;
}
/**
* @see IJavaThread
*/
public String getThreadGroupName() throws DebugException {
ThreadGroupReference tgr= getUnderlyingThreadGroup();
if (tgr != null) {
try {
return fThreadGroup.name();
} catch (VMDisconnectedException e) {
} catch (RuntimeException e) {
targetRequestFailed(ERROR_GET_THREAD_GROUP_NAME, e);
}
}
return getUnknownMessage();
}
/**
* @see ITerminate
*/
public boolean isTerminated() {
return fTerminated;
}
/**
* @see ISuspendResume
*/
public void resume() throws DebugException {
if (!isSuspended()) {
return;
}
try {
setRunning(true);
fThread.resume();
} catch (VMDisconnectedException e) {
} catch (RuntimeException e) {
setRunning(false);
targetRequestFailed(ERROR_RESUME, e);
}
}
/**
* Sets the running state for this thread. Invalidates
* children on a step start, or clears them on a resume.
* Fires resume/suspend events. Starts/stops step timer.
*/
void setRunning(boolean running, int detail) {
if (fRunning != running) {
fRunning= running;
if (fRunning) {
fCurrentBreakpoint= null;
fRefreshChildren = true;
if (detail == DebugEvent.STEP_START) {
fStepCount++;
fStepping = true;
if (fStepCount == 1) {
invalidateStackFrames();
startStepTimer();
}
} else {
fChildren = null;
}
if (!fStepping || fStepCount == 1) {
fireResumeEvent(detail);
}
} else {
if (detail == DebugEvent.STEP_END) {
fStepCount--;
}
if (fStepCount == 0) {
stopStepTimer();
// update underlying stack frames
try {
getChildren0();
} catch (DebugException e) {
internalError(e);
}
fStepping= false;
fireSuspendEvent(detail);
}
fEventSuspend = detail != DebugEvent.CLIENT_REQUEST;
}
}
}
void setRunning(boolean running) {
setRunning(running, -1);
}
protected void invalidateStackFrames() {
if (fChildren != null) {
Iterator frames = fChildren.iterator();
while (frames.hasNext()) {
((JDIStackFrame)frames.next()).invalidateVariables();
}
}
}
protected void step(int type) throws DebugException {
try {
setRunning(true, DebugEvent.STEP_START);
enableStepRequest(type);
fThread.resume();
} catch (VMDisconnectedException e) {
} catch (RuntimeException e) {
setRunning(false, DebugEvent.STEP_END);
targetRequestFailed(ERROR_STEP, e);
}
}
/**
* A step has timed out. Children are disposed.
*/
public void timeout() {
fChildren = Collections.EMPTY_LIST;
fireChangeEvent();
}
/**
* @see IStep
*/
public void stepInto() throws DebugException {
if (!canStepInto()) {
return;
}
stepInto0();
}
private void stepInto0() throws DebugException {
step(StepRequest.STEP_INTO);
}
/**
* @see IStep
*/
public void stepOver() throws DebugException {
if (!canStepOver()) {
return;
}
step(StepRequest.STEP_OVER);
}
/**
* @see IStep
*/
public void stepReturn() throws DebugException {
if (!canStepReturn()) {
return;
}
stepReturn0();
}
private void stepReturn0() throws DebugException {
step(StepRequest.STEP_OUT);
}
/**
* @see ISuspendResume
*/
public void suspend() throws DebugException {
try {
// remove any pending step request
if (fStepRequest != null) {
try {
getEventRequestManager().deleteEventRequest(fStepRequest);
} catch (VMDisconnectedException e) {
} catch (RuntimeException e) {
targetRequestFailed(ERROR_SUSPEND, e);
}
}
fThread.suspend();
abortDropAndStep();
setRunning(false, DebugEvent.CLIENT_REQUEST);
} catch (VMDisconnectedException e) {
} catch (RuntimeException e) {
setRunning(true);
targetRequestFailed(ERROR_SUSPEND, e);
}
}
/**
* @see ITerminate
*/
public void terminate() throws DebugException {
ObjectReference threadDeath= ((JDIDebugTarget) getDebugTarget()).getThreadDeathInstance();
if (threadDeath != null) {
try {
fThread.stop(threadDeath);
} catch (InvalidTypeException e) {
targetRequestFailed(ERROR_TERMINATE, e);
} catch (VMDisconnectedException e) {
} catch (RuntimeException e) {
targetRequestFailed(ERROR_TERMINATE, e);
}
// Resume the thread so that stop will work
resume();
} else {
requestFailed(CANT_TERMINATE, null);
}
}
/**
* Replaces the StackFrame objects in the old frames list with the objects
* from the new frames list. StackFrames are invalid after a resume or step
* and must be replaced with the new objects.
*/
protected void updateStackFrames(List newFrames, int offset, List oldFrames, int length) throws DebugException {
for (int i= 0; i < length; i++) {
JDIStackFrame frame= (JDIStackFrame) oldFrames.get(offset);
frame.setUnderlyingStackFrame((StackFrame) newFrames.get(offset));
offset++;
}
}
/**
* Drops to the given stack frame
*/
protected void dropToFrame(IStackFrame frame) throws DebugException {
fFramesToDrop= getChildren0().indexOf(frame);
fDropping= fFramesToDrop > 0;
if (fDropping) {
dropTopFrame();
} else {
reenterTopFrame();
}
}
/**
* Drops the top frame, sending a step start event
*/
protected void dropTopFrame() throws DebugException {
try {
enableStepRequest(StepRequest.STEP_OUT);
setRunning(true, DebugEvent.STEP_START);
// Resume with a do return
org.eclipse.jdi.hcr.ThreadReference hcrThread= (org.eclipse.jdi.hcr.ThreadReference) fThread;
hcrThread.doReturn(null, true);
} catch (VMDisconnectedException e) {
setRunning(false);
} catch (RuntimeException e) {
setRunning(false);
targetRequestFailed(ERROR_DROPPING_FRAME, e);
}
}
protected void stepToFrame(IStackFrame frame) throws DebugException {
if (!canStepReturn()) {
return;
}
fDestinationFrame = frame;
stepReturn();
}
/**
* Reenters the top frame
*
* @exception DebugException on failure
*/
private void reenterTopFrame() throws DebugException {
try {
fReentering= true;
EventRequestManager erm= getEventRequestManager();
if (fStepRequest != null) {
erm.deleteEventRequest(fStepRequest);
}
fStepRequest= ((org.eclipse.jdi.hcr.EventRequestManager) erm).createReenterStepRequest(fThread);
fStepRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
fStepRequest.addCountFilter(1);
fStepRequest.enable();
// Resume with a do return
org.eclipse.jdi.hcr.ThreadReference hcrThread= (org.eclipse.jdi.hcr.ThreadReference) fThread;
hcrThread.doReturn(null, true);
setRunning(true, DebugEvent.STEP_START);
} catch (VMDisconnectedException e) {
} catch (RuntimeException e) {
fReentering= false;
setRunning(false);
targetRequestFailed(ERROR_DROPPING_FRAME, e);
}
}
protected void abortDropAndStep() {
fStepCount = 0;
abortDrop();
abortStep();
}
/**
* Aborts the drop
*/
protected void abortDrop() {
fDropping= false;
fFramesToDrop= 0;
}
/**
* Aborts the current step
*/
protected void abortStep() {
fDestinationFrame = null;
EventRequestManager erm= getEventRequestManager();
try {
if (fStepRequest != null)
erm.deleteEventRequest(fStepRequest);
fStepRequest = null;
} catch (VMDisconnectedException e) {
} catch (RuntimeException e) {
internalError(e);
}
}
/**
* @see IVariableLookup
*/
public IVariable findVariable(String varName) throws DebugException {
if (isSuspended()) {
Iterator stackframes= getChildren0().iterator();
while (stackframes.hasNext()) {
JDIStackFrame sf= (JDIStackFrame) stackframes.next();
IVariable var= sf.findVariable(varName);
if (var != null) {
return var;
}
}
}
return null;
}
/**
* Evaluates the snippet using this thread (no stack frame context)
*
* @see IJavaThread
*/
public void evaluate(String snippet, IJavaEvaluationListener listener, IJavaProject project) throws DebugException {
IEvaluationContext underlyingContext = ((JDIDebugTarget)getDebugTarget()).getEvaluationContext(project);
evaluate(snippet, listener, underlyingContext);
}
/**
*
* @see IJavaThread
*/
public void evaluate(String snippet, IJavaEvaluationListener listener, IEvaluationContext evaluationContext) throws DebugException {
verifyEvaluation(evaluationContext);
ThreadEvaluationContext context = new ThreadEvaluationContext(this, evaluationContext);
context.evaluate(snippet, listener);
}
protected void verifyEvaluation(IEvaluationContext evaluationContext) throws DebugException {
if (fInEvaluation) {
requestFailed(IN_EVALUATION, null);
}
if (!evaluationContext.getProject().hasBuildState()) {
requestFailed(NO_BUILT_STATE, null);
}
if (!fEventSuspend) {
requestFailed(INVALID_EVALUATION_LOCATION, null);
}
}
/**
* @see IJavaEvaluate
*/
public boolean canPerformEvaluation() {
return isSuspended() && !fInEvaluation && fEventSuspend;
}
protected void dispose() {
if (fTimer != null) {
fTimer.dispose();
}
}
/**
* Notification this thread has terminated - update state
*/
protected void terminated() {
fTerminated= true;
fRunning= false;
dispose();
fireTerminateEvent();
}
/**
* Returns this thread's underlying thread reference
*/
protected ThreadReference getUnderlyingThread() {
return fThread;
}
/**
* Returns this thread's underlying thread group
*/
protected ThreadGroupReference getUnderlyingThreadGroup() throws DebugException {
if (fThreadGroup == null) {
try {
fThreadGroup = getUnderlyingThread().threadGroup();
} catch (VMDisconnectedException e) {
return null;
} catch (UnsupportedOperationException e) {
return null;
} catch (RuntimeException e) {
targetRequestFailed(ERROR_GET_THREAD_GROUP, e);
}
}
return fThreadGroup;
}
/**
* Starts the step timer.
*/
protected void startStepTimer() {
if (fTimer == null) {
fTimer = new Timer();
}
fTimer.start(this, 3000);
}
/**
* Stops the step timer.
*/
protected void stopStepTimer() {
if (fTimer != null) {
fTimer.stop();
}
}
}