From 57e0227a02b81dcec113cbccce9eb3cdb3297ce8 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Thu, 1 Dec 2022 17:33:35 +0100 Subject: [PATCH] Wasm: trying to improve debug information emitter --- .../teavm/backend/wasm/debug/DebugLines.java | 2 + .../backend/wasm/debug/DebugLinesBuilder.java | 5 + .../backend/wasm/debug/info/LineInfo.java | 13 +- .../debug/info/LineInfoCommandExecutor.java | 2 +- .../wasm/debug/info/LineInfoSequence.java | 5 +- .../wasm/render/WasmBinaryRenderer.java | 8 +- .../render/WasmBinaryRenderingVisitor.java | 176 ++++++++++++++---- 7 files changed, 158 insertions(+), 53 deletions(-) diff --git a/core/src/main/java/org/teavm/backend/wasm/debug/DebugLines.java b/core/src/main/java/org/teavm/backend/wasm/debug/DebugLines.java index 72fc06506..f41b2d2ef 100644 --- a/core/src/main/java/org/teavm/backend/wasm/debug/DebugLines.java +++ b/core/src/main/java/org/teavm/backend/wasm/debug/DebugLines.java @@ -22,6 +22,8 @@ public interface DebugLines { void location(String file, int line); + void emptyLocation(); + void start(MethodReference methodReference); void end(); diff --git a/core/src/main/java/org/teavm/backend/wasm/debug/DebugLinesBuilder.java b/core/src/main/java/org/teavm/backend/wasm/debug/DebugLinesBuilder.java index 50dd4f809..9f577e05b 100644 --- a/core/src/main/java/org/teavm/backend/wasm/debug/DebugLinesBuilder.java +++ b/core/src/main/java/org/teavm/backend/wasm/debug/DebugLinesBuilder.java @@ -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); diff --git a/core/src/main/java/org/teavm/backend/wasm/debug/info/LineInfo.java b/core/src/main/java/org/teavm/backend/wasm/debug/info/LineInfo.java index 18c624f67..98ca9e12f 100644 --- a/core/src/main/java/org/teavm/backend/wasm/debug/info/LineInfo.java +++ b/core/src/main/java/org/teavm/backend/wasm/debug/info/LineInfo.java @@ -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(""); + } } } } diff --git a/core/src/main/java/org/teavm/backend/wasm/debug/info/LineInfoCommandExecutor.java b/core/src/main/java/org/teavm/backend/wasm/debug/info/LineInfoCommandExecutor.java index 791c370ea..2b5d05866 100644 --- a/core/src/main/java/org/teavm/backend/wasm/debug/info/LineInfoCommandExecutor.java +++ b/core/src/main/java/org/teavm/backend/wasm/debug/info/LineInfoCommandExecutor.java @@ -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 diff --git a/core/src/main/java/org/teavm/backend/wasm/debug/info/LineInfoSequence.java b/core/src/main/java/org/teavm/backend/wasm/debug/info/LineInfoSequence.java index 889472c48..464f6e5c1 100644 --- a/core/src/main/java/org/teavm/backend/wasm/debug/info/LineInfoSequence.java +++ b/core/src/main/java/org/teavm/backend/wasm/debug/info/LineInfoSequence.java @@ -56,7 +56,10 @@ public class LineInfoSequence { var locations = new ArrayList(); 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); } diff --git a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java index a88225566..f959c335c 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java @@ -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); diff --git a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderingVisitor.java b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderingVisitor.java index 22faf21ab..c32bcb80b 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderingVisitor.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderingVisitor.java @@ -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 blockDepths = new HashMap<>(); private List methodStack = new ArrayList<>(); private List currentMethodStack = new ArrayList<>(); + private TextLocation textLocationToEmit; + private boolean deferTextLocationToEmit; + private TextLocation lastEmittedLocation; + private int positionToEmit; + private List locationStack = new ArrayList<>(); WasmBinaryRenderingVisitor(WasmBinaryWriter writer, WasmBinaryVersion version, Map functionIndexes, Map importedIndexes, Map 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(); + } } } }