Introduce a PC based debug info subclass.
Bug: 205910335
Change-Id: I1c4513ee4db838cfeed84fc86caee4c92214e82f
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 5e43f29..9d43396 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -982,10 +982,10 @@
}
private static boolean verifyOriginalMethodInDebugInfo(DexCode code, DexMethod originalMethod) {
- if (code.getDebugInfo() == null) {
+ if (code.getDebugInfo() == null || code.getDebugInfo().isPcBasedInfo()) {
return true;
}
- for (DexDebugEvent event : code.getDebugInfo().events) {
+ for (DexDebugEvent event : code.getDebugInfo().asEventBasedInfo().events) {
assert !event.isSetInlineFrame() || event.asSetInlineFrame().hasOuterPosition(originalMethod);
}
return true;
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
index f99eee5..39e491e 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -26,7 +26,7 @@
import com.android.tools.r8.graph.DexAnnotationDirectory;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexApplication;
-import com.android.tools.r8.graph.DexDebugInfo;
+import com.android.tools.r8.graph.DexDebugInfoForWriting;
import com.android.tools.r8.graph.DexEncodedArray;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -132,7 +132,7 @@
}
@Override
- public boolean add(DexDebugInfo dexDebugInfo) {
+ public boolean add(DexDebugInfoForWriting dexDebugInfo) {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/dex/DebugBytecodeWriter.java b/src/main/java/com/android/tools/r8/dex/DebugBytecodeWriter.java
index 2c3e18a..5a6a377 100644
--- a/src/main/java/com/android/tools/r8/dex/DebugBytecodeWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/DebugBytecodeWriter.java
@@ -3,8 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.dex;
-import com.android.tools.r8.graph.DexDebugEvent;
-import com.android.tools.r8.graph.DexDebugInfo;
+import com.android.tools.r8.graph.DexDebugInfoForWriting;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
@@ -17,32 +16,19 @@
private final ObjectToOffsetMapping mapping;
private final GraphLens graphLens;
- private final DexDebugInfo info;
+ private final DexDebugInfoForWriting info;
private ByteBuffer buffer;
public DebugBytecodeWriter(
- DexDebugInfo info, ObjectToOffsetMapping mapping, GraphLens graphLens) {
+ DexDebugInfoForWriting info, ObjectToOffsetMapping mapping, GraphLens graphLens) {
this.info = info;
this.mapping = mapping;
this.graphLens = graphLens;
- // Never allocate a zero-sized buffer, as we need to write the header, and the growth policy
- // requires it to have a positive capacity.
- this.buffer = ByteBuffer.allocate(info.events.length * 5 + 4);
+ this.buffer = ByteBuffer.allocate(info.estimatedWriteSize());
}
public byte[] generate() {
- // Header.
- putUleb128(info.startLine); // line_start
- putUleb128(info.parameters.length);
- for (DexString name : info.parameters) {
- putString(name);
- }
- // Body.
- for (DexDebugEvent event : info.events) {
- event.writeOn(this, mapping, graphLens);
- }
- // Tail.
- putByte(Constants.DBG_END_SEQUENCE);
+ info.write(this, mapping, graphLens);
return Arrays.copyOf(buffer.array(), buffer.position());
}
diff --git a/src/main/java/com/android/tools/r8/dex/DexParser.java b/src/main/java/com/android/tools/r8/dex/DexParser.java
index 43a9a57..3f870f9 100644
--- a/src/main/java/com/android/tools/r8/dex/DexParser.java
+++ b/src/main/java/com/android/tools/r8/dex/DexParser.java
@@ -26,6 +26,7 @@
import com.android.tools.r8.graph.DexCode.TryHandler.TypeAddrPair;
import com.android.tools.r8.graph.DexDebugEvent;
import com.android.tools.r8.graph.DexDebugInfo;
+import com.android.tools.r8.graph.DexDebugInfo.EventBasedDebugInfo;
import com.android.tools.r8.graph.DexEncodedAnnotation;
import com.android.tools.r8.graph.DexEncodedArray;
import com.android.tools.r8.graph.DexEncodedField;
@@ -592,7 +593,7 @@
}
}
}
- return new DexDebugInfo(start, parameters, events.toArray(DexDebugEvent.EMPTY_ARRAY));
+ return new EventBasedDebugInfo(start, parameters, events.toArray(DexDebugEvent.EMPTY_ARRAY));
}
private static class MemberAnnotationIterator<R extends DexMember<?, R>, T extends DexItem> {
diff --git a/src/main/java/com/android/tools/r8/dex/FileWriter.java b/src/main/java/com/android/tools/r8/dex/FileWriter.java
index 84b245c..ebf21c6 100644
--- a/src/main/java/com/android/tools/r8/dex/FileWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/FileWriter.java
@@ -22,7 +22,6 @@
import com.android.tools.r8.graph.DexCode.Try;
import com.android.tools.r8.graph.DexCode.TryHandler;
import com.android.tools.r8.graph.DexCode.TryHandler.TypeAddrPair;
-import com.android.tools.r8.graph.DexDebugInfo;
import com.android.tools.r8.graph.DexDebugInfoForWriting;
import com.android.tools.r8.graph.DexEncodedAnnotation;
import com.android.tools.r8.graph.DexEncodedArray;
@@ -184,7 +183,7 @@
} else {
// Ensure deterministic ordering of debug info by sorting consistent with the code objects.
layout.setDebugInfosOffset(dest.align(1));
- Set<DexDebugInfo> seen = new HashSet<>(mixedSectionOffsets.getDebugInfos().size());
+ Set<DexDebugInfoForWriting> seen = new HashSet<>(mixedSectionOffsets.getDebugInfos().size());
for (ProgramDexCode code : codes) {
DexDebugInfoForWriting info = code.getCode().getDebugInfoForWriting();
if (info != null && seen.add(info)) {
@@ -480,7 +479,7 @@
dest.putInt(mixedSectionOffsets.getOffsetFor(staticFieldValues.get(clazz)));
}
- private void writeDebugItem(DexDebugInfo debugInfo, GraphLens graphLens) {
+ private void writeDebugItem(DexDebugInfoForWriting debugInfo, GraphLens graphLens) {
mixedSectionOffsets.setOffsetFor(debugInfo, dest.position());
dest.putBytes(new DebugBytecodeWriter(debugInfo, mapping, graphLens).generate());
}
@@ -1070,7 +1069,7 @@
private static final int NOT_KNOWN = -2;
private final Reference2IntMap<DexEncodedMethod> codes = createReference2IntMap();
- private final Object2IntMap<DexDebugInfo> debugInfos = createObject2IntMap();
+ private final Object2IntMap<DexDebugInfoForWriting> debugInfos = createObject2IntMap();
private final Object2IntMap<DexTypeList> typeLists = createObject2IntMap();
private final Reference2IntMap<DexString> stringData = createReference2IntMap();
private final Object2IntMap<DexAnnotation> annotations = createObject2IntMap();
@@ -1149,7 +1148,7 @@
}
@Override
- public boolean add(DexDebugInfo debugInfo) {
+ public boolean add(DexDebugInfoForWriting debugInfo) {
return add(debugInfos, debugInfo);
}
@@ -1190,7 +1189,7 @@
return codes.keySet();
}
- public Collection<DexDebugInfo> getDebugInfos() {
+ public Collection<DexDebugInfoForWriting> getDebugInfos() {
return debugInfos.keySet();
}
@@ -1263,7 +1262,7 @@
return lookup(encodedArray, encodedArrays);
}
- public int getOffsetFor(DexDebugInfo debugInfo) {
+ public int getOffsetFor(DexDebugInfoForWriting debugInfo) {
return lookup(debugInfo, debugInfos);
}
@@ -1311,7 +1310,7 @@
assert old <= NOT_SET;
}
- void setOffsetFor(DexDebugInfo debugInfo, int offset) {
+ void setOffsetFor(DexDebugInfoForWriting debugInfo, int offset) {
setOffsetFor(debugInfo, offset, debugInfos);
}
diff --git a/src/main/java/com/android/tools/r8/dex/JumboStringRewriter.java b/src/main/java/com/android/tools/r8/dex/JumboStringRewriter.java
index 990d545..a98a415 100644
--- a/src/main/java/com/android/tools/r8/dex/JumboStringRewriter.java
+++ b/src/main/java/com/android/tools/r8/dex/JumboStringRewriter.java
@@ -29,6 +29,7 @@
import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.code.Nop;
import com.android.tools.r8.code.SwitchPayload;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.graph.DexCode.Try;
import com.android.tools.r8.graph.DexCode.TryHandler;
@@ -37,6 +38,7 @@
import com.android.tools.r8.graph.DexDebugEvent.AdvancePC;
import com.android.tools.r8.graph.DexDebugEvent.Default;
import com.android.tools.r8.graph.DexDebugInfo;
+import com.android.tools.r8.graph.DexDebugInfo.EventBasedDebugInfo;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexString;
@@ -216,11 +218,13 @@
private DexDebugInfo rewriteDebugInfoOffsets() {
DexCode code = method.getCode().asDexCode();
- if (debugEventTargets.size() != 0) {
+ if (!debugEventTargets.isEmpty()) {
+ assert code.getDebugInfo().isEventBasedInfo();
+ EventBasedDebugInfo eventBasedInfo = code.getDebugInfo().asEventBasedInfo();
int lastOriginalOffset = 0;
int lastNewOffset = 0;
List<DexDebugEvent> events = new ArrayList<>();
- for (DexDebugEvent event : code.getDebugInfo().events) {
+ for (DexDebugEvent event : eventBasedInfo.events) {
if (event instanceof AdvancePC) {
AdvancePC advance = (AdvancePC) event;
lastOriginalOffset += advance.delta;
@@ -240,9 +244,9 @@
events.add(event);
}
}
- return new DexDebugInfo(
- code.getDebugInfo().startLine,
- code.getDebugInfo().parameters,
+ return new EventBasedDebugInfo(
+ eventBasedInfo.startLine,
+ eventBasedInfo.parameters,
events.toArray(DexDebugEvent.EMPTY_ARRAY));
}
return code.getDebugInfo();
@@ -480,22 +484,31 @@
private void recordDebugEventTargets(Int2ReferenceMap<Instruction> offsetToInstruction) {
DexDebugInfo debugInfo = method.getCode().asDexCode().getDebugInfo();
- if (debugInfo != null) {
- int address = 0;
- for (DexDebugEvent event : debugInfo.events) {
- if (event instanceof AdvancePC) {
- AdvancePC advance = (AdvancePC) event;
- address += advance.delta;
- Instruction target = offsetToInstruction.get(address);
- assert target != null;
- debugEventTargets.put(address, target);
- } else if (event instanceof Default) {
- Default defaultEvent = (Default) event;
- address += defaultEvent.getPCDelta();
- Instruction target = offsetToInstruction.get(address);
- assert target != null;
- debugEventTargets.put(address, target);
- }
+ if (debugInfo == null) {
+ return;
+ }
+ if (debugInfo.isPcBasedInfo()) {
+ // TODO(b/205910335): merging pc based builds may require computing new pc mappings.
+ // In these cases the old PC should be treated as a "line" and the translation must be
+ // recorded and amended in the output. Reading PC based debug info as inputs is not yet
+ // supported so this is unreachable.
+ throw new Unreachable();
+ }
+ EventBasedDebugInfo eventBasedInfo = debugInfo.asEventBasedInfo();
+ int address = 0;
+ for (DexDebugEvent event : eventBasedInfo.events) {
+ if (event instanceof AdvancePC) {
+ AdvancePC advance = (AdvancePC) event;
+ address += advance.delta;
+ Instruction target = offsetToInstruction.get(address);
+ assert target != null;
+ debugEventTargets.put(address, target);
+ } else if (event instanceof Default) {
+ Default defaultEvent = (Default) event;
+ address += defaultEvent.getPCDelta();
+ Instruction target = offsetToInstruction.get(address);
+ assert target != null;
+ debugEventTargets.put(address, target);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/dex/MixedSectionCollection.java b/src/main/java/com/android/tools/r8/dex/MixedSectionCollection.java
index e082a31..f0c4c06 100644
--- a/src/main/java/com/android/tools/r8/dex/MixedSectionCollection.java
+++ b/src/main/java/com/android/tools/r8/dex/MixedSectionCollection.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.graph.DexAnnotationDirectory;
import com.android.tools.r8.graph.DexAnnotationSet;
-import com.android.tools.r8.graph.DexDebugInfo;
+import com.android.tools.r8.graph.DexDebugInfoForWriting;
import com.android.tools.r8.graph.DexEncodedArray;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItem;
@@ -74,11 +74,11 @@
/**
* Adds the given debug info to the collection.
*
- * Does not add any dependencies.
+ * <p>Does not add any dependencies.
*
* @return true if the item was not added before
*/
- public abstract boolean add(DexDebugInfo dexDebugInfo);
+ public abstract boolean add(DexDebugInfoForWriting dexDebugInfo);
/**
* Adds the given type list to the collection.
diff --git a/src/main/java/com/android/tools/r8/graph/DexCode.java b/src/main/java/com/android/tools/r8/graph/DexCode.java
index 703977e..6cd9cfe 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.graph.DexCode.TryHandler.TypeAddrPair;
import com.android.tools.r8.graph.DexDebugEvent.SetInlineFrame;
import com.android.tools.r8.graph.DexDebugEvent.StartLocal;
+import com.android.tools.r8.graph.DexDebugInfo.EventBasedDebugInfo;
import com.android.tools.r8.graph.bytecodemetadata.BytecodeInstructionMetadata;
import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadata;
import com.android.tools.r8.ir.code.IRCode;
@@ -230,15 +231,17 @@
public DexDebugInfo debugInfoWithFakeThisParameter(DexItemFactory factory) {
if (debugInfo == null) {
- return null;
+ return debugInfo;
}
+ assert debugInfo.isEventBasedInfo();
+ EventBasedDebugInfo eventBasedInfo = debugInfo.asEventBasedInfo();
// User code may already have variables named '_*this'. Use one more than the largest number of
// underscores present as a prefix to 'this'.
int largestPrefix = 0;
- for (DexString parameter : debugInfo.parameters) {
+ for (DexString parameter : eventBasedInfo.parameters) {
largestPrefix = Integer.max(largestPrefix, getLargestPrefix(factory, parameter));
}
- for (DexDebugEvent event : debugInfo.events) {
+ for (DexDebugEvent event : eventBasedInfo.events) {
if (event instanceof DexDebugEvent.StartLocal) {
DexString name = ((StartLocal) event).name;
largestPrefix = Integer.max(largestPrefix, getLargestPrefix(factory, name));
@@ -246,11 +249,11 @@
}
String fakeThisName = Strings.repeat(FAKE_THIS_PREFIX, largestPrefix + 1) + FAKE_THIS_SUFFIX;
- DexString[] parameters = debugInfo.parameters;
+ DexString[] parameters = eventBasedInfo.parameters;
DexString[] newParameters = new DexString[parameters.length + 1];
newParameters[0] = factory.createString(fakeThisName);
System.arraycopy(parameters, 0, newParameters, 1, parameters.length);
- return new DexDebugInfo(debugInfo.startLine, newParameters, debugInfo.events);
+ return new EventBasedDebugInfo(eventBasedInfo.startLine, newParameters, eventBasedInfo.events);
}
@Override
@@ -268,10 +271,12 @@
private DexDebugInfo debugInfoAsInlining(DexMethod caller, DexMethod callee) {
Position callerPosition = SyntheticPosition.builder().setLine(0).setMethod(caller).build();
if (debugInfo == null) {
+ // Inlining is not supported for PC based debug info. The conversion to PC should happen
+ // after optimization (or only for D8 merge inputs) so this should be unreachable.
// If the method has no debug info we generate a preamble position to denote the inlining.
// This is consistent with the building IR for inlining which will always ensure the method
// has a position.
- return new DexDebugInfo(
+ return new EventBasedDebugInfo(
0,
new DexString[callee.getArity()],
new DexDebugEvent[] {
@@ -279,7 +284,9 @@
DexDebugEvent.ZERO_CHANGE_DEFAULT_EVENT
});
}
- DexDebugEvent[] oldEvents = debugInfo.events;
+ assert debugInfo.isEventBasedInfo();
+ EventBasedDebugInfo eventBasedInfo = debugInfo.asEventBasedInfo();
+ DexDebugEvent[] oldEvents = eventBasedInfo.events;
DexDebugEvent[] newEvents = new DexDebugEvent[oldEvents.length + 1];
int i = 0;
newEvents[i++] = new DexDebugEvent.SetInlineFrame(callee, callerPosition);
@@ -296,7 +303,7 @@
newEvents[i++] = event;
}
}
- return new DexDebugInfo(debugInfo.startLine, debugInfo.parameters, newEvents);
+ return new EventBasedDebugInfo(eventBasedInfo.startLine, eventBasedInfo.parameters, newEvents);
}
public static int getLargestPrefix(DexItemFactory factory, DexString name) {
@@ -313,15 +320,17 @@
public DexDebugInfo debugInfoWithoutFirstParameter() {
if (debugInfo == null) {
- return null;
- }
- DexString[] parameters = debugInfo.parameters;
- if(parameters.length == 0) {
return debugInfo;
}
+ assert debugInfo.isEventBasedInfo();
+ EventBasedDebugInfo eventBasedInfo = debugInfo.asEventBasedInfo();
+ DexString[] parameters = eventBasedInfo.parameters;
+ if(parameters.length == 0) {
+ return eventBasedInfo;
+ }
DexString[] newParameters = new DexString[parameters.length - 1];
System.arraycopy(parameters, 1, newParameters, 0, parameters.length - 1);
- return new DexDebugInfo(debugInfo.startLine, newParameters, debugInfo.events);
+ return new EventBasedDebugInfo(eventBasedInfo.startLine, newParameters, eventBasedInfo.events);
}
@Override
@@ -566,18 +575,15 @@
if (debugInfo != null) {
getDebugInfoForWriting().collectIndexedItems(indexedItems, graphLens);
}
- for (TryHandler handler : handlers) {
- handler.collectIndexedItems(indexedItems, graphLens);
- }
+ for (TryHandler handler : handlers) {
+ handler.collectIndexedItems(indexedItems, graphLens);
+ }
}
@Override
public DexDebugInfoForWriting getDebugInfoForWriting() {
- if (debugInfo == null) {
- return null;
- }
if (debugInfoForWriting == null) {
- debugInfoForWriting = DexDebugInfoForWriting.create(debugInfo);
+ debugInfoForWriting = DexDebugInfo.convertToWritable(debugInfo);
}
return debugInfoForWriting;
}
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 ce338d6..d8b6a9b 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugEntryBuilder.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugEntryBuilder.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.graph.DexDebugEvent.SetOutlineCallerFrame;
import com.android.tools.r8.graph.DexDebugEvent.SetOutlineFrame;
+import com.android.tools.r8.graph.DexDebugInfo.EventBasedDebugInfo;
import com.android.tools.r8.ir.code.ValueType;
import com.google.common.collect.ImmutableMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceArrayMap;
@@ -67,11 +68,11 @@
public DexDebugEntryBuilder(DexEncodedMethod method, DexItemFactory factory) {
assert method != null && method.getReference() != null;
this.method = method.getReference();
- positionState =
- new DexDebugPositionState(
- method.getCode().asDexCode().getDebugInfo().startLine, method.getReference());
DexCode code = method.getCode().asDexCode();
- DexDebugInfo info = code.getDebugInfo();
+ EventBasedDebugInfo info = code.getDebugInfo().asEventBasedInfo();
+ // Only event based debug info supports conversion to entries.
+ assert info != null;
+ positionState = new DexDebugPositionState(info.startLine, method.getReference());
int argumentRegister = code.registerSize - code.incomingRegisterSize;
if (!method.accessFlags.isStatic()) {
DexString name = factory.thisName;
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java b/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
index 71822f6..dc90361 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugEventBuilder.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.DexDebugEvent.Default;
import com.android.tools.r8.graph.DexDebugEvent.StartLocal;
+import com.android.tools.r8.graph.DexDebugInfo.EventBasedDebugInfo;
import com.android.tools.r8.ir.code.Argument;
import com.android.tools.r8.ir.code.DebugLocalsChange;
import com.android.tools.r8.ir.code.IRCode;
@@ -120,7 +121,7 @@
params[i] = (local == null || local.signature != null) ? null : local.name;
}
}
- return new DexDebugInfo(startLine, params, events.toArray(DexDebugEvent.EMPTY_ARRAY));
+ return new EventBasedDebugInfo(startLine, params, events.toArray(DexDebugEvent.EMPTY_ARRAY));
}
private void updateBlockEntry(Instruction instruction) {
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 75588f6..a72d269 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java
@@ -3,92 +3,321 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.dex.DebugBytecodeWriter;
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.MixedSectionCollection;
+import com.android.tools.r8.errors.Unimplemented;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.utils.ArrayUtils;
+import com.android.tools.r8.utils.LebUtils;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.Equatable;
+import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralItem;
import com.android.tools.r8.utils.structural.StructuralMapping;
import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
-public class DexDebugInfo extends CachedHashValueDexItem implements StructuralItem<DexDebugInfo> {
+public abstract class DexDebugInfo extends CachedHashValueDexItem
+ implements StructuralItem<DexDebugInfo> {
- public final int startLine;
- public final DexString[] parameters;
- public DexDebugEvent[] events;
-
- private static void specify(StructuralSpecification<DexDebugInfo, ?> spec) {
- spec.withInt(d -> d.startLine)
- .withItemArrayAllowingNullMembers(d -> d.parameters)
- .withItemArray(d -> d.events);
+ private enum DebugInfoKind {
+ EVENT_BASED,
+ PC_BASED
}
- public DexDebugInfo(int startLine, DexString[] parameters, DexDebugEvent[] events) {
- assert startLine >= 0;
- this.startLine = startLine;
- this.parameters = parameters;
- this.events = events;
- // This call to hashCode is just an optimization to speedup equality when
- // canonicalizing DexDebugInfo objects inside a synchronize method.
- hashCode();
+ abstract DebugInfoKind getKind();
+
+ abstract int internalAcceptCompareTo(DexDebugInfo other, CompareToVisitor visitor);
+
+ abstract int getParameterCount();
+
+ public boolean isEventBasedInfo() {
+ return getKind() == DebugInfoKind.EVENT_BASED;
+ }
+
+ public boolean isPcBasedInfo() {
+ return getKind() == DebugInfoKind.PC_BASED;
+ }
+
+ public EventBasedDebugInfo asEventBasedInfo() {
+ return null;
+ }
+
+ public PcBasedDebugInfo asPcBasedInfo() {
+ return null;
}
@Override
- public DexDebugInfo self() {
- return this;
- }
+ abstract void collectMixedSectionItems(MixedSectionCollection collection);
+
+ @Override
+ public abstract DexDebugInfo self();
@Override
public StructuralMapping<DexDebugInfo> getStructuralMapping() {
- return DexDebugInfo::specify;
+ throw new Unreachable();
}
- public List<DexDebugEntry> computeEntries(DexMethod method) {
- DexDebugEntryBuilder builder = new DexDebugEntryBuilder(startLine, method);
- for (DexDebugEvent event : events) {
- event.accept(builder);
+ @Override
+ public abstract void acceptHashing(HashingVisitor visitor);
+
+ @Override
+ public int acceptCompareTo(DexDebugInfo other, CompareToVisitor visitor) {
+ int diff = visitor.visitInt(getKind().ordinal(), other.getKind().ordinal());
+ if (diff != 0) {
+ return diff;
}
- return builder.build();
+ return internalAcceptCompareTo(other, visitor);
}
@Override
- public int computeHashCode() {
- return startLine
- + Arrays.hashCode(parameters) * 7
- + Arrays.hashCode(events) * 13;
- }
-
- @Override
- public final boolean computeEquals(Object other) {
+ protected final boolean computeEquals(Object other) {
return Equatable.equalsImpl(this, other);
}
- public void collectIndexedItems(IndexedItemCollection indexedItems, GraphLens graphLens) {
- for (DexString parameter : parameters) {
- if (parameter != null) {
- parameter.collectIndexedItems(indexedItems);
+ public static class PcBasedDebugInfo extends DexDebugInfo implements DexDebugInfoForWriting {
+ private static final int START_LINE = 0;
+ private final int parameterCount;
+ private final int maxPc;
+
+ private static void specify(StructuralSpecification<PcBasedDebugInfo, ?> spec) {
+ spec.withInt(d -> d.parameterCount).withInt(d -> d.maxPc);
+ }
+
+ public PcBasedDebugInfo(int parameterCount, int maxPc) {
+ this.parameterCount = parameterCount;
+ this.maxPc = maxPc;
+ }
+
+ @Override
+ public int getParameterCount() {
+ return parameterCount;
+ }
+
+ @Override
+ public DexDebugInfo self() {
+ return this;
+ }
+
+ @Override
+ public PcBasedDebugInfo asPcBasedInfo() {
+ return this;
+ }
+
+ @Override
+ DebugInfoKind getKind() {
+ return DebugInfoKind.PC_BASED;
+ }
+
+ @Override
+ protected int computeHashCode() {
+ return Objects.hash(parameterCount, maxPc);
+ }
+
+ @Override
+ public void acceptHashing(HashingVisitor visitor) {
+ visitor.visit(this, PcBasedDebugInfo::specify);
+ }
+
+ @Override
+ int internalAcceptCompareTo(DexDebugInfo other, CompareToVisitor visitor) {
+ assert other.isPcBasedInfo();
+ return visitor.visit(this, other.asPcBasedInfo(), PcBasedDebugInfo::specify);
+ }
+
+ @Override
+ public void collectMixedSectionItems(MixedSectionCollection collection) {
+ collection.add(this);
+ }
+
+ @Override
+ public void collectIndexedItems(IndexedItemCollection indexedItems, GraphLens graphLens) {
+ // No indexed items to collect.
+ }
+
+ @Override
+ public int estimatedWriteSize() {
+ return LebUtils.sizeAsUleb128(START_LINE)
+ + LebUtils.sizeAsUleb128(parameterCount)
+ + parameterCount * LebUtils.sizeAsUleb128(0)
+ + 1
+ + maxPc
+ + 1;
+ }
+
+ @Override
+ public void write(
+ DebugBytecodeWriter writer, ObjectToOffsetMapping mapping, GraphLens graphLens) {
+ writer.putUleb128(START_LINE);
+ writer.putUleb128(parameterCount);
+ for (int i = 0; i < parameterCount; i++) {
+ writer.putString(null);
+ }
+ DexDebugEvent.ZERO_CHANGE_DEFAULT_EVENT.writeOn(writer, mapping, graphLens);
+ for (int i = 0; i < maxPc; i++) {
+ throw new Unimplemented("add 1,1 increment");
+ }
+ writer.putByte(Constants.DBG_END_SEQUENCE);
+ }
+
+ @Override
+ public String toString() {
+ return "PcBasedDebugInfo (params: " + parameterCount + ", max-pc: " + maxPc + ")";
+ }
+ }
+
+ public static class EventBasedDebugInfo extends DexDebugInfo {
+
+ public final int startLine;
+ public final DexString[] parameters;
+ public DexDebugEvent[] events;
+
+ private static void specify(StructuralSpecification<EventBasedDebugInfo, ?> spec) {
+ spec.withInt(d -> d.startLine)
+ .withItemArrayAllowingNullMembers(d -> d.parameters)
+ .withItemArray(d -> d.events);
+ }
+
+ public EventBasedDebugInfo(int startLine, DexString[] parameters, DexDebugEvent[] events) {
+ assert startLine >= 0;
+ this.startLine = startLine;
+ this.parameters = parameters;
+ this.events = events;
+ }
+
+ @Override
+ public DexDebugInfo self() {
+ return this;
+ }
+
+ @Override
+ public EventBasedDebugInfo asEventBasedInfo() {
+ return this;
+ }
+
+ @Override
+ DebugInfoKind getKind() {
+ return DebugInfoKind.EVENT_BASED;
+ }
+
+ @Override
+ int getParameterCount() {
+ return parameters.length;
+ }
+
+ public List<DexDebugEntry> computeEntries(DexMethod method) {
+ DexDebugEntryBuilder builder = new DexDebugEntryBuilder(startLine, method);
+ for (DexDebugEvent event : events) {
+ event.accept(builder);
+ }
+ return builder.build();
+ }
+
+ @Override
+ public int computeHashCode() {
+ return startLine + Arrays.hashCode(parameters) * 7 + Arrays.hashCode(events) * 13;
+ }
+
+ @Override
+ public void acceptHashing(HashingVisitor visitor) {
+ visitor.visit(this, EventBasedDebugInfo::specify);
+ }
+
+ @Override
+ int internalAcceptCompareTo(DexDebugInfo other, CompareToVisitor visitor) {
+ assert other.isEventBasedInfo();
+ return visitor.visit(this, other.asEventBasedInfo(), EventBasedDebugInfo::specify);
+ }
+
+ public void collectIndexedItems(IndexedItemCollection indexedItems, GraphLens graphLens) {
+ for (DexString parameter : parameters) {
+ if (parameter != null) {
+ parameter.collectIndexedItems(indexedItems);
+ }
+ }
+ for (DexDebugEvent event : events) {
+ event.collectIndexedItems(indexedItems, graphLens);
}
}
- for (DexDebugEvent event : events) {
- event.collectIndexedItems(indexedItems, graphLens);
+
+ @Override
+ void collectMixedSectionItems(MixedSectionCollection collection) {
+ // Only writable info should be iterated for collection.
+ throw new Unreachable();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("DebugInfo (line " + startLine + ") events: [\n");
+ for (DexDebugEvent event : events) {
+ builder.append(" ").append(event).append("\n");
+ }
+ builder.append(" END_SEQUENCE\n");
+ builder.append("]\n");
+ return builder.toString();
}
}
- @Override
- void collectMixedSectionItems(MixedSectionCollection collection) {
- collection.add(this);
+ public static DexDebugInfoForWriting convertToWritable(DexDebugInfo debugInfo) {
+ if (debugInfo == null) {
+ return null;
+ }
+ if (debugInfo.isPcBasedInfo()) {
+ return debugInfo.asPcBasedInfo();
+ }
+ EventBasedDebugInfo eventBasedInfo = debugInfo.asEventBasedInfo();
+ DexDebugEvent[] writableEvents =
+ ArrayUtils.filter(
+ eventBasedInfo.events, DexDebugEvent::isWritableEvent, DexDebugEvent.EMPTY_ARRAY);
+ return new WritableEventBasedDebugInfo(
+ eventBasedInfo.startLine, eventBasedInfo.parameters, writableEvents);
}
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder();
- builder.append("DebugInfo (line " + startLine + ") events: [\n");
- for (DexDebugEvent event : events) {
- builder.append(" ").append(event).append("\n");
+ private static class WritableEventBasedDebugInfo extends EventBasedDebugInfo
+ implements DexDebugInfoForWriting {
+
+ private WritableEventBasedDebugInfo(
+ int startLine, DexString[] parameters, DexDebugEvent[] writableEvents) {
+ super(startLine, parameters, writableEvents);
}
- builder.append(" END_SEQUENCE\n");
- builder.append("]\n");
- return builder.toString();
+
+ @Override
+ public void collectIndexedItems(IndexedItemCollection indexedItems, GraphLens graphLens) {
+ super.collectIndexedItems(indexedItems, graphLens);
+ }
+
+ @Override
+ public void collectMixedSectionItems(MixedSectionCollection collection) {
+ collection.add(this);
+ }
+
+ @Override
+ public int estimatedWriteSize() {
+ return LebUtils.sizeAsUleb128(startLine)
+ + LebUtils.sizeAsUleb128(parameters.length)
+ // Estimate 4 bytes per parameter pointer.
+ + parameters.length * 4
+ + events.length
+ + 1;
+ }
+
+ @Override
+ public void write(
+ DebugBytecodeWriter writer, ObjectToOffsetMapping mapping, GraphLens graphLens) {
+ writer.putUleb128(startLine);
+ writer.putUleb128(parameters.length);
+ for (DexString name : parameters) {
+ writer.putString(name);
+ }
+ for (DexDebugEvent event : events) {
+ event.writeOn(writer, mapping, graphLens);
+ }
+ writer.putByte(Constants.DBG_END_SEQUENCE);
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugInfoForSingleLineMethod.java b/src/main/java/com/android/tools/r8/graph/DexDebugInfoForSingleLineMethod.java
index 32d3126..8d41561 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugInfoForSingleLineMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugInfoForSingleLineMethod.java
@@ -4,7 +4,9 @@
package com.android.tools.r8.graph;
-public class DexDebugInfoForSingleLineMethod extends DexDebugInfo {
+import com.android.tools.r8.graph.DexDebugInfo.EventBasedDebugInfo;
+
+public class DexDebugInfoForSingleLineMethod extends EventBasedDebugInfo {
private static final DexDebugInfoForSingleLineMethod INSTANCE =
new DexDebugInfoForSingleLineMethod(0, DexString.EMPTY_ARRAY, DexDebugEvent.EMPTY_ARRAY);
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugInfoForWriting.java b/src/main/java/com/android/tools/r8/graph/DexDebugInfoForWriting.java
index ddb4efc..5f94db9 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugInfoForWriting.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugInfoForWriting.java
@@ -4,36 +4,18 @@
package com.android.tools.r8.graph;
-/**
- * Wraps DexDebugInfo to make comparison and hashcode not consider
- * the SetInlineFrames
- */
-public class DexDebugInfoForWriting extends DexDebugInfo {
+import com.android.tools.r8.dex.DebugBytecodeWriter;
+import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.dex.MixedSectionCollection;
- private DexDebugInfoForWriting(int startLine, DexString[] parameters, DexDebugEvent[] events) {
- super(startLine, parameters, events);
- }
+/** Interface to guarantee that the info only contains writable events. */
+public interface DexDebugInfoForWriting {
- public static DexDebugInfoForWriting create(DexDebugInfo debugInfo) {
- assert debugInfo != null;
- int nonWritableEvents = 0;
- for (DexDebugEvent event : debugInfo.events) {
- if (!event.isWritableEvent()) {
- nonWritableEvents++;
- }
- }
- DexDebugEvent[] writableEvents;
- if (nonWritableEvents == 0) {
- writableEvents = debugInfo.events;
- } else {
- writableEvents = new DexDebugEvent[debugInfo.events.length - nonWritableEvents];
- int i = 0;
- for (DexDebugEvent event : debugInfo.events) {
- if (event.isWritableEvent()) {
- writableEvents[i++] = event;
- }
- }
- }
- return new DexDebugInfoForWriting(debugInfo.startLine, debugInfo.parameters, writableEvents);
- }
+ void collectMixedSectionItems(MixedSectionCollection collection);
+
+ void collectIndexedItems(IndexedItemCollection indexedItems, GraphLens graphLens);
+
+ int estimatedWriteSize();
+
+ void write(DebugBytecodeWriter writer, ObjectToOffsetMapping mapping, GraphLens graphLens);
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 289f255..d056899 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -992,9 +992,9 @@
public static void setDebugInfoWithFakeThisParameter(Code code, int arity, AppView<?> appView) {
if (code.isDexCode()) {
DexCode dexCode = code.asDexCode();
- dexCode.setDebugInfo(dexCode.debugInfoWithFakeThisParameter(appView.dexItemFactory()));
- assert (dexCode.getDebugInfo() == null)
- || (arity == dexCode.getDebugInfo().parameters.length);
+ DexDebugInfo newDebugInfo = dexCode.debugInfoWithFakeThisParameter(appView.dexItemFactory());
+ assert (newDebugInfo == null) || (arity == newDebugInfo.getParameterCount());
+ dexCode.setDebugInfo(newDebugInfo);
} else {
assert code.isCfCode();
CfCode cfCode = code.asCfCode();
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
index f2c1d8d..c3c65fe 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
@@ -83,7 +83,9 @@
this.originalMethod = originalMethod;
DexDebugInfo info = code.getDebugInfo();
if (info != null) {
- debugEntries = info.computeEntries(originalMethod);
+ // IR converting inputs with PC based debug info is not supported.
+ assert info.isEventBasedInfo();
+ debugEntries = info.asEventBasedInfo().computeEntries(originalMethod);
}
canonicalPositions =
new CanonicalPositions(
diff --git a/src/main/java/com/android/tools/r8/utils/ArrayUtils.java b/src/main/java/com/android/tools/r8/utils/ArrayUtils.java
index 24c6a60..06fdc4c 100644
--- a/src/main/java/com/android/tools/r8/utils/ArrayUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ArrayUtils.java
@@ -131,6 +131,10 @@
return results != null ? results.toArray(emptyArray) : original;
}
+ public static <T> T[] filter(T[] original, Predicate<T> test, T[] emptyArray) {
+ return map(original, e -> test.test(e) ? e : null, emptyArray);
+ }
+
public static int[] createIdentityArray(int size) {
int[] array = new int[size];
for (int i = 0; i < size; i++) {
diff --git a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
index 71da5cc..b72dbae 100644
--- a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
@@ -27,6 +27,7 @@
import com.android.tools.r8.graph.DexDebugEventBuilder;
import com.android.tools.r8.graph.DexDebugEventVisitor;
import com.android.tools.r8.graph.DexDebugInfo;
+import com.android.tools.r8.graph.DexDebugInfo.EventBasedDebugInfo;
import com.android.tools.r8.graph.DexDebugInfoForSingleLineMethod;
import com.android.tools.r8.graph.DexDebugPositionState;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -727,7 +728,9 @@
}
if (code.isDexCode()) {
DexDebugInfo dexDebugInfo = code.asDexCode().getDebugInfo();
- return dexDebugInfo == null ? 0 : dexDebugInfo.startLine;
+ return dexDebugInfo == null || !dexDebugInfo.isEventBasedInfo()
+ ? 0
+ : dexDebugInfo.asEventBasedInfo().startLine;
} else if (code.isCfCode()) {
List<CfInstruction> instructions = code.asCfCode().getInstructions();
for (CfInstruction instruction : instructions) {
@@ -823,7 +826,10 @@
if (debugInfo == null) {
return false;
}
- for (DexDebugEvent event : debugInfo.events) {
+ if (debugInfo.isPcBasedInfo()) {
+ return true;
+ }
+ for (DexDebugEvent event : debugInfo.asEventBasedInfo().events) {
if (event instanceof DexDebugEvent.Default) {
return true;
}
@@ -851,7 +857,9 @@
// Do the actual processing for each method.
DexApplication application = appView.appInfo().app();
DexCode dexCode = method.getCode().asDexCode();
- DexDebugInfo debugInfo = dexCode.getDebugInfo();
+ EventBasedDebugInfo debugInfo = dexCode.getDebugInfo().asEventBasedInfo();
+ // TODO(b/205910335): Reconsider this to support pc-based debug info from inputs.
+ assert debugInfo != null;
List<DexDebugEvent> processedEvents = new ArrayList<>();
PositionEventEmitter positionEventEmitter =
@@ -949,8 +957,8 @@
return mappedPositions;
}
- DexDebugInfo optimizedDebugInfo =
- new DexDebugInfo(
+ EventBasedDebugInfo optimizedDebugInfo =
+ new EventBasedDebugInfo(
positionEventEmitter.getStartLine(),
debugInfo.parameters,
processedEvents.toArray(DexDebugEvent.EMPTY_ARRAY));
@@ -989,7 +997,9 @@
List<MappedPosition> mappedPositions = new ArrayList<>();
// Do the actual processing for each method.
DexCode dexCode = method.getCode().asDexCode();
- DexDebugInfo debugInfo = dexCode.getDebugInfo();
+ EventBasedDebugInfo debugInfo = dexCode.getDebugInfo().asEventBasedInfo();
+ // TODO(b/205910335): Reconsider this to support pc-based debug info from inputs.
+ assert debugInfo != null;
Pair<Integer, Position> lastPosition = new Pair<>();
@@ -1034,7 +1044,7 @@
}
private static boolean verifyIdentityMapping(
- DexDebugInfo originalDebugInfo, DexDebugInfo optimizedDebugInfo) {
+ EventBasedDebugInfo originalDebugInfo, EventBasedDebugInfo optimizedDebugInfo) {
assert optimizedDebugInfo.startLine == originalDebugInfo.startLine;
assert optimizedDebugInfo.events.length == originalDebugInfo.events.length;
for (int i = 0; i < originalDebugInfo.events.length; ++i) {
diff --git a/src/test/java/com/android/tools/r8/debuginfo/DebugInfoInspector.java b/src/test/java/com/android/tools/r8/debuginfo/DebugInfoInspector.java
index 3ccf46d..c1fad9f 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/DebugInfoInspector.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/DebugInfoInspector.java
@@ -11,11 +11,10 @@
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.graph.DexDebugEntry;
import com.android.tools.r8.graph.DexDebugEntryBuilder;
-import com.android.tools.r8.graph.DexDebugEvent;
import com.android.tools.r8.graph.DexDebugInfo;
+import com.android.tools.r8.graph.DexDebugInfo.EventBasedDebugInfo;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.DescriptorUtils;
@@ -36,15 +35,18 @@
private final DexEncodedMethod method;
private final List<DexDebugEntry> entries;
- final DexDebugInfo info;
+ final EventBasedDebugInfo info;
public DebugInfoInspector(DexEncodedMethod method, DexItemFactory factory) {
this.method = method;
- info = method.getCode().asDexCode().getDebugInfo();
- if (info != null) {
+ DexDebugInfo debugInfo = method.getCode().asDexCode().getDebugInfo();
+ if (debugInfo != null) {
+ assert debugInfo.isEventBasedInfo();
+ info = debugInfo.asEventBasedInfo();
entries = new DexDebugEntryBuilder(method, factory).build();
checkConsistentEntries();
} else {
+ info = null;
entries = Collections.emptyList();
}
}
@@ -58,24 +60,6 @@
this(new CodeInspector(app), clazz, method);
}
- public boolean hasLocalsInfo() {
- DexDebugInfo dexInfo = method.getCode().asDexCode().getDebugInfo();
- if (info == null || dexInfo == null) {
- return false;
- }
- for (DexString parameter : dexInfo.parameters) {
- if (parameter != null) {
- return true;
- }
- }
- for (DexDebugEvent event : dexInfo.events) {
- if (event instanceof DexDebugEvent.StartLocal) {
- return true;
- }
- }
- return false;
- }
-
public void checkStartLine(int i) {
assertEquals(i, info.startLine);
}
diff --git a/src/test/java/com/android/tools/r8/debuginfo/DebugSetFileSmaliTest.java b/src/test/java/com/android/tools/r8/debuginfo/DebugSetFileSmaliTest.java
index e64b7d7..008d3cf 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/DebugSetFileSmaliTest.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/DebugSetFileSmaliTest.java
@@ -71,6 +71,7 @@
.getCode()
.asDexCode()
.getDebugInfo()
+ .asEventBasedInfo()
.events)
.anyMatch(e -> e instanceof SetFile));
})
diff --git a/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java b/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java
index 5aeaddc..9c4c113 100644
--- a/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java
+++ b/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexDebugEvent;
import com.android.tools.r8.graph.DexDebugInfo;
+import com.android.tools.r8.graph.DexDebugInfo.EventBasedDebugInfo;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.GraphLens;
@@ -68,10 +69,13 @@
@Test
public void testEmptyDebugInfo() {
- DexDebugInfo debugInfo = new DexDebugInfo(1, DexString.EMPTY_ARRAY, new DexDebugEvent[]{});
+ DexDebugInfo debugInfo =
+ new EventBasedDebugInfo(1, DexString.EMPTY_ARRAY, new DexDebugEvent[] {});
DebugBytecodeWriter writer =
new DebugBytecodeWriter(
- debugInfo, emptyObjectTObjectMapping(), GraphLens.getIdentityLens());
+ DexDebugInfo.convertToWritable(debugInfo),
+ emptyObjectTObjectMapping(),
+ GraphLens.getIdentityLens());
Assert.assertEquals(3, writer.generate().length);
}
}
diff --git a/src/test/java/com/android/tools/r8/jasmin/DebugLocalTests.java b/src/test/java/com/android/tools/r8/jasmin/DebugLocalTests.java
index a6505c8..3531c36 100644
--- a/src/test/java/com/android/tools/r8/jasmin/DebugLocalTests.java
+++ b/src/test/java/com/android/tools/r8/jasmin/DebugLocalTests.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.debuginfo.DebugInfoInspector;
import com.android.tools.r8.graph.DexCode;
-import com.android.tools.r8.graph.DexDebugInfo;
+import com.android.tools.r8.graph.DexDebugInfo.EventBasedDebugInfo;
import com.android.tools.r8.jasmin.JasminBuilder.ClassFileVersion;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.utils.AndroidApp;
@@ -24,65 +24,70 @@
public void testSwap() throws Exception {
JasminBuilder builder = new JasminBuilder();
JasminBuilder.ClassBuilder clazz = builder.addClass("Test");
- MethodSignature foo = clazz.addVirtualMethod("foo", ImmutableList.of("Ljava/lang/String;"), "V",
- // The first three vars are out-of-order to verify that the order is not relied on.
- ".var 5 is t I from L4 to L6",
- ".var 1 is bar Ljava/lang/String; from L0 to L9",
- ".var 0 is this LTest; from L0 to L9",
- ".var 2 is x I from L1 to L9",
- ".var 3 is y I from L2 to L9",
- ".var 4 is z I from L3 to L9",
- ".var 5 is foobar Ljava/lang/String; from L7 to L9",
- ".limit locals 6",
- ".limit stack 2",
- "L0:",
- ".line 23",
- " iconst_1",
- " istore 2",
- "L1:",
- ".line 24",
- " iconst_2",
- " istore 3",
- "L2:",
- ".line 25",
- " iconst_3",
- " istore 4",
- "L3:",
- " .line 27",
- " iload 3",
- " istore 5",
- "L4:",
- " .line 28",
- " iload 2",
- " istore 3",
- "L5:",
- " .line 29",
- " iload 5",
- " istore 2",
- "L6:",
- " .line 32",
- " new java/lang/StringBuilder",
- " dup",
- " invokespecial java/lang/StringBuilder/<init>()V",
- " ldc \"And the value of y is: \"",
- " invokevirtual java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
- " iload 2",
- " invokevirtual java/lang/StringBuilder/append(I)Ljava/lang/StringBuilder;",
- " iload 3",
- " invokevirtual java/lang/StringBuilder/append(I)Ljava/lang/StringBuilder;",
- " iload 4",
- " invokevirtual java/lang/StringBuilder/append(I)Ljava/lang/StringBuilder;",
- " invokevirtual java/lang/StringBuilder/toString()Ljava/lang/String;",
- " astore 5",
- "L7:",
- " .line 34",
- " getstatic java/lang/System/out Ljava/io/PrintStream;",
- " aload 5",
- " invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V",
- "L8:",
- " .line 35",
- " return",
- "L9:");
+ MethodSignature foo =
+ clazz.addVirtualMethod(
+ "foo",
+ ImmutableList.of("Ljava/lang/String;"),
+ "V",
+ // The first three vars are out-of-order to verify that the order is not relied on.
+ ".var 5 is t I from L4 to L6",
+ ".var 1 is bar Ljava/lang/String; from L0 to L9",
+ ".var 0 is this LTest; from L0 to L9",
+ ".var 2 is x I from L1 to L9",
+ ".var 3 is y I from L2 to L9",
+ ".var 4 is z I from L3 to L9",
+ ".var 5 is foobar Ljava/lang/String; from L7 to L9",
+ ".limit locals 6",
+ ".limit stack 2",
+ "L0:",
+ ".line 23",
+ " iconst_1",
+ " istore 2",
+ "L1:",
+ ".line 24",
+ " iconst_2",
+ " istore 3",
+ "L2:",
+ ".line 25",
+ " iconst_3",
+ " istore 4",
+ "L3:",
+ " .line 27",
+ " iload 3",
+ " istore 5",
+ "L4:",
+ " .line 28",
+ " iload 2",
+ " istore 3",
+ "L5:",
+ " .line 29",
+ " iload 5",
+ " istore 2",
+ "L6:",
+ " .line 32",
+ " new java/lang/StringBuilder",
+ " dup",
+ " invokespecial java/lang/StringBuilder/<init>()V",
+ " ldc \"And the value of y is: \"",
+ " invokevirtual"
+ + " java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder;",
+ " iload 2",
+ " invokevirtual java/lang/StringBuilder/append(I)Ljava/lang/StringBuilder;",
+ " iload 3",
+ " invokevirtual java/lang/StringBuilder/append(I)Ljava/lang/StringBuilder;",
+ " iload 4",
+ " invokevirtual java/lang/StringBuilder/append(I)Ljava/lang/StringBuilder;",
+ " invokevirtual java/lang/StringBuilder/toString()Ljava/lang/String;",
+ " astore 5",
+ "L7:",
+ " .line 34",
+ " getstatic java/lang/System/out Ljava/io/PrintStream;",
+ " aload 5",
+ " invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V",
+ "L8:",
+ " .line 35",
+ " return",
+ "L9:");
clazz.addMainMethod(
".limit stack 3",
@@ -105,7 +110,7 @@
ClassSubject classSubject = inspector.clazz("Test");
MethodSubject methodSubject = classSubject.method(foo);
DexCode code = methodSubject.getMethod().getCode().asDexCode();
- DexDebugInfo info = code.getDebugInfo();
+ EventBasedDebugInfo info = code.getDebugInfo().asEventBasedInfo();
assertEquals(23, info.startLine);
assertEquals(1, info.parameters.length);
assertEquals("bar", info.parameters[0].toString());
diff --git a/src/test/java/com/android/tools/r8/reachabilitysensitive/ReachabilitySensitiveTest.java b/src/test/java/com/android/tools/r8/reachabilitysensitive/ReachabilitySensitiveTest.java
index 5ed7de6..c09e451 100644
--- a/src/test/java/com/android/tools/r8/reachabilitysensitive/ReachabilitySensitiveTest.java
+++ b/src/test/java/com/android/tools/r8/reachabilitysensitive/ReachabilitySensitiveTest.java
@@ -138,7 +138,7 @@
// as this is a release build.
assertTrue(
(code.getDebugInfo() == null)
- || Arrays.stream(code.getDebugInfo().events)
+ || Arrays.stream(code.getDebugInfo().asEventBasedInfo().events)
.allMatch(event -> !(event instanceof StartLocal)));
}
diff --git a/src/test/java/com/android/tools/r8/regress/b147865212/Regress147865212.java b/src/test/java/com/android/tools/r8/regress/b147865212/Regress147865212.java
index d7133e7..fa3661e 100644
--- a/src/test/java/com/android/tools/r8/regress/b147865212/Regress147865212.java
+++ b/src/test/java/com/android/tools/r8/regress/b147865212/Regress147865212.java
@@ -35,7 +35,8 @@
}
private boolean hasLocal(MethodSubject method) {
- return Arrays.stream(method.getMethod().getCode().asDexCode().getDebugInfo().events)
+ return Arrays.stream(
+ method.getMethod().getCode().asDexCode().getDebugInfo().asEventBasedInfo().events)
.anyMatch(event -> event instanceof StartLocal);
}
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnTargetedMethodTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnTargetedMethodTest.java
index 153bf38..02947f7 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnTargetedMethodTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnTargetedMethodTest.java
@@ -8,14 +8,29 @@
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import java.lang.reflect.Proxy;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+@RunWith(Parameterized.class)
public class IfOnTargetedMethodTest extends TestBase {
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimes().withApiLevel(AndroidApiLevel.B).build();
+ }
+
+ @Parameter public TestParameters parameters;
+
@Test
public void test() throws Exception {
String expectedOutput = StringUtils.lines("Hello world!");
@@ -23,13 +38,14 @@
testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expectedOutput);
CodeInspector inspector =
- testForR8(Backend.DEX)
+ testForR8(parameters.getBackend())
+ .setMinApi(parameters.getApiLevel())
.addInnerClasses(IfOnTargetedMethodTest.class)
.addKeepMainRule(TestClass.class)
.addKeepRules(
"-if interface * { @" + MyAnnotation.class.getTypeName() + " <methods>; }",
"-keep,allowobfuscation interface <1>")
- .run(TestClass.class)
+ .run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(expectedOutput)
.inspector();
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
index 813739b..d276f5f 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
@@ -20,6 +20,7 @@
import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.graph.DexDebugEvent;
import com.android.tools.r8.graph.DexDebugInfo;
+import com.android.tools.r8.graph.DexDebugInfo.EventBasedDebugInfo;
import com.android.tools.r8.graph.DexDebugPositionState;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
@@ -217,16 +218,21 @@
}
if (code.isDexCode()) {
DexCode dexCode = code.asDexCode();
- if (dexCode.getDebugInfo() != null) {
- for (DexString parameter : dexCode.getDebugInfo().parameters) {
- if (parameter != null) {
- return true;
- }
+ if (dexCode.getDebugInfo() == null) {
+ return false;
+ }
+ EventBasedDebugInfo eventBasedInfo = dexCode.getDebugInfo().asEventBasedInfo();
+ if (eventBasedInfo == null) {
+ return false;
+ }
+ for (DexString parameter : eventBasedInfo.parameters) {
+ if (parameter != null) {
+ return true;
}
- for (DexDebugEvent event : dexCode.getDebugInfo().events) {
- if (event instanceof DexDebugEvent.StartLocal) {
- return true;
- }
+ }
+ for (DexDebugEvent event : eventBasedInfo.events) {
+ if (event instanceof DexDebugEvent.StartLocal) {
+ return true;
}
}
return false;
@@ -272,10 +278,18 @@
if (debugInfo == null) {
return null;
}
+ if (debugInfo.isPcBasedInfo()) {
+ // For testing we could either view PC based encoding as not having a line table
+ // or as having the full line table for each PC, or we could trim the table to the PC at
+ // each valid instruction. It is unclear which choice that makes most sense so this throws
+ // for now.
+ throw new Unimplemented();
+ }
+ EventBasedDebugInfo eventBasedInfo = debugInfo.asEventBasedInfo();
Object2IntMap<InstructionSubject> lineNumberTable = new Object2IntOpenHashMap<>();
DexDebugPositionState state =
- new DexDebugPositionState(debugInfo.startLine, getMethod().getReference());
- Iterator<DexDebugEvent> iterator = Arrays.asList(debugInfo.events).iterator();
+ new DexDebugPositionState(eventBasedInfo.startLine, getMethod().getReference());
+ Iterator<DexDebugEvent> iterator = Arrays.asList(eventBasedInfo.events).iterator();
for (Instruction insn : code.instructions) {
int offset = insn.getOffset();
while (state.getCurrentPc() < offset && iterator.hasNext()) {