KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > debug > core > model > JDIThread


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  * BEA - Daniel R Somerfield - Bug 89643
11  *******************************************************************************/

12 package org.eclipse.jdt.internal.debug.core.model;
13
14
15 import java.util.ArrayList JavaDoc;
16 import java.util.Collections JavaDoc;
17 import java.util.Iterator JavaDoc;
18 import java.util.List JavaDoc;
19 import java.util.Vector JavaDoc;
20
21 import org.eclipse.core.runtime.CoreException;
22 import org.eclipse.core.runtime.IProgressMonitor;
23 import org.eclipse.core.runtime.IStatus;
24 import org.eclipse.core.runtime.MultiStatus;
25 import org.eclipse.core.runtime.Status;
26 import org.eclipse.core.runtime.jobs.ISchedulingRule;
27 import org.eclipse.core.runtime.jobs.Job;
28 import org.eclipse.debug.core.DebugEvent;
29 import org.eclipse.debug.core.DebugException;
30 import org.eclipse.debug.core.DebugPlugin;
31 import org.eclipse.debug.core.IStatusHandler;
32 import org.eclipse.debug.core.model.IBreakpoint;
33 import org.eclipse.debug.core.model.IStackFrame;
34 import org.eclipse.debug.core.model.ITerminate;
35 import org.eclipse.jdt.core.Signature;
36 import org.eclipse.jdt.debug.core.IEvaluationRunnable;
37 import org.eclipse.jdt.debug.core.IJavaBreakpoint;
38 import org.eclipse.jdt.debug.core.IJavaObject;
39 import org.eclipse.jdt.debug.core.IJavaStackFrame;
40 import org.eclipse.jdt.debug.core.IJavaThread;
41 import org.eclipse.jdt.debug.core.IJavaThreadGroup;
42 import org.eclipse.jdt.debug.core.IJavaValue;
43 import org.eclipse.jdt.debug.core.IJavaVariable;
44 import org.eclipse.jdt.debug.core.JDIDebugModel;
45 import org.eclipse.jdt.internal.debug.core.IJDIEventListener;
46 import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin;
47 import org.eclipse.jdt.internal.debug.core.breakpoints.JavaBreakpoint;
48
49 import com.ibm.icu.text.MessageFormat;
50 import com.sun.jdi.BooleanValue;
51 import com.sun.jdi.ClassNotLoadedException;
52 import com.sun.jdi.ClassType;
53 import com.sun.jdi.Field;
54 import com.sun.jdi.IncompatibleThreadStateException;
55 import com.sun.jdi.IntegerValue;
56 import com.sun.jdi.InvalidStackFrameException;
57 import com.sun.jdi.InvalidTypeException;
58 import com.sun.jdi.InvocationException;
59 import com.sun.jdi.Location;
60 import com.sun.jdi.Method;
61 import com.sun.jdi.ObjectCollectedException;
62 import com.sun.jdi.ObjectReference;
63 import com.sun.jdi.ReferenceType;
64 import com.sun.jdi.StackFrame;
65 import com.sun.jdi.ThreadGroupReference;
66 import com.sun.jdi.ThreadReference;
67 import com.sun.jdi.VMDisconnectedException;
68 import com.sun.jdi.Value;
69 import com.sun.jdi.event.Event;
70 import com.sun.jdi.event.StepEvent;
71 import com.sun.jdi.request.EventRequest;
72 import com.sun.jdi.request.EventRequestManager;
73 import com.sun.jdi.request.StepRequest;
74
75 /**
76  * Model thread implementation for an underlying
77  * thread on a VM.
78  */

