View | Details | Raw Unified | Return to bug 289798 | Differences between
and this patch

Collapse All | Expand All

(-)eval/org/eclipse/jdt/internal/debug/eval/ast/engine/RuntimeContext.java (-8 / +8 lines)
Lines 37-43 Link Here
37
	 * @return a new runtime context
37
	 * @return a new runtime context
38
	 */
38
	 */
39
	public RuntimeContext(IJavaProject project, IJavaStackFrame frame) {
39
	public RuntimeContext(IJavaProject project, IJavaStackFrame frame) {
40
		super(project);
40
		super(project, (IJavaThread) frame.getThread());
41
		setFrame(frame);
41
		setFrame(frame);
42
	}
42
	}
43
	
43
	
Lines 89-101 Link Here
89
	 */
89
	 */
90
	private void setFrame(IJavaStackFrame frame) {
90
	private void setFrame(IJavaStackFrame frame) {
91
		fFrame = frame;
91
		fFrame = frame;
92
	}	
93
94
	/**
95
	 * @see IRuntimeContext#getThread()
96
	 */
97
	public IJavaThread getThread() {
98
		return (IJavaThread)getFrame().getThread();
99
	}
92
	}
100
93
101
	/**
94
	/**
Lines 104-109 Link Here
104
	public boolean isConstructor() throws CoreException {
97
	public boolean isConstructor() throws CoreException {
105
		return getFrame().isConstructor();
98
		return getFrame().isConstructor();
106
	}
99
	}
100
	
101
	/* (non-Javadoc)
102
	 * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#isStatic()
103
	 */
104
	public boolean isStatic() throws CoreException {
105
		return getFrame().isStatic();
106
	}
107
107
108
}
108
}
109
109
(-)eval/org/eclipse/jdt/internal/debug/eval/ast/engine/AbstractRuntimeContext.java (-3 / +28 lines)
Lines 10-17 Link Here
10
 *******************************************************************************/
10
 *******************************************************************************/
11
package org.eclipse.jdt.internal.debug.eval.ast.engine;
11
package org.eclipse.jdt.internal.debug.eval.ast.engine;
12
12
13
import com.ibm.icu.text.MessageFormat;
14
15
import org.eclipse.core.runtime.CoreException;
13
import org.eclipse.core.runtime.CoreException;
16
import org.eclipse.core.runtime.IStatus;
14
import org.eclipse.core.runtime.IStatus;
17
import org.eclipse.core.runtime.Status;
15
import org.eclipse.core.runtime.Status;
Lines 19-29 Link Here
19
import org.eclipse.jdt.debug.core.IJavaClassObject;
17
import org.eclipse.jdt.debug.core.IJavaClassObject;
20
import org.eclipse.jdt.debug.core.IJavaClassType;
18
import org.eclipse.jdt.debug.core.IJavaClassType;
21
import org.eclipse.jdt.debug.core.IJavaObject;
19
import org.eclipse.jdt.debug.core.IJavaObject;
20
import org.eclipse.jdt.debug.core.IJavaThread;
22
import org.eclipse.jdt.debug.core.IJavaType;
21
import org.eclipse.jdt.debug.core.IJavaType;
23
import org.eclipse.jdt.debug.core.IJavaValue;
22
import org.eclipse.jdt.debug.core.IJavaValue;
24
import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin;
23
import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin;
24
import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget;
25
import org.eclipse.jdt.internal.debug.eval.ast.instructions.InstructionsEvaluationMessages;
25
import org.eclipse.jdt.internal.debug.eval.ast.instructions.InstructionsEvaluationMessages;
26
26
27
import com.ibm.icu.text.MessageFormat;
27
import com.sun.jdi.InvocationException;
28
import com.sun.jdi.InvocationException;
28
29
29
/**
30
/**
Lines 44-49 Link Here
44
     * Cache of java.lang.Class type
45
     * Cache of java.lang.Class type
45
     */
46
     */
46
    private IJavaClassType fJavaLangClass;
47
    private IJavaClassType fJavaLangClass;
48
    
49
    /**
50
     * Thread to perform message sends in
51
     */
52
    private IJavaThread fThread;
47
53
48
    /**
54
    /**
49
     * Java project context
55
     * Java project context
Lines 55-62 Link Here
55
    public static final String FOR_NAME_SIGNATURE= "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"; //$NON-NLS-1$
61
    public static final String FOR_NAME_SIGNATURE= "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"; //$NON-NLS-1$
56
62
57
63
58
    public AbstractRuntimeContext(IJavaProject project) {
64
    public AbstractRuntimeContext(IJavaProject project, IJavaThread thread) {
59
    	fProject = project;
65
    	fProject = project;
66
    	fThread = thread;
60
    }
67
    }
61
    
68
    
62
    /**
69
    /**
Lines 70-75 Link Here
70
    protected IJavaObject getClassLoaderObject() throws CoreException {
77
    protected IJavaObject getClassLoaderObject() throws CoreException {
71
        if (fClassLoader == null) {
78
        if (fClassLoader == null) {
72
            fClassLoader = getReceivingType().getClassLoaderObject();
79
            fClassLoader = getReceivingType().getClassLoaderObject();
80
    		//loader is null for those classes loaded by the bootstrap loader
81
    		if (fClassLoader == null) {
82
    			IJavaObject child = ((JDIDebugTarget)getVM()).getSomeClassLoader();
83
    			IJavaObject parent = child;
84
    			while (parent != null && !parent.isNull()) {
85
    				child = parent;
86
    				parent = (IJavaObject)child.sendMessage("getParent", "()Ljava/lang/ClassLoader;", null, getThread(), false);  //$NON-NLS-1$//$NON-NLS-2$
87
    			}
88
    			fClassLoader = child;
89
    		}
73
        }
90
        }
74
        return fClassLoader;
91
        return fClassLoader;
75
    } 
92
    } 
Lines 132-135 Link Here
132
	public IJavaProject getProject() {
149
	public IJavaProject getProject() {
133
		return fProject;
150
		return fProject;
134
	}
151
	}
152
	
153
	/* (non-Javadoc)
154
	 * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#getThread()
155
	 */
156
	public IJavaThread getThread() {
157
		return fThread;
158
	}
159
	
135
}
160
}
(-)eval/org/eclipse/jdt/internal/debug/eval/ast/engine/JavaObjectRuntimeContext.java (-15 / +9 lines)
Lines 25-36 Link Here
25
	 * <code>this</code> object or this context.
25
	 * <code>this</code> object or this context.
26
	 */
26
	 */
27
	private IJavaObject fThisObject;
27
	private IJavaObject fThisObject;
28
	
28
		
29
	/**
30
	 * The thread for this context.
31
	 */
32
	private IJavaThread fThread;
33
	
34
	/**
29
	/**
35
	 * ObjectValueRuntimeContext constructor.
30
	 * ObjectValueRuntimeContext constructor.
36
	 * 
31
	 * 
Lines 39-47 Link Here
39
	 * @param thread the thread for this context.
34
	 * @param thread the thread for this context.
40
	 */
35
	 */
41
	public JavaObjectRuntimeContext(IJavaObject thisObject, IJavaProject javaProject, IJavaThread thread) {
36
	public JavaObjectRuntimeContext(IJavaObject thisObject, IJavaProject javaProject, IJavaThread thread) {
42
		super(javaProject);
37
		super(javaProject, thread);
43
		fThisObject= thisObject;
38
		fThisObject= thisObject;
44
		fThread= thread;
45
	}
39
	}
