### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.debug Index: eval/org/eclipse/jdt/internal/debug/eval/ast/engine/RuntimeContext.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/RuntimeContext.java,v retrieving revision 1.8 diff -u -r1.8 RuntimeContext.java --- eval/org/eclipse/jdt/internal/debug/eval/ast/engine/RuntimeContext.java 4 Aug 2005 18:58:14 -0000 1.8 +++ eval/org/eclipse/jdt/internal/debug/eval/ast/engine/RuntimeContext.java 18 Sep 2009 18:48:07 -0000 @@ -37,7 +37,7 @@ * @return a new runtime context */ public RuntimeContext(IJavaProject project, IJavaStackFrame frame) { - super(project); + super(project, (IJavaThread) frame.getThread()); setFrame(frame); } @@ -89,13 +89,6 @@ */ private void setFrame(IJavaStackFrame frame) { fFrame = frame; - } - - /** - * @see IRuntimeContext#getThread() - */ - public IJavaThread getThread() { - return (IJavaThread)getFrame().getThread(); } /** @@ -104,6 +97,13 @@ public boolean isConstructor() throws CoreException { return getFrame().isConstructor(); } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#isStatic() + */ + public boolean isStatic() throws CoreException { + return getFrame().isStatic(); + } } Index: eval/org/eclipse/jdt/internal/debug/eval/ast/engine/AbstractRuntimeContext.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/AbstractRuntimeContext.java,v retrieving revision 1.6 diff -u -r1.6 AbstractRuntimeContext.java --- eval/org/eclipse/jdt/internal/debug/eval/ast/engine/AbstractRuntimeContext.java 8 May 2006 20:23:01 -0000 1.6 +++ eval/org/eclipse/jdt/internal/debug/eval/ast/engine/AbstractRuntimeContext.java 18 Sep 2009 18:48:07 -0000 @@ -10,8 +10,6 @@ *******************************************************************************/ package org.eclipse.jdt.internal.debug.eval.ast.engine; -import com.ibm.icu.text.MessageFormat; - import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; @@ -19,11 +17,14 @@ import org.eclipse.jdt.debug.core.IJavaClassObject; import org.eclipse.jdt.debug.core.IJavaClassType; import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaThread; import org.eclipse.jdt.debug.core.IJavaType; import org.eclipse.jdt.debug.core.IJavaValue; import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; +import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; import org.eclipse.jdt.internal.debug.eval.ast.instructions.InstructionsEvaluationMessages; +import com.ibm.icu.text.MessageFormat; import com.sun.jdi.InvocationException; /** @@ -44,6 +45,11 @@ * Cache of java.lang.Class type */ private IJavaClassType fJavaLangClass; + + /** + * Thread to perform message sends in + */ + private IJavaThread fThread; /** * Java project context @@ -55,8 +61,9 @@ public static final String FOR_NAME_SIGNATURE= "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"; //$NON-NLS-1$ - public AbstractRuntimeContext(IJavaProject project) { + public AbstractRuntimeContext(IJavaProject project, IJavaThread thread) { fProject = project; + fThread = thread; } /** @@ -70,6 +77,16 @@ protected IJavaObject getClassLoaderObject() throws CoreException { if (fClassLoader == null) { fClassLoader = getReceivingType().getClassLoaderObject(); + //loader is null for those classes loaded by the bootstrap loader + if (fClassLoader == null) { + IJavaObject child = ((JDIDebugTarget)getVM()).getSomeClassLoader(); + IJavaObject parent = child; + while (parent != null && !parent.isNull()) { + child = parent; + parent = (IJavaObject)child.sendMessage("getParent", "()Ljava/lang/ClassLoader;", null, getThread(), false); //$NON-NLS-1$//$NON-NLS-2$ + } + fClassLoader = child; + } } return fClassLoader; } @@ -132,4 +149,12 @@ public IJavaProject getProject() { return fProject; } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#getThread() + */ + public IJavaThread getThread() { + return fThread; + } + } Index: eval/org/eclipse/jdt/internal/debug/eval/ast/engine/JavaObjectRuntimeContext.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/JavaObjectRuntimeContext.java,v retrieving revision 1.8 diff -u -r1.8 JavaObjectRuntimeContext.java --- eval/org/eclipse/jdt/internal/debug/eval/ast/engine/JavaObjectRuntimeContext.java 4 Aug 2005 18:58:14 -0000 1.8 +++ eval/org/eclipse/jdt/internal/debug/eval/ast/engine/JavaObjectRuntimeContext.java 18 Sep 2009 18:48:07 -0000 @@ -25,12 +25,7 @@ * this object or this context. */ private IJavaObject fThisObject; - - /** - * The thread for this context. - */ - private IJavaThread fThread; - + /** * ObjectValueRuntimeContext constructor. * @@ -39,9 +34,8 @@ * @param thread the thread for this context. */ public JavaObjectRuntimeContext(IJavaObject thisObject, IJavaProject javaProject, IJavaThread thread) { - super(javaProject); + super(javaProject, thread); fThisObject= thisObject; - fThread= thread; } /** @@ -73,17 +67,17 @@ } /** - * @see IRuntimeContext#getThread() - */ - public IJavaThread getThread() { - return fThread; - } - - /** * @see IRuntimeContext#isConstructor() */ public boolean isConstructor() { return false; } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#isStatic() + */ + public boolean isStatic() { + return false; + } } Index: eval/org/eclipse/jdt/internal/debug/eval/ast/engine/IRuntimeContext.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/IRuntimeContext.java,v retrieving revision 1.7 diff -u -r1.7 IRuntimeContext.java --- eval/org/eclipse/jdt/internal/debug/eval/ast/engine/IRuntimeContext.java 13 Jul 2005 19:09:44 -0000 1.7 +++ eval/org/eclipse/jdt/internal/debug/eval/ast/engine/IRuntimeContext.java 18 Sep 2009 18:48:07 -0000 @@ -54,6 +54,14 @@ IJavaObject getThis() throws CoreException; /** + * Returns whether this evaluation context is static. + * + * @return whether the evaluation context is static + * @exception CoreException on failure + */ + boolean isStatic() throws CoreException; + + /** * Returns the receiving type context in which to perform * the evaluation. The type of 'this', or in the case of a * static context, the class or interface in which the evaluation is being Index: eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ArrayRuntimeContext.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ArrayRuntimeContext.java,v retrieving revision 1.6 diff -u -r1.6 ArrayRuntimeContext.java --- eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ArrayRuntimeContext.java 29 May 2008 15:47:44 -0000 1.6 +++ eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ArrayRuntimeContext.java 18 Sep 2009 18:48:07 -0000 @@ -37,13 +37,11 @@ private IJavaArray fArray = null; private IJavaReferenceType fReceivingType = null; - private IJavaThread fThread = null; private IJavaVariable fLocalArray = null; public ArrayRuntimeContext(IJavaArray arrayObject, IJavaThread thread, IJavaProject project) { - super(project); + super(project, thread); fArray = arrayObject; - fThread = thread; fLocalArray = new JDIPlaceholderVariable(ARRAY_THIS_VARIABLE, arrayObject); } @@ -85,16 +83,16 @@ } /* (non-Javadoc) - * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#getThread() + * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#isConstructor() */ - public IJavaThread getThread() { - return fThread; + public boolean isConstructor() throws CoreException { + return false; } - + /* (non-Javadoc) - * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#isConstructor() + * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#isStatic() */ - public boolean isConstructor() throws CoreException { + public boolean isStatic() { return false; } Index: eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java,v retrieving revision 1.70 diff -u -r1.70 ASTEvaluationEngine.java --- eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java 21 May 2009 20:22:26 -0000 1.70 +++ eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java 18 Sep 2009 18:48:07 -0000 @@ -214,7 +214,7 @@ // Compile in context of declaring type to get proper visibility of locals and members. // Compiling in context of receiving type potentially provides access to more members, // but does not allow access to privates members in declaring type - IJavaReferenceType receivingType = frame.getReferenceType(); + IJavaReferenceType receivingType = context.getReceivingType(); // currently disabled - see bugs 99416 and 106492 // if (frame.isStatic()) { Index: model/org/eclipse/jdt/internal/debug/core/model/JDIDebugTarget.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugTarget.java,v retrieving revision 1.141 diff -u -r1.141 JDIDebugTarget.java --- model/org/eclipse/jdt/internal/debug/core/model/JDIDebugTarget.java 10 Sep 2009 18:45:15 -0000 1.141 +++ model/org/eclipse/jdt/internal/debug/core/model/JDIDebugTarget.java 18 Sep 2009 18:48:08 -0000 @@ -46,6 +46,8 @@ import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.debug.core.IJavaBreakpoint; import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaReferenceType; import org.eclipse.jdt.debug.core.IJavaThread; import org.eclipse.jdt.debug.core.IJavaThreadGroup; import org.eclipse.jdt.debug.core.IJavaType; @@ -69,6 +71,7 @@ import com.sun.jdi.VMDisconnectedException; import com.sun.jdi.Value; import com.sun.jdi.VirtualMachine; +import com.sun.jdi.event.ClassPrepareEvent; import com.sun.jdi.event.Event; import com.sun.jdi.event.EventSet; import com.sun.jdi.event.ThreadDeathEvent; @@ -452,11 +455,12 @@ /** * Registers event handlers for thread creation, - * thread termination. + * thread termination, and class prepare requests. */ protected void initializeRequests() { setThreadStartHandler(new ThreadStartHandler()); - new ThreadDeathHandler(); + new ThreadDeathHandler(); + new ClassLoaderHandler(); } /** @@ -1951,6 +1955,83 @@ } + /** + * Listens to all class prepare events to discover the bootstrap class loader. + */ + class ClassLoaderHandler implements IJDIEventListener { + + public ClassLoaderHandler() { + createRequest(); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.debug.core.IJDIEventListener#eventSetComplete(com.sun.jdi.event.Event, org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget, boolean, com.sun.jdi.event.EventSet) + */ + public void eventSetComplete(Event event, JDIDebugTarget target, boolean suspend, EventSet eventSet) { + // do nothing + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.debug.core.IJDIEventListener#handleEvent(com.sun.jdi.event.Event, org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget, boolean, com.sun.jdi.event.EventSet) + */ + public boolean handleEvent(Event event, JDIDebugTarget target, boolean suspendVote, EventSet eventSet) { + if (event instanceof ClassPrepareEvent) { + ClassPrepareEvent cpe = (ClassPrepareEvent) event; + IJavaObject loader = null; + try { + ReferenceType type = cpe.referenceType(); + IJavaReferenceType refType = (IJavaReferenceType) JDIType.createType(target, type); + loader = refType.getClassLoaderObject(); + } catch (DebugException e) { + // do nothing + } + if (loader != null) { + fSomeClassLoader = loader; + // remove listener & disable request + removeJDIEventListener(this, cpe.request()); + cpe.request().disable(); + } + } + // always resume + return true; + } + + /** + * Creates and registers a request to handle all class prepare + * events + */ + protected void createRequest() { + EventRequestManager manager = getEventRequestManager(); + if (manager != null) { + try { + ClassPrepareRequest req= manager.createClassPrepareRequest(); + req.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + req.enable(); + addJDIEventListener(this, req); + } catch (RuntimeException e) { + logError(e); + } + } + } + + } + + /** + * The first class loader that the VM can find. Cached for debugger evaluations + * so we can locate the boot strap class loader when needed. + */ + private IJavaObject fSomeClassLoader = null; + + /** + * Returns the first class loader object found by this target, or null + * if none yet. + * + * @return some class loader object or null + */ + public IJavaObject getSomeClassLoader() { + return fSomeClassLoader; + } + class CleanUpJob extends Job { /** Index: META-INF/MANIFEST.MF =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.debug/META-INF/MANIFEST.MF,v retrieving revision 1.19 diff -u -r1.19 MANIFEST.MF --- META-INF/MANIFEST.MF 22 Jun 2009 15:30:35 -0000 1.19 +++ META-INF/MANIFEST.MF 18 Sep 2009 18:48:07 -0000 @@ -31,7 +31,8 @@ org.eclipse.jdt.internal.debug.core.model;x-friends:="org.eclipse.jdt.debug.ui", org.eclipse.jdt.internal.debug.eval;x-friends:="org.eclipse.jdt.debug.ui", org.eclipse.jdt.internal.debug.eval.ast.engine;x-friends:="org.eclipse.jdt.debug.ui", - org.eclipse.jdt.internal.debug.eval.ast.instructions;x-friends:="org.eclipse.jdt.debug.ui" + org.eclipse.jdt.internal.debug.eval.ast.instructions;x-friends:="org.eclipse.jdt.debug.ui", + org.eclipse.jdt.internal.debug.eval.engine;x-internal:=true Require-Bundle: org.eclipse.core.resources;bundle-version="[3.5.0,4.0.0)", org.eclipse.debug.core;bundle-version="[3.5.0,4.0.0)", org.eclipse.jdt.core;bundle-version="[3.5.0,4.0.0)", Index: model/org/eclipse/jdt/internal/debug/core/IJDIEventListener.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/IJDIEventListener.java,v retrieving revision 1.13 diff -u -r1.13 IJDIEventListener.java --- model/org/eclipse/jdt/internal/debug/core/IJDIEventListener.java 7 Apr 2009 18:21:18 -0000 1.13 +++ model/org/eclipse/jdt/internal/debug/core/IJDIEventListener.java 18 Sep 2009 18:48:07 -0000 @@ -17,12 +17,12 @@ import com.sun.jdi.event.EventSet; /** - * A jdi event listener is notified of events associated with - * a specific jdi event request. A listener registers/deregisters - * event requests with a debug target. + * A JDI event listener is notified of events associated with + * a specific JDI event request. A listener registers/unregisters + * event requests with a JDI debug element. * - * @see JDIDebugTarget#addJDIEventListener(IJDIEventListener, EventRequest) - * @see JDIDebugTarget#removeJDIEventListener(IJDIEventListener, EventRequest) + * @see org.eclipse.jdt.internal.debug.core.model.JDIDebugElement#addJDIEventListener(IJDIEventListener, com.sun.jdi.request.EventRequest) + * @see org.eclipse.jdt.internal.debug.core.model.JDIDebugElement#removeJDIEventListener(IJDIEventListener, com.sun.jdi.request.EventRequest) */ public interface IJDIEventListener { Index: eval/org/eclipse/jdt/debug/eval/EvaluationManager.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.debug/eval/org/eclipse/jdt/debug/eval/EvaluationManager.java,v retrieving revision 1.19 diff -u -r1.19 EvaluationManager.java --- eval/org/eclipse/jdt/debug/eval/EvaluationManager.java 29 May 2008 15:47:44 -0000 1.19 +++ eval/org/eclipse/jdt/debug/eval/EvaluationManager.java 18 Sep 2009 18:48:07 -0000 @@ -16,7 +16,7 @@ import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.debug.core.IJavaDebugTarget; import org.eclipse.jdt.internal.debug.eval.LocalEvaluationEngine; -import org.eclipse.jdt.internal.debug.eval.ast.engine.ASTEvaluationEngine; +import org.eclipse.jdt.internal.debug.eval.engine.RemoteEvaluationEngine; /** * The evaluation manager provides factory methods for @@ -67,7 +67,7 @@ * @return an evaluation engine */ public static IAstEvaluationEngine newAstEvaluationEngine(IJavaProject project, IJavaDebugTarget target) { - return new ASTEvaluationEngine(project, target); + return new RemoteEvaluationEngine(target, project); } } Index: eval/org/eclipse/jdt/internal/debug/eval/engine/RemoteEvaluationEngine.java =================================================================== RCS file: eval/org/eclipse/jdt/internal/debug/eval/engine/RemoteEvaluationEngine.java diff -N eval/org/eclipse/jdt/internal/debug/eval/engine/RemoteEvaluationEngine.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ eval/org/eclipse/jdt/internal/debug/eval/engine/RemoteEvaluationEngine.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,460 @@ +/******************************************************************************* + * Copyright (c) 2009 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.jdt.internal.debug.eval.engine; + +import java.util.HashSet; +import java.util.Set; +import java.util.StringTokenizer; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.IDebugEventFilter; +import org.eclipse.debug.core.model.ITerminate; +import org.eclipse.jdt.core.Flags; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.Signature; +import org.eclipse.jdt.core.eval.IEvaluationContext; +import org.eclipse.jdt.debug.core.IEvaluationRunnable; +import org.eclipse.jdt.debug.core.IJavaClassType; +import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.eclipse.jdt.debug.core.IJavaInterfaceType; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaReferenceType; +import org.eclipse.jdt.debug.core.IJavaStackFrame; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.debug.core.IJavaVariable; +import org.eclipse.jdt.debug.core.JDIDebugModel; +import org.eclipse.jdt.debug.eval.IAstEvaluationEngine; +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.core.JavaDebugUtils; +import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; +import org.eclipse.jdt.internal.debug.core.model.JDIThread; +import org.eclipse.jdt.internal.debug.core.model.JDIValue; +import org.eclipse.jdt.internal.debug.eval.EvaluationResult; +import org.eclipse.jdt.internal.debug.eval.ast.engine.EvaluationEngineMessages; +import org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext; +import org.eclipse.jdt.internal.debug.eval.ast.engine.JavaObjectRuntimeContext; +import org.eclipse.jdt.internal.debug.eval.ast.engine.RuntimeContext; +import org.eclipse.jdt.internal.debug.eval.ast.engine.TypeRuntimeContext; + +import com.sun.jdi.InvocationException; +import com.sun.jdi.ObjectReference; + +/** + * + */ +public class RemoteEvaluationEngine implements IAstEvaluationEngine { + + /** + * Associated Java project + */ + private IJavaProject fProject; + + /** + * Associated debug target + */ + private IJavaDebugTarget fTarget; + + /** + * Runnable serialized on a thread to perform submit an evaluation + */ + class EvalRunnable implements Runnable { + + private CompiledExpression fExpression; + + private int fEvaluationDetail; + + private boolean fHitBreakpoints; + + private IRuntimeContext fContext; + + private IEvaluationListener fListener; + + public EvalRunnable(CompiledExpression expression, IRuntimeContext context, IEvaluationListener listener, int evaluationDetail, boolean hitBreakpoints) { + fExpression= expression; + fContext= context; + fListener= listener; + fEvaluationDetail= evaluationDetail; + fHitBreakpoints= hitBreakpoints; + } + + public void run() { + EvaluationResult result = new EvaluationResult(RemoteEvaluationEngine.this, fExpression.getSnippet(), fContext.getThread()); + if (fExpression.hasErrors()) { + String[] errors = fExpression.getErrorMessages(); + for (int i = 0, numErrors = errors.length; i < numErrors; i++) { + result.addError(errors[i]); + } + evaluationFinished(result); + return; + } + + class EvaluationRunnable implements IEvaluationRunnable, ITerminate { + + CoreException fException; + boolean fTerminated = false; + + public void run(IJavaThread jt, IProgressMonitor pm) { + EventFilter filter = new EventFilter(); + try { + DebugPlugin.getDefault().addDebugEventFilter(filter); + fExpression.execute(fContext); + } catch (CoreException exception) { + fException = exception; + if (fEvaluationDetail == DebugEvent.EVALUATION && exception.getStatus().getException() instanceof InvocationException) { + // print the stack trace for the exception if an *explicit* evaluation + InvocationException invocationException = (InvocationException)exception.getStatus().getException(); + ObjectReference exObject = invocationException.exception(); + IJavaObject modelObject = (IJavaObject)JDIValue.createValue((JDIDebugTarget)getDebugTarget(), exObject); + try { + modelObject.sendMessage("printStackTrace", "()V", null, jt, false); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (DebugException e) { + // unable to print stack trace + } + } + } finally { + DebugPlugin.getDefault().removeDebugEventFilter(filter); + fTerminated = true; + } + } + public void terminate() { + fTerminated = true; + // TODO: how to support terminate? + } + public boolean canTerminate() { + return !fTerminated; + } + public boolean isTerminated() { + return fTerminated; + } + + public CoreException getException() { + return fException; + } + } + + EvaluationRunnable er = new EvaluationRunnable(); + CoreException exception = null; + try { + fContext.getThread().runEvaluation(er, null, fEvaluationDetail, fHitBreakpoints); + } catch (DebugException e) { + exception = e; + } + + IJavaValue value = fExpression.getResult(); + + if (exception == null) { + exception = er.getException(); + } + + result.setTerminated(er.fTerminated); + if (exception != null) { + if (exception instanceof DebugException) { + result.setException((DebugException)exception); + } else { + result.setException(new DebugException(exception.getStatus())); + } + } else { + if (value != null) { + result.setValue(value); + } else { + result.addError(EvaluationEngineMessages.ASTEvaluationEngine_An_unknown_error_occurred_during_evaluation); + } + } + + + evaluationFinished(result); + } + private void evaluationFinished(IEvaluationResult result) { + // only notify if plug-in not yet shutdown - bug# 8693 + if(JDIDebugPlugin.getDefault() != null) { + fListener.evaluationComplete(result); + } + } + + } + + /** + * Filters variable change events during an evaluation to avoid refreshing the variables + * view until done. + */ + class EventFilter implements IDebugEventFilter { + + /* (non-Javadoc) + * @see org.eclipse.debug.core.IDebugEventFilter#filterDebugEvents(org.eclipse.debug.core.DebugEvent[]) + */ + public DebugEvent[] filterDebugEvents(DebugEvent[] events) { + if (events.length == 1) { + DebugEvent event = events[0]; + if (event.getSource() instanceof IJavaVariable && event.getKind() == DebugEvent.CHANGE) { + if (((IJavaVariable)event.getSource()).getDebugTarget().equals(getDebugTarget())) { + return null; + } + } + } + return events; + } + + } + + /** + * Constructs a new engine on the given target and project. + * + * @param target debug target + * @param project associated project for compilation purposes + */ + public RemoteEvaluationEngine(IJavaDebugTarget target, IJavaProject project) { + fProject = project; + fTarget = target; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.debug.eval.IAstEvaluationEngine#evaluateExpression(org.eclipse.jdt.debug.eval.ICompiledExpression, org.eclipse.jdt.debug.core.IJavaStackFrame, org.eclipse.jdt.debug.eval.IEvaluationListener, int, boolean) + */ + public void evaluateExpression(ICompiledExpression expression, IJavaStackFrame frame, final IEvaluationListener listener, int evaluationDetail, boolean hitBreakpoints) throws DebugException { + IRuntimeContext debugContext = new RuntimeContext(getJavaProject(), frame); + evaluateExpression(expression, debugContext, listener, evaluationDetail, hitBreakpoints); + } + + /** + * Evaluates the given expression in the specified thread and the context. + * + * @param expression expression to evaluate + * @param context context to evaluate in + * @param listener listener to report results to + * @param evaluationDetail detail event to fire with evaluation resume/suspend + * @param hitBreakpoints whether to honor breakpoints during the evaluation + */ + private void evaluateExpression(ICompiledExpression expression, IRuntimeContext context, IEvaluationListener listener, int evaluationDetail, boolean hitBreakpoints) throws DebugException { + if (expression instanceof CompiledExpression) { + IJavaThread thread = context.getThread(); + // don't queue explicit evaluation if the thread is all ready performing an evaluation. + if (thread.isSuspended() && ((JDIThread)thread).isInvokingMethod() || thread.isPerformingEvaluation() && evaluationDetail == DebugEvent.EVALUATION) { + EvaluationResult result= new EvaluationResult(this, expression.getSnippet(), thread); + result.addError(EvaluationEngineMessages.ASTEvaluationEngine_Cannot_perform_nested_evaluations); + listener.evaluationComplete(result); + return; + } + thread.queueRunnable(new EvalRunnable((CompiledExpression)expression, context, listener, evaluationDetail, hitBreakpoints)); + } else { + throw new DebugException(new Status(IStatus.ERROR, JDIDebugPlugin.getUniqueIdentifier(), IStatus.OK, EvaluationEngineMessages.ASTEvaluationEngine_AST_evaluation_engine_cannot_evaluate_expression, null)); + } + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.debug.eval.IAstEvaluationEngine#evaluateExpression(org.eclipse.jdt.debug.eval.ICompiledExpression, org.eclipse.jdt.debug.core.IJavaObject, org.eclipse.jdt.debug.core.IJavaThread, org.eclipse.jdt.debug.eval.IEvaluationListener, int, boolean) + */ + public void evaluateExpression(ICompiledExpression expression, + IJavaObject object, IJavaThread thread, + IEvaluationListener listener, int evaluationDetail, + boolean hitBreakpoints) throws DebugException { + IRuntimeContext debugContext = new JavaObjectRuntimeContext(object, getJavaProject(), thread); + evaluateExpression(expression, debugContext, listener, evaluationDetail, hitBreakpoints); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.debug.eval.IAstEvaluationEngine#getCompiledExpression(java.lang.String, org.eclipse.jdt.debug.core.IJavaStackFrame) + */ + public ICompiledExpression getCompiledExpression(String expression, IJavaStackFrame frame) throws DebugException { + return getCompiledExpression(expression, new RuntimeContext(getJavaProject(), frame)); + } + + /** + * Returns a compiled expression for the given snippet in the given debugger context. + * + * @param snippet expression to compile + * @param debugContext current execution context to compile in + * @return compiled expression + * @throws DebugException on failure + */ + private ICompiledExpression getCompiledExpression(final String snippet, final IRuntimeContext debugContext) throws DebugException { + IJavaProject javaProject = getJavaProject(); + final IEvaluationContext evalContext = javaProject.newEvaluationContext(); + + try { + IJavaVariable[] localsVar = debugContext.getLocals(); + int numLocalsVar= localsVar.length; + Set names = new HashSet(); + // ****** + // to hide problems with local variable declare as instance of Local Types + // and to remove locals with duplicate names + IJavaVariable[] locals= new IJavaVariable[numLocalsVar]; + int numLocals= 0; + for (int i = 0; i < numLocalsVar; i++) { + if (!isLocalType(localsVar[i].getSignature()) && !names.contains(localsVar[i].getName())) { + locals[numLocals++]= localsVar[i]; + names.add(localsVar[i].getName()); + } + } + // to solve and remove + // ****** + final String[] localTypesNames= new String[numLocals]; + final String[] localVariables= new String[numLocals]; + final int[] localModifiers = new int[numLocals]; + for (int i = 0; i < numLocals; i++) { + localVariables[i] = locals[i].getName(); + localTypesNames[i] = Signature.toString(locals[i].getGenericSignature()).replace('/', '.'); + localModifiers[i] = Flags.AccDefault; + if (locals[i].isFinal()) { + localModifiers[i] = Flags.AccFinal; + } + } + // Compile in context of declaring type to get proper visibility of locals and members. + // Compiling in context of receiving type potentially provides access to more members, + // but does not allow access to privates members in declaring type + IJavaReferenceType receivingType = debugContext.getReceivingType(); + IType iType = JavaDebugUtils.resolveType(receivingType); + while (iType.isAnonymous() && receivingType instanceof IJavaClassType) { + // cannot compile in context of anonymous classes, so compile in context of their superclass + receivingType = ((IJavaClassType)receivingType).getSuperclass(); + iType = JavaDebugUtils.resolveType(receivingType); + } + + final IType declaringType = iType; + final CompiledExpression compiledExpression = new CompiledExpression(snippet, localVariables); + Job job = new Job("Debugger Evaluation") { + protected IStatus run(IProgressMonitor monitor) { + try { + evalContext.evaluateCodeSnippet( + snippet, + localTypesNames, + localVariables, + localModifiers, + declaringType, + debugContext.isStatic(), + debugContext.isConstructor(), + compiledExpression, + new NullProgressMonitor()); + } catch (JavaModelException e) { + return e.getStatus(); + } catch (CoreException e) { + return e.getStatus(); + } + return Status.OK_STATUS; + } + }; + job.setSystem(true); + job.schedule(); + try { + job.join(); + } catch (InterruptedException e) { + throw new DebugException(new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(), "Evaluation interrupted", e)); + } + + return compiledExpression; + } catch (CoreException e) { + throw new DebugException(e.getStatus()); + } + } + + //TODO: local types might be OK with this new engine + + // ****** + // to hide problems with local variable declare as instance of Local Types + private boolean isLocalType(String typeName) { + StringTokenizer strTok= new StringTokenizer(typeName,"$"); //$NON-NLS-1$ + strTok.nextToken(); + while (strTok.hasMoreTokens()) { + char char0= strTok.nextToken().charAt(0); + if ('0' <= char0 && char0 <= '9') { + return true; + } + } + return false; + } + // ****** + + /* (non-Javadoc) + * @see org.eclipse.jdt.debug.eval.IAstEvaluationEngine#getCompiledExpression(java.lang.String, org.eclipse.jdt.debug.core.IJavaObject) + */ + public ICompiledExpression getCompiledExpression(String expression, IJavaObject object) throws DebugException { + return getCompiledExpression(expression, new JavaObjectRuntimeContext(object, getJavaProject(), null)); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.debug.eval.IAstEvaluationEngine#getCompiledExpression(java.lang.String, org.eclipse.jdt.debug.core.IJavaReferenceType) + */ + public ICompiledExpression getCompiledExpression(String expression, IJavaReferenceType type) throws DebugException { + return getCompiledExpression(expression, new TypeRuntimeContext(getJavaProject(), null, type)); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.debug.eval.IEvaluationEngine#dispose() + */ + public void dispose() { + // TODO Auto-generated method stub + + } + + /** + * Checks if the stack frame is declared in an interface an aborts + * if so. + * + * @param frame stack frame + * @throws DebugException if declaring type is an interface + */ + private void checkInterface(IJavaStackFrame frame) throws DebugException { + if (frame.getReferenceType() instanceof IJavaInterfaceType) { + IStatus status = new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(), DebugException.REQUEST_FAILED, + EvaluationEngineMessages.ASTEvaluationEngine_0, null); + throw new DebugException(status); + } + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.debug.eval.IEvaluationEngine#evaluate(java.lang.String, org.eclipse.jdt.debug.core.IJavaStackFrame, org.eclipse.jdt.debug.eval.IEvaluationListener, int, boolean) + */ + public void evaluate(String snippet, IJavaStackFrame frame, IEvaluationListener listener, int evaluationDetail, boolean hitBreakpoints) throws DebugException { + checkInterface(frame); + IRuntimeContext context = new RuntimeContext(getJavaProject(), frame); + ICompiledExpression expression= getCompiledExpression(snippet, context); + evaluateExpression(expression, context, listener, evaluationDetail, hitBreakpoints); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.debug.eval.IEvaluationEngine#evaluate(java.lang.String, org.eclipse.jdt.debug.core.IJavaObject, org.eclipse.jdt.debug.core.IJavaThread, org.eclipse.jdt.debug.eval.IEvaluationListener, int, boolean) + */ + public void evaluate(String snippet, IJavaObject thisContext, + IJavaThread thread, IEvaluationListener listener, + int evaluationDetail, boolean hitBreakpoints) throws DebugException { + IRuntimeContext context = new JavaObjectRuntimeContext(thisContext, getJavaProject(), thread); + ICompiledExpression expression= getCompiledExpression(snippet, context); + evaluateExpression(expression, context, listener, evaluationDetail, hitBreakpoints); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.debug.eval.IEvaluationEngine#getDebugTarget() + */ + public IJavaDebugTarget getDebugTarget() { + return fTarget; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.debug.eval.IEvaluationEngine#getJavaProject() + */ + public IJavaProject getJavaProject() { + return fProject; + } + +} Index: eval/org/eclipse/jdt/internal/debug/eval/ast/engine/TypeRuntimeContext.java =================================================================== RCS file: eval/org/eclipse/jdt/internal/debug/eval/ast/engine/TypeRuntimeContext.java diff -N eval/org/eclipse/jdt/internal/debug/eval/ast/engine/TypeRuntimeContext.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ eval/org/eclipse/jdt/internal/debug/eval/ast/engine/TypeRuntimeContext.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright (c) 2009 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.jdt.internal.debug.eval.ast.engine; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaReferenceType; +import org.eclipse.jdt.debug.core.IJavaThread; +import org.eclipse.jdt.debug.core.IJavaVariable; + +/** + * Expression evaluation in the context of a type. Not a static context - used + * for logical structures which are evaluated in a nont-static context. + * + * @since 3.6 + */ +public class TypeRuntimeContext extends AbstractRuntimeContext { + + /** + * Type context for evaluation + */ + private IJavaReferenceType fType; + + /** + * Constructs a new evaluation context for the given type. + * + * @param project associated project + * @param thread thread for message sends + * @param type reference type + */ + public TypeRuntimeContext(IJavaProject project, IJavaThread thread, IJavaReferenceType type) { + super(project, thread); + fType = type; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#getLocals() + */ + public IJavaVariable[] getLocals() throws CoreException { + return new IJavaVariable[0]; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#getReceivingType() + */ + public IJavaReferenceType getReceivingType() throws CoreException { + return fType; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#getThis() + */ + public IJavaObject getThis() throws CoreException { + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#getVM() + */ + public IJavaDebugTarget getVM() { + return (IJavaDebugTarget) fType.getDebugTarget(); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#isConstructor() + */ + public boolean isConstructor() throws CoreException { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#isStatic() + */ + public boolean isStatic() throws CoreException { + return false; + } + +} Index: eval/org/eclipse/jdt/internal/debug/eval/engine/CompiledExpression.java =================================================================== RCS file: eval/org/eclipse/jdt/internal/debug/eval/engine/CompiledExpression.java diff -N eval/org/eclipse/jdt/internal/debug/eval/engine/CompiledExpression.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ eval/org/eclipse/jdt/internal/debug/eval/engine/CompiledExpression.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,348 @@ +/******************************************************************************* + * Copyright (c) 2009 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.jdt.internal.debug.eval.engine; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.model.IVariable; +import org.eclipse.jdt.core.dom.Message; +import org.eclipse.jdt.core.eval.ICodeSnippetRequestor; +import org.eclipse.jdt.debug.core.IJavaArray; +import org.eclipse.jdt.debug.core.IJavaArrayType; +import org.eclipse.jdt.debug.core.IJavaClassObject; +import org.eclipse.jdt.debug.core.IJavaClassType; +import org.eclipse.jdt.debug.core.IJavaDebugTarget; +import org.eclipse.jdt.debug.core.IJavaObject; +import org.eclipse.jdt.debug.core.IJavaReferenceType; +import org.eclipse.jdt.debug.core.IJavaValue; +import org.eclipse.jdt.debug.core.IJavaVariable; +import org.eclipse.jdt.debug.core.JDIDebugModel; +import org.eclipse.jdt.debug.eval.ICompiledExpression; +import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; +import org.eclipse.jdt.internal.debug.eval.EvaluationMessages; +import org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext; + +/** + * + */ +public class CompiledExpression implements ICompiledExpression, ICodeSnippetRequestor { + + /** + * List of Strings describing compilation problems. + */ + private List fErrors = new ArrayList(); + + /** + * Expression to evaluate + */ + private String fSnippet; + + List fClassFileBytes = new ArrayList(); + + List fClassFileNames = new ArrayList(); + + private String fCodeSnippetClass; + + private String[] fLocalNames; + + /** + * Result of the evaluation or null if none + */ + private IJavaValue fResult; + + /** + * Constructs a new compiled expression + * + * @param expression the expression being evaluated + */ + public CompiledExpression(String expression, String[] localVarNames) { + fSnippet = expression; + fLocalNames = localVarNames; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.debug.eval.ICompiledExpression#getErrorMessages() + */ + public String[] getErrorMessages() { + return (String[])fErrors.toArray(new String[fErrors.size()]); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.debug.eval.ICompiledExpression#getErrors() + */ + public Message[] getErrors() { + Message[] messages= new Message[fErrors.size()]; + int i= 0; + for (Iterator iter= fErrors.iterator(); iter.hasNext();) { + messages[i++]= new Message((String) iter.next(), -1); + } + return messages; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.debug.eval.ICompiledExpression#getSnippet() + */ + public String getSnippet() { + return fSnippet; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.debug.eval.ICompiledExpression#hasErrors() + */ + public boolean hasErrors() { + return fErrors.size() > 0; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.eval.ICodeSnippetRequestor#acceptClassFiles(byte[][], java.lang.String[][], java.lang.String) + */ + public boolean acceptClassFiles(byte[][] classFileBytes, String[][] classFileCompoundNames, String codeSnippetClassName) { + for (int i = 0; i < classFileBytes.length; i++) { + byte[] bs = classFileBytes[i]; + String[] ids = classFileCompoundNames[i]; + StringBuffer buffer = new StringBuffer(); + for (int j = 0; j < ids.length; j++) { + if (j > 0) { + buffer.append('.'); + } + buffer.append(ids[j]); + } + fClassFileBytes.add(bs); + fClassFileNames.add(buffer.toString()); + } + fCodeSnippetClass = codeSnippetClassName; + return true; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.eval.ICodeSnippetRequestor#acceptProblem(org.eclipse.core.resources.IMarker, java.lang.String, int) + */ + public void acceptProblem(IMarker problemMarker, String fragmentSource, int fragmentKind) { + if (problemMarker.getAttribute(IMarker.SEVERITY, -1) != IMarker.SEVERITY_ERROR) { + return; + } + fErrors.add(problemMarker.getAttribute(IMarker.MESSAGE, "")); //$NON-NLS-1$ + } + + byte[][] getClassFiles() { + return (byte[][]) fClassFileBytes.toArray(new byte[fClassFileBytes.size()][]); + } + + String[] getClassFileNames() { + return (String[]) fClassFileNames.toArray(new String[fClassFileNames.size()]); + } + + String getSnippetClass() { + return fCodeSnippetClass; + } + + String[] getLocalVarNames() { + return fLocalNames; + } + + IJavaValue execute(IRuntimeContext debugContext) throws CoreException { + IJavaReferenceType receivingType = debugContext.getReceivingType(); + IJavaDebugTarget target = debugContext.getVM(); + IJavaObject loader = receivingType.getClassLoaderObject(); + //loader is null for those classes loaded by the bootstrap loader + if (loader == null) { + IJavaObject child = ((JDIDebugTarget)target).getSomeClassLoader(); + IJavaObject parent = child; + while (parent != null && !parent.isNull()) { + child = parent; + parent = (IJavaObject)child.sendMessage("getParent", "()Ljava/lang/ClassLoader;", null, debugContext.getThread(), false); //$NON-NLS-1$//$NON-NLS-2$ + } + loader = child; + } + if (loader == null) { + throw new CoreException(new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(), "Unable to locate bootstrap class loader")); + } + String[] names = getClassFileNames(); + byte[][] bytes = getClassFiles(); + for (int i = 0; i < bytes.length; i++) { + byte[] bs = bytes[i]; + String name = names[i]; + IJavaClassObject loaded = debugContext.classForName(name); + if (loaded == null) { + IJavaValue[] args = new IJavaValue[4]; + + args[0] = target.newValue(name); + IJavaClassObject clazz = debugContext.classForName("[B"); //$NON-NLS-1$ + IJavaArrayType byteArrayType = (IJavaArrayType) clazz.getInstanceType(); + IJavaArray array = byteArrayType.newInstance(bs.length); + IJavaValue[] values = new IJavaValue[bs.length]; + for (int j = 0; j < bs.length; j++) { + values[j] = target.newValue(bs[j]); + } + array.setValues(0, bs.length, values, 0); + args[1] = array; + + args[2] = target.newValue(0); + args[3] = target.newValue(bs.length); + IJavaValue result = loader.sendMessage("defineClass", "(Ljava/lang/String;[BII)Ljava/lang/Class;", args, debugContext.getThread(), false); //$NON-NLS-1$ //$NON-NLS-2$ + System.out.println(result); + args = new IJavaValue[1]; + args[0] = result; + IJavaValue voidRes = loader.sendMessage("resolveClass", "(Ljava/lang/Class;)V", args, debugContext.getThread(), false); //$NON-NLS-1$ //$NON-NLS-2$ + System.out.println(voidRes); + } + } + + // invoke the snippet method + IJavaClassObject snippetClazz = debugContext.classForName(getSnippetClass()); + IJavaClassType refType = (IJavaClassType) snippetClazz.getInstanceType(); + IJavaObject receiver = refType.newInstance("()V", null, debugContext.getThread()); //$NON-NLS-1$ + // initialize locals + initializeLocals(debugContext, receiver); + // execute code + receiver.sendMessage(ICodeSnippetRequestor.RUN_METHOD, "()V", null, debugContext.getThread(), false); //$NON-NLS-1$ + + // retrieve the result + // now retrieve the description of the result + IVariable[] fields = receiver.getVariables(); + IJavaVariable resultValue = null; + IJavaVariable resultType = null; + for (int i = 0; i < fields.length; i++) { + if (fields[i].getName().equals(ICodeSnippetRequestor.RESULT_TYPE_FIELD)) { + resultType = (IJavaVariable)fields[i]; + } + if (fields[i].getName().equals(ICodeSnippetRequestor.RESULT_VALUE_FIELD)) { + resultValue = (IJavaVariable)fields[i]; + } + } + // TODO: copy locals back + fResult = convertResult((IJavaClassObject)resultType.getValue(), (IJavaValue)resultValue.getValue()); + return fResult; + } + + /** + * Returns the result of the evaluation or null if + * none (evaluation failed). + * + * @return evaluation result or null + */ + public IJavaValue getResult() { + return fResult; + } + + /** + * Initializes the value of instance variables in the + * 'code snippet object' that are used as place holders + * for locals and 'this' in the current stack frame. + * + * @param context debug context + * @exception DebugException if an exception is thrown + * accessing the given object + */ + protected void initializeLocals(IRuntimeContext context, IJavaObject snippetObject) throws CoreException { + IJavaVariable[] locals = context.getLocals(); + IJavaObject thisObject = context.getThis(); + if (locals != null) { + for (int i = 0; i < locals.length; i++) { + IJavaVariable local = locals[i]; + IJavaVariable field = snippetObject.getField(ICodeSnippetRequestor.LOCAL_VAR_PREFIX + local.getName(), false); + // internal error if field is not found + if (field == null) { + throw new DebugException( + new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(), + DebugException.REQUEST_FAILED, EvaluationMessages.LocalEvaluationEngine_Evaluation_failed___unable_to_initialize_local_variables__4, null) + ); + } + field.setValue(local.getValue()); + } + } + if (thisObject != null) { + IJavaVariable field = snippetObject.getField(ICodeSnippetRequestor.DELEGATE_THIS, false); + // internal error if field is not found + if (field == null) { + throw new DebugException( + new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(), + DebugException.REQUEST_FAILED, EvaluationMessages.LocalEvaluationEngine_Evaluation_failed___unable_to_initialize___this___context__5, null) + ); + } + field.setValue(thisObject); + } + } + + /** + * Interpretts and returns the result of the running the snippet + * class file. The type of the result is described by an instance of + * java.lang.Class. The value is interpretted based + * on the result type. + *