79 public class JDIThread extends JDIDebugElement implements IJavaThread {
80     
81     /**
82      * Constant for the name of the default Java stratum
83      */

84     private static final String JavaDoc JAVA_STRATUM_CONSTANT = "Java"; //$NON-NLS-1$
85

86     /**
87      * Constant for the name of the main thread group.
88      */

89     private static final String JavaDoc MAIN_THREAD_GROUP = "main"; //$NON-NLS-1$
90
/**
91      * Status code indicating that a request to suspend this thread has timed out
92      */

93     public static final int SUSPEND_TIMEOUT= 161;
94     /**
95      * Underlying thread.
96      */

97     private ThreadReference fThread;
98     /**
99      * Cache of previous name, used in case thread is garbage collected.
100      */

101     private String JavaDoc fPreviousName;
102     /**
103      * Collection of stack frames
104      */

105     private List JavaDoc fStackFrames;
106     /**
107      * Underlying thread group, cached on first access.
108      */

109     private ThreadGroupReference fThreadGroup;
110     /**
111      * Name of underlying thread group, cached on first access.
112      */

113     private String JavaDoc fThreadGroupName;
114     /**
115      * Whether children need to be refreshed. Set to
116      * <code>true</code> when stack frames are re-used
117      * on the next suspend.
118      */

119     private boolean fRefreshChildren = true;
120     /**
121      * Currently pending step handler, <code>null</code>
122      * when not performing a step.
123      */

124     private StepHandler fStepHandler= null;
125     /**
126      * Whether running.
127      */

128     private boolean fRunning;
129     /**
130      * Whether terminated.
131      */

132     private boolean fTerminated;
133     /**
134      * whether suspended but without firing the equivalent events.
135      */

136     private boolean fSuspendedQuiet;
137     /**
138      * Whether this thread is a system thread.
139      */

140     private boolean fIsSystemThread;
141     
142     /**
143      * Whether this thread is a daemon thread
144      * @since 3.3
145      */

146     private boolean fIsDaemon = false;
147     
148     /**
149      * The collection of breakpoints that caused the last suspend, or
150      * an empty collection if the thread is not suspended or was not
151      * suspended by any breakpoint(s).
152      */

153     private List JavaDoc fCurrentBreakpoints = new ArrayList JavaDoc(2);
154     /**
155      * Whether this thread is currently performing
156      * an evaluation. An evaluation may involve a series
157      * of method invocations.
158      */

159     private boolean fIsPerformingEvaluation= false;
160     private IEvaluationRunnable fEvaluationRunnable;
161     
162     /**
163      * Whether this thread was manually suspended during an
164      * evaluation.
165      */

166     private boolean fEvaluationInterrupted = false;
167     
168     /**
169      * Whether this thread is currently invoking a method.
170      * Nested method invocations cannot be performed.
171      */

172     private boolean fIsInvokingMethod = false;
173     /**
174      * Whether or not this thread is currently honoring
175      * breakpoints. This flag allows breakpoints to be
176      * disabled during evaluations.
177      */

178     private boolean fHonorBreakpoints= true;
179     /**
180      * The kind of step that was originally requested. Zero or
181      * more 'secondary steps' may be performed programmatically after
182      * the original user-requested step, and this field tracks the
183      * type (step into, over, return) of the original step.
184      */

185     private int fOriginalStepKind;
186     /**
187      * The JDI Location from which an original user-requested step began.
188      */

189     private Location fOriginalStepLocation;
190     /**
191      * The total stack depth at the time an original (user-requested) step
192      * is initiated. This is used along with the original step Location
193      * to determine if a step into comes back to the starting location and
194      * needs to be 'nudged' forward. Checking the stack depth eliminates
195      * undesired 'nudging' in recursive methods.
196      */

197     private int fOriginalStepStackDepth;
198     
199     /**
200      * Whether or not this thread is currently suspending (user-requested).
201      */

202     private boolean fIsSuspending= false;
203     /**
204      * Whether or not this thread is currently evaluating an expression for a conditional breakpoint
205      */

206     private boolean fIsEvaluatingConditionalBreakpoint= false;
207
208     private ThreadJob fAsyncJob;
209     
210     private ThreadJob fRunningAsyncJob;
211     
212     /**
213      * Creates a new thread on the underlying thread reference
214      * in the given debug target.
215      *
216      * @param target the debug target in which this thread is contained
217      * @param thread the underlying thread on the VM
218      * @exception ObjectCollectedException if the underlying thread has been
219      * garbage collected and cannot be properly initialized
220      */

221     public JDIThread(JDIDebugTarget target, ThreadReference thread) throws ObjectCollectedException {
222         super(target);
223         setUnderlyingThread(thread);
224         initialize();
225     }
226
227     /**
228      * Thread initialization:<ul>
229      * <li>Determines if this thread is a system thread</li>
230      * <li>Sets terminated state to <code>false</code></li>
231      * <li>Determines suspended state from underlying thread</li>
232      * <li>Sets this threads stack frames to an empty collection</li>
233      * </ul>
234      * @exception ObjectCollectedException if the thread has been garbage
235      * collected and cannot be initialized
236      */

237     protected void initialize() throws ObjectCollectedException {
238         fStackFrames= new ArrayList JavaDoc();
239         // system thread
240
try {
241             determineIfSystemThread();
242         } catch (DebugException e) {
243             Throwable JavaDoc underlyingException= e.getStatus().getException();
244             if (underlyingException instanceof VMDisconnectedException) {
245                 // Threads may be created by the VM at shutdown
246
// as finalizers. The VM may be disconnected by
247
// the time we hear about the thread creation.
248
disconnected();
249                 return;
250             }
251             if (underlyingException instanceof ObjectCollectedException) {
252                 throw (ObjectCollectedException)underlyingException;
253             }
254             logError(e);
255         }
256         
257         try {
258             determineIfDaemonThread();
259         } catch (DebugException e) {
260             Throwable JavaDoc underlyingException= e.getStatus().getException();
261             if (underlyingException instanceof VMDisconnectedException) {
262                 // Threads may be created by the VM at shutdown
263
// as finalizers. The VM may be disconnected by
264
// the time we hear about the thread creation.
265
disconnected();
266                 return;
267             }
268             logError(e);
269         }
270         
271         try {
272             ThreadGroupReference group = getUnderlyingThreadGroup();
273             // might already be terminated
274
if (group != null) {
275                 getJavaDebugTarget().addThreadGroup(group);
276             }
277         } catch (DebugException e1) {
278         }
279
280         // state
281
setTerminated(false);
282         setRunning(false);
283         try {
284             // see bug 30816
285
if (fThread.status() == ThreadReference.THREAD_STATUS_UNKNOWN) {
286                 setRunning(true);
287                 return;
288             }
289         } catch (VMDisconnectedException e) {
290             disconnected();
291             return;
292         } catch (ObjectCollectedException e){
293             throw e;
294         } catch (RuntimeException JavaDoc e) {
295             logError(e);
296         }
297         
298         try {
299             boolean suspended = fThread.isSuspended();
300             if (suspended) {
301                 // Unless we're at a breakpoint, set status to running. The thread state
302
// will be properly updated to suspended in the case that a breakpoint
303
// is hit. Otherwise this is likely just a transient suspend state (for
304
// example, a breakpoint is handling a class prepare event quietly).
305
// See bug 120385
306
suspended = getBreakpoints().length > 0;
307             }
308             setRunning(!suspended);
309         } catch (VMDisconnectedException e) {
310             disconnected();
311             return;
312         } catch (ObjectCollectedException e){
313             throw e;
314         } catch (RuntimeException JavaDoc e) {
315             logError(e);
316         }
317     }
318
319     /**
320      * Adds the given breakpoint to the list of breakpoints
321      * this thread is suspended at
322      */

323     protected void addCurrentBreakpoint(IBreakpoint bp) {
324         fCurrentBreakpoints.add(bp);
325     }
326     
327     /**
328      * Removes the given breakpoint from the list of breakpoints
329      * this thread is suspended at (called when a breakpoint is
330      * deleted, in case we are suspended at that breakpoint)
331      */

332     protected void removeCurrentBreakpoint(IBreakpoint bp) {
333         fCurrentBreakpoints.remove(bp);
334     }
335     
336     /**
337      * @see org.eclipse.debug.core.model.IThread#getBreakpoints()
338      */

339     public synchronized IBreakpoint[] getBreakpoints() {
340         return (IBreakpoint[])fCurrentBreakpoints.toArray(new IBreakpoint[fCurrentBreakpoints.size()]);
341     }
342
343     /**
344      * @see ISuspendResume#canResume()
345      */

346     public boolean canResume() {
347         return isSuspended() && !isSuspendedQuiet() && (!isPerformingEvaluation() || isInvokingMethod());
348     }
349
350     /**
351      * @see ISuspendResume#canSuspend()
352      */

353     public boolean canSuspend() {
354         return !isSuspended() || isSuspendedQuiet() || (isPerformingEvaluation() && !isInvokingMethod());
355     }
356
357     /**
358      * @see ITerminate#canTerminate()
359      */

360     public boolean canTerminate() {
361         return getDebugTarget().canTerminate();
362     }
363
364     /**
365      * @see IStep#canStepInto()
366      */

367     public boolean canStepInto() {
368         return canStep();
369     }
370
371     /**
372      * @see IStep#canStepOver()
373      */

374     public boolean canStepOver() {
375         return canStep();
376     }
377
378     /**
379      * @see IStep#canStepReturn()
380      */

381     public boolean canStepReturn() {
382         return canStep();
383     }
384
385     /**
386      * Returns whether this thread is in a valid state to
387      * step.
388      *
389      * @return whether this thread is in a valid state to
390      * step
391      */

392     protected boolean canStep() {
393         try {
394             return isSuspended()
395                 && !isSuspendedQuiet()
396                 && (!isPerformingEvaluation() || isInvokingMethod())
397                 && !isStepping()
398                 && getTopStackFrame() != null
399                 && !getJavaDebugTarget().isPerformingHotCodeReplace();
400         } catch (DebugException e) {
401             return false;
402         }
403     }
404
405     /**
406      * Determines and sets whether this thread represents a system thread.
407      *
408      * @exception DebugException if this method fails. Reasons include:
409      * <ul>
410      * <li>Failure communicating with the VM. The DebugException's
411      * status code contains the underlying exception responsible for
412      * the failure.</li>
413      * </ul>
414      */

415     protected void determineIfSystemThread() throws DebugException {
416         fIsSystemThread= false;
417         ThreadGroupReference tgr= getUnderlyingThreadGroup();
418         fIsSystemThread = tgr != null;
419         while (tgr != null) {
420             String JavaDoc tgn= null;
421             try {
422                 tgn= tgr.name();
423                 tgr= tgr.parent();
424             } catch (UnsupportedOperationException JavaDoc e) {
425                 fIsSystemThread = false;
426                 break;
427             } catch (RuntimeException JavaDoc e) {
428                 targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_determining_if_system_thread, new String JavaDoc[] {e.toString()}), e);
429                 // execution will not reach this line, as
430
// #targetRequestFailed will throw an exception
431
return;
432             }
433             if (tgn != null && tgn.equals(MAIN_THREAD_GROUP)) {
434                 fIsSystemThread= false;
435                 break;
436             }
437         }
438     }
439     
440     /**
441      * Determines whether this is a daemon thread.
442      *
443      * @throws DebugException on failure
444      */