46
40
47
	/**
41
	/**
Lines 73-89 Link Here
73
	}
67
	}
74
68
75
	/**
69
	/**
76
	 * @see IRuntimeContext#getThread()
77
	 */
78
	public IJavaThread getThread() {
79
		return fThread;
80
	}
81
82
	/**
83
	 * @see IRuntimeContext#isConstructor()
70
	 * @see IRuntimeContext#isConstructor()
84
	 */
71
	 */
85
	public boolean isConstructor() {
72
	public boolean isConstructor() {
86
		return false;
73
		return false;
87
	}
74
	}
75
	
76
	/* (non-Javadoc)
77
	 * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#isStatic()
78
	 */
79
	public boolean isStatic() {
80
		return false;
81
	}
88
82
89
}
83
}
(-)eval/org/eclipse/jdt/internal/debug/eval/ast/engine/IRuntimeContext.java (+8 lines)
Lines 54-59 Link Here
54
	IJavaObject getThis() throws CoreException;
54
	IJavaObject getThis() throws CoreException;
55
	
55
	
56
	/**
56
	/**
57
	 * Returns whether this evaluation context is static.
58
	 * 
59
	 * @return whether the evaluation context is static
60
	 * @exception CoreException on failure
61
	 */
62
	boolean isStatic() throws CoreException;
63
	
64
	/**
57
	 * Returns the receiving type context in which to perform 
65
	 * Returns the receiving type context in which to perform 
58
	 * the evaluation. The type of 'this', or in the case of a 
66
	 * the evaluation. The type of 'this', or in the case of a 
59
	 * static context, the class or interface in which the evaluation is being
67
	 * static context, the class or interface in which the evaluation is being
(-)eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ArrayRuntimeContext.java (-9 / +7 lines)
Lines 37-49 Link Here
37
	
37
	
38
	private IJavaArray fArray = null;
38
	private IJavaArray fArray = null;
39
	private IJavaReferenceType fReceivingType = null;
39
	private IJavaReferenceType fReceivingType = null;
40
	private IJavaThread fThread = null;
41
	private IJavaVariable fLocalArray = null;
40
	private IJavaVariable fLocalArray = null;
42
	
41
	
43
	public ArrayRuntimeContext(IJavaArray arrayObject, IJavaThread thread, IJavaProject project) {
42
	public ArrayRuntimeContext(IJavaArray arrayObject, IJavaThread thread, IJavaProject project) {
44
		super(project);
43
		super(project, thread);
45
		fArray = arrayObject;
44
		fArray = arrayObject;
46
		fThread = thread;
47
		fLocalArray = new JDIPlaceholderVariable(ARRAY_THIS_VARIABLE, arrayObject); 
45
		fLocalArray = new JDIPlaceholderVariable(ARRAY_THIS_VARIABLE, arrayObject); 
48
	}
46
	}
49
47
Lines 85-100 Link Here
85
	}
83
	}
86
84
87
	/* (non-Javadoc)
85
	/* (non-Javadoc)
88
	 * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#getThread()
86
	 * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#isConstructor()
89
	 */
87
	 */
90
	public IJavaThread getThread() {
88
	public boolean isConstructor() throws CoreException {
91
		return fThread;
89
		return false;
92
	}
90
	}
93
91
	
94
	/* (non-Javadoc)
92
	/* (non-Javadoc)
95
	 * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#isConstructor()
93
	 * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#isStatic()
96
	 */
94
	 */
97
	public boolean isConstructor() throws CoreException {
95
	public boolean isStatic() {
98
		return false;
96
		return false;
99
	}
97
	}
100
98
(-)eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java (-1 / +1 lines)
Lines 214-220 Link Here
214
			// Compile in context of declaring type to get proper visibility of locals and members.
214
			// Compile in context of declaring type to get proper visibility of locals and members.
215
			// Compiling in context of receiving type potentially provides access to more members,
215
			// Compiling in context of receiving type potentially provides access to more members,
216
			// but does not allow access to privates members in declaring type
216
			// but does not allow access to privates members in declaring type
217
			IJavaReferenceType receivingType = frame.getReferenceType();
217
			IJavaReferenceType receivingType = context.getReceivingType();
218
			
218
			
219
//			currently disabled - see bugs 99416 and 106492
219
//			currently disabled - see bugs 99416 and 106492
220
//			if (frame.isStatic()) {
220
//			if (frame.isStatic()) {
(-)model/org/eclipse/jdt/internal/debug/core/model/JDIDebugTarget.java (-2 / +83 lines)
Lines 46-51 Link Here
46
import org.eclipse.jdt.core.IJavaProject;
46
import org.eclipse.jdt.core.IJavaProject;
47
import org.eclipse.jdt.debug.core.IJavaBreakpoint;
47
import org.eclipse.jdt.debug.core.IJavaBreakpoint;
48
import org.eclipse.jdt.debug.core.IJavaDebugTarget;
48
import org.eclipse.jdt.debug.core.IJavaDebugTarget;
49
import org.eclipse.jdt.debug.core.IJavaObject;
50
import org.eclipse.jdt.debug.core.IJavaReferenceType;
49
import org.eclipse.jdt.debug.core.IJavaThread;
51
import org.eclipse.jdt.debug.core.IJavaThread;
50
import org.eclipse.jdt.debug.core.IJavaThreadGroup;
52
import org.eclipse.jdt.debug.core.IJavaThreadGroup;
51
import org.eclipse.jdt.debug.core.IJavaType;
53
import org.eclipse.jdt.debug.core.IJavaType;
Lines 69-74 Link Here
69
import com.sun.jdi.VMDisconnectedException;
71
import com.sun.jdi.VMDisconnectedException;
70
import com.sun.jdi.Value;
72
import com.sun.jdi.Value;
71
import com.sun.jdi.VirtualMachine;
73
import com.sun.jdi.VirtualMachine;
74
import com.sun.jdi.event.ClassPrepareEvent;
72
import com.sun.jdi.event.Event;
75
import com.sun.jdi.event.Event;
73
import com.sun.jdi.event.EventSet;
76
import com.sun.jdi.event.EventSet;
74
import com.sun.jdi.event.ThreadDeathEvent;
77
import com.sun.jdi.event.ThreadDeathEvent;
Lines 452-462 Link Here
452
	 
455
	 
453
	/**
456
	/**
454
	 * Registers event handlers for thread creation,
457
	 * Registers event handlers for thread creation,
455
	 * thread termination.
458
	 * thread termination, and class prepare requests.
456
	 */
459
	 */
457
	protected void initializeRequests() {
460
	protected void initializeRequests() {
458
		setThreadStartHandler(new ThreadStartHandler());
461
		setThreadStartHandler(new ThreadStartHandler());
459
		new ThreadDeathHandler();		
462
		new ThreadDeathHandler();	
463
		new ClassLoaderHandler();
460
	}
464
	}
461
465
462
	/**
466
	/**
Lines 1951-1956 Link Here
1951
	
1955
	
1952
	}
1956
	}
1953
	
1957
	
1958
	/**
1959
	 * Listens to all class prepare events to discover the bootstrap class loader.
1960
	 */
