Fix crash in DexCallSite.collectIndexedItems()
Set DexCallSite.method and instructionOffset before calling indexedItems
.addCallSite() to avoid AssertionError/NullPointerException inside
DexCallSite.compareTo().
Since DexCallSite implements Comparable, a HashMap containing
DexCallSites is allowed to use compareTo() when placing multiple
elements in the same hash bucket. Since indexedItems.addCallSite() adds
the DexCallSite to a HashMap, compareTo() must not throw an exception
when addCallSite() is called.
Fixes I4b9e8f36b 33c5b35e3 ("Make output deterministic for dex code with
invoke-custom.", 2018-05-14).
Bug: 78569026
Change-Id: I954fcfa8667586792f6201067ea312c1fa9543a0
diff --git a/src/main/java/com/android/tools/r8/graph/DexCallSite.java b/src/main/java/com/android/tools/r8/graph/DexCallSite.java
index e690317..11bca5a 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCallSite.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCallSite.java
@@ -118,10 +118,14 @@
public void collectIndexedItems(IndexedItemCollection indexedItems,
DexMethod method, int instructionOffset) {
assert method != null;
+ // Since collectIndexedItems() is called in transactions that may be rolled back, we may end up
+ // setting this.method and this.instructionOffset more than once. If we do set them more than
+ // once, then we must have the same values for method and instructionOffset every time.
+ assert this.method == null || this.method == method;
+ assert this.instructionOffset == 0 || this.instructionOffset == instructionOffset;
+ this.method = method;
+ this.instructionOffset = instructionOffset;
if (indexedItems.addCallSite(this)) {
- assert this.method == null;
- this.method = method;
- this.instructionOffset = instructionOffset;
methodName.collectIndexedItems(indexedItems, method, instructionOffset);
methodProto.collectIndexedItems(indexedItems, method, instructionOffset);
bootstrapMethod.collectIndexedItems(indexedItems, method, instructionOffset);