mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 06:50:54 +07:00
[debugger] IDEA-361080 Add workaround to fix ObjectCollectedException during evaluating conditional breakpoints
(cherry picked from commit 9922fc513d0c4e4d7daa4cc89d078fbb6b5a8f72) IJ-CR-147314 GitOrigin-RevId: ffc72ca98c6b98842cde50e1a9e76f88c89f9228
This commit is contained in:
committed by
intellij-monorepo-bot
parent
5d73c19f18
commit
720ce629f0
@@ -28,6 +28,8 @@ public final class EvaluationContextImpl implements EvaluationContext {
|
||||
|
||||
private @Nullable ThreadReferenceProxyImpl myPreferableThread = null;
|
||||
|
||||
private boolean myMayRetryEvaluation = false;
|
||||
|
||||
private EvaluationContextImpl(@NotNull SuspendContextImpl suspendContext,
|
||||
@Nullable StackFrameProxyImpl frameProxy,
|
||||
@NotNull DebuggerComputableValue thisObjectComputableValue) {
|
||||
@@ -177,4 +179,14 @@ public final class EvaluationContextImpl implements EvaluationContext {
|
||||
return "Evaluating requested on " + myPreferableThread + ", started on " + myThreadForEvaluation + " for " + mySuspendContext;
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public boolean isMayRetryEvaluation() {
|
||||
return myMayRetryEvaluation;
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public void setMayRetryEvaluation(boolean mayRetryEvaluation) {
|
||||
myMayRetryEvaluation = mayRetryEvaluation;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.intellij.debugger.engine.evaluation.expression;
|
||||
|
||||
import com.intellij.debugger.JavaDebuggerBundle;
|
||||
import com.intellij.debugger.engine.DebuggerUtils;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContext;
|
||||
@@ -48,7 +49,24 @@ public class ExpressionEvaluatorImpl implements ExpressionEvaluator {
|
||||
throw EvaluateExceptionUtil.NULL_STACK_FRAME;
|
||||
}
|
||||
|
||||
Object value = myEvaluator.evaluate((EvaluationContextImpl)context);
|
||||
EvaluationContextImpl evaluationContextImpl = (EvaluationContextImpl)context;
|
||||
|
||||
final Object value;
|
||||
if (evaluationContextImpl.isMayRetryEvaluation()) {
|
||||
value = DebuggerUtils.getInstance().processCollectibleValue(
|
||||
() -> myEvaluator.evaluate(evaluationContextImpl),
|
||||
r -> {
|
||||
if (r instanceof Value v) {
|
||||
evaluationContextImpl.keep(v);
|
||||
}
|
||||
return r;
|
||||
},
|
||||
context
|
||||
);
|
||||
}
|
||||
else {
|
||||
value = myEvaluator.evaluate(evaluationContextImpl);
|
||||
}
|
||||
|
||||
if (value != null && !(value instanceof Value)) {
|
||||
throw EvaluateExceptionUtil
|
||||
|
||||
@@ -351,14 +351,14 @@ public final class DebuggerUtilsImpl extends DebuggerUtilsEx {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, T extends Value> R processCollectibleValue(
|
||||
public <R, T> R processCollectibleValue(
|
||||
@NotNull ThrowableComputable<? extends T, ? extends EvaluateException> valueComputable,
|
||||
@NotNull Function<? super T, ? extends R> processor,
|
||||
@NotNull EvaluationContext evaluationContext) throws EvaluateException {
|
||||
int retries = 3;
|
||||
while (true) {
|
||||
T result = valueComputable.compute();
|
||||
try {
|
||||
T result = valueComputable.compute();
|
||||
return processor.apply(result);
|
||||
}
|
||||
catch (ObjectCollectedException oce) {
|
||||
|
||||
@@ -474,7 +474,15 @@ public abstract class Breakpoint<P extends JavaBreakpointProperties> implements
|
||||
condition,
|
||||
this::createConditionCodeFragment));
|
||||
});
|
||||
boolean evaluationResult = DebuggerUtilsEx.evaluateBoolean(evaluator, context);
|
||||
boolean evaluationResult;
|
||||
try {
|
||||
if (Registry.is("debugger.retry.conditional.breakpoints", true)) {
|
||||
context.setMayRetryEvaluation(true);
|
||||
}
|
||||
evaluationResult = DebuggerUtilsEx.evaluateBoolean(evaluator, context);
|
||||
} finally {
|
||||
context.setMayRetryEvaluation(false);
|
||||
}
|
||||
JavaDebuggerEvaluatorStatisticsCollector.logEvaluationResult(myProject, evaluator, true, XEvaluationOrigin.BREAKPOINT_CONDITION);
|
||||
if (!evaluationResult) {
|
||||
return false;
|
||||
|
||||
@@ -143,7 +143,7 @@ public abstract class DebuggerUtils {
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public abstract <R, T extends Value> R processCollectibleValue(
|
||||
public abstract <R, T> R processCollectibleValue(
|
||||
@NotNull ThrowableComputable<? extends T, ? extends EvaluateException> valueComputable,
|
||||
@NotNull Function<? super T, ? extends R> processor,
|
||||
@NotNull EvaluationContext evaluationContext) throws EvaluateException;
|
||||
|
||||
@@ -648,6 +648,8 @@ 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.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
|
||||
debugger.retry.conditional.breakpoints.description=Retry to evaluate a condition in conditional breakpoints in case of ObjectCollectedException
|
||||
debugger.call.tracing=false
|
||||
debugger.call.tracing.arguments=true
|
||||
debugger.renderers.annotations=true
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
package org.jetbrains.kotlin.idea.debugger.evaluate
|
||||
|
||||
import com.intellij.debugger.SourcePosition
|
||||
import com.intellij.debugger.engine.DebuggerUtils
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
|
||||
@@ -14,6 +15,7 @@ import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.progress.ProcessCanceledException
|
||||
import com.intellij.openapi.project.IndexNotReadyException
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.ThrowableComputable
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.CachedValueProvider
|
||||
import com.intellij.psi.util.CachedValuesManager
|
||||
@@ -232,6 +234,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, private val sourcePositi
|
||||
compiledData: CompiledCodeFragmentData,
|
||||
classLoader: ClassLoaderReference?
|
||||
): InterpreterResult {
|
||||
val mayRetry = context.evaluationContext.isMayRetryEvaluation
|
||||
val mainClassBytecode = compiledData.mainClass.bytes
|
||||
val mainClassAsmNode = ClassNode().apply { ClassReader(mainClassBytecode).accept(this, 0) }
|
||||
val mainMethod = mainClassAsmNode.methods.first { it.isEvaluationEntryPoint }
|
||||
@@ -279,7 +282,23 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, private val sourcePositi
|
||||
return context.debugProcess.findClass(context.evaluationContext, classType.className, classLoader)
|
||||
}
|
||||
}
|
||||
interpreterLoop(mainMethod, makeInitialFrame(mainMethod, args.map { it.asValue() }), eval)
|
||||
|
||||
fun interpreterLoop() = interpreterLoop(mainMethod, makeInitialFrame(mainMethod, args.map { it.asValue() }), eval)
|
||||
fun keepResult(result: InterpreterResult) {
|
||||
val jdiObject = when (result) {
|
||||
is ValueReturned -> result.result
|
||||
is ExceptionThrown -> result.exception
|
||||
else -> return
|
||||
}.obj() as? ObjectReference? ?: return
|
||||
context.evaluationContext.keep(jdiObject)
|
||||
}
|
||||
if (mayRetry) {
|
||||
DebuggerUtils.getInstance().processCollectibleValue(object : ThrowableComputable<InterpreterResult, EvaluateException> {
|
||||
override fun compute() = interpreterLoop()
|
||||
}, { keepResult(it); it }, context.evaluationContext)
|
||||
} else {
|
||||
interpreterLoop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user