445     protected void determineIfDaemonThread() throws DebugException {
446         fIsDaemon = false;
447         try {
448             ReferenceType referenceType = getUnderlyingThread().referenceType();
449             Field field = referenceType.fieldByName("daemon"); //$NON-NLS-1$
450
if (field == null) {
451                 field = referenceType.fieldByName("isDaemon"); //$NON-NLS-1$
452
}
453             if (field != null) {
454                 if (field.signature().equals(Signature.SIG_BOOLEAN)) {
455                     Value value = getUnderlyingThread().getValue(field);
456                     if (value instanceof BooleanValue) {
457                         fIsDaemon = ((BooleanValue)value).booleanValue();
458                     }
459                 }
460             }
461         }
462         catch(ObjectCollectedException oce) {/*do nothing thread does not exist*/}
463         catch (RuntimeException JavaDoc e) {
464             targetRequestFailed(JDIDebugModelMessages.JDIThread_47, e);
465         }
466     }
467
468     /**
469      * NOTE: this method returns a copy of this thread's stack frames.
470      *
471      * @see IThread#getStackFrames()
472      */

473     public synchronized IStackFrame[] getStackFrames() throws DebugException {
474         if (isSuspendedQuiet()) {
475             return new IStackFrame[0];
476         }
477         List JavaDoc list = computeStackFrames();
478         return (IStackFrame[])list.toArray(new IStackFrame[list.size()]);
479     }
480     
481     /**
482      * @see computeStackFrames()
483      *
484      * @param refreshChildren whether or not this method should request new stack
485      * frames from the VM
486      */

