Skip to content

Commit f921a67

Browse files
Fix variable perf issue & logical structure doesn't work with JDK 11 (#268)
* Fix variable perf issue & logical structure doesn't work with JDK 11 Signed-off-by: Jinbo Wang <[email protected]> * Address review comments Signed-off-by: Jinbo Wang <[email protected]> * Refactor the logical structure evaluation code Signed-off-by: Jinbo Wang <[email protected]>
1 parent 81bdeb2 commit f921a67

File tree

3 files changed

+180
-53
lines changed

3 files changed

+180
-53
lines changed

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/VariablesRequestHandler.java

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@
2525
import java.util.logging.Logger;
2626
import java.util.stream.Collectors;
2727

28-
import org.apache.commons.lang3.StringUtils;
29-
3028
import com.microsoft.java.debug.core.Configuration;
3129
import com.microsoft.java.debug.core.DebugSettings;
3230
import com.microsoft.java.debug.core.adapter.AdapterUtils;
@@ -37,6 +35,7 @@
3735
import com.microsoft.java.debug.core.adapter.IStackFrameManager;
3836
import com.microsoft.java.debug.core.adapter.variables.IVariableFormatter;
3937
import com.microsoft.java.debug.core.adapter.variables.JavaLogicalStructure;
38+
import com.microsoft.java.debug.core.adapter.variables.JavaLogicalStructure.LogicalStructureExpression;
4039
import com.microsoft.java.debug.core.adapter.variables.JavaLogicalStructure.LogicalVariable;
4140
import com.microsoft.java.debug.core.adapter.variables.JavaLogicalStructureManager;
4241
import com.microsoft.java.debug.core.adapter.variables.StackFrameReference;
@@ -51,9 +50,13 @@
5150
import com.microsoft.java.debug.core.protocol.Types;
5251
import com.sun.jdi.AbsentInformationException;
5352
import com.sun.jdi.ArrayReference;
53+
import com.sun.jdi.ClassNotLoadedException;
54+
import com.sun.jdi.IncompatibleThreadStateException;
5455
import com.sun.jdi.IntegerValue;
5556
import com.sun.jdi.InternalException;
5657
import com.sun.jdi.InvalidStackFrameException;
58+
import com.sun.jdi.InvalidTypeException;
59+
import com.sun.jdi.InvocationException;
5760
import com.sun.jdi.ObjectReference;
5861
import com.sun.jdi.StackFrame;
5962
import com.sun.jdi.Type;
@@ -121,35 +124,38 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
121124
} else {
122125
try {
123126
ObjectReference containerObj = (ObjectReference) containerNode.getProxiedVariable();
124-
if (DebugSettings.getCurrent().showLogicalStructure) {
127+
IEvaluationProvider evaluationEngine = context.getProvider(IEvaluationProvider.class);
128+
if (DebugSettings.getCurrent().showLogicalStructure && evaluationEngine != null) {
125129
JavaLogicalStructure logicalStructure = JavaLogicalStructureManager.getLogicalStructure(containerObj);
126-
IEvaluationProvider evaluationEngine = context.getProvider(IEvaluationProvider.class);
127-
if (logicalStructure != null && evaluationEngine != null) {
128-
String expression = logicalStructure.getValue();
130+
while (logicalStructure != null) {
131+
LogicalStructureExpression valueExpression = logicalStructure.getValueExpression();
129132
LogicalVariable[] logicalVariables = logicalStructure.getVariables();
130133
try {
131-
if (StringUtils.isNotEmpty(expression)) {
132-
Value value = evaluationEngine.evaluate(expression, containerObj,
133-
containerNode.getThread()).get();
134+
if (valueExpression != null) {
135+
Value value = logicalStructure.getValue(containerObj, containerNode.getThread(), evaluationEngine);
134136
if (value instanceof ObjectReference) {
135137
containerObj = (ObjectReference) value;
138+
logicalStructure = JavaLogicalStructureManager.getLogicalStructure(containerObj);
139+
continue;
136140
} else {
137141
childrenList = Arrays.asList(new Variable("logical structure", value));
138142
}
139143
} else if (logicalVariables != null && logicalVariables.length > 0) {
140144
for (LogicalVariable logicalVariable : logicalVariables) {
141145
String name = logicalVariable.getName();
142-
Value value = evaluationEngine.evaluate(logicalVariable.getValue(), containerObj,
143-
containerNode.getThread()).get();
146+
Value value = logicalVariable.getValue(containerObj, containerNode.getThread(), evaluationEngine);
144147
childrenList.add(new Variable(name, value));
145148
}
146149
}
147-
} catch (InterruptedException | ExecutionException e) {
150+
} catch (InterruptedException | ExecutionException | InvalidTypeException
151+
| ClassNotLoadedException | IncompatibleThreadStateException | InvocationException e) {
148152
logger.log(Level.WARNING,
149153
String.format("Failed to get the logical structure for the type %s, fall back to the Object view.",
150154
containerObj.type().name()),
151155
e);
152156
}
157+
158+
logicalStructure = null;
153159
}
154160
}
155161

@@ -211,24 +217,22 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
211217
int indexedVariables = -1;
212218
if (value instanceof ArrayReference) {
213219
indexedVariables = ((ArrayReference) value).length();
214-
} else if (DebugSettings.getCurrent().showLogicalStructure
215-
&& value instanceof ObjectReference
220+
} else if (value instanceof ObjectReference && DebugSettings.getCurrent().showLogicalStructure
221+
&& context.getProvider(IEvaluationProvider.class) != null
216222
&& JavaLogicalStructureManager.isIndexedVariable((ObjectReference) value)) {
217-
String logicalSizeExpression = JavaLogicalStructureManager.getLogicalSize((ObjectReference) value);
218223
IEvaluationProvider evaluationEngine = context.getProvider(IEvaluationProvider.class);
219-
if (StringUtils.isNotBlank(logicalSizeExpression) && evaluationEngine != null) {
220-
try {
221-
Value size = evaluationEngine.evaluate(logicalSizeExpression, (ObjectReference) value,
222-
containerNode.getThread()).get();
223-
if (size instanceof IntegerValue) {
224-
indexedVariables = ((IntegerValue) size).value();
225-
}
226-
} catch (InterruptedException | ExecutionException e) {
227-
logger.log(Level.INFO,
228-
String.format("Failed to get the logical size for the type %s.", value.type().name()), e);
224+
try {
225+
Value sizeValue = JavaLogicalStructureManager.getLogicalSize((ObjectReference) value, containerNode.getThread(), evaluationEngine);
226+
if (sizeValue != null && sizeValue instanceof IntegerValue) {
227+
indexedVariables = ((IntegerValue) sizeValue).value();
229228
}
229+
} catch (InvalidTypeException | ClassNotLoadedException | IncompatibleThreadStateException
230+
| InvocationException | InterruptedException | ExecutionException | UnsupportedOperationException e) {
231+
logger.log(Level.INFO,
232+
String.format("Failed to get the logical size for the type %s.", value.type().name()), e);
230233
}
231234
}
235+
232236
int referenceId = 0;
233237
if (indexedVariables > 0 || (indexedVariables < 0 && VariableUtils.hasChildren(value, showStaticVariables))) {
234238
VariableProxy varProxy = new VariableProxy(containerNode.getThread(), containerNode.getScope(), value);

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/variables/JavaLogicalStructure.java

Lines changed: 115 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,42 +11,52 @@
1111

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

14+
import java.util.Collections;
1415
import java.util.List;
1516
import java.util.Objects;
17+
import java.util.concurrent.ExecutionException;
1618

17-
import org.apache.commons.lang3.StringUtils;
18-
19+
import com.microsoft.java.debug.core.adapter.IEvaluationProvider;
20+
import com.sun.jdi.ClassNotLoadedException;
1921
import com.sun.jdi.ClassType;
22+
import com.sun.jdi.Field;
23+
import com.sun.jdi.IncompatibleThreadStateException;
2024
import com.sun.jdi.InterfaceType;
25+
import com.sun.jdi.InvalidTypeException;
26+
import com.sun.jdi.InvocationException;
27+
import com.sun.jdi.Method;
2128
import com.sun.jdi.ObjectReference;
29+
import com.sun.jdi.ThreadReference;
2230
import com.sun.jdi.Type;
31+
import com.sun.jdi.Value;
2332

2433
public class JavaLogicalStructure {
2534
private final String type;
26-
private final String value;
27-
private final String size;
35+
private final LogicalStructureExpression valueExpression;
36+
private final LogicalStructureExpression sizeExpression;
2837
private final LogicalVariable[] variables;
2938

3039
/**
3140
* Constructor.
3241
*/
33-
public JavaLogicalStructure(String type, String value, String size, LogicalVariable[] variables) {
34-
this.value = value;
42+
public JavaLogicalStructure(String type, LogicalStructureExpression valueExpression, LogicalStructureExpression sizeExpression,
43+
LogicalVariable[] variables) {
44+
this.valueExpression = valueExpression;
3545
this.type = type;
36-
this.size = size;
46+
this.sizeExpression = sizeExpression;
3747
this.variables = variables;
3848
}
3949

40-
public String getValue() {
41-
return value;
42-
}
43-
4450
public String getType() {
4551
return type;
4652
}
4753

48-
public String getSize() {
49-
return size;
54+
public LogicalStructureExpression getValueExpression() {
55+
return valueExpression;
56+
}
57+
58+
public LogicalStructureExpression getSizeExpression() {
59+
return sizeExpression;
5060
}
5161

5262
public LogicalVariable[] getVariables() {
@@ -81,25 +91,110 @@ public boolean providesLogicalStructure(ObjectReference obj) {
8191
return false;
8292
}
8393

84-
public boolean isIndexedVariable() {
85-
return StringUtils.isNotBlank(size);
94+
/**
95+
* Return the logical size of the specified thisObject.
96+
*/
97+
public Value getSize(ObjectReference thisObject, ThreadReference thread, IEvaluationProvider evaluationEngine)
98+
throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException, InvocationException,
99+
InterruptedException, ExecutionException, UnsupportedOperationException {
100+
if (sizeExpression == null) {
101+
throw new UnsupportedOperationException("The object hasn't defined the logical size operation.");
102+
}
103+
104+
return getValue(thisObject, sizeExpression, thread, evaluationEngine);
105+
}
106+
107+
/**
108+
* Return the logical value of the specified thisObject.
109+
*/
110+
public Value getValue(ObjectReference thisObject, ThreadReference thread, IEvaluationProvider evaluationEngine)
111+
throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException, InvocationException,
112+
InterruptedException, ExecutionException {
113+
return getValue(thisObject, valueExpression, thread, evaluationEngine);
114+
}
115+
116+
private static Value getValue(ObjectReference thisObject, LogicalStructureExpression expression, ThreadReference thread,
117+
IEvaluationProvider evaluationEngine)
118+
throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException, InvocationException,
119+
InterruptedException, ExecutionException {
120+
if (expression.type == LogicalStructureExpressionType.METHOD) {
121+
return getValueByMethod(thisObject, expression.value, thread);
122+
} else if (expression.type == LogicalStructureExpressionType.FIELD) {
123+
return getValueByField(thisObject, expression.value, thread);
124+
} 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;
137+
}
138+
}
139+
140+
if (targetMethod == null) {
141+
return null;
142+
}
143+
144+
return thisObject.invokeMethod(thread, targetMethod, Collections.EMPTY_LIST, ObjectReference.INVOKE_SINGLE_THREADED);
145+
}
146+
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+
157+
if (targetField == null) {
158+
return null;
159+
}
160+
161+
return thisObject.getValue(targetField);
86162
}
87163

88164
public static class LogicalVariable {
89165
private final String name;
90-
private final String value;
166+
private final LogicalStructureExpression valueExpression;
91167

92-
public LogicalVariable(String name, String value) {
168+
public LogicalVariable(String name, LogicalStructureExpression valueExpression) {
93169
this.name = name;
94-
this.value = value;
170+
this.valueExpression = valueExpression;
95171
}
96172

97173
public String getName() {
98174
return name;
99175
}
100176

101-
public String getValue() {
102-
return value;
177+
public Value getValue(ObjectReference thisObject, ThreadReference thread, IEvaluationProvider evaluationEngine)
178+
throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException, InvocationException,
179+
InterruptedException, ExecutionException {
180+
return JavaLogicalStructure.getValue(thisObject, valueExpression, thread, evaluationEngine);
103181
}
104182
}
183+
184+
public static class LogicalStructureExpression {
185+
public LogicalStructureExpressionType type;
186+
public String value;
187+
188+
/**
189+
* Constructor.
190+
*/
191+
public LogicalStructureExpression(LogicalStructureExpressionType type, String value) {
192+
this.type = type;
193+
this.value = value;
194+
}
195+
}
196+
197+
public static enum LogicalStructureExpressionType {
198+
FIELD, METHOD, EVALUATION_SNIPPET
199+
}
105200
}

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/variables/JavaLogicalStructureManager.java

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,36 @@
1414
import java.util.ArrayList;
1515
import java.util.Collections;
1616
import java.util.List;
17+
import java.util.concurrent.ExecutionException;
1718

19+
import com.microsoft.java.debug.core.adapter.IEvaluationProvider;
20+
import com.microsoft.java.debug.core.adapter.variables.JavaLogicalStructure.LogicalStructureExpression;
21+
import com.microsoft.java.debug.core.adapter.variables.JavaLogicalStructure.LogicalStructureExpressionType;
1822
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;
1927
import com.sun.jdi.ObjectReference;
28+
import com.sun.jdi.ThreadReference;
29+
import com.sun.jdi.Value;
2030

2131
public class JavaLogicalStructureManager {
2232
private static final List<JavaLogicalStructure> supportedLogicalStructures = Collections.synchronizedList(new ArrayList<>());
2333

2434
static {
25-
supportedLogicalStructures.add(new JavaLogicalStructure("java.util.Map", "return entrySet().toArray();", "return size();", new LogicalVariable[0]));
35+
supportedLogicalStructures.add(new JavaLogicalStructure("java.util.Map",
36+
new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, "entrySet"),
37+
new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, "size"),
38+
new LogicalVariable[0]));
2639
supportedLogicalStructures.add(new JavaLogicalStructure("java.util.Map$Entry", null, null, new LogicalVariable[] {
27-
new LogicalVariable("key", "return getKey();"),
28-
new LogicalVariable("value", "return getValue();")
40+
new LogicalVariable("key", new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, "getKey")),
41+
new LogicalVariable("value", new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, "getValue"))
2942
}));
30-
supportedLogicalStructures.add(new JavaLogicalStructure("java.util.Collection", "return toArray();", "return size();", new LogicalVariable[0]));
43+
supportedLogicalStructures.add(new JavaLogicalStructure("java.util.Collection",
44+
new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, "toArray"),
45+
new LogicalStructureExpression(LogicalStructureExpressionType.METHOD, "size"),
46+
new LogicalVariable[0]));
3147
}
3248

3349
/**
@@ -43,13 +59,25 @@ public static JavaLogicalStructure getLogicalStructure(ObjectReference obj) {
4359
return null;
4460
}
4561

62+
/**
63+
* Return true if the specified Object has defined the logical size.
64+
*/
4665
public static boolean isIndexedVariable(ObjectReference obj) {
4766
JavaLogicalStructure structure = getLogicalStructure(obj);
48-
return structure != null && structure.isIndexedVariable();
67+
return structure != null && structure.getSizeExpression() != null;
4968
}
5069

51-
public static String getLogicalSize(ObjectReference obj) {
52-
JavaLogicalStructure structure = getLogicalStructure(obj);
53-
return structure == null ? null : structure.getSize();
70+
/**
71+
* Return the logical size if the specified Object has defined the logical size.
72+
*/
73+
public static Value getLogicalSize(ObjectReference thisObject, ThreadReference thread, IEvaluationProvider evaluationEngine)
74+
throws InvalidTypeException, ClassNotLoadedException, IncompatibleThreadStateException, InvocationException,
75+
InterruptedException, ExecutionException, UnsupportedOperationException {
76+
JavaLogicalStructure structure = getLogicalStructure(thisObject);
77+
if (structure == null) {
78+
return null;
79+
}
80+
81+
return structure.getSize(thisObject, thread, evaluationEngine);
5482
}
5583
}

0 commit comments

Comments
 (0)