1961
	class ClassLoaderHandler implements IJDIEventListener {
1962
		
1963
		public ClassLoaderHandler() {
1964
			createRequest();
1965
		}
1966
1967
		/* (non-Javadoc)
1968
		 * @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)
1969
		 */
1970
		public void eventSetComplete(Event event, JDIDebugTarget target, boolean suspend, EventSet eventSet) {
1971
			// do nothing
1972
		}
1973
1974
		/* (non-Javadoc)
1975
		 * @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)
1976
		 */
1977
		public boolean handleEvent(Event event, JDIDebugTarget target, boolean suspendVote, EventSet eventSet) {
1978
			if (event instanceof ClassPrepareEvent) {
1979
				ClassPrepareEvent cpe = (ClassPrepareEvent) event;
1980
				IJavaObject loader = null;
1981
				try {
1982
					ReferenceType type = cpe.referenceType();
1983
					IJavaReferenceType refType = (IJavaReferenceType) JDIType.createType(target, type);
1984
					loader = refType.getClassLoaderObject();
1985
				} catch (DebugException e) {
1986
					// do nothing
1987
				}
1988
				if (loader != null) {
1989
					fSomeClassLoader = loader;
1990
					// remove listener & disable request
1991
					removeJDIEventListener(this, cpe.request());
1992
					cpe.request().disable();
1993
				}
1994
			}
1995
			// always resume
1996
			return true;
1997
		}
1998
		
1999
		/**
2000
		 * Creates and registers a request to handle all class prepare
2001
		 * events
2002
		 */
2003
		protected void createRequest() {
2004
			EventRequestManager manager = getEventRequestManager();
2005
			if (manager != null) {			
2006
				try {
2007
					ClassPrepareRequest req= manager.createClassPrepareRequest();
2008
					req.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
2009
					req.enable();
2010
					addJDIEventListener(this, req);
2011
				} catch (RuntimeException e) {
2012
					logError(e);
2013
				}
2014
			}
2015
		}
2016
		
2017
	}
2018
	
2019
	/**
2020
	 * The first class loader that the VM can find. Cached for debugger evaluations
2021
	 * so we can locate the boot strap class loader when needed.
2022
	 */
2023
	private IJavaObject fSomeClassLoader = null;
2024
	
2025
	/**
2026
	 * Returns the first class loader object found by this target, or <code>null</code>
2027
	 * if none yet.
2028
	 * 
2029
	 * @return some class loader object or <code>null</code>
2030
	 */
2031
	public IJavaObject getSomeClassLoader() {
2032
		return fSomeClassLoader;
2033
	}
2034
	
