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
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017-2019 Microsoft Corporation and others.
* Copyright (c) 2017-2020 Microsoft Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
Expand Down Expand Up @@ -41,6 +41,7 @@ public final class DebugSettings {
public StepFilters stepFilters = new StepFilters();
public ClassFilters exceptionFilters = new ClassFilters();
public boolean exceptionFiltersUpdated = false;
public int limitOfVariablesPerJdwpRequest = 100;

public static DebugSettings getCurrent() {
return current;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017-2019 Microsoft Corporation and others.
* Copyright (c) 2017-2020 Microsoft Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
Expand Down Expand Up @@ -32,6 +32,7 @@
import com.microsoft.java.debug.core.adapter.IDebugRequestHandler;
import com.microsoft.java.debug.core.adapter.IEvaluationProvider;
import com.microsoft.java.debug.core.adapter.variables.IVariableFormatter;
import com.microsoft.java.debug.core.adapter.variables.JavaLogicalStructure;
import com.microsoft.java.debug.core.adapter.variables.JavaLogicalStructureManager;
import com.microsoft.java.debug.core.adapter.variables.StackFrameReference;
import com.microsoft.java.debug.core.adapter.variables.VariableDetailUtils;
Expand Down Expand Up @@ -93,13 +94,14 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
Value sizeValue = null;
if (value instanceof ArrayReference) {
indexedVariables = ((ArrayReference) value).length();
} else if (value instanceof ObjectReference && DebugSettings.getCurrent().showLogicalStructure
&& engine != null
&& JavaLogicalStructureManager.isIndexedVariable((ObjectReference) value)) {
} else if (value instanceof ObjectReference && DebugSettings.getCurrent().showLogicalStructure && engine != null) {
try {
sizeValue = JavaLogicalStructureManager.getLogicalSize((ObjectReference) value, stackFrameReference.getThread(), engine);
if (sizeValue != null && sizeValue instanceof IntegerValue) {
indexedVariables = ((IntegerValue) sizeValue).value();
JavaLogicalStructure structure = JavaLogicalStructureManager.getLogicalStructure((ObjectReference) value);
if (structure != null && structure.getSizeExpression() != null) {
sizeValue = structure.getSize((ObjectReference) value, stackFrameReference.getThread(), engine);
if (sizeValue != null && sizeValue instanceof IntegerValue) {
indexedVariables = ((IntegerValue) sizeValue).value();
}
}
} catch (CancellationException | IllegalArgumentException | InterruptedException
| ExecutionException | UnsupportedOperationException e) {
Expand All @@ -108,7 +110,7 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
}
}
int referenceId = 0;
if (indexedVariables > 0 || (indexedVariables < 0 && VariableUtils.hasChildren(value, showStaticVariables))) {
if (indexedVariables > 0 || (indexedVariables < 0 && value instanceof ObjectReference)) {
referenceId = context.getRecyclableIdPool().addObject(threadId, varProxy);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,13 +232,14 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
Value sizeValue = null;
if (value instanceof ArrayReference) {
indexedVariables = ((ArrayReference) value).length();
} else if (value instanceof ObjectReference && DebugSettings.getCurrent().showLogicalStructure
&& evaluationEngine != null
&& JavaLogicalStructureManager.isIndexedVariable((ObjectReference) value)) {
} else if (value instanceof ObjectReference && DebugSettings.getCurrent().showLogicalStructure && evaluationEngine != null) {
try {
sizeValue = JavaLogicalStructureManager.getLogicalSize((ObjectReference) value, containerNode.getThread(), evaluationEngine);
if (sizeValue != null && sizeValue instanceof IntegerValue) {
indexedVariables = ((IntegerValue) sizeValue).value();
JavaLogicalStructure structure = JavaLogicalStructureManager.getLogicalStructure((ObjectReference) value);
if (structure != null && structure.getSizeExpression() != null) {
sizeValue = structure.getSize((ObjectReference) value, containerNode.getThread(), evaluationEngine);
if (sizeValue != null && sizeValue instanceof IntegerValue) {
indexedVariables = ((IntegerValue) sizeValue).value();
}
}
} catch (CancellationException | IllegalArgumentException | InterruptedException | ExecutionException | UnsupportedOperationException e) {
logger.log(Level.INFO,
Expand Down Expand Up @@ -267,7 +268,7 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
}

int referenceId = 0;
if (indexedVariables > 0 || (indexedVariables < 0 && VariableUtils.hasChildren(value, showStaticVariables))) {
if (indexedVariables > 0 || (indexedVariables < 0 && value instanceof ObjectReference)) {
VariableProxy varProxy = new VariableProxy(containerNode.getThread(), containerNode.getScope(), value, containerNode, evaluateName);
referenceId = context.getRecyclableIdPool().addObject(containerNode.getThreadId(), varProxy);
varProxy.setIndexedVariable(indexedVariables >= 0);
Expand All @@ -290,6 +291,11 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
}
list.add(typedVariables);
}

if (list.isEmpty() && containerNode.getProxiedVariable() instanceof ObjectReference) {
list.add(new Types.Variable("Class has no fields", "", null, 0, null));
}

response.body = new Responses.VariablesResponseBody(list);

return CompletableFuture.completedFuture(response);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ public class JavaLogicalStructure {
private final LogicalStructureExpression valueExpression;
private final LogicalStructureExpression sizeExpression;
private final LogicalVariable[] variables;
// Indicates whether the specified type is an interface.
private final boolean isInterface;

/**
* Constructor.
Expand All @@ -47,9 +49,15 @@ public JavaLogicalStructure(String type, LogicalStructureExpression valueExpress
*/
public JavaLogicalStructure(String type, String fullyQualifiedName, LogicalStructureExpression valueExpression, LogicalStructureExpression sizeExpression,
LogicalVariable[] variables) {
this(type, type, true, valueExpression, sizeExpression, variables);
}

public JavaLogicalStructure(String type, String fullyQualifiedName, boolean isInterface, LogicalStructureExpression valueExpression,
LogicalStructureExpression sizeExpression, LogicalVariable[] variables) {
this.valueExpression = valueExpression;
this.type = type;
this.fullyQualifiedName = fullyQualifiedName;
this.isInterface = isInterface;
this.sizeExpression = sizeExpression;
this.variables = variables;
}
Expand Down Expand Up @@ -84,18 +92,24 @@ public boolean providesLogicalStructure(ObjectReference obj) {
}

ClassType classType = (ClassType) variableType;
while (classType != null) {
if (Objects.equals(type, classType.name())) {
return true;
}

classType = classType.superclass();
if (Objects.equals(type, classType.name())) {
return true;
}

List<InterfaceType> interfaceTypes = ((ClassType) variableType).allInterfaces();
for (InterfaceType interfaceType : interfaceTypes) {
if (Objects.equals(type, interfaceType.name())) {
return true;
if (isInterface) {
List<InterfaceType> interfaceTypes = ((ClassType) variableType).allInterfaces();
for (InterfaceType interfaceType : interfaceTypes) {
if (Objects.equals(type, interfaceType.name())) {
return true;
}
}
} else {
while (classType != null) {
if (Objects.equals(type, classType.name())) {
return true;
}

classType = classType.superclass();
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017-2019 Microsoft Corporation and others.
* Copyright (c) 2017-2020 Microsoft Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
Expand All @@ -15,6 +15,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -55,12 +56,11 @@ public static boolean hasChildren(Value value, boolean includeStatic) {
if (value == null || !(value instanceof ObjectReference)) {
return false;
}
Type type = value.type();
ReferenceType type = ((ObjectReference) value).referenceType();
if (type instanceof ArrayType) {
return ((ArrayReference) value).length() > 0;
}
return value.type() instanceof ReferenceType && ((ReferenceType) type).allFields().stream()
.filter(t -> includeStatic || !t.isStatic()).toArray().length > 0;
return type.allFields().stream().anyMatch(t -> includeStatic || !t.isStatic());
}

/**
Expand All @@ -74,7 +74,7 @@ public static boolean hasChildren(Value value, boolean includeStatic) {
*/
public static List<Variable> listFieldVariables(ObjectReference obj, boolean includeStatic) throws AbsentInformationException {
List<Variable> res = new ArrayList<>();
Type type = obj.type();
ReferenceType type = obj.referenceType();
if (type instanceof ArrayType) {
int arrayIndex = 0;
boolean isUnboundedArrayType = Objects.equals(type.signature(), "[Ljava/lang/Object;");
Expand All @@ -85,7 +85,7 @@ public static List<Variable> listFieldVariables(ObjectReference obj, boolean inc
}
return res;
}
List<Field> fields = obj.referenceType().allFields().stream().filter(t -> includeStatic || !t.isStatic())
List<Field> fields = type.allFields().stream().filter(t -> includeStatic || !t.isStatic())
.sorted((a, b) -> {
try {
boolean v1isStatic = a.isStatic();
Expand All @@ -102,11 +102,16 @@ public static List<Variable> listFieldVariables(ObjectReference obj, boolean inc
return -1;
}
}).collect(Collectors.toList());
fields.forEach(f -> {
Variable var = new Variable(f.name(), obj.getValue(f));
var.field = f;
res.add(var);
});

bulkFetchValues(fields, DebugSettings.getCurrent().limitOfVariablesPerJdwpRequest, (currentPage -> {
Map<Field, Value> fieldValues = obj.getValues(currentPage);
for (Field currentField : currentPage) {
Variable var = new Variable(currentField.name(), fieldValues.get(currentField));
var.field = currentField;
res.add(var);
}
}));

return res;
}

Expand Down Expand Up @@ -155,13 +160,18 @@ public static List<Variable> listLocalVariables(StackFrame stackFrame) throws Ab
return res;
}
try {
List<LocalVariable> localVariables = stackFrame.visibleVariables();
Map<LocalVariable, Value> values = stackFrame.getValues(localVariables);
for (LocalVariable localVariable : localVariables) {
Variable var = new Variable(localVariable.name(), values.get(localVariable));
var.local = localVariable;
res.add(var);
}
List<LocalVariable> visibleVariables = stackFrame.visibleVariables();
// When using the API StackFrame.getValues() to batch fetch the variable values, the JDI
// probably throws timeout exception if the variables to be passed at one time are large.
// So use paging to fetch the values in chunks.
bulkFetchValues(visibleVariables, DebugSettings.getCurrent().limitOfVariablesPerJdwpRequest, (currentPage -> {
Map<LocalVariable, Value> values = stackFrame.getValues(currentPage);
for (LocalVariable localVariable : currentPage) {
Variable var = new Variable(localVariable.name(), values.get(localVariable));
var.local = localVariable;
res.add(var);
}
}));
} catch (AbsentInformationException ex) {
// avoid listing variable on native methods

Expand Down Expand Up @@ -228,11 +238,16 @@ public static Variable getThisVariable(StackFrame stackFrame) {
public static List<Variable> listStaticVariables(StackFrame stackFrame) {
List<Variable> res = new ArrayList<>();
ReferenceType type = stackFrame.location().declaringType();
type.allFields().stream().filter(TypeComponent::isStatic).forEach(field -> {
Variable staticVar = new Variable(field.name(), type.getValue(field));
staticVar.field = field;
res.add(staticVar);
});
List<Field> fields = type.allFields().stream().filter(TypeComponent::isStatic).collect(Collectors.toList());
bulkFetchValues(fields, DebugSettings.getCurrent().limitOfVariablesPerJdwpRequest, (currentPage -> {
Map<Field, Value> fieldValues = type.getValues(currentPage);
for (Field currentField : currentPage) {
Variable var = new Variable(currentField.name(), fieldValues.get(currentField));
var.field = currentField;
res.add(var);
}
}));

return res;
}

Expand Down Expand Up @@ -289,6 +304,18 @@ public static String getEvaluateName(String name, String containerName, boolean
return String.format("%s.%s", containerName, name);
}

private static <T> void bulkFetchValues(List<T> elements, int numberPerPage, Consumer<List<T>> consumer) {
int size = elements.size();
numberPerPage = numberPerPage < 1 ? 1 : numberPerPage;
int page = size / numberPerPage + Math.min(size % numberPerPage, 1);
for (int i = 0; i < page; i++) {
int pageStart = i * numberPerPage;
int pageEnd = Math.min(pageStart + numberPerPage, size);
List<T> currentPage = elements.subList(pageStart, pageEnd);
consumer.accept(currentPage);
}
}

private VariableUtils() {

}
Expand Down