blob: f64a81c2d0c72df14b64b134b752fca54ff61819 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.core.tests.eval;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import org.eclipse.jdt.core.tests.runtime.RuntimeConstants;
import org.eclipse.jdt.internal.eval.EvaluationConstants;
import org.eclipse.jdt.internal.eval.EvaluationResult;
import org.eclipse.jdt.internal.eval.InstallException;
import com.sun.jdi.AbsentInformationException;
import com.sun.jdi.ClassNotLoadedException;
import com.sun.jdi.ClassType;
import com.sun.jdi.Field;
import com.sun.jdi.IncompatibleThreadStateException;
import com.sun.jdi.InvalidTypeException;
import com.sun.jdi.InvocationException;
import com.sun.jdi.LocalVariable;
import com.sun.jdi.Location;
import com.sun.jdi.Method;
import com.sun.jdi.ObjectReference;
import com.sun.jdi.ReferenceType;
import com.sun.jdi.StackFrame;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.Value;
import com.sun.jdi.VirtualMachine;
import com.sun.jdi.event.BreakpointEvent;
import com.sun.jdi.event.Event;
import com.sun.jdi.event.EventSet;
import com.sun.jdi.request.BreakpointRequest;
import com.sun.jdi.request.EventRequest;
public class JDIStackFrame implements EvaluationConstants, RuntimeConstants {
VirtualMachine jdiVM;
ThreadReference jdiThread;
String userCode;
String breakpointClassName;
String breakpointMethodName;
int breakpointLine;
public JDIStackFrame(VirtualMachine jdiVM, DebugEvaluationTest test, String userCode) {
this(jdiVM, test, userCode, "_JDIStackFrame_", "foo", Integer.MAX_VALUE);
}
public JDIStackFrame(
VirtualMachine jdiVM,
DebugEvaluationTest test,
String userCode,
String breakpointClassName,
String breakpointMethodName,
int breakpointLine) {
this.jdiVM = jdiVM;
this.userCode = userCode;
this.breakpointClassName = breakpointClassName;
this.breakpointMethodName = breakpointMethodName;
this.breakpointLine = breakpointLine;
test.jdiStackFrame = null;
this.jdiThread = this.getDebuggedThread(test);
test.jdiStackFrame = this;
}
public char[] declaringTypeName() {
if (this.breakpointLine != Integer.MAX_VALUE) { // if not in a code snippet
StackFrame frame = getStackFrame();
return frame.location().declaringType().name().toCharArray();
}
return null;
}
protected ThreadReference getDebuggedThread(DebugEvaluationTest test) {
try {
// desintall previous breakpoints
this.jdiVM.eventRequestManager().deleteAllBreakpoints();
// install a breakpoint at the breakpointLine
List classes = this.jdiVM.classesByName(this.breakpointClassName);
if (classes.size() == 0) {
if (this.breakpointClassName.equals("_JDIStackFrame_")) {
// install special class
String source =
"public class _JDIStackFrame_ {\n" +
" public int foo() {\n" +
" return -1;\n" +
" }\n" +
"}";
test.compileAndDeploy(source, "_JDIStackFrame_");
}
// force load of class
test.evaluateWithExpectedDisplayString(
("return Class.forName(\"" + this.breakpointClassName + "\");").toCharArray(),
("class " + this.breakpointClassName).toCharArray()
);
classes = this.jdiVM.classesByName(this.breakpointClassName);
if (classes.size() == 0) {
// workaround bug in Standard VM
Iterator iterator = this.jdiVM.allClasses().iterator();
while (iterator.hasNext()) {
ReferenceType type = (ReferenceType)iterator.next();
if (type.name().equals(this.breakpointClassName)) {
classes = new ArrayList(1);
classes.add(type);
break;
}
}
if (classes.size() == 0) {
throw new Error("JDI could not retrieve class for " + this.breakpointClassName);
}
}
}
ClassType clazz = (ClassType)classes.get(0);
Method method = (Method)clazz.methodsByName(this.breakpointMethodName).get(0);
Location location;
if (this.breakpointLine < 0 || this.breakpointLine == Integer.MAX_VALUE) {
location = method.location();
} else {
location = (Location)method.locationsOfLine(this.breakpointLine).get(0);
}
BreakpointRequest request = this.jdiVM.eventRequestManager().createBreakpointRequest(location);
request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
request.enable();
// create a new thread that hit the breakpoint
EvaluationTest.Requestor requestor = test.new Requestor();
try {
test.resetEnv();
test.context.evaluate(
("(new Thread() {\n" +
" public void run() {\n" +
userCode + "\n" +
(this.breakpointClassName.equals("_JDIStackFrame_") ? " new _JDIStackFrame_().foo();\n" : "") +
" }\n" +
" public String toString() {\n" +
" return \"my thread\";\n" +
" }\n" +
"}).start();\n").toCharArray(),
test.getEnv(),
test.getOptions(),
requestor,
test.getProblemFactory());
} catch (InstallException e) {
EvaluationTest.assertTrue("Target exception " + e.getMessage(), false);
}
EvaluationResult[] results = requestor.results;
for (int i = 0; i < requestor.resultIndex + 1; i++){
if (results[i].hasErrors()) {
EvaluationTest.assertTrue("Compilation error in user code", false);
}
}
// Wait for the breakpoint event
Event event = null;
do {
EventSet set = this.jdiVM.eventQueue().remove();
Iterator iterator = set.eventIterator();
while (iterator.hasNext()) {
event = (Event)iterator.next();
if (event instanceof BreakpointEvent)
break;
}
} while (!(event instanceof BreakpointEvent));
// Return the suspended thread
return ((BreakpointEvent)event).thread();
} catch (AbsentInformationException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
protected StackFrame getStackFrame() {
try {
if (this.breakpointLine == Integer.MAX_VALUE) {
return this.jdiThread.frame(1);
} else {
return this.jdiThread.frame(0);
}
} catch (IncompatibleThreadStateException e) {
e.printStackTrace();
return null;
}
}
public boolean isConstructorCall() {
if (this.breakpointLine != Integer.MAX_VALUE) { // if not in a code snippet
StackFrame frame = getStackFrame();
return frame.location().method().isConstructor();
}
return false;
}
public boolean isStatic() {
if (this.breakpointLine != Integer.MAX_VALUE) { // if not in a code snippet
StackFrame frame = getStackFrame();
return frame.location().method().isStatic();
}
return false;
}
public int[] localVariableModifiers() {
try {
StackFrame frame = getStackFrame();
List variables = frame.visibleVariables();
int[] modifiers = new int[variables.size()];
/* Iterator iterator = variables.iterator();
int i = 0;
while (iterator.hasNext()) {
LocalVariable var = (LocalVariable)iterator.next();
// TBD modifiers[i++] = var. ??? ;
}
*/ return modifiers;
} catch (AbsentInformationException e) {
return null;
}
}
public char[][] localVariableNames() {
try {
StackFrame frame = getStackFrame();
Iterator variables = frame.visibleVariables().iterator();
Vector names = new Vector();
while (variables.hasNext()) {
LocalVariable var = (LocalVariable)variables.next();
names.addElement(var.name().toCharArray());
}
char[][] result = new char[names.size()][];
names.copyInto(result);
return result;
} catch (AbsentInformationException e) {
return null;
}
}
public char[][] localVariableTypeNames() {
try {
StackFrame frame = getStackFrame();
Iterator variables = frame.visibleVariables().iterator();
Vector names = new Vector();
while (variables.hasNext()) {
LocalVariable var = (LocalVariable)variables.next();
names.addElement(var.typeName().toCharArray());
}
char[][] result = new char[names.size()][];
names.copyInto(result);
return result;
} catch (AbsentInformationException e) {
return null;
}
}
public boolean run(String codeSnippetClassName) {
ClassType codeSnippetClass;
ObjectReference codeSnippet;
Method method;
List arguments;
ObjectReference codeSnippetRunner;
try {
// Get the code snippet class
List classes = jdiVM.classesByName(codeSnippetClassName);
while (classes.size() == 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
classes = jdiVM.classesByName(codeSnippetClassName);
if (classes.size() == 0) {
// workaround bug in Standard VM
Iterator iterator = this.jdiVM.allClasses().iterator();
while (iterator.hasNext()) {
ReferenceType type = (ReferenceType)iterator.next();
if (type.name().equals(codeSnippetClassName)) {
classes = new ArrayList(1);
classes.add(type);
break;
}
}
}
}
codeSnippetClass = (ClassType)classes.get(0);
// Create a new code snippet
Method constructor = (Method)codeSnippetClass.methodsByName("<init>").get(0);
codeSnippet = codeSnippetClass.newInstance(jdiThread, constructor, new ArrayList(), ClassType.INVOKE_SINGLE_THREADED);
// Install local variables and "this" into generated fields
StackFrame stackFrame = getStackFrame();
try {
Iterator variables = stackFrame.visibleVariables().iterator();
while (variables.hasNext()) {
LocalVariable jdiVariable = (LocalVariable)variables.next();
Value value = stackFrame.getValue(jdiVariable);
Field field = codeSnippetClass.fieldByName(new String(LOCAL_VAR_PREFIX) + jdiVariable.name());
codeSnippet.setValue(field, value);
}
} catch (AbsentInformationException e) {
// No variables
}
Field delegateThis = codeSnippetClass.fieldByName(new String(DELEGATE_THIS));
ObjectReference thisObject;
if (delegateThis != null && ((thisObject = stackFrame.thisObject()) != null)) {
codeSnippet.setValue(delegateThis, thisObject);
}
// Get the code snippet runner
ClassType codeSnippetRunnerClass = (ClassType)jdiVM.classesByName(CODE_SNIPPET_RUNNER_CLASS_NAME).get(0);
Field theRunner = codeSnippetRunnerClass.fieldByName(THE_RUNNER_FIELD);
codeSnippetRunner = (ObjectReference)codeSnippetRunnerClass.getValue(theRunner);
// Get the method 'runCodeSnippet' and its arguments
method = (Method)codeSnippetRunnerClass.methodsByName(RUN_CODE_SNIPPET_METHOD).get(0);
arguments = new ArrayList();
arguments.add(codeSnippet);
} catch (ClassNotLoadedException e) {
e.printStackTrace();
return false;
} catch (IncompatibleThreadStateException e) {
e.printStackTrace();
return false;
} catch (InvalidTypeException e) {
e.printStackTrace();
return false;
} catch (InvocationException e) {
e.printStackTrace();
return false;
}
try {
// Invoke runCodeSnippet(CodeSnippet)
codeSnippetRunner.invokeMethod(jdiThread, method, arguments, ClassType.INVOKE_SINGLE_THREADED);
// Retrieve values of local variables and put them back in the stack frame
StackFrame stackFrame = getStackFrame();
try {
Iterator variables = stackFrame.visibleVariables().iterator();
while (variables.hasNext()) {
LocalVariable jdiVariable = (LocalVariable)variables.next();
Field field = codeSnippetClass.fieldByName(new String(LOCAL_VAR_PREFIX) + jdiVariable.name());
Value value = codeSnippet.getValue(field);
stackFrame.setValue(jdiVariable, value);
}
} catch (AbsentInformationException e) {
// No variables
}
} catch (ClassNotLoadedException e) {
e.printStackTrace();
} catch (IncompatibleThreadStateException e) {
e.printStackTrace();
} catch (InvalidTypeException e) {
e.printStackTrace();
} catch (InvocationException e) {
e.printStackTrace();
}
return true;
}
}