487     protected synchronized List JavaDoc computeStackFrames(boolean refreshChildren) throws DebugException {
488         if (isSuspended()) {
489             if (isTerminated()) {
490                 fStackFrames.clear();
491             } else if (refreshChildren) {
492                 List JavaDoc frames = getUnderlyingFrames();
493                 int oldSize = fStackFrames.size();
494                 int newSize = frames.size();
495                 int discard = oldSize - newSize; // number of old frames to discard, if any
496
for (int i = 0; i < discard; i++) {
497                     JDIStackFrame invalid = (JDIStackFrame) fStackFrames.remove(0);
498                     invalid.bind(null, -1);
499                 }
500                 int newFrames = newSize - oldSize; // number of frames to create, if any
501
int depth = oldSize;
502                 for (int i = newFrames - 1; i >= 0; i--) {
503                     fStackFrames.add(0, new JDIStackFrame(this, (StackFrame) frames.get(i), depth));
504                     depth++;
505                 }
506                 int numToRebind = Math.min(newSize, oldSize); // number of frames to attempt to rebind
507
int offset = newSize - 1;
508                 for (depth = 0; depth < numToRebind; depth++) {
509                     JDIStackFrame oldFrame = (JDIStackFrame) fStackFrames.get(offset);
510                     StackFrame frame = (StackFrame) frames.get(offset);
511                     JDIStackFrame newFrame = oldFrame.bind(frame, depth);
512                     if (newFrame != oldFrame) {
513                         fStackFrames.set(offset, newFrame);
514                     }
515                     offset--;
516                 }
517                 
518
519             }
520             fRefreshChildren = false;
521         } else {
522             return Collections.EMPTY_LIST;
523         }
524         return fStackFrames;
525     }
526     
527     /**
528      * Returns this thread's current stack frames as a list, computing
529      * them if required. Returns an empty collection if this thread is
530      * not currently suspended, or this thread is terminated. This
531      * method should be used internally to get the current stack frames,
532      * instead of calling <code>#getStackFrames()</code>, which makes a
533      * copy of the current list.
534      * <p>
535      * Before a thread is resumed a call must be made to one of:<ul>
536      * <li><code>preserveStackFrames()</code></li>
537      * <li><code>disposeStackFrames()</code></li>
538      * </ul>
539      * If stack frames are disposed before a thread is resumed, stack frames
540      * are completely re-computed on the next call to this method. If stack
541      * frames are to be preserved, this method will attempt to re-use any stack
542      * frame objects which represent the same stack frame as on the previous
543      * suspend. Stack frames are cached until a subsequent call to preserve
544      * or dispose stack frames.
545      * </p>
546      *
547      * @return list of <code>IJavaStackFrame</code>
548      * @exception DebugException if this method fails. Reasons include:
549      * <ul>
550      * <li>Failure communicating with the VM. The DebugException's
551      * status code contains the underlying exception responsible for
552      * the failure.</li>
553      * </ul>
554      */

