summaryrefslogtreecommitdiff
path: root/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java')
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java210
1 files changed, 179 insertions, 31 deletions
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java
index 042216c40f05..467cf985f04c 100644
--- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java
@@ -15,28 +15,57 @@
*/
package com.intellij.debugger.ui.impl.watch;
+import com.intellij.debugger.DebuggerInvocationUtil;
+import com.intellij.debugger.EvaluatingComputable;
+import com.intellij.debugger.engine.ContextUtil;
import com.intellij.debugger.engine.DebugProcess;
-import com.intellij.debugger.engine.evaluation.EvaluateException;
-import com.intellij.debugger.engine.evaluation.EvaluationContext;
-import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.engine.evaluation.*;
import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
import com.intellij.debugger.engine.evaluation.expression.Modifier;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Computable;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiCodeFragment;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiJavaFile;
+import com.intellij.refactoring.extractMethodObject.ExtractLightMethodObjectHandler;
import com.sun.jdi.*;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.org.objectweb.asm.ClassReader;
+import org.jetbrains.org.objectweb.asm.ClassVisitor;
+import org.jetbrains.org.objectweb.asm.ClassWriter;
+import org.jetbrains.org.objectweb.asm.Opcodes;
import javax.tools.*;
import java.io.ByteArrayOutputStream;
import java.net.URI;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
/**
* @author egor
*/
-class CompilingEvaluator implements ExpressionEvaluator {
+public class CompilingEvaluator implements ExpressionEvaluator {
private final TextWithImports myText;
-
- public CompilingEvaluator(TextWithImports text) {
+ private final PsiCodeFragment myCodeFragment;
+ private final PsiElement myPsiContext;
+ @NotNull private final ExtractLightMethodObjectHandler.ExtractedData myData;
+ private final EvaluationDescriptor myDescriptor;
+
+ public CompilingEvaluator(TextWithImports text,
+ PsiCodeFragment codeFragment,
+ PsiElement context,
+ @NotNull ExtractLightMethodObjectHandler.ExtractedData data,
+ EvaluationDescriptor descriptor) {
myText = text;
+ myCodeFragment = codeFragment;
+ myPsiContext = context;
+ myData = data;
+ myDescriptor = descriptor;
}
@Override
@@ -49,20 +78,41 @@ class CompilingEvaluator implements ExpressionEvaluator {
return null;
}
+ private TextWithImports getCallCode() {
+ return new TextWithImportsImpl(CodeFragmentKind.CODE_BLOCK, myData.getGeneratedCallText());
+ }
+
@Override
- public Value evaluate(EvaluationContext context) throws EvaluateException {
+ public Value evaluate(final EvaluationContext evaluationContext) throws EvaluateException {
try {
- DebugProcess process = context.getDebugProcess();
- ThreadReference threadReference = context.getSuspendContext().getThread().getThreadReference();
+ DebugProcess process = evaluationContext.getDebugProcess();
+ ThreadReference threadReference = evaluationContext.getSuspendContext().getThread().getThreadReference();
- ClassLoaderReference classLoader = getClassLoader(context);
+ ClassLoaderReference classLoader = getClassLoader(evaluationContext);
Collection<OutputFileObject> classes = compile();
- ClassType mainClass = defineClasses(classes, context, process, threadReference, classLoader);
-
- Method foo = mainClass.methodsByName(GEN_METHOD_NAME).get(0);
- return mainClass.invokeMethod(threadReference, foo, Collections.<Value>emptyList() ,ClassType.INVOKE_SINGLE_THREADED);
+ ClassType mainClass = defineClasses(classes, evaluationContext, process, threadReference, classLoader);
+
+ //Method foo = mainClass.methodsByName(GEN_METHOD_NAME).get(0);
+ //return mainClass.invokeMethod(threadReference, foo, Collections.<Value>emptyList() ,ClassType.INVOKE_SINGLE_THREADED);
+
+ // invoke base evaluator on call code
+ final Project project = myPsiContext.getProject();
+ ExpressionEvaluator evaluator =
+ DebuggerInvocationUtil.commitAndRunReadAction(project, new EvaluatingComputable<ExpressionEvaluator>() {
+ @Override
+ public ExpressionEvaluator compute() throws EvaluateException {
+ final TextWithImports callCode = getCallCode();
+ PsiElement copyContext = myData.getAnchor();
+ final CodeFragmentFactory factory = DebuggerUtilsEx.findAppropriateCodeFragmentFactory(callCode, copyContext);
+ return factory.getEvaluatorBuilder().
+ build(factory.createCodeFragment(callCode, copyContext, project),
+ ContextUtil.getSourcePosition(evaluationContext));
+ }
+ });
+ ((EvaluationContextImpl)evaluationContext).setClassLoader(classLoader);
+ return evaluator.evaluate(evaluationContext);
}
catch (Exception e) {
throw new EvaluateException(e.getMessage());
@@ -74,13 +124,13 @@ class CompilingEvaluator implements ExpressionEvaluator {
// TODO: cache
DebugProcess process = context.getDebugProcess();
ClassType loaderClass = (ClassType)process.findClass(context, "java.net.URLClassLoader", context.getClassLoader());
- Method ctorMethod = loaderClass.concreteMethodByName("<init>", "([Ljava/net/URL;)V");
+ Method ctorMethod = loaderClass.concreteMethodByName("<init>", "([Ljava/net/URL;Ljava/lang/ClassLoader;)V");
ThreadReference threadReference = context.getSuspendContext().getThread().getThreadReference();
return (ClassLoaderReference)loaderClass.newInstance(threadReference, ctorMethod,
- Arrays.asList(createURLArray(context)), ClassType.INVOKE_SINGLE_THREADED);
+ Arrays.asList(createURLArray(context), context.getClassLoader()), ClassType.INVOKE_SINGLE_THREADED);
}
- private static ClassType defineClasses(Collection<OutputFileObject> classes,
+ private ClassType defineClasses(Collection<OutputFileObject> classes,
EvaluationContext context,
DebugProcess process,
ThreadReference threadReference,
@@ -89,16 +139,34 @@ class CompilingEvaluator implements ExpressionEvaluator {
VirtualMachineProxyImpl proxy = (VirtualMachineProxyImpl)process.getVirtualMachineProxy();
for (OutputFileObject cls : classes) {
- Method defineMethod = ((ClassType)classLoader.referenceType()).concreteMethodByName("defineClass", "(Ljava/lang/String;[BII)Ljava/lang/Class;");
- byte[] bytes = cls.toByteArray();
- ArrayList<Value> args = new ArrayList<Value>();
- args.add(proxy.mirrorOf(cls.myOrigName));
- args.add(mirrorOf(bytes, context, process));
- args.add(proxy.mirrorOf(0));
- args.add(proxy.mirrorOf(bytes.length));
- classLoader.invokeMethod(threadReference, defineMethod, args, ClassType.INVOKE_SINGLE_THREADED);
+ if (cls.getName().contains(getGenClassName())) {
+ Method defineMethod =
+ ((ClassType)classLoader.referenceType()).concreteMethodByName("defineClass", "(Ljava/lang/String;[BII)Ljava/lang/Class;");
+ byte[] bytes = changeSuperToMagicAccessor(cls.toByteArray());
+ ArrayList<Value> args = new ArrayList<Value>();
+ args.add(proxy.mirrorOf(cls.myOrigName));
+ args.add(mirrorOf(bytes, context, process));
+ args.add(proxy.mirrorOf(0));
+ args.add(proxy.mirrorOf(bytes.length));
+ classLoader.invokeMethod(threadReference, defineMethod, args, ClassType.INVOKE_SINGLE_THREADED);
+ }
}
- return (ClassType)process.findClass(context, GEN_CLASS_FULL_NAME, classLoader);
+ return (ClassType)process.findClass(context, getGenClassFullName(), classLoader);
+ }
+
+ private static byte[] changeSuperToMagicAccessor(byte[] bytes) {
+ ClassWriter classWriter = new ClassWriter(0);
+ ClassVisitor classVisitor = new ClassVisitor(Opcodes.ASM5, classWriter) {
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ if ("java/lang/Object".equals(superName)) {
+ superName = "sun/reflect/MagicAccessorImpl";
+ }
+ super.visit(version, access, name, signature, superName, interfaces);
+ }
+ };
+ new ClassReader(bytes).accept(classVisitor, 0);
+ return classWriter.toByteArray();
}
private static ArrayReference mirrorOf(byte[] bytes, EvaluationContext context, DebugProcess process)
@@ -112,10 +180,90 @@ class CompilingEvaluator implements ExpressionEvaluator {
return reference;
}
- private static final String GEN_CLASS_NAME = "Evaluator";
+ public static String getGeneratedClassName() {
+ return GEN_CLASS_NAME;
+ }
+
+ private static final String GEN_CLASS_NAME = "GeneratedEvaluationClass";
private static final String GEN_CLASS_PACKAGE = "dummy";
private static final String GEN_CLASS_FULL_NAME = GEN_CLASS_PACKAGE + '.' + GEN_CLASS_NAME;
- private static final String GEN_METHOD_NAME = "eval";
+ private static final String GEN_METHOD_NAME = "invoke";
+
+ private String getClassCode() {
+ if (myData != null) {
+ return ApplicationManager.getApplication().runReadAction(new Computable<String>() {
+ @Override
+ public String compute() {
+ //String text = myData.getGeneratedInnerClass().getText();
+ ////TODO: remove
+ //String prefix = "public static";
+ //if (text.startsWith(prefix)) {
+ // text = "public" + text.substring(prefix.length());
+ //}
+ //PsiElement[] children = ((PsiJavaFile)myPsiContext.getContainingFile()).getImportList().getChildren();
+ //StringBuilder imports = new StringBuilder();
+ //for (PsiElement child : children) {
+ // if (child instanceof PsiImportStatement) {
+ // String name = ((PsiImportStatement)child).getImportReference().getQualifiedName();
+ // imports.append("import ").append(name).append(";");
+ // }
+ //}
+ //text = text.replace("class " + GEN_CLASS_NAME, "class " + getGenClassName());
+ //text = text.replace(GEN_CLASS_NAME + "(", getGenClassName() + "(");
+ //text = text.replace(((PsiClass)myData.getGeneratedInnerClass().getParent()).getName() + "." + GEN_CLASS_NAME, getGenClassName());
+ //return "package " + getGenPackageName() + "; " + imports.toString() + text;
+ return myData.getGeneratedInnerClass().getContainingFile().getText();
+ }
+ });
+ }
+ return null;
+ }
+
+ private String getGenPackageName() {
+ return ApplicationManager.getApplication().runReadAction(new Computable<String>() {
+ @Override
+ public String compute() {
+ return ((PsiJavaFile)myData.getGeneratedInnerClass().getContainingFile()).getPackageName();
+ }
+ });
+ }
+
+ private String getMainClassName() {
+ return ApplicationManager.getApplication().runReadAction(new Computable<String>() {
+ @Override
+ public String compute() {
+ return ((PsiClass)myData.getGeneratedInnerClass().getParent()).getName();
+ }
+ });
+ }
+
+ private String getGenClassName() {
+ return getMainClassName() + '$' + GEN_CLASS_NAME;
+ }
+
+ private String getGenClassFullName() {
+ String packageName = getGenPackageName();
+ if (packageName.isEmpty()) {
+ return getGenClassName();
+ }
+ return packageName + '.' + getGenClassName();
+ }
+
+ //private String createClassCode() {
+ // return ApplicationManager.getApplication().runReadAction(new Computable<String>() {
+ // @Override
+ // public String compute() {
+ // try {
+ // myExtractedData =
+ // ExtractLightMethodObjectHandler.extractLightMethodObject(myCodeFragment.getProject(), myFile , myCodeFragment, "test");
+ // }
+ // catch (PrepareFailedException e) {
+ // e.printStackTrace();
+ // }
+ // return null;
+ // }
+ // });
+ //}
private static String createClassCode(TextWithImports body) {
StringBuilder text = new StringBuilder();
@@ -155,9 +303,9 @@ class CompilingEvaluator implements ExpressionEvaluator {
MemoryFileManager manager = new MemoryFileManager(compiler);
DiagnosticCollector<JavaFileObject> diagnostic = new DiagnosticCollector<JavaFileObject>();
if (!compiler.getTask(null, manager, diagnostic, null, null, Arrays
- .asList(new SourceFileObject(GEN_CLASS_NAME, JavaFileObject.Kind.SOURCE, createClassCode(myText)))).call()) {
+ .asList(new SourceFileObject(getMainClassName(), JavaFileObject.Kind.SOURCE, getClassCode()))).call()) {
// TODO: show only errors
- throw new EvaluateException(diagnostic.getDiagnostics().get(0).getMessage(Locale.getDefault()));
+ throw new EvaluateException(diagnostic.getDiagnostics().get(0).toString());
}
return manager.classes;
}