GeezerVison is showing github.com — Fix the stack frame conflicts between logical structure and evaluatio… · mfussenegger/java-debug@6633a55
File treeExpand file treeCollapse file tree Open diff view settings com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/eval
Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/IEvaluationProvider.java +14Lines changed: 14 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -62,6 +62,20 @@ public interface IEvaluationProvider extends IProvider { | 62 | 62 | */ | 63 | 63 | CompletableFuture<Value> evaluateForBreakpoint(IEvaluatableBreakpoint breakpoint, ThreadReference thread); | 64 | 64 |
| | 65 | + /** | | 66 | + * Invoke the specified method with the given arguments at this object and the given thread, and return the result. | | 67 | + * The given thread is resumed to perform the method invocation. The thread will suspend in its originallocation when the method invocation is complete. | | 68 | + * @param thisContext The 'this' context for the invocation | | 69 | + * @param methodName The method to be invoked | | 70 | + * @param methodSignature The JNI style signature of the method to be invoked | | 71 | + * @param args The arguments of the method, which can be null or empty if there are none | | 72 | + * @param thread The thread in which to invoke the method | | 73 | + * @param invokeSuper true if the method lookup should begin in thisobject's superclass | | 74 | + * @return The result of invoking the method | | 75 | + */ | | 76 | + CompletableFuture<Value> invokeMethod(ObjectReference thisContext, String methodName, String methodSignature, | | 77 | + Value[] args, ThreadReference thread, boolean invokeSuper); | | 78 | + | 65 | 79 | /** | 66 | 80 | * Call this method when the thread is to be resumed by user, it will first cancel ongoing evaluation tasks on specified thread and | 67 | 81 | * ensure the inner states is cleaned. | |
Collapse file Copy file name to clipboardExpand all lines: com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/EvaluateRequestHandler.java +4-7Lines changed: 4 additions & 7 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 14 | 14 | import java.util.Arrays; | 15 | 15 | import java.util.List; | 16 | 16 | import java.util.Map; | | 17 | +import java.util.concurrent.CancellationException; | 17 | 18 | import java.util.concurrent.CompletableFuture; | 18 | 19 | import java.util.concurrent.CompletionException; | 19 | 20 | import java.util.concurrent.ExecutionException; | | 41 | 42 | import com.microsoft.java.debug.core.protocol.Requests.EvaluateArguments; | 42 | 43 | import com.microsoft.java.debug.core.protocol.Responses; | 43 | 44 | import com.sun.jdi.ArrayReference; | 44 | | -import com.sun.jdi.ClassNotLoadedException; | 45 | | -import com.sun.jdi.IncompatibleThreadStateException; | 46 | 45 | import com.sun.jdi.IntegerValue; | 47 | | -import com.sun.jdi.InvalidTypeException; | 48 | | -import com.sun.jdi.InvocationException; | 49 | 46 | import com.sun.jdi.ObjectReference; | 50 | 47 | import com.sun.jdi.Value; | 51 | 48 | import com.sun.jdi.VoidValue; | @@ -80,8 +77,8 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments, | 80 | 77 | } | 81 | 78 |
| 82 | 79 | return CompletableFuture.supplyAsync(() -> { | | 80 | + IEvaluationProvider engine = context.getProvider(IEvaluationProvider.class); | 83 | 81 | try { | 84 | | - IEvaluationProvider engine = context.getProvider(IEvaluationProvider.class); | 85 | 82 | Value value = engine.evaluate(expression, stackFrameReference.getThread(), stackFrameReference.getDepth()).get(); | 86 | 83 | IVariableFormatter variableFormatter = context.getVariableFormatter(); | 87 | 84 | if (value instanceof VoidValue) { | @@ -102,8 +99,8 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments, | 102 | 99 | if (sizeValue != null && sizeValue instanceof IntegerValue) { | 103 | 100 | indexedVariables = ((IntegerValue) sizeValue).value(); | 104 | 101 | } | 105 | | - } catch (InvalidTypeException | ClassNotLoadedException | IncompatibleThreadStateException | 106 | | - | InvocationException | InterruptedException | ExecutionException | UnsupportedOperationException e) { | | 102 | + } catch (CancellationException | IllegalArgumentException | InterruptedException | | 103 | + | ExecutionException | UnsupportedOperationException e) { | 107 | 104 | logger.log(Level.INFO, | 108 | 105 | String.format("Failed to get the logical size for the type %s.", value.type().name()), e); | 109 | 106 | } | |
Collapse file Copy file name to clipboardExpand all lines: com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/VariablesRequestHandler.java +4-8Lines changed: 4 additions & 8 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 19 | 19 | import java.util.List; | 20 | 20 | import java.util.Map; | 21 | 21 | import java.util.Set; | | 22 | +import java.util.concurrent.CancellationException; | 22 | 23 | import java.util.concurrent.CompletableFuture; | 23 | 24 | import java.util.concurrent.ExecutionException; | 24 | 25 | import java.util.logging.Level; | | 50 | 51 | import com.microsoft.java.debug.core.protocol.Types; | 51 | 52 | import com.sun.jdi.AbsentInformationException; | 52 | 53 | import com.sun.jdi.ArrayReference; | 53 | | -import com.sun.jdi.ClassNotLoadedException; | 54 | | -import com.sun.jdi.IncompatibleThreadStateException; | 55 | 54 | import com.sun.jdi.IntegerValue; | 56 | 55 | import com.sun.jdi.InternalException; | 57 | 56 | import com.sun.jdi.InvalidStackFrameException; | 58 | | -import com.sun.jdi.InvalidTypeException; | 59 | | -import com.sun.jdi.InvocationException; | 60 | 57 | import com.sun.jdi.ObjectReference; | 61 | 58 | import com.sun.jdi.StackFrame; | 62 | 59 | import com.sun.jdi.Type; | @@ -147,8 +144,7 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments, | 147 | 144 | childrenList.add(new Variable(name, value)); | 148 | 145 | } | 149 | 146 | } | 150 | | - } catch (InterruptedException | ExecutionException | InvalidTypeException | 151 | | - | ClassNotLoadedException | IncompatibleThreadStateException | InvocationException e) { | | 147 | + } catch (IllegalArgumentException | CancellationException | InterruptedException | ExecutionException e) { | 152 | 148 | logger.log(Level.WARNING, | 153 | 149 | String.format("Failed to get the logical structure for the type %s, fall back to the Object view.", | 154 | 150 | containerObj.type().name()), | @@ -226,8 +222,7 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments, | 226 | 222 | if (sizeValue != null && sizeValue instanceof IntegerValue) { | 227 | 223 | indexedVariables = ((IntegerValue) sizeValue).value(); | 228 | 224 | } | 229 | | - } catch (InvalidTypeException | ClassNotLoadedException | IncompatibleThreadStateException | 230 | | - | InvocationException | InterruptedException | ExecutionException | UnsupportedOperationException e) { | | 225 | + } catch (CancellationException | IllegalArgumentException | InterruptedException | ExecutionException | UnsupportedOperationException e) { | 231 | 226 | logger.log(Level.INFO, | 232 | 227 | String.format("Failed to get the logical size for the type %s.", value.type().name()), e); | 233 | 228 | } | @@ -245,6 +240,7 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments, | 245 | 240 | list.add(typedVariables); | 246 | 241 | } | 247 | 242 | response.body = new Responses.VariablesResponseBody(list); | | 243 | + | 248 | 244 | return CompletableFuture.completedFuture(response); | 249 | 245 | } | 250 | 246 |
| |
Collapse file Copy file name to clipboardExpand all lines: com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/variables/JavaLogicalStructure.java +20-47Lines changed: 20 additions & 47 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 11 | 11 |
| 12 | 12 | package com.microsoft.java.debug.core.adapter.variables; | 13 | 13 |
| 14 | | -import java.util.Collections; | 15 | 14 | import java.util.List; | 16 | 15 | import java.util.Objects; | | 16 | +import java.util.concurrent.CancellationException; | 17 | 17 | import java.util.concurrent.ExecutionException; | 18 | 18 |
| 19 | 19 | import com.microsoft.java.debug.core.adapter.IEvaluationProvider; | 20 | | -import com.sun.jdi.ClassNotLoadedException; | 21 | 20 | import com.sun.jdi.ClassType; | 22 | 21 | import com.sun.jdi.Field; | 23 | | -import com.sun.jdi.IncompatibleThreadStateException; | 24 | 22 | import com.sun.jdi.InterfaceType; | 25 | | -import com.sun.jdi.InvalidTypeException; | 26 | | -import com.sun.jdi.InvocationException; | 27 | | -import com.sun.jdi.Method; | 28 | 23 | import com.sun.jdi.ObjectReference; | 29 | 24 | import com.sun.jdi.ThreadReference; | 30 | 25 | import com.sun.jdi.Type; | @@ -95,8 +90,7 @@ public boolean providesLogicalStructure(ObjectReference obj) { | 95 | 90 | * Return the logical size of the specified thisObject. | 96 | 91 | */ | 97 | 92 | public Value getSize(ObjectReference thisObject, ThreadReference thread, IEvaluationProvider evaluationEngine) | 98 | | - throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException, InvocationException, | 99 | | - InterruptedException, ExecutionException, UnsupportedOperationException { | | 93 | + throws CancellationException, InterruptedException, IllegalArgumentException, ExecutionException, UnsupportedOperationException { | 100 | 94 | if (sizeExpression == null) { | 101 | 95 | throw new UnsupportedOperationException("The object hasn't defined the logical size operation."); | 102 | 96 | } | @@ -108,52 +102,32 @@ public Value getSize(ObjectReference thisObject, ThreadReference thread, IEvalua | 108 | 102 | * Return the logical value of the specified thisObject. | 109 | 103 | */ | 110 | 104 | public Value getValue(ObjectReference thisObject, ThreadReference thread, IEvaluationProvider evaluationEngine) | 111 | | - throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException, InvocationException, | 112 | | - InterruptedException, ExecutionException { | | 105 | + throws CancellationException, IllegalArgumentException, InterruptedException, ExecutionException { | 113 | 106 | return getValue(thisObject, valueExpression, thread, evaluationEngine); | 114 | 107 | } | 115 | 108 |
| 116 | 109 | private static Value getValue(ObjectReference thisObject, LogicalStructureExpression expression, ThreadReference thread, | 117 | | - IEvaluationProvider evaluationEngine) | 118 | | - throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException, InvocationException, | 119 | | - InterruptedException, ExecutionException { | | 110 | + IEvaluationProvider evaluationEngine) throws CancellationException, IllegalArgumentException, InterruptedException, ExecutionException { | 120 | 111 | if (expression.type == LogicalStructureExpressionType.METHOD) { | 121 | | - return getValueByMethod(thisObject, expression.value, thread); | | 112 | + if (expression.value == null || expression.value.length < 2) { | | 113 | + throw new IllegalArgumentException("The method expression should contain at least methodName and methodSignature!"); | | 114 | + } | | 115 | + return evaluationEngine.invokeMethod(thisObject, expression.value[0], expression.value[1], null, thread, false).get(); | 122 | 116 | } else if (expression.type == LogicalStructureExpressionType.FIELD) { | 123 | | - return getValueByField(thisObject, expression.value, thread); | | 117 | + if (expression.value == null || expression.value.length < 1) { | | 118 | + throw new IllegalArgumentException("The field expression should contain the field name!"); | | 119 | + } | | 120 | + return getValueByField(thisObject, expression.value[0], thread); | 124 | 121 | } else { | 125 | | - return evaluationEngine.evaluate(expression.value, thisObject, thread).get(); | 126 | | - } | 127 | | - } | 128 | | - | 129 | | - private static Value getValueByMethod(ObjectReference thisObject, String methodName, ThreadReference thread) | 130 | | - throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException, InvocationException { | 131 | | - List<Method> methods = thisObject.referenceType().allMethods(); | 132 | | - Method targetMethod = null; | 133 | | - for (Method method : methods) { | 134 | | - if (Objects.equals(method.name(), methodName) && method.argumentTypeNames().isEmpty()) { | 135 | | - targetMethod = method; | 136 | | - break; | | 122 | + if (expression.value == null || expression.value.length < 1) { | | 123 | + throw new IllegalArgumentException("The evaluation expression should contain a valid expression statement!"); | 137 | 124 | } | | 125 | + return evaluationEngine.evaluate(expression.value[0], thisObject, thread).get(); | 138 | 126 | } | 139 | | - | 140 | | - if (targetMethod == null) { | 141 | | - return null; | 142 | | - } | 143 | | - | 144 | | - return thisObject.invokeMethod(thread, targetMethod, Collections.EMPTY_LIST, ObjectReference.INVOKE_SINGLE_THREADED); | 145 | 127 | } | 146 | 128 |
| 147 | | - private static Value getValueByField(ObjectReference thisObject, String filedName, ThreadReference thread) { | 148 | | - List<Field> fields = thisObject.referenceType().allFields(); | 149 | | - Field targetField = null; | 150 | | - for (Field field : fields) { | 151 | | - if (Objects.equals(field.name(), filedName)) { | 152 | | - targetField = field; | 153 | | - break; | 154 | | - } | 155 | | - } | 156 | | - | | 129 | + private static Value getValueByField(ObjectReference thisObject, String fieldName, ThreadReference thread) { | | 130 | + Field targetField = thisObject.referenceType().fieldByName(fieldName); | 157 | 131 | if (targetField == null) { | 158 | 132 | return null; | 159 | 133 | } | @@ -175,20 +149,19 @@ public String getName() { | 175 | 149 | } | 176 | 150 |
| 177 | 151 | public Value getValue(ObjectReference thisObject, ThreadReference thread, IEvaluationProvider evaluationEngine) | 178 | | - throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException, InvocationException, | 179 | | - InterruptedException, ExecutionException { | | 152 | + throws CancellationException, IllegalArgumentException, InterruptedException, ExecutionException { | 180 | 153 | return JavaLogicalStructure.getValue(thisObject, valueExpression, thread, evaluationEngine); | 181 | 154 | } | 182 | 155 | } | 183 | 156 |
| 184 | 157 | public static class LogicalStructureExpression { | 185 | 158 | public LogicalStructureExpressionType type; | 186 | | - public String value; | | 159 | + public String[] value; | 187 | 160 |
| 188 | 161 | /** | 189 | 162 | * Constructor. | 190 | 163 | */ | 191 | | - public LogicalStructureExpression(LogicalStructureExpressionType type, String value) { | | 164 | + public LogicalStructureExpression(LogicalStructureExpressionType type, String[] value) { | 192 | 165 | this.type = type; | 193 | 166 | this.value = value; | 194 | 167 | } | |
Collapse file Copy file name to clipboardExpand all lines: com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/variables/JavaLogicalStructureManager.java +9-12Lines changed: 9 additions & 12 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 14 | 14 | import java.util.ArrayList; | 15 | 15 | import java.util.Collections; | 16 | 16 | import java.util.List; | | 17 | +import java.util.concurrent.CancellationException; | 17 | 18 | import java.util.concurrent.ExecutionException; | 18 | 19 |
| 19 | 20 | import com.microsoft.java.debug.core.adapter.IEvaluationProvider; | 20 | 21 | import com.microsoft.java.debug.core.adapter.variables.JavaLogicalStructure.LogicalStructureExpression; | 21 | 22 | import com.microsoft.java.debug.core.adapter.variables.JavaLogicalStructure.LogicalStructureExpressionType; | 22 | 23 | import com.microsoft.java.debug.core.adapter.variables.JavaLogicalStructure.LogicalVariable; | 23 | | -import com.sun.jdi.ClassNotLoadedException; | 24 | | -import com.sun.jdi.IncompatibleThreadStateException; | 25 | | -import com.sun.jdi.InvalidTypeException; | 26 | | -import com.sun.jdi.InvocationException; | 27 | 24 | import com.sun.jdi.ObjectReference; | 28 | 25 | import com.sun.jdi.ThreadReference; | 29 | 26 | import com.sun.jdi.Value; | @@ -33,16 +30,17 @@ public class JavaLogicalStructureManager { | 33 | 30 |
| 34 | 31 | static { | 35 | 32 | supportedLogicalStructures.add(new JavaLogicalStructure("java.util.Map", | 36 | | - new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, "entrySet"), | 37 | | - new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, "size"), | | 33 | + new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, new String[] {"entrySet", "()Ljava/util/Set;"}), | | 34 | + new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, new String[] {"size", "()I"}), | 38 | 35 | new LogicalVariable[0])); | 39 | 36 | supportedLogicalStructures.add(new JavaLogicalStructure("java.util.Map$Entry", null, null, new LogicalVariable[] { | 40 | | - new LogicalVariable("key", new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, "getKey")), | 41 | | - new LogicalVariable("value", new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, "getValue")) | | 37 | + new LogicalVariable("key", new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, new String[] {"getKey", "()Ljava/lang/Object;"})), | | 38 | + new LogicalVariable("value", | | 39 | + new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, new String[] {"getValue", "()Ljava/lang/Object;"})) | 42 | 40 | })); | 43 | 41 | supportedLogicalStructures.add(new JavaLogicalStructure("java.util.Collection", | 44 | | - new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, "toArray"), | 45 | | - new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, "size"), | | 42 | + new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, new String[] {"toArray", "()[Ljava/lang/Object;"}), | | 43 | + new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, new String[] {"size", "()I"}), | 46 | 44 | new LogicalVariable[0])); | 47 | 45 | } | 48 | 46 |
| @@ -71,8 +69,7 @@ public static boolean isIndexedVariable(ObjectReference obj) { | 71 | 69 | * Return the logical size if the specified Object has defined the logical size. | 72 | 70 | */ | 73 | 71 | public static Value getLogicalSize(ObjectReference thisObject, ThreadReference thread, IEvaluationProvider evaluationEngine) | 74 | | - throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException, InvocationException, | 75 | | - InterruptedException, ExecutionException, UnsupportedOperationException { | | 72 | + throws CancellationException, InterruptedException, IllegalArgumentException, ExecutionException, UnsupportedOperationException { | 76 | 73 | JavaLogicalStructure structure = getLogicalStructure(thisObject); | 77 | 74 | if (structure == null) { | 78 | 75 | return null; | |
Collapse file Copy file name to clipboardExpand all lines: com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/eval/JdtEvaluationProvider.java +37-1Lines changed: 37 additions & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
| 13 | 13 |
| 14 | 14 | import java.util.ArrayList; | 15 | 15 | import java.util.Arrays; | | 16 | +import java.util.Collections; | 16 | 17 | import java.util.HashMap; | 17 | 18 | import java.util.HashSet; | 18 | 19 | import java.util.List; | | 41 | 42 | import org.eclipse.jdt.debug.core.IJavaObject; | 42 | 43 | import org.eclipse.jdt.debug.core.IJavaStackFrame; | 43 | 44 | import org.eclipse.jdt.debug.core.IJavaThread; | | 45 | +import org.eclipse.jdt.debug.core.IJavaValue; | 44 | 46 | import org.eclipse.jdt.debug.eval.ICompiledExpression; | 45 | 47 | import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; | 46 | 48 | import org.eclipse.jdt.internal.debug.core.model.JDIObjectValue; | 47 | 49 | import org.eclipse.jdt.internal.debug.core.model.JDIStackFrame; | 48 | 50 | import org.eclipse.jdt.internal.debug.core.model.JDIThread; | | 51 | +import org.eclipse.jdt.internal.debug.core.model.JDIValue; | 49 | 52 | import org.eclipse.jdt.internal.debug.eval.ast.engine.ASTEvaluationEngine; | 50 | 53 | import org.eclipse.jdt.internal.launching.JavaSourceLookupDirector; | 51 | 54 |
| @@ -191,6 +194,34 @@ private CompletableFuture<Value> evaluate(String expression, ThreadReference thr | 191 | 194 | } | 192 | 195 | } | 193 | 196 |
| | 197 | + @Override | | 198 | + public CompletableFuture<Value> invokeMethod(ObjectReference thisContext, String methodName, String methodSignature, | | 199 | + Value[] args, ThreadReference thread, boolean invokeSuper) { | | 200 | + CompletableFuture<Value> completableFuture = new CompletableFuture<>(); | | 201 | + try { | | 202 | + ensureDebugTarget(thisContext.virtualMachine(), thisContext.type().name()); | | 203 | + JDIThread jdiThread = getMockJDIThread(thread); | | 204 | + JDIObjectValue jdiObject = new JDIObjectValue(debugTarget, thisContext); | | 205 | + List<IJavaValue> arguments = null; | | 206 | + if (args == null) { | | 207 | + arguments = Collections.EMPTY_LIST; | | 208 | + } else { | | 209 | + arguments = new ArrayList<>(args.length); | | 210 | + for (Value arg : args) { | | 211 | + arguments.add(new JDIValue(debugTarget, arg)); | | 212 | + } | | 213 | + } | | 214 | + IJavaValue javaValue = jdiObject.sendMessage(methodName, methodSignature, arguments.toArray(new IJavaValue[0]), jdiThread, invokeSuper); | | 215 | + // we need to read fValue from the result Value instance implements by JDT | | 216 | + Value value = (Value) FieldUtils.readField(javaValue, "fValue", true); | | 217 | + completableFuture.complete(value); | | 218 | + return completableFuture; | | 219 | + } catch (Exception ex) { | | 220 | + completableFuture.completeExceptionally(ex); | | 221 | + return completableFuture; | | 222 | + } | | 223 | + } | | 224 | + | 194 | 225 | private String logMessageToExpression(String logMessage) { | 195 | 226 | final String LOGMESSAGE_VARIABLE_REGEXP = "\\{(.*?)\\}"; | 196 | 227 | String format = logMessage.replaceAll(LOGMESSAGE_VARIABLE_REGEXP, "%s"); | @@ -348,7 +379,12 @@ private void internalEvaluate(ASTEvaluationEngine engine, ICompiledExpression co | 348 | 379 |
| 349 | 380 | @Override | 350 | 381 | public boolean isInEvaluation(ThreadReference thread) { | 351 | | - return debugTarget != null && getMockJDIThread(thread).isPerformingEvaluation(); | | 382 | + if (debugTarget == null) { | | 383 | + return false; | | 384 | + } | | 385 | + | | 386 | + JDIThread jdiThread = getMockJDIThread(thread); | | 387 | + return jdiThread != null && (jdiThread.isPerformingEvaluation() || jdiThread.isInvokingMethod()); | 352 | 388 | } | 353 | 389 |
| 354 | 390 | @Override | |
|