555     public synchronized List JavaDoc computeStackFrames() throws DebugException {
556         return computeStackFrames(fRefreshChildren);
557     }
558     
559     /**
560      * @see JDIThread#computeStackFrames()
561      *
562      * This method differs from computeStackFrames() in that it
563      * always requests new stack frames from the VM. As this is
564      * an expensive operation, this method should only be used
565      * by clients who know for certain that the stack frames
566      * on the VM have changed.
567      */

568     public List JavaDoc computeNewStackFrames() throws DebugException {
569         return computeStackFrames(true);
570     }
571
572     private List JavaDoc getUnderlyingFrames() throws DebugException {
573         if (!isSuspended()) {
574             // Checking isSuspended here eliminates a race condition in resume
575
// between the time stack frames are preserved and the time the
576
// underlying thread is actually resumed.
577
requestFailed(JDIDebugModelMessages.JDIThread_Unable_to_retrieve_stack_frame___thread_not_suspended__1, null, IJavaThread.ERR_THREAD_NOT_SUSPENDED);
578         }
579         try {
580             return fThread.frames();
581         } catch (IncompatibleThreadStateException e) {
582             requestFailed(JDIDebugModelMessages.JDIThread_Unable_to_retrieve_stack_frame___thread_not_suspended__1, e, IJavaThread.ERR_THREAD_NOT_SUSPENDED);
583         } catch (RuntimeException JavaDoc e) {
584             targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_retrieving_stack_frames_2, new String JavaDoc[] {e.toString()}), e);
585         } catch (InternalError JavaDoc e) {
586             targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_retrieving_stack_frames_2, new String JavaDoc[] {e.toString()}), e);
587         }
588         // execution will not reach this line, as
589
// #targetRequestFailed will thrown an exception
590
return null;
591     }
592
593     /**
594      * Returns the number of frames on the stack from the
595      * underlying thread.
596      *
597      * @return number of frames on the stack
598      * @exception DebugException if this method fails. Reasons include:
599      * <ul>
600      * <li>Failure communicating with the VM. The DebugException's
601      * status code contains the underlying exception responsible for
602      * the failure.</li>
603      * <li>This thread is not suspended</li>
604      * </ul>
605      */

