Replace CompilingEvaluatorUtils methods with ClassLoadingUtils

This commit is contained in:
Nikolay Krasko
2017-01-27 22:03:23 +03:00
committed by Nikolay Krasko
parent 3b60d56c0b
commit 2aa1b19ec9
2 changed files with 7 additions and 79 deletions
@@ -15,43 +15,19 @@
*/
package org.jetbrains.kotlin.idea.debugger.evaluate;
import com.intellij.debugger.engine.DebugProcess;
import com.intellij.debugger.engine.SuspendContextImpl;
import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.evaluation.EvaluationContext;
import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
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 java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
// Copied from com.intellij.debugger.ui.impl.watch.CompilingEvaluator
public class CompilingEvaluatorUtils {
public static ClassLoaderReference getClassLoader(EvaluationContext context, DebugProcess process)
throws EvaluateException, InvocationException, InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException {
// TODO: cache
ClassType loaderClass = (ClassType)process.findClass(context, "java.net.URLClassLoader", context.getClassLoader());
Method ctorMethod = loaderClass.concreteMethodByName("<init>", "([Ljava/net/URL;Ljava/lang/ClassLoader;)V");
ClassLoaderReference reference = (ClassLoaderReference)process.newInstance(context, loaderClass, ctorMethod, Arrays.asList(createURLArray(context), context.getClassLoader()));
keep(reference, context);
return reference;
}
public static void keep(ObjectReference reference, EvaluationContext context) {
((SuspendContextImpl)context.getSuspendContext()).keep(reference);
}
// Copied from com.intellij.debugger.ui.impl.watch.CompilingEvaluator.changeSuperToMagicAccessor
public static byte[] changeSuperToMagicAccessor(byte[] bytes) {
ClassWriter classWriter = new ClassWriter(0);
ClassVisitor classVisitor = new ClassVisitor(Opcodes.ASM5, classWriter) {
ClassVisitor classVisitor = new ClassVisitor(Opcodes.API_VERSION, classWriter) {
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
public void visit(int version, int access, @NotNull String name, String signature, String superName, String[] interfaces) {
if ("java/lang/Object".equals(superName)) {
superName = "sun/reflect/MagicAccessorImpl";
}
@@ -61,54 +37,4 @@ public class CompilingEvaluatorUtils {
new ClassReader(bytes).accept(classVisitor, 0);
return classWriter.toByteArray();
}
public static ArrayReference mirrorOf(byte[] bytes, EvaluationContext context, DebugProcess process)
throws EvaluateException, InvalidTypeException, ClassNotLoadedException {
ArrayType arrayClass = (ArrayType)process.findClass(context, "byte[]", context.getClassLoader());
ArrayReference reference = process.newInstance(arrayClass, bytes.length);
keep(reference, context);
for (int i = 0; i < bytes.length; i++) {
reference.setValue(i, ((VirtualMachineProxyImpl)process.getVirtualMachineProxy()).mirrorOf(bytes[i]));
}
return reference;
}
public static void defineClass(
@NotNull String className,
byte[] bytecodes,
@NotNull EvaluationContext context,
@NotNull DebugProcess process,
@NotNull ClassLoaderReference classLoader
) throws ClassNotLoadedException, EvaluateException, InvalidTypeException {
VirtualMachineProxyImpl proxy = (VirtualMachineProxyImpl)process.getVirtualMachineProxy();
Method defineMethod =
((ClassType)classLoader.referenceType()).concreteMethodByName("defineClass", "(Ljava/lang/String;[BII)Ljava/lang/Class;");
byte[] bytes = changeSuperToMagicAccessor(bytecodes);
ArrayList<Value> args = new ArrayList<Value>();
StringReference name = proxy.mirrorOf(className);
keep(name, context);
args.add(name);
args.add(mirrorOf(bytes, context, process));
args.add(proxy.mirrorOf(0));
args.add(proxy.mirrorOf(bytes.length));
process.invokeMethod(context, classLoader, defineMethod, args);
}
private static ArrayReference createURLArray(EvaluationContext context)
throws EvaluateException, InvocationException, InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException {
DebugProcess process = context.getDebugProcess();
ArrayType arrayType = (ArrayType)process.findClass(context, "java.net.URL[]", context.getClassLoader());
ArrayReference arrayRef = arrayType.newInstance(1);
keep(arrayRef, context);
ClassType classType = (ClassType)process.findClass(context, "java.net.URL", context.getClassLoader());
VirtualMachineProxyImpl proxy = (VirtualMachineProxyImpl)process.getVirtualMachineProxy();
StringReference url = proxy.mirrorOf("file:a");
keep(url, context);
ObjectReference reference = process.newInstance(context, classType, classType.concreteMethodByName("<init>", "(Ljava/lang/String;)V"),
Collections.singletonList(url));
keep(reference, context);
arrayRef.setValues(Collections.singletonList(reference));
return arrayRef;
}
}
@@ -20,6 +20,7 @@ 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.EvaluationContextImpl
import com.intellij.debugger.impl.ClassLoadingUtils
import com.intellij.openapi.projectRoots.JdkVersionUtil
import com.intellij.openapi.util.SystemInfo
import com.sun.jdi.ClassLoaderReference
@@ -30,7 +31,7 @@ fun loadClasses(evaluationContext: EvaluationContextImpl, classes: Collection<Pa
val classLoader: ClassLoaderReference
try {
classLoader = CompilingEvaluatorUtils.getClassLoader(evaluationContext, process)
classLoader = ClassLoadingUtils.getClassLoader(evaluationContext, process)
}
catch (e: Exception) {
throw EvaluateException("Error creating evaluation class loader: " + e, e)
@@ -61,7 +62,8 @@ private fun defineClasses(
) {
val lambdaSuperclasses = LAMBDA_SUPERCLASSES.map { it.name to it.bytes }
for ((className, bytes) in lambdaSuperclasses + classes) {
CompilingEvaluatorUtils.defineClass(className, bytes, context, process, classLoader)
val patchedBytes = CompilingEvaluatorUtils.changeSuperToMagicAccessor(bytes)
ClassLoadingUtils.defineClass(className, patchedBytes, context, process, classLoader)
}
}