blob: 427b7d1390d456f012b8ffe8e364c13a9ce0885c [file] [log] [blame]
package org.eclipse.jdt.internal.debug.eval.ast.engine;
/**********************************************************************
Copyright (c) 2000, 2002 IBM Corp. and others.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Common Public License v0.5
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/cpl-v05.html
Contributors:
IBM Corporation - Initial implementation
**********************************************************************/
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.ITerminate;
import org.eclipse.jdt.core.dom.Message;
import org.eclipse.jdt.debug.core.IEvaluationRunnable;
import org.eclipse.jdt.debug.core.IJavaThread;
import org.eclipse.jdt.debug.core.IJavaValue;
import org.eclipse.jdt.debug.eval.ICompiledExpression;
import org.eclipse.jdt.debug.eval.IEvaluationListener;
import org.eclipse.jdt.debug.eval.IEvaluationResult;
import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin;
import org.eclipse.jdt.internal.debug.eval.EvaluationResult;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.InstructionSequence;
import org.eclipse.jdt.internal.debug.eval.ast.instructions.InstructionsEvaluationMessages;
/**
* An evaluation thread is a reusable object which
* can perform a series of evaluations in a single thread.
*/
class EvaluationThread {
private boolean fEvaluating = false;
private Thread fEvaluationThread;
private boolean fStopped = false;
private Object fLock = new Object();
private ASTEvaluationEngine fEngine;
private Interpreter fInterpreter;
/**
* Evaluation variables
*/
private ICompiledExpression fExpression;
private IRuntimeContext fContext;
private IJavaThread fThread;
private IEvaluationListener fListener;
private int fEvaluationDetail;
private boolean fHitBreakpoints;
private CoreException fException;
/**
* Creates a new evaluation thread for the given
* evaluation engine. The engine will be notified
* whenever this evaluation thread completes an
* evaluation.
*/
public EvaluationThread(ASTEvaluationEngine engine) {
fEngine = engine;
}
/**
* Returns whether this evaluation thread is currently
* performing an evaluation.
*/
public boolean isEvaluating() {
return fEvaluating;
}
/**
* Stops any ongoing evaluations and allows
* the underlying thread to terminate. This method
* prevents the evaluation thread from reusing the
* underlying thread.
*/
public void stop() {
fStopped = true;
if (fInterpreter != null) {
fInterpreter.stop();
}
synchronized (fLock) {
fLock.notify();
}
}
/**
* Forcibly kills the underlying evaluation thread.
* This method will cause any current evaluations to
* be terminated with an InterruptedException.
*/
public void kill() {
fStopped= true;
fEvaluationThread.interrupt();
}
/**
* Perform an evaluation. If an underlying thread already exists, the
* evalution thread will be carried out in that thread. Otherwise,
* a new thread will be created for the evaluation.
*/
public void evaluate(ICompiledExpression expression, IRuntimeContext context, IJavaThread thread, IEvaluationListener listener, int evaluationDetail, boolean hitBreakpoints) {
fExpression = expression;
fContext = context;
fThread = thread;
fListener = listener;
fEvaluationDetail = evaluationDetail;
fHitBreakpoints = hitBreakpoints;
fException= null;
if (fEvaluationThread == null) {
// Create a new thread
fEvaluationThread = new Thread(new Runnable() {
public void run() {
while (!fStopped) {
synchronized (fLock) {
doEvaluation();
try {
// Sleep until the next evaluation
if (!fStopped) {
fLock.wait();
}
} catch (InterruptedException exception) {
}
}
}
}
}, "Evaluation thread"); //$NON-NLS-1$
fEvaluationThread.start();
} else {
// Use the existing thread
synchronized (fLock) {
fLock.notifyAll();
}
}
}
/**
* Do the actual work of an evaluation. This method
* is intended to be called from within the underlying
* evaluation thread.
*/
private void doEvaluation() {
fEvaluating = true;
EvaluationResult result = new EvaluationResult(fEngine, fExpression.getSnippet(), fThread);
if (fExpression.hasErrors()) {
Message[] errors = fExpression.getErrors();
for (int i = 0, numErrors = errors.length; i < numErrors; i++) {
result.addError(errors[i]);
}
evaluationFinished(result);
return;
}
fInterpreter = new Interpreter((InstructionSequence) fExpression, fContext);
class EvaluationRunnable implements IEvaluationRunnable, ITerminate {
public void run(IJavaThread jt, IProgressMonitor pm) {
try {
fInterpreter.execute();
} catch (CoreException exception) {
fException = exception;
} catch (Throwable exception) {
JDIDebugPlugin.log(exception);
fException = new CoreException(new Status(IStatus.ERROR, JDIDebugPlugin.getUniqueIdentifier(), IStatus.ERROR, InstructionsEvaluationMessages.getString("InstructionSequence.Runtime_exception_occurred_during_evaluation._See_log_for_details_1"), exception)); //$NON-NLS-1$
}
}
public void terminate() {
fInterpreter.stop();
}
public boolean canTerminate() {
return true;
}
public boolean isTerminated() {
return false;
}
}
IEvaluationRunnable er = new EvaluationRunnable();
CoreException exception = null;
try {
fThread.runEvaluation(er, null, fEvaluationDetail, fHitBreakpoints);
} catch (DebugException e) {
exception = e;
}
IJavaValue value = fInterpreter.getResult();
if (exception == null) {
exception = fException;
}
if (value != null) {
result.setValue(value);
} else {
result.addError(new Message(EvaluationEngineMessages.getString("EvaluationThread.An_unknown_error_occurred_during_evaluation_1"), 0)); //$NON-NLS-1$
}
if (exception != null) {
if (exception instanceof DebugException) {
result.setException((DebugException)exception);
} else {
result.setException(new DebugException(exception.getStatus()));
}
}
evaluationFinished(result);
}
/**
* Notifies the listener and the evaluation engine that
* this thread has finished an evaluation.
*/
private void evaluationFinished(IEvaluationResult result) {
fEngine.evaluationThreadFinished(this);
// only notify if plugin not yet shutdown - bug# 8693
if(JDIDebugPlugin.getDefault() != null) {
fListener.evaluationComplete(result);
}
fExpression= null;
fContext= null;
fThread= null;
fListener= null;
fException= null;
fEvaluating = false;
}
}