Fix bugs in debugger

This commit is contained in:
Alexey Andreev 2018-12-19 19:28:35 +03:00
parent 75295f50e5
commit a4b61bac19
6 changed files with 79 additions and 47 deletions

View File

@ -46,6 +46,13 @@ public class Optimizer {
boolean[] preservedVars = new boolean[stats.writes.length]; boolean[] preservedVars = new boolean[stats.writes.length];
BreakEliminator breakEliminator = new BreakEliminator(); BreakEliminator breakEliminator = new BreakEliminator();
breakEliminator.eliminate(method.getBody()); breakEliminator.eliminate(method.getBody());
if (friendlyToDebugger) {
for (int i = 0; i < method.getVariables().size(); ++i) {
if (method.getVariables().get(i).getName() != null) {
preservedVars[i] = true;
}
}
}
OptimizingVisitor optimizer = new OptimizingVisitor(preservedVars, stats.writes, stats.reads, OptimizingVisitor optimizer = new OptimizingVisitor(preservedVars, stats.writes, stats.reads,
moveConstants ? stats.constants : new Object[stats.constants.length], friendlyToDebugger); moveConstants ? stats.constants : new Object[stats.constants.length], friendlyToDebugger);
method.getBody().acceptVisitor(optimizer); method.getBody().acceptVisitor(optimizer);

View File

@ -54,9 +54,24 @@ public class Value {
type = jsValue.getClassName().then(className -> { type = jsValue.getClassName().then(className -> {
if (className.startsWith("a/")) { if (className.startsWith("a/")) {
className = className.substring(2); className = className.substring(2);
String origClassName = className;
int degree = 0;
while (className.endsWith("[]")) {
className = className.substring(0, className.length() - 2);
++degree;
}
String javaClassName = debugInformation.getClassNameByJsName(className); String javaClassName = debugInformation.getClassNameByJsName(className);
if (javaClassName != null) { if (javaClassName != null) {
if (degree > 0) {
StringBuilder sb = new StringBuilder(javaClassName);
for (int i = 0; i < degree; ++i) {
sb.append("[]");
}
javaClassName = sb.toString();
}
className = javaClassName; className = javaClassName;
} else {
className = origClassName;
} }
} }
return className; return className;
@ -68,35 +83,42 @@ public class Value {
public Promise<Map<String, Variable>> getProperties() { public Promise<Map<String, Variable>> getProperties() {
if (properties == null) { if (properties == null) {
properties = jsValue.getProperties().thenAsync(jsVariables -> { properties = jsValue.getProperties().thenAsync(jsVariables -> {
return jsValue.getClassName().then(className -> { return getType().thenAsync(className -> {
if (!className.startsWith("@") && className.endsWith("[]") && jsVariables.containsKey("data")) {
return jsVariables.get("data").getValue().getProperties()
.then(arrayData -> fillArray(arrayData));
}
Map<String, Variable> vars = new HashMap<>(); Map<String, Variable> vars = new HashMap<>();
for (Map.Entry<String, ? extends JavaScriptVariable> entry : jsVariables.entrySet()) { for (Map.Entry<String, ? extends JavaScriptVariable> entry : jsVariables.entrySet()) {
JavaScriptVariable jsVar = entry.getValue(); JavaScriptVariable jsVar = entry.getValue();
String name; String name;
if (className.endsWith("[]")) { name = debugger.mapField(className, entry.getKey());
if (entry.getKey().equals("data")) { if (name == null) {
name = entry.getKey(); continue;
} else {
continue;
}
} else if (isNumeric(entry.getKey())) {
name = entry.getKey();
} else {
name = debugger.mapField(className, entry.getKey());
if (name == null) {
continue;
}
} }
Value value = new Value(debugger, debugInformation, jsVar.getValue()); Value value = new Value(debugger, debugInformation, jsVar.getValue());
vars.put(name, new Variable(name, value)); vars.put(name, new Variable(name, value));
} }
return vars; return Promise.of(vars);
}); });
}); });
} }
return properties; return properties;
} }
private Map<String, Variable> fillArray(Map<String, ? extends JavaScriptVariable> jsVariables) {
Map<String, Variable> vars = new HashMap<>();
for (Map.Entry<String, ? extends JavaScriptVariable> entry : jsVariables.entrySet()) {
JavaScriptVariable jsVar = entry.getValue();
if (!isNumeric(entry.getKey())) {
continue;
}
Value value = new Value(debugger, debugInformation, jsVar.getValue());
vars.put(entry.getKey(), new Variable(entry.getKey(), value));
}
return vars;
}
public boolean hasInnerStructure() { public boolean hasInnerStructure() {
if (getType().equals("long")) { if (getType().equals("long")) {
return false; return false;

View File

@ -30,6 +30,8 @@ import org.teavm.model.BasicBlock;
import org.teavm.model.Instruction; import org.teavm.model.Instruction;
import org.teavm.model.Program; import org.teavm.model.Program;
import org.teavm.model.TextLocation; import org.teavm.model.TextLocation;
import org.teavm.model.instructions.EmptyInstruction;
import org.teavm.model.instructions.JumpInstruction;
class LocationGraphBuilder { class LocationGraphBuilder {
private Map<TextLocation, Set<TextLocation>> graphBuilder; private Map<TextLocation, Set<TextLocation>> graphBuilder;
@ -44,7 +46,7 @@ class LocationGraphBuilder {
} }
private void dfs(Graph graph, Program program) { private void dfs(Graph graph, Program program) {
startLocations = new ArrayList<>(Collections.<Set<TextLocation>>nCopies(graph.size(), null)); startLocations = new ArrayList<>(Collections.nCopies(graph.size(), null));
additionalConnections = new ArrayList<>(); additionalConnections = new ArrayList<>();
Deque<Step> stack = new ArrayDeque<>(); Deque<Step> stack = new ArrayDeque<>();
for (int i = 0; i < graph.size(); ++i) { for (int i = 0; i < graph.size(); ++i) {
@ -69,6 +71,9 @@ class LocationGraphBuilder {
TextLocation location = step.location; TextLocation location = step.location;
boolean started = false; boolean started = false;
for (Instruction insn : block) { for (Instruction insn : block) {
if (insn instanceof JumpInstruction || insn instanceof EmptyInstruction) {
continue;
}
if (insn.getLocation() != null) { if (insn.getLocation() != null) {
if (!started) { if (!started) {
step.startLocations.add(insn.getLocation()); step.startLocations.add(insn.getLocation());

View File

@ -36,7 +36,7 @@ import org.teavm.model.instructions.AssignInstruction;
import org.teavm.model.instructions.JumpInstruction; import org.teavm.model.instructions.JumpInstruction;
public class RegisterAllocator { public class RegisterAllocator {
public void allocateRegisters(MethodReader method, Program program) { public void allocateRegisters(MethodReader method, Program program, boolean debuggerFriendly) {
insertPhiArgumentsCopies(program); insertPhiArgumentsCopies(program);
InterferenceGraphBuilder interferenceBuilder = new InterferenceGraphBuilder(); InterferenceGraphBuilder interferenceBuilder = new InterferenceGraphBuilder();
LivenessAnalyzer liveness = new LivenessAnalyzer(); LivenessAnalyzer liveness = new LivenessAnalyzer();
@ -61,7 +61,7 @@ public class RegisterAllocator {
maxClass = Math.max(maxClass, cls + 1); maxClass = Math.max(maxClass, cls + 1);
} }
int[] categories = getVariableCategories(program, method.getReference()); int[] categories = getVariableCategories(program, method.getReference());
String[] names = getVariableNames(program); String[] names = getVariableNames(program, debuggerFriendly);
colorer.colorize(MutableGraphNode.toGraph(interferenceGraph), colors, categories, names); colorer.colorize(MutableGraphNode.toGraph(interferenceGraph), colors, categories, names);
int maxColor = 0; int maxColor = 0;
@ -100,10 +100,13 @@ public class RegisterAllocator {
return categories; return categories;
} }
private String[] getVariableNames(ProgramReader program) { private String[] getVariableNames(ProgramReader program, boolean debuggerFriendly) {
String[] names = new String[program.variableCount()]; String[] names = new String[program.variableCount()];
for (int i = 0; i < names.length; ++i) { for (int i = 0; i < names.length; ++i) {
names[i] = program.variableAt(i).getDebugName(); names[i] = program.variableAt(i).getDebugName();
if (debuggerFriendly && names[i] == null) {
names[i] = "";
}
} }
return names; return names;
} }
@ -231,14 +234,14 @@ public class RegisterAllocator {
} }
} }
private void renameVariables(final Program program, final int[] varMap) { private void renameVariables(Program program, int[] varMap) {
InstructionVariableMapper mapper = new InstructionVariableMapper(var -> InstructionVariableMapper mapper = new InstructionVariableMapper(var ->
program.variableAt(varMap[var.getIndex()])); program.variableAt(varMap[var.getIndex()]));
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i); BasicBlock block = program.basicBlockAt(i);
mapper.apply(block); mapper.apply(block);
} }
String[] originalNames = getVariableNames(program); String[] originalNames = getVariableNames(program, false);
for (int i = 0; i < program.variableCount(); ++i) { for (int i = 0; i < program.variableCount(); ++i) {
program.variableAt(i).setDebugName(null); program.variableAt(i).setDebugName(null);
} }

View File

@ -575,7 +575,8 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
target.afterOptimizations(optimizedProgram, method, classSource); target.afterOptimizations(optimizedProgram, method, classSource);
if (target.requiresRegisterAllocation()) { if (target.requiresRegisterAllocation()) {
RegisterAllocator allocator = new RegisterAllocator(); RegisterAllocator allocator = new RegisterAllocator();
allocator.allocateRegisters(method, optimizedProgram); allocator.allocateRegisters(method, optimizedProgram,
optimizationLevel == TeaVMOptimizationLevel.SIMPLE);
} }
} }

View File

@ -63,32 +63,26 @@ public class TeaVMValue extends XNamedValue {
if (charactersProperty == null) { if (charactersProperty == null) {
return errorString(); return errorString();
} }
return charactersProperty.getValue().getProperties().thenAsync(charsProperties -> { return charactersProperty.getValue().getProperties().thenAsync(dataValueProperties -> {
Variable dataProperty = charsProperties.get("data"); int[] indexes = dataValueProperties.keySet().stream()
if (dataProperty == null) { .filter(t -> isDigits(t))
return errorString(); .mapToInt(Integer::parseInt)
} .toArray();
return dataProperty.getValue().getProperties().thenAsync(dataValueProperties -> { int maxIndex = Math.min(Arrays.stream(indexes).max().orElse(-1) + 1, 256);
int[] indexes = dataValueProperties.keySet().stream() char[] chars = new char[maxIndex];
.filter(t -> isDigits(t)) List<Promise<Void>> promises = new ArrayList<>();
.mapToInt(Integer::parseInt) for (int i = 0; i < maxIndex; ++i) {
.toArray(); Variable charProperty = dataValueProperties.get(Integer.toString(i));
int maxIndex = Math.min(Arrays.stream(indexes).max().orElse(-1) + 1, 256); if (charProperty != null) {
char[] chars = new char[maxIndex]; int index = i;
List<Promise<Void>> promises = new ArrayList<>(); promises.add(charProperty.getValue().getRepresentation().thenVoid(charRepr -> {
for (int i = 0; i < maxIndex; ++i) { if (isDigits(charRepr)) {
Variable charProperty = dataValueProperties.get(Integer.toString(i)); chars[index] = (char) Integer.parseInt(charRepr);
if (charProperty != null) { }
int index = i; }));
promises.add(charProperty.getValue().getRepresentation().thenVoid(charRepr -> {
if (isDigits(charRepr)) {
chars[index] = (char) Integer.parseInt(charRepr);
}
}));
}
} }
return Promise.allVoid(promises).thenAsync(v -> Promise.of(new String(chars))); }
}); return Promise.allVoid(promises).thenAsync(v -> Promise.of(new String(chars)));
}); });
}); });
} }