diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaStackFrame.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaStackFrame.java index bb47dfe3385c..83a110020e16 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaStackFrame.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaStackFrame.java @@ -320,7 +320,7 @@ public class JavaStackFrame extends XStackFrame implements JVMStackFrameInfoProv else { superBuildVariables(evaluationContext, children); } - final EvaluationContextImpl evalContextCopy = evaluationContext.createEvaluationContext(evaluationContext.getThisObject()); + final EvaluationContextImpl evalContextCopy = evaluationContext.createEvaluationContext(evaluationContext.computeThisObject()); evalContextCopy.setAutoLoadClasses(false); if (sourcePosition != null) { diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DebuggerComputableValue.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DebuggerComputableValue.java new file mode 100644 index 000000000000..90649a8e269a --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DebuggerComputableValue.java @@ -0,0 +1,66 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.debugger.engine.evaluation; + +import com.intellij.debugger.EvaluatingComputable; +import com.sun.jdi.Value; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author egor + */ +public class DebuggerComputableValue { + private boolean myComputed; + @Nullable private Value myValue; + @Nullable private EvaluateException myException; + + @NotNull private final EvaluatingComputable myComputable; + + public DebuggerComputableValue(@NotNull EvaluatingComputable computable) { + myComputable = computable; + } + + public DebuggerComputableValue(@Nullable Value value) { + myComputed = true; + myValue = value; + myComputable = () -> value; + } + + public static DebuggerComputableValue computed(Value value) { + DebuggerComputableValue res = new DebuggerComputableValue(() -> value); + res.myComputed = true; + res.myValue = value; + return res; + } + + @Nullable + public Value getValue() throws EvaluateException { + if (!myComputed) { + try { + myValue = myComputable.compute(); + } + catch (EvaluateException e) { + myException = e; + } + myComputed = true; + } + if (myException != null) { + throw myException; + } + return myValue; + } +} diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/EvaluationContextImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/EvaluationContextImpl.java index a4184ef4a8d7..bf76cfcec5aa 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/EvaluationContextImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/EvaluationContextImpl.java @@ -15,46 +15,65 @@ */ package com.intellij.debugger.engine.evaluation; +import com.intellij.debugger.EvaluatingComputable; import com.intellij.debugger.engine.DebugProcessImpl; import com.intellij.debugger.engine.DebuggerManagerThreadImpl; import com.intellij.debugger.engine.SuspendContextImpl; import com.intellij.debugger.jdi.StackFrameProxyImpl; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.NullableLazyValue; import com.sun.jdi.ClassLoaderReference; import com.sun.jdi.Value; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public final class EvaluationContextImpl implements EvaluationContext{ - private final NullableLazyValue myThisObject; +public final class EvaluationContextImpl implements EvaluationContext { + private static final Logger LOG = Logger.getInstance(EvaluationContextImpl.class); + + private final DebuggerComputableValue myThisObject; private final SuspendContextImpl mySuspendContext; private final StackFrameProxyImpl myFrameProxy; private boolean myAutoLoadClasses = true; private ClassLoaderReference myClassLoader; - - public EvaluationContextImpl(@NotNull SuspendContextImpl suspendContext, StackFrameProxyImpl frameProxy, @Nullable Value thisObject) { - myThisObject = NullableLazyValue.createValue(() -> thisObject); + + private EvaluationContextImpl(@NotNull SuspendContextImpl suspendContext, + @Nullable StackFrameProxyImpl frameProxy, + @NotNull DebuggerComputableValue thisObjectComputableValue) { + myThisObject = thisObjectComputableValue; myFrameProxy = frameProxy; mySuspendContext = suspendContext; } - public EvaluationContextImpl(@NotNull SuspendContextImpl suspendContext, @NotNull StackFrameProxyImpl frameProxy) { - myThisObject = NullableLazyValue.createValue(() -> { - try { - return frameProxy.thisObject(); - } - catch (EvaluateException ignore) { - } - return null; - }); - myFrameProxy = frameProxy; - mySuspendContext = suspendContext; + public EvaluationContextImpl(@NotNull SuspendContextImpl suspendContext, + @Nullable StackFrameProxyImpl frameProxy, + @NotNull EvaluatingComputable thisObjectFactory) { + this(suspendContext, frameProxy, new DebuggerComputableValue(thisObjectFactory)); + } + + public EvaluationContextImpl(@NotNull SuspendContextImpl suspendContext, @Nullable StackFrameProxyImpl frameProxy, @Nullable Value thisObject) { + this(suspendContext, frameProxy, new DebuggerComputableValue(thisObject)); + } + + public EvaluationContextImpl(@NotNull SuspendContextImpl suspendContext, @Nullable StackFrameProxyImpl frameProxy) { + this(suspendContext, frameProxy, () -> frameProxy != null ? frameProxy.thisObject() : null); } @Nullable @Override + @Deprecated public Value getThisObject() { + try { + return computeThisObject(); + } + catch (EvaluateException e) { + LOG.info(e); + } + return null; + } + + @Nullable + @Override + public Value computeThisObject() throws EvaluateException { return myThisObject.getValue(); } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ThisEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ThisEvaluator.java index 7ca4c21924d8..673eba10c186 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ThisEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ThisEvaluator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,7 +43,7 @@ public class ThisEvaluator implements Evaluator { } public Object evaluate(EvaluationContextImpl context) throws EvaluateException { - Value objRef = context.getThisObject(); + Value objRef = context.computeThisObject(); if(myIterations > 0) { ObjectReference thisRef = (ObjectReference)objRef; for (int idx = 0; idx < myIterations && thisRef != null; idx++) { diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerContextImpl.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerContextImpl.java index 17032215cd24..354efedd3461 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerContextImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerContextImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,7 +33,6 @@ import com.intellij.debugger.jdi.ThreadReferenceProxyImpl; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; -import com.sun.jdi.ObjectReference; import com.sun.jdi.Value; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -127,17 +126,8 @@ public final class DebuggerContextImpl implements DebuggerContext { @Nullable public EvaluationContextImpl createEvaluationContext() { DebuggerManagerThreadImpl.assertIsManagerThread(); - StackFrameProxyImpl frameProxy = getFrameProxy(); - ObjectReference objectReference; - try { - objectReference = frameProxy != null ? frameProxy.thisObject() : null; - } - catch (EvaluateException e) { - LOG.info(e); - objectReference = null; - } SuspendContextImpl context = getSuspendContext(); - return context != null ? new EvaluationContextImpl(context, frameProxy, objectReference) : null; + return context != null ? new EvaluationContextImpl(context, getFrameProxy()) : null; } @NotNull diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java index 9d001083a62c..28ed78b216bc 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java @@ -33,8 +33,8 @@ import com.intellij.debugger.jdi.ThreadReferenceProxyImpl; import com.intellij.debugger.requests.ClassPrepareRequestor; import com.intellij.debugger.requests.Requestor; import com.intellij.debugger.settings.DebuggerSettings; -import com.intellij.debugger.ui.impl.watch.CompilingEvaluatorImpl; import com.intellij.debugger.ui.OverheadTimings; +import com.intellij.debugger.ui.impl.watch.CompilingEvaluatorImpl; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.project.Project; @@ -241,7 +241,7 @@ public abstract class Breakpoint

implements return false; } - EvaluationContextImpl evaluationContext = new EvaluationContextImpl(context, frameProxy, getThisObject(context, event)); + EvaluationContextImpl evaluationContext = new EvaluationContextImpl(context, frameProxy, () -> getThisObject(context, event)); if (!evaluateCondition(evaluationContext, event)) { return false; @@ -325,7 +325,7 @@ public abstract class Breakpoint

implements debugProcess.getVirtualMachineProxy().resume(); } if (isInstanceFiltersEnabled()) { - Value value = context.getThisObject(); + Value value = context.computeThisObject(); if (value != null) { // non-static ObjectReference reference = (ObjectReference)value; if (!hasObjectID(reference.uniqueID())) { diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java index 3cea80f01226..370819daa7d1 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/LineBreakpoint.java @@ -317,7 +317,7 @@ public class LineBreakpoint

extends Breakpoi @Override protected String calculateEventClass(EvaluationContextImpl context, LocatableEvent event) throws EvaluateException { String className = null; - final ObjectReference thisObject = (ObjectReference)context.getThisObject(); + final ObjectReference thisObject = (ObjectReference)context.computeThisObject(); if (thisObject != null) { className = thisObject.referenceType().name(); } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java index 4caeb947277c..4d15f36bd7e8 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java @@ -72,7 +72,7 @@ public abstract class CompilingEvaluator implements ExpressionEvaluator { public Value evaluate(final EvaluationContext evaluationContext) throws EvaluateException { DebugProcess process = evaluationContext.getDebugProcess(); - EvaluationContextImpl autoLoadContext = ((EvaluationContextImpl)evaluationContext).createEvaluationContext(evaluationContext.getThisObject()); + EvaluationContextImpl autoLoadContext = ((EvaluationContextImpl)evaluationContext).createEvaluationContext(evaluationContext.computeThisObject()); autoLoadContext.setAutoLoadClasses(true); ClassLoaderReference classLoader = ClassLoadingUtils.getClassLoader(autoLoadContext, process); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ThisDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ThisDescriptorImpl.java index d0241b01b903..ee9cb1efe5ac 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ThisDescriptorImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ThisDescriptorImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,7 +32,7 @@ public class ThisDescriptorImpl extends ValueDescriptorImpl{ } public Value calcValue(EvaluationContextImpl evaluationContext) throws EvaluateException { - return evaluationContext != null? evaluationContext.getThisObject() : null; + return evaluationContext != null ? evaluationContext.computeThisObject() : null; } public String getName() { diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ClassRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ClassRenderer.java index cf9cb1b9a129..f9d174ed7533 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ClassRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ClassRenderer.java @@ -202,7 +202,10 @@ public class ClassRenderer extends NodeRendererImpl{ final StackFrameProxy frameProxy = context.getFrameProxy(); if (frameProxy != null) { final Location location = frameProxy.location(); - if (location != null && objInstance.equals(context.getThisObject()) && Comparing.equal(objInstance.referenceType(), location.declaringType()) && StringUtil.startsWith(field.name(), FieldDescriptorImpl.OUTER_LOCAL_VAR_FIELD_PREFIX)) { + if (location != null && + objInstance.equals(context.computeThisObject()) && + Comparing.equal(objInstance.referenceType(), location.declaringType()) && + StringUtil.startsWith(field.name(), FieldDescriptorImpl.OUTER_LOCAL_VAR_FIELD_PREFIX)) { return false; } } diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/EvaluationContext.java b/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/EvaluationContext.java index f6e1531cb978..8105235ec78b 100644 --- a/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/EvaluationContext.java +++ b/java/debugger/openapi/src/com/intellij/debugger/engine/evaluation/EvaluationContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,6 +39,13 @@ public interface EvaluationContext extends StackFrameContext{ @Nullable ClassLoaderReference getClassLoader() throws EvaluateException; + /** + * @deprecated Use {@link #computeThisObject()} instead, EvaluationContext now may lazily compute this object + */ + @Deprecated @Nullable Value getThisObject(); + + @Nullable + Value computeThisObject() throws EvaluateException; } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/DebuggerMethods.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/DebuggerMethods.groovy index 0988fbadc884..f63d46f68f09 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/DebuggerMethods.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/DebuggerMethods.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -142,7 +142,7 @@ trait DebuggerMethods extends CompilerMethods { EvaluationContextImpl evaluationContext() { final SuspendContextImpl suspendContext = debugProcess.suspendManager.pausedContext - new EvaluationContextImpl(suspendContext, suspendContext.frameProxy, suspendContext.frameProxy.thisObject()) + new EvaluationContextImpl(suspendContext, suspendContext.frameProxy) } void eval(final String codeText, String expected) throws EvaluateException {