Replace CompilingEvaluatorUtils methods with ClassLoadingUtils
This commit is contained in:
committed by
Nikolay Krasko
parent
3b60d56c0b
commit
2aa1b19ec9
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user