606     protected int getUnderlyingFrameCount() throws DebugException {
607         try {
608             return fThread.frameCount();
609         } catch (RuntimeException JavaDoc e) {
610             targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_retrieving_frame_count, new String JavaDoc[] {e.toString()}), e);
611         } catch (IncompatibleThreadStateException e) {
612             requestFailed(MessageFormat.format(JDIDebugModelMessages.JDIThread_exception_retrieving_frame_count, new String JavaDoc[] {e.toString()}), e, IJavaThread.ERR_THREAD_NOT_SUSPENDED);
613         }
614         // execution will not reach here - try block will either
615
// return or exception will be thrown
616
return -1;
617     }
618     
619     /**
620      * @see IJavaThread#runEvaluation(IEvaluationRunnable, IProgressMonitor, int, boolean)
621      */

622     public void runEvaluation(IEvaluationRunnable evaluation, IProgressMonitor monitor, int evaluationDetail, boolean hitBreakpoints) throws DebugException {
623         if (isPerformingEvaluation()) {
624             requestFailed(JDIDebugModelMessages.JDIThread_Cannot_perform_nested_evaluations, null, IJavaThread.ERR_NESTED_METHOD_INVOCATION); //
625
}
626         
627         if (!canRunEvaluation()) {
628             requestFailed(JDIDebugModelMessages.JDIThread_Evaluation_failed___thread_not_suspended, null, IJavaThread.ERR_THREAD_NOT_SUSPENDED);
629         }
630         
631         fIsPerformingEvaluation = true;
632         fEvaluationRunnable= evaluation;
633         fHonorBreakpoints= hitBreakpoints;
634         fireResumeEvent(evaluationDetail);
635         //save and restore current breakpoint information - bug 30837
636
IBreakpoint[] breakpoints = getBreakpoints();
637         ISchedulingRule rule = null;
638         if (evaluationDetail == DebugEvent.EVALUATION_IMPLICIT) {
639             rule = getThreadRule();
640         }
641         try {
642             if (rule != null) {
643                 Job.getJobManager().beginRule(rule, monitor);
644             }
645             if (monitor == null || !monitor.isCanceled()) {
646                 evaluation.run(this, monitor);
647             }
648         } catch (DebugException e) {
649             throw e;
650         } finally {
651             if (rule != null) {
652                 Job.getJobManager().endRule(rule);
653             }
654             fIsPerformingEvaluation = false;
655             fEvaluationRunnable= null;
656             fHonorBreakpoints= true;
657             if (getBreakpoints().length == 0 && breakpoints.length > 0) {
658                 for (int i = 0; i < breakpoints.length; i++) {
659                     addCurrentBreakpoint(breakpoints[i]);
660                 }
661             }
662             fireSuspendEvent(evaluationDetail);
663             if (fEvaluationInterrupted && (fAsyncJob == null || fAsyncJob.isEmpty()) && (fRunningAsyncJob == null || fRunningAsyncJob.isEmpty())) {
664                 // @see bug 31585:
665
// When an evaluation was interrupted & resumed, the launch view does
666
// not update properly. It cannot know when it is safe to display frames
667
// since it does not know about queued evaluations. Thus, when the queue
668
// is empty, we fire a change event to force the view to update.
669
fEvaluationInterrupted = false;
670                 fireChangeEvent(DebugEvent.CONTENT);
671             }
672         }
673     }
674     
675     /**
676      * Returns whether this thread is in a valid state to
677      * run an evaluation.
678      *
679      * @return whether this thread is in a valid state to
680      * run an evaluation
681      */

