mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-364527 Helper classes are loaded into a separate classloader for every call
GitOrigin-RevId: 7316e26e048ccb91ffc8dd80929893ab2ac7735e
This commit is contained in:
committed by
intellij-monorepo-bot
parent
74c235bb7f
commit
5378001c87
@@ -9,6 +9,8 @@ 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.jdi.VirtualMachineProxyImpl;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.jdi.MethodImpl;
|
||||
import com.sun.jdi.*;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -43,7 +45,7 @@ public final class ClassLoadingUtils {
|
||||
byte[] bytes,
|
||||
EvaluationContextImpl context,
|
||||
DebugProcess process,
|
||||
ClassLoaderReference classLoader) throws EvaluateException {
|
||||
ObjectReference classLoader) throws EvaluateException {
|
||||
try {
|
||||
VirtualMachineProxyImpl proxy = context.getVirtualMachineProxy();
|
||||
Method defineMethod =
|
||||
@@ -83,22 +85,45 @@ public final class ClassLoadingUtils {
|
||||
String name = cls.getName();
|
||||
evaluationContext = evaluationContext.withAutoLoadClasses(true);
|
||||
DebugProcess process = evaluationContext.getDebugProcess();
|
||||
ClassLoaderReference currentClassLoader = evaluationContext.getClassLoader();
|
||||
try {
|
||||
return (ClassType)process.findClass(evaluationContext, name, evaluationContext.getClassLoader());
|
||||
return (ClassType)process.findClass(evaluationContext, name, currentClassLoader);
|
||||
}
|
||||
catch (EvaluateException e) {
|
||||
Throwable cause = e.getCause();
|
||||
if (cause instanceof InvocationException) {
|
||||
if ("java.lang.ClassNotFoundException".equals(((InvocationException)cause).exception().type().name())) {
|
||||
// need to define
|
||||
ClassLoaderReference classLoader = getClassLoader(evaluationContext, process);
|
||||
if (!defineClass(name, cls, evaluationContext, process, classLoader)) return null;
|
||||
for (String fqn : additionalClassesToLoad) {
|
||||
ObjectReference classLoader;
|
||||
boolean newClassLoader = Registry.is("debugger.evaluate.load.helper.in.separate.classloader") || currentClassLoader == null;
|
||||
if (newClassLoader) {
|
||||
classLoader = getClassLoader(evaluationContext, process);
|
||||
}
|
||||
else { // find the top classloader
|
||||
classLoader = currentClassLoader;
|
||||
while (true) {
|
||||
Method parentMethod = DebuggerUtils.findMethod(classLoader.referenceType(), "getParent", "()Ljava/lang/ClassLoader;");
|
||||
Value parent = evaluationContext.getDebugProcess().invokeInstanceMethod(
|
||||
evaluationContext, classLoader, parentMethod, Collections.emptyList(), 0, true);
|
||||
if (!(parent instanceof ObjectReference objectReference)) {
|
||||
break;
|
||||
}
|
||||
classLoader = objectReference;
|
||||
}
|
||||
}
|
||||
|
||||
for (String fqn : ContainerUtil.prepend(Arrays.asList(additionalClassesToLoad), name)) {
|
||||
if (!defineClass(fqn, cls, evaluationContext, process, classLoader)) return null;
|
||||
}
|
||||
|
||||
evaluationContext.setClassLoader(classLoader);
|
||||
return (ClassType)process.findClass(evaluationContext, name, classLoader);
|
||||
if (newClassLoader) {
|
||||
ClassLoaderReference newClassLoaderReference = (ClassLoaderReference)classLoader;
|
||||
evaluationContext.setClassLoader(newClassLoaderReference);
|
||||
return (ClassType)process.findClass(evaluationContext, name, newClassLoaderReference);
|
||||
}
|
||||
else {
|
||||
return (ClassType)process.findClass(evaluationContext, name, currentClassLoader);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
@@ -109,7 +134,7 @@ public final class ClassLoadingUtils {
|
||||
Class<?> cls,
|
||||
EvaluationContextImpl evaluationContext,
|
||||
DebugProcess process,
|
||||
ClassLoaderReference classLoader) throws EvaluateException {
|
||||
ObjectReference classLoader) throws EvaluateException {
|
||||
try (InputStream stream = cls.getResourceAsStream('/' + name.replace('.', '/') + ".class")) {
|
||||
if (stream == null) return false;
|
||||
defineClass(name, stream.readAllBytes(), evaluationContext, process, classLoader);
|
||||
|
||||
@@ -138,13 +138,15 @@ public class RemoteConnectionBuilder {
|
||||
}
|
||||
|
||||
private static void addRtJar(@NotNull PathsList pathsList) {
|
||||
if (PluginManagerCore.isRunningFromSources()) {
|
||||
String path = DebuggerUtilsImpl.getIdeaRtPath();
|
||||
pathsList.remove(JavaSdkUtil.getIdeaRtJarPath());
|
||||
pathsList.addTail(path);
|
||||
}
|
||||
else {
|
||||
JavaSdkUtil.addRtJar(pathsList);
|
||||
if (Registry.is("debugger.add.rt.jar", true)) {
|
||||
if (PluginManagerCore.isRunningFromSources()) {
|
||||
String path = DebuggerUtilsImpl.getIdeaRtPath();
|
||||
pathsList.remove(JavaSdkUtil.getIdeaRtJarPath());
|
||||
pathsList.addTail(path);
|
||||
}
|
||||
else {
|
||||
JavaSdkUtil.addRtJar(pathsList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -643,10 +643,14 @@ debugger.variablesView.rss.depth=4
|
||||
debugger.variablesView.rss.depth.description=Depth of search in variables view
|
||||
debugger.attach.to.process.action=false
|
||||
debugger.sa.jdwp.debug=false
|
||||
debugger.add.rt.jar=true
|
||||
debugger.add.rt.jar.description=Add rt.jar to the classpath
|
||||
debugger.evaluate.method.helper=false
|
||||
debugger.evaluate.method.helper.description=Use helper to invoke methods avoiding the immediate return value collection
|
||||
debugger.evaluate.single.threaded.timeout=1000
|
||||
debugger.evaluate.single.threaded.timeout.description=Number of milliseconds to evaluate resuming only the current thread, then resume all threads
|
||||
debugger.evaluate.load.helper.in.separate.classloader=true
|
||||
debugger.evaluate.load.helper.in.separate.classloader.description=Always load helper classes in a new classloader
|
||||
debugger.new.invocation.watcher=true
|
||||
debugger.new.invocation.watcher.description=When resume all, take into account the debugger model state of contexts and theirs resumed threads
|
||||
debugger.retry.conditional.breakpoints=true
|
||||
|
||||
Reference in New Issue
Block a user