Refactor DexDebugEvent/EntryBuilder into visitor pattern, also ...
... extract the position-related part of the state machine in
DexDebugEntryBuilder into a standalone class PositionalDebugEventCollector.
Bug:
Change-Id: I55b404f4c9d14ec720da81d28a0130f80be33592
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEntryBuilder.java b/src/main/java/com/android/tools/r8/graph/DexDebugEntryBuilder.java
index 6ca2268..38195ae 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugEntryBuilder.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugEntryBuilder.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
-import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.ValueType;
import com.google.common.collect.ImmutableMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceArrayMap;
@@ -17,10 +16,10 @@
/**
* Builder to construct a "per position" representation of the debug information.
*
- * This builder is relatively relaxed about the stream of build operations and should accept
- * any stream from any input file we expect to process correctly.
+ * <p>This builder is relatively relaxed about the stream of build operations and should accept any
+ * stream from any input file we expect to process correctly.
*/
-public class DexDebugEntryBuilder {
+public class DexDebugEntryBuilder implements DexDebugEventVisitor {
private static class LocalEntry {
DebugLocalInfo current;
@@ -41,11 +40,6 @@
}
// The variables of the state machine.
- private int currentPc = 0;
- private int currentLine;
- private DexString currentFile = null;
- private DexMethod currentMethod = null;
- private Position currentCallerPosition = null;
private boolean prologueEnd = false;
private boolean epilogueBegin = false;
private final Map<Integer, LocalEntry> locals = new HashMap<>();
@@ -60,17 +54,20 @@
// Resulting debug entries.
private List<DexDebugEntry> entries = new ArrayList<>();
+ private DexDebugPositionState positionState;
public DexDebugEntryBuilder(int startLine, DexMethod method) {
- currentLine = startLine;
+ assert method != null;
this.method = method;
- assert this.method != null;
- currentMethod = method;
+ positionState = new DexDebugPositionState(startLine, method);
}
public DexDebugEntryBuilder(DexEncodedMethod method, DexItemFactory factory) {
+ assert method != null && method.method != null;
this.method = method.method;
- assert this.method != null;
+ positionState =
+ new DexDebugPositionState(
+ method.getCode().asDexCode().getDebugInfo().startLine, method.method);
DexCode code = method.getCode().asDexCode();
DexDebugInfo info = code.getDebugInfo();
int argumentRegister = code.registerSize - code.incomingRegisterSize;
@@ -89,10 +86,8 @@
}
argumentRegister += ValueType.fromDexType(types[i]).requiredRegisters();
}
- currentLine = info.startLine;
- currentMethod = this.method;
for (DexDebugEvent event : info.events) {
- event.addToBuilder(this);
+ event.accept(this);
}
}
@@ -100,31 +95,39 @@
return arguments;
}
- public void setFile(DexString file) {
- currentFile = file;
+ @Override
+ public void visit(DexDebugEvent.AdvancePC advancePC) {
+ positionState.visit(advancePC);
}
- public void setInlineFrame(DexMethod callee, Position caller) {
- assert (caller == null && callee == method)
- || (caller != null && caller.getOutermostCaller().method == method);
- currentMethod = callee;
- currentCallerPosition = caller;
+ @Override
+ public void visit(DexDebugEvent.AdvanceLine advanceLine) {
+ positionState.visit(advanceLine);
}
- public void advancePC(int pcDelta) {
- assert pcDelta >= 0;
- currentPc += pcDelta;
+ @Override
+ public void visit(DexDebugEvent.SetInlineFrame setInlineFrame) {
+ positionState.visit(setInlineFrame);
}
- public void advanceLine(int line) {
- currentLine += line;
+ @Override
+ public void visit(DexDebugEvent.Default defaultEvent) {
+ positionState.visit(defaultEvent);
+ defaultEventReceived();
}
- public void endPrologue() {
+ @Override
+ public void visit(DexDebugEvent.SetFile setFile) {
+ positionState.visit(setFile);
+ }
+
+ @Override
+ public void visit(DexDebugEvent.SetPrologueEnd setPrologueEnd) {
prologueEnd = true;
}
- public void beginEpilogue() {
+ @Override
+ public void visit(DexDebugEvent.SetEpilogueBegin setEpilogueBegin) {
epilogueBegin = true;
}
@@ -134,20 +137,23 @@
getEntry(register).set(argument);
}
- public void startLocal(int register, DexString name, DexType type, DexString signature) {
- getEntry(register).set(canonicalize(name, type, signature));
+ @Override
+ public void visit(DexDebugEvent.StartLocal setStartLocal) {
+ getEntry(setStartLocal.registerNum)
+ .set(canonicalize(setStartLocal.name, setStartLocal.type, setStartLocal.signature));
}
- public void endLocal(int register) {
- getEntry(register).unset();
+ @Override
+ public void visit(DexDebugEvent.EndLocal endLocal) {
+ getEntry(endLocal.registerNum).unset();
}
- public void restartLocal(int register) {
- getEntry(register).reset();
+ @Override
+ public void visit(DexDebugEvent.RestartLocal restartLocal) {
+ getEntry(restartLocal.registerNum).reset();
}
- public void setPosition(int pcDelta, int lineDelta) {
- assert pcDelta >= 0;
+ public void defaultEventReceived() {
if (pending != null) {
// Local changes contribute to the pending position entry.
entries.add(
@@ -161,18 +167,16 @@
pending.method,
pending.callerPosition));
}
- currentPc += pcDelta;
- currentLine += lineDelta;
pending =
new DexDebugEntry(
- currentPc,
- currentLine,
- currentFile,
+ positionState.getCurrentPc(),
+ positionState.getCurrentLine(),
+ positionState.getCurrentFile(),
prologueEnd,
epilogueBegin,
null,
- currentMethod,
- currentCallerPosition);
+ positionState.getCurrentMethod(),
+ positionState.getCurrentCallerPosition());
prologueEnd = false;
epilogueBegin = false;
}
@@ -180,7 +184,7 @@
public List<DexDebugEntry> build() {
// Flush any pending entry.
if (pending != null) {
- setPosition(0, 0);
+ defaultEventReceived(); // To flush 'pending'.
pending = null;
}
List<DexDebugEntry> result = entries;
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java b/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java
index 724c10b..9d42c82 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java
@@ -34,7 +34,7 @@
public abstract void writeOn(DebugBytecodeWriter writer, ObjectToOffsetMapping mapping);
- public abstract void addToBuilder(DexDebugEntryBuilder builder);
+ public abstract void accept(DexDebugEventVisitor visitor);
public static class AdvancePC extends DexDebugEvent {
@@ -51,11 +51,12 @@
}
@Override
- public void addToBuilder(DexDebugEntryBuilder builder) {
+ public void accept(DexDebugEventVisitor visitor) {
assert delta >= 0;
- builder.advancePC(delta);
+ visitor.visit(this);
}
+
@Override
public String toString() {
return "ADVANCE_PC " + delta;
@@ -85,8 +86,8 @@
}
@Override
- public void addToBuilder(DexDebugEntryBuilder builder) {
- builder.endPrologue();
+ public void accept(DexDebugEventVisitor visitor) {
+ visitor.visit(this);
}
@Override
@@ -118,8 +119,8 @@
}
@Override
- public void addToBuilder(DexDebugEntryBuilder builder) {
- builder.beginEpilogue();
+ public void accept(DexDebugEventVisitor visitor) {
+ visitor.visit(this);
}
@Override
@@ -153,8 +154,8 @@
}
@Override
- public void addToBuilder(DexDebugEntryBuilder builder) {
- builder.advanceLine(delta);
+ public void accept(DexDebugEventVisitor visitor) {
+ visitor.visit(this);
}
@Override
@@ -220,8 +221,8 @@
}
@Override
- public void addToBuilder(DexDebugEntryBuilder builder) {
- builder.startLocal(registerNum, name, type, signature);
+ public void accept(DexDebugEventVisitor visitor) {
+ visitor.visit(this);
}
@Override
@@ -272,8 +273,8 @@
}
@Override
- public void addToBuilder(DexDebugEntryBuilder builder) {
- builder.endLocal(registerNum);
+ public void accept(DexDebugEventVisitor visitor) {
+ visitor.visit(this);
}
@Override
@@ -309,8 +310,8 @@
}
@Override
- public void addToBuilder(DexDebugEntryBuilder builder) {
- builder.restartLocal(registerNum);
+ public void accept(DexDebugEventVisitor visitor) {
+ visitor.visit(this);
}
@Override
@@ -339,14 +340,6 @@
this.fileName = fileName;
}
- public DexString getFileName() {
- return fileName;
- }
-
- public void setFileName(DexString fileName) {
- this.fileName = fileName;
- }
-
@Override
public void writeOn(DebugBytecodeWriter writer, ObjectToOffsetMapping mapping) {
writer.putByte(Constants.DBG_SET_FILE);
@@ -359,8 +352,8 @@
}
@Override
- public void addToBuilder(DexDebugEntryBuilder builder) {
- builder.setFile(fileName);
+ public void accept(DexDebugEventVisitor visitor) {
+ visitor.visit(this);
}
@Override
@@ -398,8 +391,8 @@
}
@Override
- public void addToBuilder(DexDebugEntryBuilder builder) {
- builder.setInlineFrame(callee, caller);
+ public void accept(DexDebugEventVisitor visitor) {
+ visitor.visit(this);
}
@Override
@@ -437,11 +430,8 @@
}
@Override
- public void addToBuilder(DexDebugEntryBuilder builder) {
- int adjustedOpcode = value - Constants.DBG_FIRST_SPECIAL;
- int line = Constants.DBG_LINE_BASE + (adjustedOpcode % Constants.DBG_LINE_RANGE);
- int address = adjustedOpcode / Constants.DBG_LINE_RANGE;
- builder.setPosition(address, line);
+ public void accept(DexDebugEventVisitor visitor) {
+ visitor.visit(this);
}
public int getPCDelta() {
@@ -456,7 +446,7 @@
@Override
public String toString() {
- return "DEFAULT " + value;
+ return String.format("DEFAULT %d (dpc %d, %dline %d)", value, getPCDelta(), getLineDelta());
}
@Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEventVisitor.java b/src/main/java/com/android/tools/r8/graph/DexDebugEventVisitor.java
new file mode 100644
index 0000000..464c93d
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugEventVisitor.java
@@ -0,0 +1,37 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.graph;
+
+import com.android.tools.r8.graph.DexDebugEvent.AdvanceLine;
+import com.android.tools.r8.graph.DexDebugEvent.AdvancePC;
+import com.android.tools.r8.graph.DexDebugEvent.Default;
+import com.android.tools.r8.graph.DexDebugEvent.EndLocal;
+import com.android.tools.r8.graph.DexDebugEvent.RestartLocal;
+import com.android.tools.r8.graph.DexDebugEvent.SetEpilogueBegin;
+import com.android.tools.r8.graph.DexDebugEvent.SetFile;
+import com.android.tools.r8.graph.DexDebugEvent.SetInlineFrame;
+import com.android.tools.r8.graph.DexDebugEvent.SetPrologueEnd;
+import com.android.tools.r8.graph.DexDebugEvent.StartLocal;
+
+public interface DexDebugEventVisitor {
+ void visit(AdvancePC advancePC);
+
+ void visit(AdvanceLine advanceLine);
+
+ void visit(SetInlineFrame setInlineFrame);
+
+ void visit(Default defaultEvent);
+
+ void visit(SetFile setFile);
+
+ void visit(SetPrologueEnd setPrologueEnd);
+
+ void visit(SetEpilogueBegin setEpilogueBegin);
+
+ void visit(StartLocal startLocal);
+
+ void visit(EndLocal endLocal);
+
+ void visit(RestartLocal restartLocal);
+}
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java b/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java
index 99d1227..4b8c4b8 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java
@@ -27,7 +27,7 @@
public List<DexDebugEntry> computeEntries(DexMethod method) {
DexDebugEntryBuilder builder = new DexDebugEntryBuilder(startLine, method);
for (DexDebugEvent event : events) {
- event.addToBuilder(builder);
+ event.accept(builder);
}
return builder.build();
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugPositionState.java b/src/main/java/com/android/tools/r8/graph/DexDebugPositionState.java
new file mode 100644
index 0000000..9a551db
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugPositionState.java
@@ -0,0 +1,105 @@
+package com.android.tools.r8.graph;
+
+import com.android.tools.r8.graph.DexDebugEvent.AdvanceLine;
+import com.android.tools.r8.graph.DexDebugEvent.AdvancePC;
+import com.android.tools.r8.graph.DexDebugEvent.Default;
+import com.android.tools.r8.graph.DexDebugEvent.EndLocal;
+import com.android.tools.r8.graph.DexDebugEvent.RestartLocal;
+import com.android.tools.r8.graph.DexDebugEvent.SetEpilogueBegin;
+import com.android.tools.r8.graph.DexDebugEvent.SetFile;
+import com.android.tools.r8.graph.DexDebugEvent.SetInlineFrame;
+import com.android.tools.r8.graph.DexDebugEvent.SetPrologueEnd;
+import com.android.tools.r8.graph.DexDebugEvent.StartLocal;
+import com.android.tools.r8.ir.code.Position;
+
+/**
+ * State machine to process and accumulate position-related DexDebugEvents. Clients should retrieve
+ * the current state using the getters after a Default event.
+ */
+public class DexDebugPositionState implements DexDebugEventVisitor {
+ private final DexMethod method;
+
+ private int currentPc = 0;
+ private int currentLine;
+ private DexString currentFile = null;
+ private DexMethod currentMethod = null;
+ private Position currentCallerPosition = null;
+
+ public DexDebugPositionState(int startLine, DexMethod method) {
+ this.method = method;
+ currentLine = startLine;
+ currentMethod = method;
+ }
+
+ public void visit(AdvancePC advancePC) {
+ assert advancePC.delta >= 0;
+ currentPc += advancePC.delta;
+ }
+
+ public void visit(AdvanceLine advanceLine) {
+ currentLine += advanceLine.delta;
+ }
+
+ public void visit(SetInlineFrame setInlineFrame) {
+ assert (setInlineFrame.caller == null && setInlineFrame.callee == method)
+ || (setInlineFrame.caller != null
+ && setInlineFrame.caller.getOutermostCaller().method == method);
+ currentMethod = setInlineFrame.callee;
+ currentCallerPosition = setInlineFrame.caller;
+ }
+
+ public void visit(Default defaultEvent) {
+ assert defaultEvent.getPCDelta() >= 0;
+ currentPc += defaultEvent.getPCDelta();
+ currentLine += defaultEvent.getLineDelta();
+ }
+
+ public void visit(SetFile setFile) {
+ currentFile = setFile.fileName;
+ }
+
+ @Override
+ public void visit(SetPrologueEnd setPrologueEnd) {
+ // Empty.
+ }
+
+ @Override
+ public void visit(SetEpilogueBegin setEpilogueBegin) {
+ // Empty.
+ }
+
+ @Override
+ public void visit(StartLocal startLocal) {
+ // Empty.
+ }
+
+ @Override
+ public void visit(EndLocal endLocal) {
+ // Empty.
+ }
+
+ @Override
+ public void visit(RestartLocal restartLocal) {
+ // Empty.
+ }
+
+ public int getCurrentPc() {
+ return currentPc;
+ }
+
+ public int getCurrentLine() {
+ return currentLine;
+ }
+
+ public DexString getCurrentFile() {
+ return currentFile;
+ }
+
+ public DexMethod getCurrentMethod() {
+ return currentMethod;
+ }
+
+ public Position getCurrentCallerPosition() {
+ return currentCallerPosition;
+ }
+}