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;
|
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.annotations.NotNull;
|
||||||
import org.jetbrains.org.objectweb.asm.ClassReader;
|
import org.jetbrains.org.objectweb.asm.ClassReader;
|
||||||
import org.jetbrains.org.objectweb.asm.ClassVisitor;
|
import org.jetbrains.org.objectweb.asm.ClassVisitor;
|
||||||
import org.jetbrains.org.objectweb.asm.ClassWriter;
|
import org.jetbrains.org.objectweb.asm.ClassWriter;
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
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 class CompilingEvaluatorUtils {
|
||||||
public static ClassLoaderReference getClassLoader(EvaluationContext context, DebugProcess process)
|
// Copied from com.intellij.debugger.ui.impl.watch.CompilingEvaluator.changeSuperToMagicAccessor
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] changeSuperToMagicAccessor(byte[] bytes) {
|
public static byte[] changeSuperToMagicAccessor(byte[] bytes) {
|
||||||
ClassWriter classWriter = new ClassWriter(0);
|
ClassWriter classWriter = new ClassWriter(0);
|
||||||
ClassVisitor classVisitor = new ClassVisitor(Opcodes.ASM5, classWriter) {
|
ClassVisitor classVisitor = new ClassVisitor(Opcodes.API_VERSION, classWriter) {
|
||||||
@Override
|
@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)) {
|
if ("java/lang/Object".equals(superName)) {
|
||||||
superName = "sun/reflect/MagicAccessorImpl";
|
superName = "sun/reflect/MagicAccessorImpl";
|
||||||
}
|
}
|
||||||
@@ -61,54 +37,4 @@ public class CompilingEvaluatorUtils {
|
|||||||
new ClassReader(bytes).accept(classVisitor, 0);
|
new ClassReader(bytes).accept(classVisitor, 0);
|
||||||
return classWriter.toByteArray();
|
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.EvaluateException
|
||||||
import com.intellij.debugger.engine.evaluation.EvaluationContext
|
import com.intellij.debugger.engine.evaluation.EvaluationContext
|
||||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
|
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
|
||||||
|
import com.intellij.debugger.impl.ClassLoadingUtils
|
||||||
import com.intellij.openapi.projectRoots.JdkVersionUtil
|
import com.intellij.openapi.projectRoots.JdkVersionUtil
|
||||||
import com.intellij.openapi.util.SystemInfo
|
import com.intellij.openapi.util.SystemInfo
|
||||||
import com.sun.jdi.ClassLoaderReference
|
import com.sun.jdi.ClassLoaderReference
|
||||||
@@ -30,7 +31,7 @@ fun loadClasses(evaluationContext: EvaluationContextImpl, classes: Collection<Pa
|
|||||||
|
|
||||||
val classLoader: ClassLoaderReference
|
val classLoader: ClassLoaderReference
|
||||||
try {
|
try {
|
||||||
classLoader = CompilingEvaluatorUtils.getClassLoader(evaluationContext, process)
|
classLoader = ClassLoadingUtils.getClassLoader(evaluationContext, process)
|
||||||
}
|
}
|
||||||
catch (e: Exception) {
|
catch (e: Exception) {
|
||||||
throw EvaluateException("Error creating evaluation class loader: " + e, e)
|
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 }
|
val lambdaSuperclasses = LAMBDA_SUPERCLASSES.map { it.name to it.bytes }
|
||||||
for ((className, bytes) in lambdaSuperclasses + classes) {
|
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