682     protected boolean canRunEvaluation() {
683         // NOTE similar to #canStep, except a quiet suspend state is OK
684
try {
685             return isSuspendedQuiet() || (isSuspended()
686                 && !(isPerformingEvaluation() || isInvokingMethod())
687                 && !isStepping()
688                 && getTopStackFrame() != null
689                 && !getJavaDebugTarget().isPerformingHotCodeReplace());
690         } catch (DebugException e) {
691             return false;
692         }
693     }
694     
695     /**
696      * @see org.eclipse.jdt.debug.core.IJavaThread#queueRunnable(Runnable)
697      */

698     public void queueRunnable(Runnable JavaDoc evaluation) {
699         if (fAsyncJob == null) {
700             fAsyncJob= new ThreadJob(this);
701         }
702         fAsyncJob.addRunnable(evaluation);
703     }
704     
705     /**
706      * @see IJavaThread#terminateEvaluation()
707      */

708     public void terminateEvaluation() throws DebugException {
709         if (canTerminateEvaluation()) {
710             ((ITerminate) fEvaluationRunnable).terminate();
711         }
712     }
713     
714     /**
715      * @see IJavaThread#canTerminateEvaluation()
716      */

717     public boolean canTerminateEvaluation() {
718         return fEvaluationRunnable instanceof ITerminate;
719     }
720
721     /**
722      * Invokes a method on the target, in this thread, and returns the result. Only
723      * one receiver may be specified - either a class or an object, the other must
724      * be <code>null</code>. This thread is left suspended after the invocation
725      * is complete, unless a call is made to <code>abortEvaluation<code> while
726      * performing a method invocation. In that case, this thread is automatically
727      * resumed when/if this invocation (eventually) completes.
728      * <p>
729      * Method invocations cannot be nested. That is, this method must
730      * return before another call to this method can be made. This
731      * method does not return until the invocation is complete.
732      * Breakpoints can suspend a method invocation, and it is possible
733      * that an invocation will not complete due to an infinite loop
734      * or deadlock.
735      * </p>
736      * <p>
737      * Stack frames are preserved during method invocations, unless
738      * a timeout occurs. Although this thread's state is updated to
739      * running while performing an evaluation, no debug events are
740      * fired unless this invocation is interrupted by a breakpoint,
741      * or the invocation times out.
742      * </p>
743      * <p>
744      * When performing an invocation, the communication timeout with
745      * the target VM is set to infinite, as the invocation may not
746      * complete in a timely fashion, if at all. The timeout value
747      * is reset to its original value when the invocation completes.
748      * </p>
749      *
750      * @param receiverClass the class in the target representing the receiver
751      * of a static message send, or <code>null</code>
752      * @param receiverObject the object in the target to be the receiver of
753      * the message send, or <code>null</code>
754      * @param method the underlying method to be invoked
755      * @param args the arguments to invoke the method with (an empty list
756      * if none)
757      * @return the result of the method, as an underlying value
758      * @exception DebugException if this method fails. Reasons include:
759      * <ul>
760      * <li>Failure communicating with the VM. The DebugException's
761      * status code contains the underlying exception responsible for
762      * the failure.</li>
763      * <li>This thread is not suspended
764      * (status code <code>IJavaThread.ERR_THREAD_NOT_SUSPENDED</code>)</li>
765      * <li>This thread is already invoking a method
766      * (status code <code>IJavaThread.ERR_NESTED_METHOD_INVOCATION</code>)</li>
767      * <li>This thread is not suspended by a JDI request
768      * (status code <code>IJavaThread.ERR_INCOMPATIBLE_THREAD_STATE</code>)</li>
769      * </ul>
770      */

