Fixes bugs with variable debug information tracking

This commit is contained in:
konsoletyper 2014-08-06 18:12:50 +04:00
parent cbe2ccb499
commit 36d76885a7
6 changed files with 75 additions and 91 deletions

View File

@ -56,7 +56,8 @@ public class TeaVMRunner {
.create()); .create());
options.addOption(OptionBuilder options.addOption(OptionBuilder
.withDescription("causes TeaVM to log bytecode") .withDescription("causes TeaVM to log bytecode")
.create("logbytecode")); .withLongOpt("logbytecode")
.create());
options.addOption(OptionBuilder options.addOption(OptionBuilder
.withDescription("Generate debug information") .withDescription("Generate debug information")
.withLongOpt("debug") .withLongOpt("debug")

View File

@ -31,15 +31,13 @@ public class InstructionStringifier implements InstructionReader {
this.sb = sb; this.sb = sb;
} }
public InstructionLocation getLocation() {
return location;
}
@Override @Override
public void location(InstructionLocation location) { public void location(InstructionLocation location) {
if (this.location != location) { this.location = location;
if (location != null) {
sb.append("at " + (location.getFileName() != null ? location.getFileName() : "<unknown>") + ":" +
(location.getLine() >= 0 ? String.valueOf(location.getLine()) : "<unknown>"));
}
this.location = location;
}
} }
@Override @Override

View File

@ -26,6 +26,14 @@ public class ListingBuilder {
public String buildListing(ProgramReader program, String prefix) { public String buildListing(ProgramReader program, String prefix) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
InstructionStringifier stringifier = new InstructionStringifier(sb); InstructionStringifier stringifier = new InstructionStringifier(sb);
for (int i = 0; i < program.variableCount(); ++i) {
sb.append(prefix).append("var @").append(i);
VariableReader var = program.variableAt(i);
if (var.getDebugName() != null) {
sb.append(" as ").append(var.getDebugName());
}
sb.append('\n');
}
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlockReader block = program.basicBlockAt(i); BasicBlockReader block = program.basicBlockAt(i);
sb.append(prefix).append("$").append(i).append(":\n"); sb.append(prefix).append("$").append(i).append(":\n");

View File

@ -20,7 +20,6 @@ import org.objectweb.asm.*;
import org.objectweb.asm.tree.*; import org.objectweb.asm.tree.*;
import org.teavm.model.*; import org.teavm.model.*;
import org.teavm.model.instructions.*; import org.teavm.model.instructions.*;
import org.teavm.model.util.DefinitionExtractor;
import org.teavm.model.util.InstructionTransitionExtractor; import org.teavm.model.util.InstructionTransitionExtractor;
/** /**
@ -50,8 +49,7 @@ public class ProgramParser implements VariableDebugInformation {
private boolean lineNumberChanged; private boolean lineNumberChanged;
private InstructionLocation lastInsnLocation; private InstructionLocation lastInsnLocation;
private Map<Integer, List<LocalVariableNode>> localVariableMap = new HashMap<>(); private Map<Integer, List<LocalVariableNode>> localVariableMap = new HashMap<>();
private Map<Instruction, String> variableDebugNames = new HashMap<>(); private Map<Instruction, Map<Integer, String>> variableDebugNames = new HashMap<>();
private Map<Integer, String> parameterNames = new HashMap<>();
private static class Step { private static class Step {
public final int source; public final int source;
@ -117,32 +115,11 @@ public class ProgramParser implements VariableDebugInformation {
} }
int signatureVars = countSignatureVariables(method.desc); int signatureVars = countSignatureVariables(method.desc);
while (program.variableCount() <= signatureVars) { while (program.variableCount() <= signatureVars) {
program.createVariable(getVariableDebugName(program.variableCount(), 0)); program.createVariable(null);
}
for (int i = 0; i <= signatureVars; ++i) {
parameterNames.put(i, getVariableDebugName(i, 0));
} }
return program; return program;
} }
private String getVariableDebugName(int var, int location) {
if (var < 0) {
return null;
}
List<LocalVariableNode> nodes = localVariableMap.get(var);
if (nodes == null) {
return null;
}
for (LocalVariableNode node : nodes) {
int start = labelIndexes.get(node.start.getLabel());
int end = labelIndexes.get(node.end.getLabel());
if (location >= start && location < end) {
return node.name;
}
}
return null;
}
private int countSignatureVariables(String desc) { private int countSignatureVariables(String desc) {
int count = 1; int count = 1;
for (Type paramType : Type.getArgumentTypes(desc)) { for (Type paramType : Type.getArgumentTypes(desc)) {
@ -185,13 +162,9 @@ public class ProgramParser implements VariableDebugInformation {
} }
@Override @Override
public String getDefinitionDebugName(Instruction insn) { public Map<Integer, String> getDebugNames(Instruction insn) {
return variableDebugNames.get(insn); Map<Integer, String> map = variableDebugNames.get(insn);
} return map != null ? Collections.unmodifiableMap(map) : Collections.<Integer, String>emptyMap();
@Override
public String getParameterDebugName(int index) {
return parameterNames.get(index);
} }
private void prepare(MethodNode method) { private void prepare(MethodNode method) {
@ -213,10 +186,11 @@ public class ProgramParser implements VariableDebugInformation {
} }
} }
for (LocalVariableNode localVar : method.localVariables) { for (LocalVariableNode localVar : method.localVariables) {
List<LocalVariableNode> vars = localVariableMap.get(localVar.index); int location = labelIndexes.get(localVar.start.getLabel());
List<LocalVariableNode> vars = localVariableMap.get(location);
if (vars == null) { if (vars == null) {
vars = new ArrayList<>(); vars = new ArrayList<>();
localVariableMap.put(localVar.index, vars); localVariableMap.put(location, vars);
} }
vars.add(localVar); vars.add(localVar);
} }
@ -293,24 +267,8 @@ public class ProgramParser implements VariableDebugInformation {
} }
private void assemble() { private void assemble() {
DefinitionExtractor defExtractor = new DefinitionExtractor();
for (int i = 0; i < targetInstructions.size(); ++i) {
List<Instruction> instructionList = targetInstructions.get(i);
if (instructionList == null) {
continue;
}
for (Instruction insn : instructionList) {
insn.acceptVisitor(defExtractor);
for (Variable var : defExtractor.getDefinedVariables()) {
String debugName = getVariableDebugName(var.getIndex() - minLocal, i);
if (debugName != null) {
variableDebugNames.put(insn, debugName);
}
}
}
}
BasicBlock basicBlock = null; BasicBlock basicBlock = null;
Map<Integer, String> accumulatedDebugNames = new HashMap<>();
for (int i = 0; i < basicBlocks.size(); ++i) { for (int i = 0; i < basicBlocks.size(); ++i) {
BasicBlock newBasicBlock = basicBlocks.get(i); BasicBlock newBasicBlock = basicBlocks.get(i);
if (newBasicBlock != null) { if (newBasicBlock != null) {
@ -320,8 +278,24 @@ public class ProgramParser implements VariableDebugInformation {
basicBlock.getInstructions().add(insn); basicBlock.getInstructions().add(insn);
} }
basicBlock = newBasicBlock; basicBlock = newBasicBlock;
if (!basicBlock.getInstructions().isEmpty()) {
Map<Integer, String> debugNames = new HashMap<>(accumulatedDebugNames);
variableDebugNames.put(basicBlock.getInstructions().get(0), debugNames);
}
} }
List<Instruction> builtInstructions = targetInstructions.get(i); List<Instruction> builtInstructions = targetInstructions.get(i);
List<LocalVariableNode> localVarNodes = localVariableMap.get(i);
if (localVarNodes != null) {
if (builtInstructions == null || builtInstructions.isEmpty()) {
builtInstructions = Arrays.<Instruction>asList(new EmptyInstruction());
}
Map<Integer, String> debugNames = new HashMap<>();
variableDebugNames.put(builtInstructions.get(0), debugNames);
for (LocalVariableNode localVar : localVarNodes) {
debugNames.put(localVar.index + minLocal, localVar.name);
}
accumulatedDebugNames.putAll(debugNames);
}
if (builtInstructions != null) { if (builtInstructions != null) {
basicBlock.getInstructions().addAll(builtInstructions); basicBlock.getInstructions().addAll(builtInstructions);
} }

View File

@ -39,6 +39,7 @@ public class SSATransformer {
private int[][] phiIndexMap; private int[][] phiIndexMap;
private ValueType[] arguments; private ValueType[] arguments;
private VariableDebugInformation variableDebugInfo; private VariableDebugInformation variableDebugInfo;
private Map<Integer, String> variableDebugMap = new HashMap<>();
public void transformToSSA(Program program, VariableDebugInformation variableDebugInfo, ValueType[] arguments) { public void transformToSSA(Program program, VariableDebugInformation variableDebugInfo, ValueType[] arguments) {
if (program.basicBlockCount() == 0) { if (program.basicBlockCount() == 0) {
@ -47,6 +48,7 @@ public class SSATransformer {
this.program = program; this.program = program;
this.variableDebugInfo = variableDebugInfo; this.variableDebugInfo = variableDebugInfo;
this.arguments = arguments; this.arguments = arguments;
variableDebugMap.clear();
cfg = ProgramUtils.buildControlFlowGraphWithoutTryCatch(program); cfg = ProgramUtils.buildControlFlowGraphWithoutTryCatch(program);
domTree = GraphUtils.buildDominatorTree(cfg); domTree = GraphUtils.buildDominatorTree(cfg);
domFrontiers = new int[cfg.size()][]; domFrontiers = new int[cfg.size()][];
@ -57,9 +59,6 @@ public class SSATransformer {
phiMap[i] = new Phi[program.variableCount()]; phiMap[i] = new Phi[program.variableCount()];
phiIndexMap[i] = new int[program.variableCount()]; phiIndexMap[i] = new int[program.variableCount()];
} }
for (int i = 0; i < program.variableCount(); ++i) {
program.variableAt(i).setDebugName(variableDebugInfo.getParameterDebugName(i));
}
applySignature(); applySignature();
domFrontiers = GraphUtils.findDominanceFrontiers(cfg, domTree); domFrontiers = GraphUtils.findDominanceFrontiers(cfg, domTree);
estimatePhis(); estimatePhis();
@ -160,6 +159,7 @@ public class SSATransformer {
specialPhis.get(currentBlock.getIndex()).add(phi); specialPhis.get(currentBlock.getIndex()).add(phi);
} }
for (Instruction insn : currentBlock.getInstructions()) { for (Instruction insn : currentBlock.getInstructions()) {
variableDebugMap.putAll(variableDebugInfo.getDebugNames(insn));
insn.acceptVisitor(consumer); insn.acceptVisitor(consumer);
} }
int[] successors = domGraph.outgoingEdges(currentBlock.getIndex()); int[] successors = domGraph.outgoingEdges(currentBlock.getIndex());
@ -216,8 +216,8 @@ public class SSATransformer {
} }
} }
private Variable define(Variable var, String debugName) { private Variable define(Variable var) {
Variable result = program.createVariable(debugName); Variable result = program.createVariable(null);
variableMap[var.getIndex()] = result; variableMap[var.getIndex()] = result;
return result; return result;
} }
@ -227,6 +227,10 @@ public class SSATransformer {
if (mappedVar == null) { if (mappedVar == null) {
throw new AssertionError(); throw new AssertionError();
} }
String debugName = variableDebugMap.get(var.getIndex());
if (debugName != null) {
mappedVar.setDebugName(debugName);
}
return mappedVar; return mappedVar;
} }
@ -237,56 +241,56 @@ public class SSATransformer {
@Override @Override
public void visit(ClassConstantInstruction insn) { public void visit(ClassConstantInstruction insn) {
insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn))); insn.setReceiver(define(insn.getReceiver()));
} }
@Override @Override
public void visit(NullConstantInstruction insn) { public void visit(NullConstantInstruction insn) {
insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn))); insn.setReceiver(define(insn.getReceiver()));
} }
@Override @Override
public void visit(IntegerConstantInstruction insn) { public void visit(IntegerConstantInstruction insn) {
insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn))); insn.setReceiver(define(insn.getReceiver()));
} }
@Override @Override
public void visit(LongConstantInstruction insn) { public void visit(LongConstantInstruction insn) {
insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn))); insn.setReceiver(define(insn.getReceiver()));
} }
@Override @Override
public void visit(FloatConstantInstruction insn) { public void visit(FloatConstantInstruction insn) {
insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn))); insn.setReceiver(define(insn.getReceiver()));
} }
@Override @Override
public void visit(DoubleConstantInstruction insn) { public void visit(DoubleConstantInstruction insn) {
insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn))); insn.setReceiver(define(insn.getReceiver()));
} }
@Override @Override
public void visit(StringConstantInstruction insn) { public void visit(StringConstantInstruction insn) {
insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn))); insn.setReceiver(define(insn.getReceiver()));
} }
@Override @Override
public void visit(BinaryInstruction insn) { public void visit(BinaryInstruction insn) {
insn.setFirstOperand(use(insn.getFirstOperand())); insn.setFirstOperand(use(insn.getFirstOperand()));
insn.setSecondOperand(use(insn.getSecondOperand())); insn.setSecondOperand(use(insn.getSecondOperand()));
insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn))); insn.setReceiver(define(insn.getReceiver()));
} }
@Override @Override
public void visit(NegateInstruction insn) { public void visit(NegateInstruction insn) {
insn.setOperand(use(insn.getOperand())); insn.setOperand(use(insn.getOperand()));
insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn))); insn.setReceiver(define(insn.getReceiver()));
} }
@Override @Override
public void visit(AssignInstruction insn) { public void visit(AssignInstruction insn) {
insn.setAssignee(use(insn.getAssignee())); insn.setAssignee(use(insn.getAssignee()));
insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn))); insn.setReceiver(define(insn.getReceiver()));
} }
@Override @Override
@ -324,12 +328,12 @@ public class SSATransformer {
@Override @Override
public void visit(ConstructArrayInstruction insn) { public void visit(ConstructArrayInstruction insn) {
insn.setSize(use(insn.getSize())); insn.setSize(use(insn.getSize()));
insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn))); insn.setReceiver(define(insn.getReceiver()));
} }
@Override @Override
public void visit(ConstructInstruction insn) { public void visit(ConstructInstruction insn) {
insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn))); insn.setReceiver(define(insn.getReceiver()));
} }
@Override @Override
@ -338,7 +342,7 @@ public class SSATransformer {
for (int i = 0; i < dimensions.size(); ++i) { for (int i = 0; i < dimensions.size(); ++i) {
dimensions.set(i, use(dimensions.get(i))); dimensions.set(i, use(dimensions.get(i)));
} }
insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn))); insn.setReceiver(define(insn.getReceiver()));
} }
@Override @Override
@ -346,7 +350,7 @@ public class SSATransformer {
if (insn.getInstance() != null) { if (insn.getInstance() != null) {
insn.setInstance(use(insn.getInstance())); insn.setInstance(use(insn.getInstance()));
} }
insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn))); insn.setReceiver(define(insn.getReceiver()));
} }
@Override @Override
@ -361,7 +365,7 @@ public class SSATransformer {
public void visit(GetElementInstruction insn) { public void visit(GetElementInstruction insn) {
insn.setArray(use(insn.getArray())); insn.setArray(use(insn.getArray()));
insn.setIndex(use(insn.getIndex())); insn.setIndex(use(insn.getIndex()));
insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn))); insn.setReceiver(define(insn.getReceiver()));
} }
@Override @Override
@ -381,50 +385,50 @@ public class SSATransformer {
insn.setInstance(use(insn.getInstance())); insn.setInstance(use(insn.getInstance()));
} }
if (insn.getReceiver() != null) { if (insn.getReceiver() != null) {
insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn))); insn.setReceiver(define(insn.getReceiver()));
} }
} }
@Override @Override
public void visit(IsInstanceInstruction insn) { public void visit(IsInstanceInstruction insn) {
insn.setValue(use(insn.getValue())); insn.setValue(use(insn.getValue()));
insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn))); insn.setReceiver(define(insn.getReceiver()));
} }
@Override @Override
public void visit(CastInstruction insn) { public void visit(CastInstruction insn) {
insn.setValue(use(insn.getValue())); insn.setValue(use(insn.getValue()));
insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn))); insn.setReceiver(define(insn.getReceiver()));
} }
@Override @Override
public void visit(CastNumberInstruction insn) { public void visit(CastNumberInstruction insn) {
insn.setValue(use(insn.getValue())); insn.setValue(use(insn.getValue()));
insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn))); insn.setReceiver(define(insn.getReceiver()));
} }
@Override @Override
public void visit(CastIntegerInstruction insn) { public void visit(CastIntegerInstruction insn) {
insn.setValue(use(insn.getValue())); insn.setValue(use(insn.getValue()));
insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn))); insn.setReceiver(define(insn.getReceiver()));
} }
@Override @Override
public void visit(ArrayLengthInstruction insn) { public void visit(ArrayLengthInstruction insn) {
insn.setArray(use(insn.getArray())); insn.setArray(use(insn.getArray()));
insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn))); insn.setReceiver(define(insn.getReceiver()));
} }
@Override @Override
public void visit(UnwrapArrayInstruction insn) { public void visit(UnwrapArrayInstruction insn) {
insn.setArray(use(insn.getArray())); insn.setArray(use(insn.getArray()));
insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn))); insn.setReceiver(define(insn.getReceiver()));
} }
@Override @Override
public void visit(CloneArrayInstruction insn) { public void visit(CloneArrayInstruction insn) {
insn.setArray(use(insn.getArray())); insn.setArray(use(insn.getArray()));
insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn))); insn.setReceiver(define(insn.getReceiver()));
} }
@Override @Override
@ -434,7 +438,7 @@ public class SSATransformer {
@Override @Override
public void visit(NullCheckInstruction insn) { public void visit(NullCheckInstruction insn) {
insn.setValue(use(insn.getValue())); insn.setValue(use(insn.getValue()));
insn.setReceiver(define(insn.getReceiver(), variableDebugInfo.getDefinitionDebugName(insn))); insn.setReceiver(define(insn.getReceiver()));
} }
}; };
} }

View File

@ -15,6 +15,7 @@
*/ */
package org.teavm.parsing; package org.teavm.parsing;
import java.util.Map;
import org.teavm.model.Instruction; import org.teavm.model.Instruction;
/** /**
@ -22,7 +23,5 @@ import org.teavm.model.Instruction;
* @author Alexey Andreev <konsoletyper@gmail.com> * @author Alexey Andreev <konsoletyper@gmail.com>
*/ */
public interface VariableDebugInformation { public interface VariableDebugInformation {
String getDefinitionDebugName(Instruction insn); Map<Integer, String> getDebugNames(Instruction insn);
String getParameterDebugName(int index);
} }