+ * Objects as well as primitve data types (boolean, int, etc.), + * have class objects, which are created by the VM. If the class object + * represents a primitive data type, then the associated value + * is stored in an instance of its "object" class. For example, when + * the result type is the class object for int, the result + * object is an instance of java.lang.Integer, and the + * actual int is stored in the intValue(). + * When the result type is the class object for java.lang.Integer + * the result object is an instance of java.lang.Integer, + * to be interpretted as a java.lang.Integer. + *

+ * + * @param resultType the class of the result + * @param resultValue the value of ther result, to be interpretted + * based on resultType + * @return the result of running the code snipped class file + */ + protected IJavaValue convertResult(IJavaClassObject resultType, IJavaValue result) throws DebugException { + if (resultType == null) { + // there was an exception or compilation problem - no result + return null; + } + + // check the type of the result - if a primitive type, convert it + String sig = resultType.getInstanceType().getSignature(); + if (sig.equals("V") || sig.equals("Lvoid;")) { //$NON-NLS-2$ //$NON-NLS-1$ + // void + return ((IJavaDebugTarget)resultType.getDebugTarget()).voidValue(); + } + + if (result.getJavaType() == null) { + // null result + return result; + } + + if (sig.length() == 1) { + // primitive type - find the instance variable with the + // signature of the result type we are looking for + IVariable[] vars = result.getVariables(); + IJavaVariable var = null; + for (int i = 0; i < vars.length; i++) { + IJavaVariable jv = (IJavaVariable)vars[i]; + if (!jv.isStatic() && jv.getSignature().equals(sig)) { + var = jv; + break; + } + } + if (var != null) { + return (IJavaValue)var.getValue(); + } + } else { + // an object + return result; + } + throw new DebugException( + new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(), + DebugException.REQUEST_FAILED, EvaluationMessages.LocalEvaluationEngine_Evaluation_failed___internal_error_retreiving_result__17, null) + ); + } + +}