1954
	class CleanUpJob extends Job {
2035
	class CleanUpJob extends Job {
1955
2036
1956
		/**
2037
		/**
(-)META-INF/MANIFEST.MF (-1 / +2 lines)
Lines 31-37 Link Here
31
 org.eclipse.jdt.internal.debug.core.model;x-friends:="org.eclipse.jdt.debug.ui",
31
 org.eclipse.jdt.internal.debug.core.model;x-friends:="org.eclipse.jdt.debug.ui",
32
 org.eclipse.jdt.internal.debug.eval;x-friends:="org.eclipse.jdt.debug.ui",
32
 org.eclipse.jdt.internal.debug.eval;x-friends:="org.eclipse.jdt.debug.ui",
33
 org.eclipse.jdt.internal.debug.eval.ast.engine;x-friends:="org.eclipse.jdt.debug.ui",
33
 org.eclipse.jdt.internal.debug.eval.ast.engine;x-friends:="org.eclipse.jdt.debug.ui",
34
 org.eclipse.jdt.internal.debug.eval.ast.instructions;x-friends:="org.eclipse.jdt.debug.ui"
34
 org.eclipse.jdt.internal.debug.eval.ast.instructions;x-friends:="org.eclipse.jdt.debug.ui",
35
 org.eclipse.jdt.internal.debug.eval.engine;x-internal:=true
35
Require-Bundle: org.eclipse.core.resources;bundle-version="[3.5.0,4.0.0)",
36
Require-Bundle: org.eclipse.core.resources;bundle-version="[3.5.0,4.0.0)",
36
 org.eclipse.debug.core;bundle-version="[3.5.0,4.0.0)",
37
 org.eclipse.debug.core;bundle-version="[3.5.0,4.0.0)",
37
 org.eclipse.jdt.core;bundle-version="[3.5.0,4.0.0)",
38
 org.eclipse.jdt.core;bundle-version="[3.5.0,4.0.0)",
(-)model/org/eclipse/jdt/internal/debug/core/IJDIEventListener.java (-5 / +5 lines)
Lines 17-28 Link Here
17
import com.sun.jdi.event.EventSet;
17
import com.sun.jdi.event.EventSet;
18
18
19
/**
19
/**
20
 * A jdi event listener is notified of events associated with
20
 * A JDI event listener is notified of events associated with
21
 * a specific jdi event request. A listener registers/deregisters
21
 * a specific JDI event request. A listener registers/unregisters
22
 * event requests with a debug target.
22
 * event requests with a JDI debug element.
23
 * 
23
 * 
24
 * @see JDIDebugTarget#addJDIEventListener(IJDIEventListener, EventRequest)
24
 * @see org.eclipse.jdt.internal.debug.core.model.JDIDebugElement#addJDIEventListener(IJDIEventListener, com.sun.jdi.request.EventRequest)
25
 * @see JDIDebugTarget#removeJDIEventListener(IJDIEventListener, EventRequest)
25
 * @see org.eclipse.jdt.internal.debug.core.model.JDIDebugElement#removeJDIEventListener(IJDIEventListener, com.sun.jdi.request.EventRequest)
26
 */
26
 */
27
27
28
public interface IJDIEventListener {
28
public interface IJDIEventListener {
(-)eval/org/eclipse/jdt/debug/eval/EvaluationManager.java (-2 / +2 lines)
Lines 16-22 Link Here
16
import org.eclipse.jdt.core.IJavaProject;
16
import org.eclipse.jdt.core.IJavaProject;
17
import org.eclipse.jdt.debug.core.IJavaDebugTarget;
17
import org.eclipse.jdt.debug.core.IJavaDebugTarget;
18
import org.eclipse.jdt.internal.debug.eval.LocalEvaluationEngine;
18
import org.eclipse.jdt.internal.debug.eval.LocalEvaluationEngine;
19
import org.eclipse.jdt.internal.debug.eval.ast.engine.ASTEvaluationEngine;
19
import org.eclipse.jdt.internal.debug.eval.engine.RemoteEvaluationEngine;
20
20
21
/**
21
/**
22
 * The evaluation manager provides factory methods for
22
 * The evaluation manager provides factory methods for
Lines 67-73 Link Here
67
	 * @return an evaluation engine
67
	 * @return an evaluation engine
68
	 */
68
	 */
69
	public static IAstEvaluationEngine newAstEvaluationEngine(IJavaProject project, IJavaDebugTarget target) {
69
	public static IAstEvaluationEngine newAstEvaluationEngine(IJavaProject project, IJavaDebugTarget target) {
70
		return new ASTEvaluationEngine(project, target);
70
		return new RemoteEvaluationEngine(target, project);
71
	}
71
	}
72
}
72
}
73
73
(-)eval/org/eclipse/jdt/internal/debug/eval/engine/RemoteEvaluationEngine.java (+460 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 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
 *******************************************************************************/
11
package org.eclipse.jdt.internal.debug.eval.engine;
12
13
import java.util.HashSet;
14
import java.util.Set;
15
import java.util.StringTokenizer;
16
17
import org.eclipse.core.runtime.CoreException;
18
import org.eclipse.core.runtime.IProgressMonitor;
19
import org.eclipse.core.runtime.IStatus;
20
import org.eclipse.core.runtime.NullProgressMonitor;
21
import org.eclipse.core.runtime.Status;
22
import org.eclipse.core.runtime.jobs.Job;
23
import org.eclipse.debug.core.DebugEvent;
24
import org.eclipse.debug.core.DebugException;
25
import org.eclipse.debug.core.DebugPlugin;
26
import org.eclipse.debug.core.IDebugEventFilter;
27
import org.eclipse.debug.core.model.ITerminate;
28
import org.eclipse.jdt.core.Flags;
29
import org.eclipse.jdt.core.IJavaProject;
30
import org.eclipse.jdt.core.IType;
31
import org.eclipse.jdt.core.JavaModelException;
32
import org.eclipse.jdt.core.Signature;
33
import org.eclipse.jdt.core.eval.IEvaluationContext;
34
import org.eclipse.jdt.debug.core.IEvaluationRunnable;
35
import org.eclipse.jdt.debug.core.IJavaClassType;
36
import org.eclipse.jdt.debug.core.IJavaDebugTarget;
37
import org.eclipse.jdt.debug.core.IJavaInterfaceType;
38
import org.eclipse.jdt.debug.core.IJavaObject;
39
import org.eclipse.jdt.debug.core.IJavaReferenceType;
40
import org.eclipse.jdt.debug.core.IJavaStackFrame;
41
import org.eclipse.jdt.debug.core.IJavaThread;
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.debug.eval.IAstEvaluationEngine;
46
import org.eclipse.jdt.debug.eval.ICompiledExpression;
47
import org.eclipse.jdt.debug.eval.IEvaluationListener;
48
import org.eclipse.jdt.debug.eval.IEvaluationResult;
49
import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin;
50
import org.eclipse.jdt.internal.debug.core.JavaDebugUtils;
51
import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget;
52
import org.eclipse.jdt.internal.debug.core.model.JDIThread;
53
import org.eclipse.jdt.internal.debug.core.model.JDIValue;
54
import org.eclipse.jdt.internal.debug.eval.EvaluationResult;
55
import org.eclipse.jdt.internal.debug.eval.ast.engine.EvaluationEngineMessages;
56
import org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext;
57
import org.eclipse.jdt.internal.debug.eval.ast.engine.JavaObjectRuntimeContext;
58
import org.eclipse.jdt.internal.debug.eval.ast.engine.RuntimeContext;
59
import org.eclipse.jdt.internal.debug.eval.ast.engine.TypeRuntimeContext;
60
61
import com.sun.jdi.InvocationException;
62
import com.sun.jdi.ObjectReference;
63
64
/**
65
 * 
66
 */
67
public class RemoteEvaluationEngine implements IAstEvaluationEngine {
68
	
69
	/**
70
	 * Associated Java project
71
	 */
72
	private IJavaProject fProject;
73
	
74
	/**
75
	 * Associated debug target
76
	 */
77
	private IJavaDebugTarget fTarget;
78
	
79
	/**
80
	 * Runnable serialized on a thread to perform submit an evaluation
81
	 */
82
	class EvalRunnable implements Runnable {
83
		
84
		private CompiledExpression fExpression;
85
		
86
		private int fEvaluationDetail;
87
		
88
		private boolean fHitBreakpoints;
89
		
90
		private IRuntimeContext fContext;
91
		
92
		private IEvaluationListener fListener;
93
		
94
		public EvalRunnable(CompiledExpression expression, IRuntimeContext context, IEvaluationListener listener, int evaluationDetail, boolean hitBreakpoints) {
95
			fExpression= expression;
96
			fContext= context;
97
			fListener= listener;
98
			fEvaluationDetail= evaluationDetail;
99
			fHitBreakpoints= hitBreakpoints;
100
		}
101
102
		public void run() {
103
			EvaluationResult result = new EvaluationResult(RemoteEvaluationEngine.this, fExpression.getSnippet(), fContext.getThread());
104
			if (fExpression.hasErrors()) {
105
				String[] errors = fExpression.getErrorMessages();
106
				for (int i = 0, numErrors = errors.length; i < numErrors; i++) {
107
					result.addError(errors[i]);
108
				}
109
				evaluationFinished(result);
110
				return;
111
			}
112
		
113
			class EvaluationRunnable implements IEvaluationRunnable, ITerminate {
114
				
115
				CoreException fException;
116
				boolean fTerminated = false;
117
				
118
				public void run(IJavaThread jt, IProgressMonitor pm) {
119
					EventFilter filter = new EventFilter();
120
					try {
121
						DebugPlugin.getDefault().addDebugEventFilter(filter);
122
						fExpression.execute(fContext);
123
					} catch (CoreException exception) {
124
						fException = exception;
125
						if (fEvaluationDetail == DebugEvent.EVALUATION && exception.getStatus().getException() instanceof InvocationException) {
126
							// print the stack trace for the exception if an *explicit* evaluation 
127
							InvocationException invocationException = (InvocationException)exception.getStatus().getException();
128
							ObjectReference exObject = invocationException.exception();
129
							IJavaObject modelObject = (IJavaObject)JDIValue.createValue((JDIDebugTarget)getDebugTarget(), exObject);
130
							try {
131
								modelObject.sendMessage("printStackTrace", "()V", null, jt, false); //$NON-NLS-1$ //$NON-NLS-2$
132
							} catch (DebugException e) {
133
								// unable to print stack trace
134
							}
135
						}
136
					} finally {
137
						DebugPlugin.getDefault().removeDebugEventFilter(filter);
138
						fTerminated = true;
139
					}
140
				}
141
				public void terminate() {
142
					fTerminated = true;
143
					// TODO: how to support terminate?
144
				}
145
				public boolean canTerminate() {
146
					return !fTerminated;
147
				}
148
				public boolean isTerminated() {
149
					return fTerminated;
150
				}
151
				
152
				public CoreException getException() {
153
					return fException;
154
				}
155
			}
156
157
			EvaluationRunnable er = new EvaluationRunnable();
158
			CoreException exception = null;
159
			try {
160
				fContext.getThread().runEvaluation(er, null, fEvaluationDetail, fHitBreakpoints);
161
			} catch (DebugException e) {
162
				exception = e;
163
			}
164
		
165
            IJavaValue value = fExpression.getResult();
166
167
			if (exception == null) {
168
				exception = er.getException();
169
			}
170
            
171
			result.setTerminated(er.fTerminated);
172
			if (exception != null) {
173
			    if (exception instanceof DebugException) {
174
			        result.setException((DebugException)exception);
175
			    } else {
176
			        result.setException(new DebugException(exception.getStatus()));
177
			    }
178
			} else {   
179
			    if (value != null) {
180
			        result.setValue(value);
181
			    } else {
182
			        result.addError(EvaluationEngineMessages.ASTEvaluationEngine_An_unknown_error_occurred_during_evaluation); 
183
			    }
184
			}
185
            
186
			
187
			evaluationFinished(result);
188
		}
189
		private void evaluationFinished(IEvaluationResult result) {
190
			// only notify if plug-in not yet shutdown - bug# 8693
191
			if(JDIDebugPlugin.getDefault() != null) {
192
				fListener.evaluationComplete(result);
193
			}
194
		}
195
		
196
	}	
197
	
198
	/**
199
	 * Filters variable change events during an evaluation to avoid refreshing the variables
200
	 * view until done.
201
	 */
202
	class EventFilter implements IDebugEventFilter {
203
204
		/* (non-Javadoc)
205
		 * @see org.eclipse.debug.core.IDebugEventFilter#filterDebugEvents(org.eclipse.debug.core.DebugEvent[])
206
		 */
207
		public DebugEvent[] filterDebugEvents(DebugEvent[] events) {
208
			if (events.length == 1) {
209
				DebugEvent event = events[0];
210
				if (event.getSource() instanceof IJavaVariable && event.getKind() == DebugEvent.CHANGE) {
211
					if (((IJavaVariable)event.getSource()).getDebugTarget().equals(getDebugTarget())) {
212
						return null;
213
					}
214
				}
215
			}
216
			return events;
217
		}
218
		
219
	}	
220
	
221
	/**
222
	 * Constructs a new engine on the given target and project.
223
	 * 
224
	 * @param target debug target
225
	 * @param project associated project for compilation purposes
226
	 */
227
	public RemoteEvaluationEngine(IJavaDebugTarget target, IJavaProject project) {
228
		fProject = project;
229
		fTarget = target;
230
	}
231
232
	/* (non-Javadoc)
233
	 * @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)
234
	 */
235
	public void evaluateExpression(ICompiledExpression expression, IJavaStackFrame frame, final IEvaluationListener listener, int evaluationDetail, boolean hitBreakpoints) throws DebugException {
236
		IRuntimeContext debugContext = new RuntimeContext(getJavaProject(), frame);
237
		evaluateExpression(expression, debugContext, listener, evaluationDetail, hitBreakpoints);
238
	}
239
	
240
	/**
241
	 * Evaluates the given expression in the specified thread and the context.
242
	 * 
243
	 * @param expression expression to evaluate
244
	 * @param context context to evaluate in
245
	 * @param listener listener to report results to
246
	 * @param evaluationDetail detail event to fire with evaluation resume/suspend
247
	 * @param hitBreakpoints whether to honor breakpoints during the evaluation
248
	 */
249
	private void evaluateExpression(ICompiledExpression expression, IRuntimeContext context, IEvaluationListener listener, int evaluationDetail, boolean hitBreakpoints) throws DebugException {		
250
		if (expression instanceof CompiledExpression) {
251
			IJavaThread thread = context.getThread();
252
			// don't queue explicit evaluation if the thread is all ready performing an evaluation.
253
			if (thread.isSuspended() && ((JDIThread)thread).isInvokingMethod() || thread.isPerformingEvaluation() && evaluationDetail == DebugEvent.EVALUATION) {
254
				EvaluationResult result= new EvaluationResult(this, expression.getSnippet(), thread);
255
				result.addError(EvaluationEngineMessages.ASTEvaluationEngine_Cannot_perform_nested_evaluations); 
256
				listener.evaluationComplete(result);
257
				return;
258
			}
259
			thread.queueRunnable(new EvalRunnable((CompiledExpression)expression, context, listener, evaluationDetail, hitBreakpoints));
260
		} else {
261
			throw new DebugException(new Status(IStatus.ERROR, JDIDebugPlugin.getUniqueIdentifier(), IStatus.OK, EvaluationEngineMessages.ASTEvaluationEngine_AST_evaluation_engine_cannot_evaluate_expression, null)); 
262
		}
263
	}
264
	
265
	/* (non-Javadoc)
266
	 * @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)
267
	 */
268
	public void evaluateExpression(ICompiledExpression expression,
269
			IJavaObject object, IJavaThread thread,
270
			IEvaluationListener listener, int evaluationDetail,
271
			boolean hitBreakpoints) throws DebugException {
272
		IRuntimeContext debugContext = new JavaObjectRuntimeContext(object, getJavaProject(), thread);
273
		evaluateExpression(expression, debugContext, listener, evaluationDetail, hitBreakpoints);
274
	}
275
276
	/* (non-Javadoc)
277
	 * @see org.eclipse.jdt.debug.eval.IAstEvaluationEngine#getCompiledExpression(java.lang.String, org.eclipse.jdt.debug.core.IJavaStackFrame)
278
	 */
279
	public ICompiledExpression getCompiledExpression(String expression, IJavaStackFrame frame) throws DebugException {
280
		return getCompiledExpression(expression, new RuntimeContext(getJavaProject(), frame));
281
	}
282
	
283
	/**
284
	 * Returns a compiled expression for the given snippet in the given debugger context.
285
	 *  
286
	 * @param snippet expression to compile
287
	 * @param debugContext current execution context to compile in
288
	 * @return compiled expression
289
	 * @throws DebugException on failure
290
	 */
291
	private ICompiledExpression getCompiledExpression(final String snippet, final IRuntimeContext debugContext) throws DebugException {
292
		IJavaProject javaProject = getJavaProject();
293
		final IEvaluationContext evalContext = javaProject.newEvaluationContext();
294
295
		try {
296
			IJavaVariable[] localsVar = debugContext.getLocals();
297
			int numLocalsVar= localsVar.length;
298
			Set names = new HashSet();
299
			// ******
300
			// to hide problems with local variable declare as instance of Local Types
301
			// and to remove locals with duplicate names
302
			IJavaVariable[] locals= new IJavaVariable[numLocalsVar];
303
			int numLocals= 0;
304
			for (int i = 0; i < numLocalsVar; i++) {
305
				if (!isLocalType(localsVar[i].getSignature()) && !names.contains(localsVar[i].getName())) {
306
					locals[numLocals++]= localsVar[i];
307
					names.add(localsVar[i].getName());
308
				}
309
			}
310
			// to solve and remove
311
			// ******
312
			final String[] localTypesNames= new String[numLocals];
313
			final String[] localVariables= new String[numLocals];
314
			final int[] localModifiers = new int[numLocals];
315
			for (int i = 0; i < numLocals; i++) {
316
				localVariables[i] = locals[i].getName();
317
				localTypesNames[i] = Signature.toString(locals[i].getGenericSignature()).replace('/', '.');
318
				localModifiers[i] = Flags.AccDefault;
319
				if (locals[i].isFinal()) {
320
					localModifiers[i] = Flags.AccFinal;
321
				}
322
			}
323
			// Compile in context of declaring type to get proper visibility of locals and members.
324
			// Compiling in context of receiving type potentially provides access to more members,
325
			// but does not allow access to privates members in declaring type
326
			IJavaReferenceType receivingType = debugContext.getReceivingType();
327
			IType iType = JavaDebugUtils.resolveType(receivingType);
328
			while (iType.isAnonymous() && receivingType instanceof IJavaClassType) {
329
				// cannot compile in context of anonymous classes, so compile in context of their superclass
330
				receivingType = ((IJavaClassType)receivingType).getSuperclass();
331
				iType = JavaDebugUtils.resolveType(receivingType);
332
			}
333
			
334
			final IType declaringType = iType;
335
			final CompiledExpression compiledExpression = new CompiledExpression(snippet, localVariables);
336
			Job job = new Job("Debugger Evaluation") {
337
				protected IStatus run(IProgressMonitor monitor) {
338
					try {
339
						evalContext.evaluateCodeSnippet(
340
								snippet,
341
								localTypesNames,
342
								localVariables,
343
								localModifiers,
344
								declaringType,
345
								debugContext.isStatic(),
346
								debugContext.isConstructor(),
347
								compiledExpression,
348
								new NullProgressMonitor());
349
					} catch (JavaModelException e) {
350
						return e.getStatus();
351
					} catch (CoreException e) {
352
						return e.getStatus();
353
					}
354
					return Status.OK_STATUS;
355
				}
356
			};
357
			job.setSystem(true);
358
			job.schedule();
359
			try {
360
				job.join();
361
			} catch (InterruptedException e) {
362
				throw new DebugException(new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(), "Evaluation interrupted", e));
363
			}
364
			
365
			return compiledExpression;
366
		} catch (CoreException e) {
367
			throw new DebugException(e.getStatus());
368
		}
369
	}	
370
	
371
	//TODO: local types might be OK with this new engine
372
	
373
	// ******
374
	// to hide problems with local variable declare as instance of Local Types
375
	private boolean isLocalType(String typeName) {
376
		StringTokenizer strTok= new StringTokenizer(typeName,"$"); //$NON-NLS-1$
377
		strTok.nextToken();
378
		while (strTok.hasMoreTokens()) {
379
			char char0= strTok.nextToken().charAt(0);
380
			if ('0' <= char0 && char0 <= '9') {
381
				return true;
382
			}
383
		}
384
		return false;
385
	}
386
	// ******	
387
388
	/* (non-Javadoc)
389
	 * @see org.eclipse.jdt.debug.eval.IAstEvaluationEngine#getCompiledExpression(java.lang.String, org.eclipse.jdt.debug.core.IJavaObject)
390
	 */
391
	public ICompiledExpression getCompiledExpression(String expression, IJavaObject object) throws DebugException {
392
		return getCompiledExpression(expression, new JavaObjectRuntimeContext(object, getJavaProject(), null));
393
	}
394
395
	/* (non-Javadoc)
396
	 * @see org.eclipse.jdt.debug.eval.IAstEvaluationEngine#getCompiledExpression(java.lang.String, org.eclipse.jdt.debug.core.IJavaReferenceType)
397
	 */
398
	public ICompiledExpression getCompiledExpression(String expression, IJavaReferenceType type) throws DebugException {
399
		return getCompiledExpression(expression, new TypeRuntimeContext(getJavaProject(), null, type));
400
	}
401
402
	/* (non-Javadoc)
403
	 * @see org.eclipse.jdt.debug.eval.IEvaluationEngine#dispose()
404
	 */
405
	public void dispose() {
406
		// TODO Auto-generated method stub
407
408
	}
409
	
410
	/**
411
     * Checks if the stack frame is declared in an interface an aborts
412
     * if so.
413
     * 
414
     * @param frame stack frame
415
     * @throws DebugException if declaring type is an interface
416
     */
417
    private void checkInterface(IJavaStackFrame frame) throws DebugException {
418
        if (frame.getReferenceType() instanceof IJavaInterfaceType) {
419
            IStatus status = new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(), DebugException.REQUEST_FAILED, 
420
                    EvaluationEngineMessages.ASTEvaluationEngine_0, null);
421
            throw new DebugException(status);
422
        }
423
    }	
424
425
	/* (non-Javadoc)
426
	 * @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)
427
	 */
428
	public void evaluate(String snippet, IJavaStackFrame frame, IEvaluationListener listener, int evaluationDetail, boolean hitBreakpoints) throws DebugException {
429
	    checkInterface(frame);
430
	    IRuntimeContext context = new RuntimeContext(getJavaProject(), frame);
431
		ICompiledExpression expression= getCompiledExpression(snippet, context);
432
		evaluateExpression(expression, context, listener, evaluationDetail, hitBreakpoints);
433
	}
434
435
	/* (non-Javadoc)
436
	 * @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)
437
	 */
438
	public void evaluate(String snippet, IJavaObject thisContext,
439
			IJavaThread thread, IEvaluationListener listener,
440
			int evaluationDetail, boolean hitBreakpoints) throws DebugException {
441
		IRuntimeContext context = new JavaObjectRuntimeContext(thisContext, getJavaProject(), thread);
442
		ICompiledExpression expression= getCompiledExpression(snippet, context);
443
		evaluateExpression(expression, context, listener, evaluationDetail, hitBreakpoints);
444
	}
445
446
	/* (non-Javadoc)
447
	 * @see org.eclipse.jdt.debug.eval.IEvaluationEngine#getDebugTarget()
448
	 */
449
	public IJavaDebugTarget getDebugTarget() {
450
		return fTarget;
451
	}
452
453
	/* (non-Javadoc)
454
	 * @see org.eclipse.jdt.debug.eval.IEvaluationEngine#getJavaProject()
455
	 */
456
	public IJavaProject getJavaProject() {
457
		return fProject;
458
	}
459
460
}
(-)eval/org/eclipse/jdt/internal/debug/eval/ast/engine/TypeRuntimeContext.java (+88 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 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
 *******************************************************************************/
11
package org.eclipse.jdt.internal.debug.eval.ast.engine;
12
13
import org.eclipse.core.runtime.CoreException;
14
import org.eclipse.jdt.core.IJavaProject;
15
import org.eclipse.jdt.debug.core.IJavaDebugTarget;
16
import org.eclipse.jdt.debug.core.IJavaObject;
17
import org.eclipse.jdt.debug.core.IJavaReferenceType;
18
import org.eclipse.jdt.debug.core.IJavaThread;
19
import org.eclipse.jdt.debug.core.IJavaVariable;
20
21
/**
22
 * Expression evaluation in the context of a type. Not a static context - used
23
 * for logical structures which are evaluated in a nont-static context.
24
 * 
25
 * @since 3.6
26
 */
27
public class TypeRuntimeContext extends AbstractRuntimeContext {
28
	
29
	/**
30
	 * Type context for evaluation
31
	 */
32
	private IJavaReferenceType fType;
33
	
34
	/**
35
	 * Constructs a new evaluation context for the given type.
36
	 * 
37
	 * @param project associated project
38
	 * @param thread thread for message sends
39
	 * @param type reference type
40
	 */
41
	public TypeRuntimeContext(IJavaProject project, IJavaThread thread, IJavaReferenceType type) {
42
		super(project, thread);
43
		fType = type;
44
	}
45
46
	/* (non-Javadoc)
47
	 * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#getLocals()
48
	 */
49
	public IJavaVariable[] getLocals() throws CoreException {
50
		return new IJavaVariable[0];
51
	}
52
53
	/* (non-Javadoc)
54
	 * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#getReceivingType()
55
	 */
56
	public IJavaReferenceType getReceivingType() throws CoreException {
57
		return fType;
58
	}
59
60
	/* (non-Javadoc)
61
	 * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#getThis()
62
	 */
63
	public IJavaObject getThis() throws CoreException {
64
		return null;
65
	}
66
67
	/* (non-Javadoc)
68
	 * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#getVM()
69
	 */
70
	public IJavaDebugTarget getVM() {
71
		return (IJavaDebugTarget) fType.getDebugTarget();
72
	}
73
74
	/* (non-Javadoc)
75
	 * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#isConstructor()
76
	 */
77
	public boolean isConstructor() throws CoreException {
78
		return false;
79
	}
80
81
	/* (non-Javadoc)
82
	 * @see org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext#isStatic()
83
	 */
84
	public boolean isStatic() throws CoreException {
85
		return false;
86
	}
87
88
}
(-)eval/org/eclipse/jdt/internal/debug/eval/engine/CompiledExpression.java (+348 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 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
 *******************************************************************************/
11
package org.eclipse.jdt.internal.debug.eval.engine;
12
13
import java.util.ArrayList;
14
import java.util.Iterator;
15
import java.util.List;
16
17
import org.eclipse.core.resources.IMarker;
18
import org.eclipse.core.runtime.CoreException;
19
import org.eclipse.core.runtime.IStatus;
20
import org.eclipse.core.runtime.Status;
21
import org.eclipse.debug.core.DebugException;
22
import org.eclipse.debug.core.model.IVariable;
23
import org.eclipse.jdt.core.dom.Message;
24
import org.eclipse.jdt.core.eval.ICodeSnippetRequestor;
25
import org.eclipse.jdt.debug.core.IJavaArray;
26
import org.eclipse.jdt.debug.core.IJavaArrayType;
27
import org.eclipse.jdt.debug.core.IJavaClassObject;
28
import org.eclipse.jdt.debug.core.IJavaClassType;
29
import org.eclipse.jdt.debug.core.IJavaDebugTarget;
30
import org.eclipse.jdt.debug.core.IJavaObject;
31
import org.eclipse.jdt.debug.core.IJavaReferenceType;
32
import org.eclipse.jdt.debug.core.IJavaValue;
33
import org.eclipse.jdt.debug.core.IJavaVariable;
34
import org.eclipse.jdt.debug.core.JDIDebugModel;
35
import org.eclipse.jdt.debug.eval.ICompiledExpression;
36
import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget;
37
import org.eclipse.jdt.internal.debug.eval.EvaluationMessages;
38
import org.eclipse.jdt.internal.debug.eval.ast.engine.IRuntimeContext;
39
40
/**
41
 * 
42
 */
43
public class CompiledExpression implements ICompiledExpression, ICodeSnippetRequestor {
44
	
45
	/**
46
	 * List of <code>String</code>s describing compilation problems.
47
	 */
48
	private List fErrors = new ArrayList();
49
	
50
	/**
51
	 * Expression to evaluate
52
	 */
53
	private String fSnippet;
54
	
55
	List fClassFileBytes = new ArrayList();
56
	
57
	List fClassFileNames = new ArrayList();
58
	
59
	private String fCodeSnippetClass;
60
	
61
	private String[] fLocalNames;
62
	
63
	/**
64
	 * Result of the evaluation or <code>null</code> if none
65
	 */
66
	private IJavaValue fResult;
67
	
68
	/**
69
	 * Constructs a new compiled expression 
70
	 * 
71
	 * @param expression the expression being evaluated
72
	 */
73
	public CompiledExpression(String expression, String[] localVarNames) {
74
		fSnippet = expression;
75
		fLocalNames = localVarNames;
76
	}
77
78
	/* (non-Javadoc)
79
	 * @see org.eclipse.jdt.debug.eval.ICompiledExpression#getErrorMessages()
80
	 */
81
	public String[] getErrorMessages() {
82
		return (String[])fErrors.toArray(new String[fErrors.size()]);
83
	}
84
85
	/* (non-Javadoc)
86
	 * @see org.eclipse.jdt.debug.eval.ICompiledExpression#getErrors()
87
	 */
88
	public Message[] getErrors() {
89
		Message[] messages= new Message[fErrors.size()];
90
		int i= 0;
91
		for (Iterator iter= fErrors.iterator(); iter.hasNext();) {
92
			messages[i++]= new Message((String) iter.next(), -1);
93
		}
94
		return messages;
95
	}
96
97
	/* (non-Javadoc)
98
	 * @see org.eclipse.jdt.debug.eval.ICompiledExpression#getSnippet()
99
	 */
100
	public String getSnippet() {
101
		return fSnippet;
102
	}
103
104
	/* (non-Javadoc)
105
	 * @see org.eclipse.jdt.debug.eval.ICompiledExpression#hasErrors()
106
	 */
107
	public boolean hasErrors() {
108
		return fErrors.size() > 0;
109
	}
110
111
	/* (non-Javadoc)
112
	 * @see org.eclipse.jdt.core.eval.ICodeSnippetRequestor#acceptClassFiles(byte[][], java.lang.String[][], java.lang.String)
113
	 */
114
	public boolean acceptClassFiles(byte[][] classFileBytes, String[][] classFileCompoundNames, String codeSnippetClassName) {
115
		for (int i = 0; i < classFileBytes.length; i++) {
116
			byte[] bs = classFileBytes[i];
117
			String[] ids = classFileCompoundNames[i];
118
			StringBuffer buffer = new StringBuffer();
119
			for (int j = 0; j < ids.length; j++) {
120
				if (j > 0) {
121
					buffer.append('.');
122
				}
123
				buffer.append(ids[j]);
124
			}
125
			fClassFileBytes.add(bs);
126
			fClassFileNames.add(buffer.toString());
127
		}
128
		fCodeSnippetClass = codeSnippetClassName;
129
		return true;
130
	}
131
132
	/* (non-Javadoc)
133
	 * @see org.eclipse.jdt.core.eval.ICodeSnippetRequestor#acceptProblem(org.eclipse.core.resources.IMarker, java.lang.String, int)
134
	 */
135
	public void acceptProblem(IMarker problemMarker, String fragmentSource, int fragmentKind) {
136
		if (problemMarker.getAttribute(IMarker.SEVERITY, -1) != IMarker.SEVERITY_ERROR) {
137
			return;
138
		}
139
		fErrors.add(problemMarker.getAttribute(IMarker.MESSAGE, "")); //$NON-NLS-1$
140
	}
141
142
	byte[][] getClassFiles() {
143
		return (byte[][]) fClassFileBytes.toArray(new byte[fClassFileBytes.size()][]);
144
	}
145
	
146
	String[] getClassFileNames() {
147
		return (String[]) fClassFileNames.toArray(new String[fClassFileNames.size()]);
148
	}
149
	
150
	String getSnippetClass() {
151
		return fCodeSnippetClass;
152
	}
153
	
154
	String[] getLocalVarNames() {
155
		return fLocalNames;
156
	}
157
	
158
	IJavaValue execute(IRuntimeContext debugContext) throws CoreException {
159
		IJavaReferenceType receivingType = debugContext.getReceivingType();
160
		IJavaDebugTarget target = debugContext.getVM();
161
		IJavaObject loader = receivingType.getClassLoaderObject();
162
		//loader is null for those classes loaded by the bootstrap loader
163
		if (loader == null) {
164
			IJavaObject child = ((JDIDebugTarget)target).getSomeClassLoader();
165
			IJavaObject parent = child;
166
			while (parent != null && !parent.isNull()) {
167
				child = parent;
168
				parent = (IJavaObject)child.sendMessage("getParent", "()Ljava/lang/ClassLoader;", null, debugContext.getThread(), false);  //$NON-NLS-1$//$NON-NLS-2$
169
			}
170
			loader = child;
171
		}
172
		if (loader == null) {
173
			throw new CoreException(new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(), "Unable to locate bootstrap class loader"));
174
		}
175
		String[] names = getClassFileNames();
176
		byte[][] bytes = getClassFiles();
177
		for (int i = 0; i < bytes.length; i++) {
178
			byte[] bs = bytes[i];
179
			String name = names[i];
180
			IJavaClassObject loaded = debugContext.classForName(name);
181
			if (loaded == null) {
182
				IJavaValue[] args = new IJavaValue[4];
183
				
184
				args[0] = target.newValue(name);
185
				IJavaClassObject clazz = debugContext.classForName("[B"); //$NON-NLS-1$
186
				IJavaArrayType byteArrayType = (IJavaArrayType) clazz.getInstanceType();
187
				IJavaArray array = byteArrayType.newInstance(bs.length);
188
				IJavaValue[] values = new IJavaValue[bs.length];
189
				for (int j = 0; j < bs.length; j++) {
190
					values[j] = target.newValue(bs[j]);
191
				}
192
				array.setValues(0, bs.length, values, 0);
193
				args[1] = array;
194
				
195
				args[2] = target.newValue(0);
196
				args[3] = target.newValue(bs.length);
197
				IJavaValue result = loader.sendMessage("defineClass", "(Ljava/lang/String;[BII)Ljava/lang/Class;", args, debugContext.getThread(), false); //$NON-NLS-1$ //$NON-NLS-2$
198
				System.out.println(result);
199
				args = new IJavaValue[1];
200
				args[0] = result;
201
				IJavaValue voidRes = loader.sendMessage("resolveClass", "(Ljava/lang/Class;)V", args, debugContext.getThread(), false); //$NON-NLS-1$ //$NON-NLS-2$
202
				System.out.println(voidRes);
203
			}
204
		}
205
		
206
		// invoke the snippet method
207
		IJavaClassObject snippetClazz = debugContext.classForName(getSnippetClass());
208
		IJavaClassType refType = (IJavaClassType) snippetClazz.getInstanceType();
209
		IJavaObject receiver = refType.newInstance("()V", null, debugContext.getThread()); //$NON-NLS-1$
210
		// initialize locals
211
		initializeLocals(debugContext, receiver);
212
		// execute code
213
		receiver.sendMessage(ICodeSnippetRequestor.RUN_METHOD, "()V", null, debugContext.getThread(), false); //$NON-NLS-1$
214
		
215
		// retrieve the result
216
		// now retrieve the description of the result
217
		IVariable[] fields = receiver.getVariables();
218
		IJavaVariable resultValue = null;
219
		IJavaVariable resultType = null;
220
		for (int i = 0; i < fields.length; i++) {
221
			if (fields[i].getName().equals(ICodeSnippetRequestor.RESULT_TYPE_FIELD)) {
222
				resultType = (IJavaVariable)fields[i];
223
			}
224
			if (fields[i].getName().equals(ICodeSnippetRequestor.RESULT_VALUE_FIELD)) {
225
				resultValue = (IJavaVariable)fields[i];
226
			}
227
		}
228
		// TODO: copy locals back
229
		fResult = convertResult((IJavaClassObject)resultType.getValue(), (IJavaValue)resultValue.getValue());
230
		return fResult;
231
	}
232
	
233
	/**
234
	 * Returns the result of the evaluation or <code>null</code> if
235
	 * none (evaluation failed).
236
	 * 
237
	 * @return evaluation result or <code>null</code>
238
	 */
239
	public IJavaValue getResult() {
240
		return fResult;
241
	}
242
	
243
	/**
244
	 * Initializes the value of instance variables in the 
245
	 * 'code snippet object' that are used as place holders
246
	 * for locals and 'this' in the current stack frame.
247
	 * 
248
	 * @param context debug context
249
	 * @exception DebugException if an exception is thrown
250
	 *  accessing the given object
251
	 */
252
	protected void initializeLocals(IRuntimeContext context, IJavaObject snippetObject) throws CoreException {
253
		IJavaVariable[] locals = context.getLocals();
254
		IJavaObject thisObject = context.getThis();
255
		if (locals != null) {
256
			for (int i = 0; i < locals.length; i++) {
257
				IJavaVariable local = locals[i];
258
				IJavaVariable field = snippetObject.getField(ICodeSnippetRequestor.LOCAL_VAR_PREFIX + local.getName(), false);
259
				// internal error if field is not found
260
				if (field == null) {
261
					throw new DebugException(
262
						new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(),
263
						DebugException.REQUEST_FAILED, EvaluationMessages.LocalEvaluationEngine_Evaluation_failed___unable_to_initialize_local_variables__4, null) 
264
					);
265
				}
266
				field.setValue(local.getValue());
267
			}
268
		}
269
		if (thisObject != null) {
270
			IJavaVariable field = snippetObject.getField(ICodeSnippetRequestor.DELEGATE_THIS, false);
271
			// internal error if field is not found
272
			if (field == null) {
273
				throw new DebugException(
274
					new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(),
275
					DebugException.REQUEST_FAILED, EvaluationMessages.LocalEvaluationEngine_Evaluation_failed___unable_to_initialize___this___context__5, null) 
276
				);				
277
			} 
278
			field.setValue(thisObject);
279
		}
280
	}	
281
	
282
	/**
283
	 * Interpretts and returns the result of the running the snippet
284
	 * class file. The type of the result is described by an instance of
285
	 * <code>java.lang.Class</code>. The value is interpretted based
286
	 * on the result type.
287
	 * <p>
288
	 * Objects as well as primitve data types (boolean, int, etc.),
289
	 * have class objects, which are created by the VM. If the class object
290
	 * represents a primitive data type, then the associated value
291
	 * is stored in an instance of its "object" class. For example, when 
292
	 * the result type is the class object for <code>int</code>, the result
293
	 * object is an instance of <code>java.lang.Integer</code>, and the
294
	 * actual <code>int</code> is stored in the </code>intValue()</code>.
295
	 * When the result type is the class object for <code>java.lang.Integer</code>
296
	 * the result object is an instance of <code>java.lang.Integer</code>,
297
	 * to be interpretted as a <ocde>java.lang.Integer</code>.
298
	 * </p>
299
	 * 
300
	 * @param resultType the class of the result
301
	 * @param resultValue the value of ther result, to be interpretted
302
	 *  based on resultType
303
	 * @return the result of running the code snipped class file
304
	 */
305
	protected IJavaValue convertResult(IJavaClassObject resultType, IJavaValue result) throws DebugException {
306
		if (resultType == null) {
307
			// there was an exception or compilation problem - no result
308
			return null;
309
		}
310
311
		// check the type of the result - if a primitive type, convert it
312
		String sig = resultType.getInstanceType().getSignature();
313
		if (sig.equals("V") || sig.equals("Lvoid;")) { //$NON-NLS-2$ //$NON-NLS-1$
314
			// void
315
			return ((IJavaDebugTarget)resultType.getDebugTarget()).voidValue();
316
		}
317
318
		if (result.getJavaType() == null) {
319
			// null result
320
			return result;
321
		}
322
		
323
		if (sig.length() == 1) {
324
			// primitive type - find the instance variable with the
325
			// signature of the result type we are looking for
326
			IVariable[] vars = result.getVariables();
327
			IJavaVariable var = null;
328
			for (int i = 0; i < vars.length; i++) {
329
				IJavaVariable jv = (IJavaVariable)vars[i];
330
				if (!jv.isStatic() && jv.getSignature().equals(sig)) {
331
					var = jv;
332
					break;
333
				}
334
			}
335
			if (var != null) {
336
				return (IJavaValue)var.getValue();
337
			}
338
		} else {
339
			// an object
340
			return result;
341
		}
342
		throw new DebugException(
343
			new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(),
344
			DebugException.REQUEST_FAILED, EvaluationMessages.LocalEvaluationEngine_Evaluation_failed___internal_error_retreiving_result__17, null) 
345
		);
346
	}	
347
	
348
}

Return to bug 289798