Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,20 @@ public interface IEvaluationProvider extends IProvider {
*/
CompletableFuture<Value> evaluateForBreakpoint(IEvaluatableBreakpoint breakpoint, ThreadReference thread);

/**
* Invoke the specified method with the given arguments at this object and the given thread, and return the result.
* The given thread is resumed to perform the method invocation. The thread will suspend in its originallocation when the method invocation is complete.
* @param thisContext The 'this' context for the invocation
* @param methodName The method to be invoked
* @param methodSignature The JNI style signature of the method to be invoked
* @param args The arguments of the method, which can be null or empty if there are none
* @param thread The thread in which to invoke the method
* @param invokeSuper true if the method lookup should begin in thisobject's superclass
* @return The result of invoking the method
*/
CompletableFuture<Value> invokeMethod(ObjectReference thisContext, String methodName, String methodSignature,
Value[] args, ThreadReference thread, boolean invokeSuper);

/**
* Call this method when the thread is to be resumed by user, it will first cancel ongoing evaluation tasks on specified thread and
* ensure the inner states is cleaned.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ExecutionException;
Expand Down Expand Up @@ -41,11 +42,7 @@
import com.microsoft.java.debug.core.protocol.Requests.EvaluateArguments;
import com.microsoft.java.debug.core.protocol.Responses;
import com.sun.jdi.ArrayReference;
import com.sun.jdi.ClassNotLoadedException;
import com.sun.jdi.IncompatibleThreadStateException;
import com.sun.jdi.IntegerValue;
import com.sun.jdi.InvalidTypeException;
import com.sun.jdi.InvocationException;
import com.sun.jdi.ObjectReference;
import com.sun.jdi.Value;
import com.sun.jdi.VoidValue;
Expand Down Expand Up @@ -80,8 +77,8 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
}

return CompletableFuture.supplyAsync(() -> {
IEvaluationProvider engine = context.getProvider(IEvaluationProvider.class);
try {
IEvaluationProvider engine = context.getProvider(IEvaluationProvider.class);
Value value = engine.evaluate(expression, stackFrameReference.getThread(), stackFrameReference.getDepth()).get();
IVariableFormatter variableFormatter = context.getVariableFormatter();
if (value instanceof VoidValue) {
Expand All @@ -102,8 +99,8 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
if (sizeValue != null && sizeValue instanceof IntegerValue) {
indexedVariables = ((IntegerValue) sizeValue).value();
}
} catch (InvalidTypeException | ClassNotLoadedException | IncompatibleThreadStateException
| InvocationException | InterruptedException | ExecutionException | UnsupportedOperationException e) {
} catch (CancellationException | IllegalArgumentException | InterruptedException
| ExecutionException | UnsupportedOperationException e) {
logger.log(Level.INFO,
String.format("Failed to get the logical size for the type %s.", value.type().name()), e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
Expand Down Expand Up @@ -50,13 +51,9 @@
import com.microsoft.java.debug.core.protocol.Types;
import com.sun.jdi.AbsentInformationException;
import com.sun.jdi.ArrayReference;
import com.sun.jdi.ClassNotLoadedException;
import com.sun.jdi.IncompatibleThreadStateException;
import com.sun.jdi.IntegerValue;
import com.sun.jdi.InternalException;
import com.sun.jdi.InvalidStackFrameException;
import com.sun.jdi.InvalidTypeException;
import com.sun.jdi.InvocationException;
import com.sun.jdi.ObjectReference;
import com.sun.jdi.StackFrame;
import com.sun.jdi.Type;
Expand Down Expand Up @@ -147,8 +144,7 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
childrenList.add(new Variable(name, value));
}
}
} catch (InterruptedException | ExecutionException | InvalidTypeException
| ClassNotLoadedException | IncompatibleThreadStateException | InvocationException e) {
} catch (IllegalArgumentException | CancellationException | InterruptedException | ExecutionException e) {
logger.log(Level.WARNING,
String.format("Failed to get the logical structure for the type %s, fall back to the Object view.",
containerObj.type().name()),
Expand Down Expand Up @@ -226,8 +222,7 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
if (sizeValue != null && sizeValue instanceof IntegerValue) {
indexedVariables = ((IntegerValue) sizeValue).value();
}
} catch (InvalidTypeException | ClassNotLoadedException | IncompatibleThreadStateException
| InvocationException | InterruptedException | ExecutionException | UnsupportedOperationException e) {
} catch (CancellationException | IllegalArgumentException | InterruptedException | ExecutionException | UnsupportedOperationException e) {
logger.log(Level.INFO,
String.format("Failed to get the logical size for the type %s.", value.type().name()), e);
}
Expand All @@ -245,6 +240,7 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
list.add(typedVariables);
}
response.body = new Responses.VariablesResponseBody(list);

return CompletableFuture.completedFuture(response);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,15 @@

package com.microsoft.java.debug.core.adapter.variables;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;

import com.microsoft.java.debug.core.adapter.IEvaluationProvider;
import com.sun.jdi.ClassNotLoadedException;
import com.sun.jdi.ClassType;
import com.sun.jdi.Field;
import com.sun.jdi.IncompatibleThreadStateException;
import com.sun.jdi.InterfaceType;
import com.sun.jdi.InvalidTypeException;
import com.sun.jdi.InvocationException;
import com.sun.jdi.Method;
import com.sun.jdi.ObjectReference;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.Type;
Expand Down Expand Up @@ -95,8 +90,7 @@ public boolean providesLogicalStructure(ObjectReference obj) {
* Return the logical size of the specified thisObject.
*/
public Value getSize(ObjectReference thisObject, ThreadReference thread, IEvaluationProvider evaluationEngine)
throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException, InvocationException,
InterruptedException, ExecutionException, UnsupportedOperationException {
throws CancellationException, InterruptedException, IllegalArgumentException, ExecutionException, UnsupportedOperationException {
if (sizeExpression == null) {
throw new UnsupportedOperationException("The object hasn't defined the logical size operation.");
}
Expand All @@ -108,52 +102,32 @@ public Value getSize(ObjectReference thisObject, ThreadReference thread, IEvalua
* Return the logical value of the specified thisObject.
*/
public Value getValue(ObjectReference thisObject, ThreadReference thread, IEvaluationProvider evaluationEngine)
throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException, InvocationException,
InterruptedException, ExecutionException {
throws CancellationException, IllegalArgumentException, InterruptedException, ExecutionException {
return getValue(thisObject, valueExpression, thread, evaluationEngine);
}

private static Value getValue(ObjectReference thisObject, LogicalStructureExpression expression, ThreadReference thread,
IEvaluationProvider evaluationEngine)
throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException, InvocationException,
InterruptedException, ExecutionException {
IEvaluationProvider evaluationEngine) throws CancellationException, IllegalArgumentException, InterruptedException, ExecutionException {
if (expression.type == LogicalStructureExpressionType.METHOD) {
return getValueByMethod(thisObject, expression.value, thread);
if (expression.value == null || expression.value.length < 2) {
throw new IllegalArgumentException("The method expression should contain at least methodName and methodSignature!");
}
return evaluationEngine.invokeMethod(thisObject, expression.value[0], expression.value[1], null, thread, false).get();
} else if (expression.type == LogicalStructureExpressionType.FIELD) {
return getValueByField(thisObject, expression.value, thread);
if (expression.value == null || expression.value.length < 1) {
throw new IllegalArgumentException("The field expression should contain the field name!");
}
return getValueByField(thisObject, expression.value[0], thread);
} else {
return evaluationEngine.evaluate(expression.value, thisObject, thread).get();
}
}

private static Value getValueByMethod(ObjectReference thisObject, String methodName, ThreadReference thread)
throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException, InvocationException {
List<Method> methods = thisObject.referenceType().allMethods();
Method targetMethod = null;
for (Method method : methods) {
if (Objects.equals(method.name(), methodName) && method.argumentTypeNames().isEmpty()) {
targetMethod = method;
break;
if (expression.value == null || expression.value.length < 1) {
throw new IllegalArgumentException("The evaluation expression should contain a valid expression statement!");
}
return evaluationEngine.evaluate(expression.value[0], thisObject, thread).get();
}

if (targetMethod == null) {
return null;
}

return thisObject.invokeMethod(thread, targetMethod, Collections.EMPTY_LIST, ObjectReference.INVOKE_SINGLE_THREADED);
}

private static Value getValueByField(ObjectReference thisObject, String filedName, ThreadReference thread) {
List<Field> fields = thisObject.referenceType().allFields();
Field targetField = null;
for (Field field : fields) {
if (Objects.equals(field.name(), filedName)) {
targetField = field;
break;
}
}

private static Value getValueByField(ObjectReference thisObject, String fieldName, ThreadReference thread) {
Field targetField = thisObject.referenceType().fieldByName(fieldName);
if (targetField == null) {
return null;
}
Expand All @@ -175,20 +149,19 @@ public String getName() {
}

public Value getValue(ObjectReference thisObject, ThreadReference thread, IEvaluationProvider evaluationEngine)
throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException, InvocationException,
InterruptedException, ExecutionException {
throws CancellationException, IllegalArgumentException, InterruptedException, ExecutionException {
return JavaLogicalStructure.getValue(thisObject, valueExpression, thread, evaluationEngine);
}
}

public static class LogicalStructureExpression {
public LogicalStructureExpressionType type;
public String value;
public String[] value;

/**
* Constructor.
*/
public LogicalStructureExpression(LogicalStructureExpressionType type, String value) {
public LogicalStructureExpression(LogicalStructureExpressionType type, String[] value) {
this.type = type;
this.value = value;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,13 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;

import com.microsoft.java.debug.core.adapter.IEvaluationProvider;
import com.microsoft.java.debug.core.adapter.variables.JavaLogicalStructure.LogicalStructureExpression;
import com.microsoft.java.debug.core.adapter.variables.JavaLogicalStructure.LogicalStructureExpressionType;
import com.microsoft.java.debug.core.adapter.variables.JavaLogicalStructure.LogicalVariable;
import com.sun.jdi.ClassNotLoadedException;
import com.sun.jdi.IncompatibleThreadStateException;
import com.sun.jdi.InvalidTypeException;
import com.sun.jdi.InvocationException;
import com.sun.jdi.ObjectReference;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.Value;
Expand All @@ -33,16 +30,17 @@ public class JavaLogicalStructureManager {

static {
supportedLogicalStructures.add(new JavaLogicalStructure("java.util.Map",
new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, "entrySet"),
new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, "size"),
new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, new String[] {"entrySet", "()Ljava/util/Set;"}),
new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, new String[] {"size", "()I"}),
new LogicalVariable[0]));
supportedLogicalStructures.add(new JavaLogicalStructure("java.util.Map$Entry", null, null, new LogicalVariable[] {
new LogicalVariable("key", new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, "getKey")),
new LogicalVariable("value", new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, "getValue"))
new LogicalVariable("key", new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, new String[] {"getKey", "()Ljava/lang/Object;"})),
new LogicalVariable("value",
new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, new String[] {"getValue", "()Ljava/lang/Object;"}))
}));
supportedLogicalStructures.add(new JavaLogicalStructure("java.util.Collection",
new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, "toArray"),
new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, "size"),
new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, new String[] {"toArray", "()[Ljava/lang/Object;"}),
new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, new String[] {"size", "()I"}),
new LogicalVariable[0]));
}