771     protected Value invokeMethod(ClassType receiverClass, ObjectReference receiverObject, Method method, List JavaDoc args, boolean invokeNonvirtual) throws DebugException {
772         if (receiverClass != null && receiverObject != null) {
773             throw new IllegalArgumentException JavaDoc(JDIDebugModelMessages.JDIThread_can_only_specify_one_receiver_for_a_method_invocation);
774         }
775         Value result= null;
776         int timeout= getRequestTimeout();
777         try {
778             // this is synchronized such that any other operation that
779
// might be resuming this thread has a chance to complete before
780
// we determine if it is safe to continue with a method invocation.
781
// See bugs 6518, 14069
782
synchronized (this) {
783                 if (!isSuspended()) {
784                     requestFailed(JDIDebugModelMessages.JDIThread_Evaluation_failed___thread_not_suspended, null, IJavaThread.ERR_THREAD_NOT_SUSPENDED);
785                 }
786                 if (isInvokingMethod()) {
787                     requestFailed(JDIDebugModelMessages.JDIThread_Cannot_perform_nested_evaluations, null, IJavaThread.ERR_NESTED_METHOD_INVOCATION);
788                 }
789                 // set the request timeout to be infinite
790
setRequestTimeout(Integer.MAX_VALUE);
791                 setRunning(true);
792                 setInvokingMethod(true);
793             }
794             preserveStackFrames();
795             int flags= ClassType.INVOKE_SINGLE_THREADED;
796             if (invokeNonvirtual) {
797                 // Superclass method invocation must be performed nonvirtual.
798
flags |= ObjectReference.INVOKE_NONVIRTUAL;
799             }
800             if (receiverClass == null) {
801                 result= receiverObject.invokeMethod(fThread, method, args, flags);
802             } else {
803                 result= receiverClass.invokeMethod(fThread, method, args, flags);
804             }
805         } catch (InvalidTypeException e) {
806             invokeFailed(e, timeout);
807         } catch (ClassNotLoadedException e) {
808             invokeFailed(e, timeout);
809         } catch (IncompatibleThreadStateException e) {
810             invokeFailed(JDIDebugModelMessages.JDIThread_Thread_must_be_suspended_by_step_or_breakpoint_to_perform_method_invocation_1, IJavaThread.ERR_INCOMPATIBLE_THREAD_STATE, e, timeout);
811         } catch (InvocationException e) {
812             invokeFailed(e, timeout);
813         } catch (RuntimeException JavaDoc e) {
814             invokeFailed(e, timeout);
815         }