Wasm: trying to improve debug information emitter

This commit is contained in:
Alexey Andreev 2022-12-01 17:33:35 +01:00
parent 1d2633ed76
commit 57e0227a02
7 changed files with 158 additions and 53 deletions

View File

@ -22,6 +22,8 @@ public interface DebugLines {
void location(String file, int line);
void emptyLocation();
void start(MethodReference methodReference);
void end();

View File

@ -66,6 +66,11 @@ public class DebugLinesBuilder extends DebugSectionBuilder implements DebugLines
}
}
@Override
public void emptyLocation() {
location(null, -1);
}
private void flushPtr() {
if (ptr != lastWrittenPtr) {
blob.writeLEB(DebugConstants.LOC_PTR);

View File

@ -55,11 +55,16 @@ public class LineInfo {
public void dump(PrintStream out) {
for (var i = 0; i < sequences.length; ++i) {
var sequence = sequences[i];
out.println("Sequence " + i + ": " + sequence.method().fullName() + " [" + sequence.startAddress() + ".."
+ sequence.endAddress() + ")");
out.println("Sequence " + i + ": " + sequence.method().fullName() + " ["
+ Integer.toHexString(sequence.startAddress()) + ".."
+ Integer.toHexString(sequence.endAddress()) + ")");
for (var location : sequence.unpack().locations()) {
out.println(" at " + location.address() + " " + location.location().file().fullName() + ":"
+ location.location().line());
out.print(" at " + Integer.toHexString(location.address()) + " ");
if (location.location() != null) {
out.println(location.location().file().fullName() + ":" + location.location().line());
} else {
out.println("<unmapped>");
}
}
}
}

View File

@ -22,7 +22,7 @@ public class LineInfoCommandExecutor implements LineInfoCommandVisitor {
private InliningLocation inliningLocation;
public InstructionLocation createLocation() {
return file != null ? new InstructionLocation(address, new Location(file, line, inliningLocation)) : null;
return new InstructionLocation(address, file != null ? new Location(file, line, inliningLocation) : null);
}
@Override

View File

@ -56,7 +56,10 @@ public class LineInfoSequence {
var locations = new ArrayList<InstructionLocation>();
for (var command : commands) {
command.acceptVisitor(commandExecutor);
locations.add(commandExecutor.createLocation());
var location = commandExecutor.createLocation();
if (location != null) {
locations.add(location);
}
}
return new LineInfoUnpackedSequence(startAddress, endAddress, method, locations);
}

View File

@ -328,13 +328,7 @@ public class WasmBinaryRenderer {
for (var part : function.getBody()) {
part.acceptVisitor(visitor);
}
if (dwarfGenerator != null) {
dwarfGenerator.endLineNumberSequence(offset + code.getPosition());
}
if (debugLines != null) {
debugLines.end();
}
visitor.endLocation();
code.writeByte(0x0B);

View File

@ -20,6 +20,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.teavm.backend.wasm.debug.DebugLines;
import org.teavm.backend.wasm.generate.DwarfGenerator;
import org.teavm.backend.wasm.model.WasmType;
@ -56,6 +57,7 @@ import org.teavm.backend.wasm.model.expression.WasmStoreInt64;
import org.teavm.backend.wasm.model.expression.WasmSwitch;
import org.teavm.backend.wasm.model.expression.WasmUnreachable;
import org.teavm.model.MethodReference;
import org.teavm.model.TextLocation;
class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
private WasmBinaryWriter writer;
@ -70,6 +72,11 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
private Map<WasmBlock, Integer> blockDepths = new HashMap<>();
private List<MethodReference> methodStack = new ArrayList<>();
private List<MethodReference> currentMethodStack = new ArrayList<>();
private TextLocation textLocationToEmit;
private boolean deferTextLocationToEmit;
private TextLocation lastEmittedLocation;
private int positionToEmit;
private List<TextLocation> locationStack = new ArrayList<>();
WasmBinaryRenderingVisitor(WasmBinaryWriter writer, WasmBinaryVersion version, Map<String, Integer> functionIndexes,
Map<String, Integer> importedIndexes, Map<WasmSignature, Integer> signatureIndexes,
@ -86,6 +93,8 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
@Override
public void visit(WasmBlock expression) {
pushLocation(expression);
pushLocation(expression);
int blockDepth = 1;
depth += blockDepth;
blockDepths.put(expression, depth);
@ -94,7 +103,9 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
for (WasmExpression part : expression.getBody()) {
part.acceptVisitor(this);
}
popLocation();
writer.writeByte(0x0B);
popLocation();
blockDepths.remove(expression);
depth -= blockDepth;
}
@ -105,34 +116,32 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
@Override
public void visit(WasmBranch expression) {
pushLocation(expression);
if (expression.getResult() != null) {
expression.getResult().acceptVisitor(this);
}
expression.getCondition().acceptVisitor(this);
emitLocation(expression);
writer.writeByte(0x0D);
writeLabel(expression.getTarget());
popLocation();
}
@Override
public void visit(WasmBreak expression) {
pushLocation(expression);
if (expression.getResult() != null) {
expression.getResult().acceptVisitor(this);
}
emitLocation(expression);
writer.writeByte(0x0C);
writeLabel(expression.getTarget());
popLocation();
}
@Override
public void visit(WasmSwitch expression) {
pushLocation(expression);
expression.getSelector().acceptVisitor(this);
emitLocation(expression);
writer.writeByte(0x0E);
writer.writeLEB(expression.getTargets().size());
@ -145,12 +154,14 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
int defaultDepth = blockDepths.get(expression.getDefaultTarget());
int relativeDepth = depth - defaultDepth;
writer.writeLEB(relativeDepth);
popLocation();
}
@Override
public void visit(WasmConditional expression) {
pushLocation(expression);
pushLocation(expression);
expression.getCondition().acceptVisitor(this);
emitLocation(expression);
writer.writeByte(0x04);
writeBlockType(expression.getType());
@ -171,73 +182,84 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
}
--depth;
popLocation();
writer.writeByte(0x0B);
popLocation();
}
@Override
public void visit(WasmReturn expression) {
pushLocation(expression);
if (expression.getValue() != null) {
expression.getValue().acceptVisitor(this);
}
emitLocation(expression);
writer.writeByte(0x0F);
popLocation();
}
@Override
public void visit(WasmUnreachable expression) {
emitLocation(expression);
pushLocation(expression);
writer.writeByte(0x0);
popLocation();
}
@Override
public void visit(WasmInt32Constant expression) {
emitLocation(expression);
pushLocation(expression);
writer.writeByte(0x41);
writer.writeSignedLEB(expression.getValue());
popLocation();
}
@Override
public void visit(WasmInt64Constant expression) {
emitLocation(expression);
pushLocation(expression);
writer.writeByte(0x42);
writer.writeSignedLEB(expression.getValue());
popLocation();
}
@Override
public void visit(WasmFloat32Constant expression) {
emitLocation(expression);
pushLocation(expression);
writer.writeByte(0x43);
writer.writeFixed(Float.floatToRawIntBits(expression.getValue()));
popLocation();
}
@Override
public void visit(WasmFloat64Constant expression) {
emitLocation(expression);
pushLocation(expression);
writer.writeByte(0x44);
writer.writeFixed(Double.doubleToRawLongBits(expression.getValue()));
popLocation();
}
@Override
public void visit(WasmGetLocal expression) {
emitLocation(expression);
pushLocation(expression);
writer.writeByte(0x20);
writer.writeLEB(expression.getLocal().getIndex());
popLocation();
}
@Override
public void visit(WasmSetLocal expression) {
pushLocation(expression);
expression.getValue().acceptVisitor(this);
emitLocation(expression);
writer.writeByte(0x21);
writer.writeLEB(expression.getLocal().getIndex());
popLocation();
}
@Override
public void visit(WasmIntBinary expression) {
pushLocation(expression);
expression.getFirst().acceptVisitor(this);
expression.getSecond().acceptVisitor(this);
emitLocation(expression);
render0xD(expression);
popLocation();
}
private void render0xD(WasmIntBinary expression) {
@ -405,10 +427,11 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
@Override
public void visit(WasmFloatBinary expression) {
pushLocation(expression);
expression.getFirst().acceptVisitor(this);
expression.getSecond().acceptVisitor(this);
emitLocation(expression);
render0xD(expression);
popLocation();
}
private void render0xD(WasmFloatBinary expression) {
@ -498,6 +521,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
@Override
public void visit(WasmIntUnary expression) {
pushLocation(expression);
expression.getOperand().acceptVisitor(this);
switch (expression.getType()) {
case INT32:
@ -527,13 +551,15 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
}
break;
}
popLocation();
}
@Override
public void visit(WasmFloatUnary expression) {
pushLocation(expression);
expression.getOperand().acceptVisitor(this);
emitLocation(expression);
render0xD(expression);
popLocation();
}
private void render0xD(WasmFloatUnary expression) {
@ -599,8 +625,8 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
@Override
public void visit(WasmConversion expression) {
pushLocation(expression);
expression.getOperand().acceptVisitor(this);
emitLocation(expression);
switch (expression.getSourceType()) {
case INT32:
switch (expression.getTargetType()) {
@ -679,17 +705,18 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
}
break;
}
popLocation();
}
@Override
public void visit(WasmCall expression) {
pushLocation(expression);
for (WasmExpression argument : expression.getArguments()) {
argument.acceptVisitor(this);
}
Integer functionIndex = !expression.isImported()
? functionIndexes.get(expression.getFunctionName())
: importedIndexes.get(expression.getFunctionName());
emitLocation(expression);
if (functionIndex == null) {
writer.writeByte(0x00);
return;
@ -697,10 +724,12 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
writer.writeByte(0x10);
writer.writeLEB(functionIndex);
popLocation();
}
@Override
public void visit(WasmIndirectCall expression) {
pushLocation(expression);
for (WasmExpression argument : expression.getArguments()) {
argument.acceptVisitor(this);
}
@ -715,19 +744,21 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
writer.writeLEB(signatureIndexes.get(new WasmSignature(signatureTypes)));
writer.writeByte(0);
popLocation();
}
@Override
public void visit(WasmDrop expression) {
pushLocation(expression);
expression.getOperand().acceptVisitor(this);
emitLocation(expression);
writer.writeByte(0x1A);
popLocation();
}
@Override
public void visit(WasmLoadInt32 expression) {
pushLocation(expression);
expression.getIndex().acceptVisitor(this);
emitLocation(expression);
switch (expression.getConvertFrom()) {
case INT8:
writer.writeByte(0x2C);
@ -747,12 +778,13 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
}
writer.writeByte(alignment(expression.getAlignment()));
writer.writeLEB(expression.getOffset());
popLocation();
}
@Override
public void visit(WasmLoadInt64 expression) {
pushLocation(expression);
expression.getIndex().acceptVisitor(this);
emitLocation(expression);
switch (expression.getConvertFrom()) {
case INT8:
writer.writeByte(0x30);
@ -778,31 +810,34 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
}
writer.writeByte(alignment(expression.getAlignment()));
writer.writeLEB(expression.getOffset());
popLocation();
}
@Override
public void visit(WasmLoadFloat32 expression) {
pushLocation(expression);
expression.getIndex().acceptVisitor(this);
emitLocation(expression);
writer.writeByte(0x2A);
writer.writeByte(alignment(expression.getAlignment()));
writer.writeLEB(expression.getOffset());
popLocation();
}
@Override
public void visit(WasmLoadFloat64 expression) {
pushLocation(expression);
expression.getIndex().acceptVisitor(this);
emitLocation(expression);
writer.writeByte(0x2B);
writer.writeByte(alignment(expression.getAlignment()));
writer.writeLEB(expression.getOffset());
popLocation();
}
@Override
public void visit(WasmStoreInt32 expression) {
pushLocation(expression);
expression.getIndex().acceptVisitor(this);
expression.getValue().acceptVisitor(this);
emitLocation(expression);
switch (expression.getConvertTo()) {
case INT8:
case UINT8:
@ -818,13 +853,14 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
}
writer.writeByte(alignment(expression.getAlignment()));
writer.writeLEB(expression.getOffset());
popLocation();
}
@Override
public void visit(WasmStoreInt64 expression) {
pushLocation(expression);
expression.getIndex().acceptVisitor(this);
expression.getValue().acceptVisitor(this);
emitLocation(expression);
switch (expression.getConvertTo()) {
case INT8:
case UINT8:
@ -844,34 +880,38 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
}
writer.writeByte(alignment(expression.getAlignment()));
writer.writeLEB(expression.getOffset());
popLocation();
}
@Override
public void visit(WasmStoreFloat32 expression) {
pushLocation(expression);
expression.getIndex().acceptVisitor(this);
expression.getValue().acceptVisitor(this);
emitLocation(expression);
writer.writeByte(0x38);
writer.writeByte(alignment(expression.getAlignment()));
writer.writeLEB(expression.getOffset());
popLocation();
}
@Override
public void visit(WasmStoreFloat64 expression) {
pushLocation(expression);
expression.getIndex().acceptVisitor(this);
expression.getValue().acceptVisitor(this);
emitLocation(expression);
writer.writeByte(0x39);
writer.writeByte(alignment(expression.getAlignment()));
writer.writeLEB(expression.getOffset());
popLocation();
}
@Override
public void visit(WasmMemoryGrow expression) {
pushLocation(expression);
expression.getAmount().acceptVisitor(this);
emitLocation(expression);
writer.writeByte(0x40);
writer.writeByte(0);
popLocation();
}
private int alignment(int value) {
@ -883,18 +923,70 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
writer.writeLEB(depth - blockDepth);
}
private void emitLocation(WasmExpression expression) {
if (expression.getLocation() == null || expression.getLocation().getFileName() == null) {
return;
private void pushLocation(WasmExpression expression) {
var location = expression.getLocation() != null
? expression.getLocation()
: locationStack.isEmpty() ? null : locationStack.get(locationStack.size() - 1);
locationStack.add(location);
if (location != null) {
emitLocation(location);
} else {
emitDeferredLocation();
}
}
private void popLocation() {
var location = locationStack.remove(locationStack.size() - 1);
if (location != null) {
emitLocation(location);
}
}
private void emitLocation(TextLocation location) {
if (deferTextLocationToEmit && location != null) {
textLocationToEmit = location;
}
flushLocation();
textLocationToEmit = location;
}
private void emitDeferredLocation() {
flushLocation();
textLocationToEmit = null;
deferTextLocationToEmit = true;
}
public void endLocation() {
emitLocation(null);
flushLocation();
if (debugLines != null) {
debugLines.end();
}
}
private void flushLocation() {
if (writer.getPosition() != positionToEmit) {
if (!Objects.equals(lastEmittedLocation, textLocationToEmit)) {
doEmitLocation();
}
lastEmittedLocation = textLocationToEmit;
positionToEmit = writer.getPosition();
}
}
private void doEmitLocation() {
var address = positionToEmit + addressOffset;
if (dwarfGenerator != null) {
dwarfGenerator.lineNumber(writer.getPosition() + addressOffset, expression.getLocation().getFileName(),
expression.getLocation().getLine());
if (textLocationToEmit == null) {
dwarfGenerator.endLineNumberSequence(address);
} else {
dwarfGenerator.lineNumber(address, textLocationToEmit.getFileName(), textLocationToEmit.getLine());
}
}
if (debugLines != null) {
debugLines.advance(writer.getPosition() + addressOffset);
var loc = expression.getLocation();
var inlining = loc.getInlining();
debugLines.advance(address);
var loc = textLocationToEmit;
var inlining = loc != null ? loc.getInlining() : null;
while (inlining != null) {
currentMethodStack.add(loc.getInlining().getMethod());
inlining = inlining.getParent();
@ -915,7 +1007,11 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
debugLines.start(method);
}
currentMethodStack.clear();
debugLines.location(loc.getFileName(), loc.getLine());
if (loc != null) {
debugLines.location(loc.getFileName(), loc.getLine());
} else {
debugLines.emptyLocation();
}
}
}
}