Expand Down Expand Up @@ -71,8 +69,7 @@ public static boolean isIndexedVariable(ObjectReference obj) {
* Return the logical size if the specified Object has defined the logical size.
*/
public static Value getLogicalSize(ObjectReference thisObject, ThreadReference thread, IEvaluationProvider evaluationEngine)
throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException, InvocationException,
InterruptedException, ExecutionException, UnsupportedOperationException {
throws CancellationException, InterruptedException, IllegalArgumentException, ExecutionException, UnsupportedOperationException {
JavaLogicalStructure structure = getLogicalStructure(thisObject);
if (structure == null) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
Expand Down Expand Up @@ -41,11 +42,13 @@
import org.eclipse.jdt.debug.core.IJavaObject;
import org.eclipse.jdt.debug.core.IJavaStackFrame;
import org.eclipse.jdt.debug.core.IJavaThread;
import org.eclipse.jdt.debug.core.IJavaValue;
import org.eclipse.jdt.debug.eval.ICompiledExpression;
import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget;
import org.eclipse.jdt.internal.debug.core.model.JDIObjectValue;
import org.eclipse.jdt.internal.debug.core.model.JDIStackFrame;
import org.eclipse.jdt.internal.debug.core.model.JDIThread;
import org.eclipse.jdt.internal.debug.core.model.JDIValue;
import org.eclipse.jdt.internal.debug.eval.ast.engine.ASTEvaluationEngine;
import org.eclipse.jdt.internal.launching.JavaSourceLookupDirector;

Expand Down Expand Up @@ -191,6 +194,34 @@ private CompletableFuture<Value> evaluate(String expression, ThreadReference thr
}
}

@Override
public CompletableFuture<Value> invokeMethod(ObjectReference thisContext, String methodName, String methodSignature,
Value[] args, ThreadReference thread, boolean invokeSuper) {
CompletableFuture<Value> completableFuture = new CompletableFuture<>();
try {
ensureDebugTarget(thisContext.virtualMachine(), thisContext.type().name());
JDIThread jdiThread = getMockJDIThread(thread);
JDIObjectValue jdiObject = new JDIObjectValue(debugTarget, thisContext);
List<IJavaValue> arguments = null;
if (args == null) {
arguments = Collections.EMPTY_LIST;
} else {
arguments = new ArrayList<>(args.length);
for (Value arg : args) {
arguments.add(new JDIValue(debugTarget, arg));
}
}
IJavaValue javaValue = jdiObject.sendMessage(methodName, methodSignature, arguments.toArray(new IJavaValue[0]), jdiThread, invokeSuper);
// we need to read fValue from the result Value instance implements by JDT
Value value = (Value) FieldUtils.readField(javaValue, "fValue", true);
completableFuture.complete(value);
return completableFuture;
} catch (Exception ex) {
completableFuture.completeExceptionally(ex);
return completableFuture;
}
}

private String logMessageToExpression(String logMessage) {
final String LOGMESSAGE_VARIABLE_REGEXP = "\\{(.*?)\\}";
String format = logMessage.replaceAll(LOGMESSAGE_VARIABLE_REGEXP, "%s");
Expand Down Expand Up @@ -348,7 +379,12 @@ private void internalEvaluate(ASTEvaluationEngine engine, ICompiledExpression co

@Override
public boolean isInEvaluation(ThreadReference thread) {
return debugTarget != null && getMockJDIThread(thread).isPerformingEvaluation();
if (debugTarget == null) {
return false;
}

JDIThread jdiThread = getMockJDIThread(thread);
return jdiThread != null && (jdiThread.isPerformingEvaluation() || jdiThread.isInvokingMethod());
}

@Override
Expand Down