Merge "Update if simplification based on ranges."
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index 2a7b4c1..9f12853 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.ir.conversion.IRConverter;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.origin.CommandLineOrigin;
@@ -192,6 +193,7 @@
               options,
               marker == null ? null : ImmutableList.copyOf(markers),
               null,
+              GraphLense.getIdentityLense(),
               NamingLens.getIdentityLens(),
               null,
               null)
diff --git a/src/main/java/com/android/tools/r8/DexFileMergerHelper.java b/src/main/java/com/android/tools/r8/DexFileMergerHelper.java
index 5987b99..a26924e 100644
--- a/src/main/java/com/android/tools/r8/DexFileMergerHelper.java
+++ b/src/main/java/com/android/tools/r8/DexFileMergerHelper.java
@@ -10,6 +10,7 @@
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.ExceptionUtils;
@@ -91,8 +92,17 @@
         List<Marker> markers = app.dexItemFactory.extractMarkers();
 
         assert !options.hasMethodsFilter();
-        new ApplicationWriter(app, options, markers, null, NamingLens.getIdentityLens(), null, null)
-            .write(executor);
+        ApplicationWriter writer =
+            new ApplicationWriter(
+                app,
+                options,
+                markers,
+                null,
+                GraphLense.getIdentityLense(),
+                NamingLens.getIdentityLens(),
+                null,
+                null);
+        writer.write(executor);
         options.printWarnings();
       } catch (ExecutionException e) {
         R8.unwrapExecutionException(e);
diff --git a/src/main/java/com/android/tools/r8/DexSplitterHelper.java b/src/main/java/com/android/tools/r8/DexSplitterHelper.java
index 3e299f2..68dc702 100644
--- a/src/main/java/com/android/tools/r8/DexSplitterHelper.java
+++ b/src/main/java/com/android/tools/r8/DexSplitterHelper.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexApplication.Builder;
 import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.utils.ExceptionUtils;
@@ -96,6 +97,7 @@
                   options,
                   markers,
                   null,
+                  GraphLense.getIdentityLense(),
                   NamingLens.getIdentityLens(),
                   null,
                   null,
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 0f663c4..215ced9 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -176,6 +176,7 @@
       ExecutorService executorService,
       DexApplication application,
       String deadCode,
+      GraphLense graphLense,
       NamingLens namingLens,
       String proguardSeedsData,
       InternalOptions options,
@@ -188,6 +189,7 @@
                 application,
                 options,
                 deadCode,
+                graphLense,
                 namingLens,
                 proguardSeedsData,
                 proguardMapSupplier)
@@ -198,6 +200,7 @@
                 options,
                 marker == null ? null : Collections.singletonList(marker),
                 deadCode,
+                graphLense,
                 namingLens,
                 proguardSeedsData,
                 proguardMapSupplier)
@@ -514,6 +517,7 @@
           executorService,
           application,
           application.deadCode,
+          appView.getGraphLense(),
           namingLens,
           proguardSeedsData,
           options,
diff --git a/src/main/java/com/android/tools/r8/bisect/Bisect.java b/src/main/java/com/android/tools/r8/bisect/Bisect.java
index 7ef43a3..60167c5 100644
--- a/src/main/java/com/android/tools/r8/bisect/Bisect.java
+++ b/src/main/java/com/android/tools/r8/bisect/Bisect.java
@@ -177,7 +177,8 @@
       throws IOException, ExecutionException {
     InternalOptions options = new InternalOptions();
     AndroidAppConsumers compatSink = new AndroidAppConsumers(options);
-    ApplicationWriter writer = new ApplicationWriter(app, options, null, null, null, null, null);
+    ApplicationWriter writer =
+        new ApplicationWriter(app, options, null, null, null, null, null, null);
     writer.write(executor);
     compatSink.build().writeToDirectory(output, OutputMode.DexIndexed);
   }
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 e1905ff..736cb3f 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -25,6 +25,7 @@
 import com.android.tools.r8.graph.DexTypeList;
 import com.android.tools.r8.graph.DexValue;
 import com.android.tools.r8.graph.EnclosingMethodAttribute;
+import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.graph.InnerClassAttribute;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ParameterAnnotationsList;
@@ -51,6 +52,7 @@
 
   public final DexApplication application;
   public final String deadCode;
+  public final GraphLense graphLense;
   public final NamingLens namingLens;
   public final String proguardSeedsData;
   public final InternalOptions options;
@@ -120,6 +122,7 @@
       InternalOptions options,
       List<Marker> markers,
       String deadCode,
+      GraphLense graphLense,
       NamingLens namingLens,
       String proguardSeedsData,
       ProguardMapSupplier proguardMapSupplier) {
@@ -128,6 +131,7 @@
         options,
         markers,
         deadCode,
+        graphLense,
         namingLens,
         proguardSeedsData,
         proguardMapSupplier,
@@ -139,6 +143,7 @@
       InternalOptions options,
       List<Marker> markers,
       String deadCode,
+      GraphLense graphLense,
       NamingLens namingLens,
       String proguardSeedsData,
       ProguardMapSupplier proguardMapSupplier,
@@ -154,6 +159,7 @@
       }
     }
     this.deadCode = deadCode;
+    this.graphLense = graphLense;
     this.namingLens = namingLens;
     this.proguardSeedsData = proguardSeedsData;
     this.proguardMapSupplier = proguardMapSupplier;
@@ -258,7 +264,13 @@
       options.reporter.failIfPendingErrors();
       // Supply info to all additional resource consumers.
       supplyAdditionalConsumers(
-          application, namingLens, options, deadCode, proguardMapSupplier, proguardSeedsData);
+          application,
+          graphLense,
+          namingLens,
+          options,
+          deadCode,
+          proguardMapSupplier,
+          proguardSeedsData);
     } finally {
       application.timing.end();
     }
@@ -266,6 +278,7 @@
 
   public static void supplyAdditionalConsumers(
       DexApplication application,
+      GraphLense graphLense,
       NamingLens namingLens,
       InternalOptions options,
       String deadCode,
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
index a9df6a3..8fd09d0 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
@@ -40,8 +40,10 @@
 import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceMap.Entry;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
+import it.unimi.dsi.fastutil.ints.IntArrayList;
 import it.unimi.dsi.fastutil.ints.IntArraySet;
 import it.unimi.dsi.fastutil.ints.IntIterator;
+import it.unimi.dsi.fastutil.ints.IntList;
 import it.unimi.dsi.fastutil.ints.IntSet;
 import it.unimi.dsi.fastutil.objects.Reference2IntArrayMap;
 import it.unimi.dsi.fastutil.objects.Reference2IntMap;
@@ -144,6 +146,10 @@
   // List of intervals that no register has been allocated to sorted by first live range.
   protected PriorityQueue<LiveIntervals> unhandled = new PriorityQueue<>();
 
+  // The registers that have been released as a result of advancing to the next live intervals.
+  // A register is released if an active or inactive interval becomes handled.
+  private IntList expiredHere = new IntArrayList();
+
   // List of intervals for the result of move-exception instructions.
   // Always empty in mode ALLOW_ARGUMENT_REUSE.
   private List<LiveIntervals> moveExceptionIntervals = new ArrayList<>();
@@ -826,6 +832,7 @@
     // Go through each unhandled live interval and find a register for it.
     while (!unhandled.isEmpty()) {
       assert invariantsHold(mode);
+      expiredHere.clear();
 
       LiveIntervals unhandledInterval = unhandled.poll();
 
@@ -849,6 +856,12 @@
         if (start >= activeIntervals.getEnd()) {
           activeIterator.remove();
           freeOccupiedRegistersForIntervals(activeIntervals);
+          if (start == activeIntervals.getEnd()) {
+            expiredHere.add(activeIntervals.getRegister());
+            if (activeIntervals.getType().isWide()) {
+              expiredHere.add(activeIntervals.getRegister() + 1);
+            }
+          }
         } else if (!activeIntervals.overlapsPosition(start)) {
           activeIterator.remove();
           assert activeIntervals.getRegister() != NO_REGISTER;
@@ -863,6 +876,12 @@
         LiveIntervals inactiveIntervals = inactiveIterator.next();
         if (start >= inactiveIntervals.getEnd()) {
           inactiveIterator.remove();
+          if (start == inactiveIntervals.getEnd()) {
+            expiredHere.add(inactiveIntervals.getRegister());
+            if (inactiveIntervals.getType().isWide()) {
+              expiredHere.add(inactiveIntervals.getRegister() + 1);
+            }
+          }
         } else if (inactiveIntervals.overlapsPosition(start)) {
           inactiveIterator.remove();
           assert inactiveIntervals.getRegister() != NO_REGISTER;
@@ -1153,17 +1172,137 @@
     return false;
   }
 
-  private int getSpillRegister(LiveIntervals intervals) {
+  private int getNewSpillRegister(LiveIntervals intervals) {
     if (intervals.isArgumentInterval()) {
       return intervals.getSplitParent().getRegister();
     }
 
     int register = maxRegisterNumber + 1;
     increaseCapacity(maxRegisterNumber + intervals.requiredRegisters());
+    return register;
+  }
+
+  private int getSpillRegister(LiveIntervals intervals, IntList excludedRegisters) {
+    if (intervals.isArgumentInterval()) {
+      return intervals.getSplitParent().getRegister();
+    }
+
+    TreeSet<Integer> previousFreeRegisters = new TreeSet<>(freeRegisters);
+    int previousMaxRegisterNumber = maxRegisterNumber;
+    freeRegisters.removeAll(expiredHere);
+    if (excludedRegisters != null) {
+      freeRegisters.removeAll(excludedRegisters);
+    }
+
+    // Check if we can use a register that was previously used as a register for intervals.
+    // This could lead to fewer moves during resolution.
+    int register = -1;
+    for (LiveIntervals split : intervals.getSplitParent().getSplitChildren()) {
+      int candidate = split.getRegister();
+      if (candidate != NO_REGISTER
+          && registersAreFreeAndConsecutive(candidate, intervals.getType().isWide())
+          && maySpillLiveIntervalsToRegister(intervals, candidate, previousMaxRegisterNumber)) {
+        register = candidate;
+        break;
+      }
+    }
+
+    if (register == -1) {
+      do {
+        // If the register needs to fit in 4 bits at the next use, then prioritize a small register.
+        // If we can find a small register, we do not need to insert a move at the next use.
+        boolean prioritizeSmallRegisters =
+            !intervals.getUses().isEmpty()
+                && intervals.getUses().first().getLimit() == Constants.U4BIT_MAX;
+        register =
+            getFreeConsecutiveRegisters(intervals.requiredRegisters(), prioritizeSmallRegisters);
+      } while (!maySpillLiveIntervalsToRegister(intervals, register, previousMaxRegisterNumber));
+    }
+
+    // Going to spill to the register (pair).
+    freeRegisters = previousFreeRegisters;
+    // If getFreeConsecutiveRegisters had to increment |maxRegisterNumber|, we need to update
+    // freeRegisters.
+    for (int i = previousMaxRegisterNumber + 1; i <= maxRegisterNumber; ++i) {
+      freeRegisters.add(i);
+    }
     assert registersAreFree(register, intervals.getType().isWide());
     return register;
   }
 
+  private boolean maySpillLiveIntervalsToRegister(
+      LiveIntervals intervals, int register, int previousMaxRegisterNumber) {
+    if (register > previousMaxRegisterNumber) {
+      // Nothing can prevent us from spilling to an entirely fresh register.
+      return true;
+    }
+
+    // If we are about to spill to an argument register, we need to be careful that the live range
+    // that is being spilled does not overlap with the live range of the corresponding argument.
+    //
+    // Note that this is *not* guaranteed when overlapsInactiveIntervals is null, because it is
+    // possible that some live ranges of the argument are still in the unhandled set.
+    if (register < numberOfArgumentRegisters) {
+      // Find the first argument value that uses the given register.
+      LiveIntervals argumentLiveIntervals = firstArgumentValue.getLiveIntervals();
+      while (!argumentLiveIntervals.usesRegister(register, intervals.getType().isWide())) {
+        argumentLiveIntervals = argumentLiveIntervals.getNextConsecutive();
+        assert argumentLiveIntervals != null;
+      }
+      do {
+        if (argumentLiveIntervals.anySplitOverlaps(intervals)) {
+          // Remove so that next invocation of getFreeConsecutiveRegisters does not consider this.
+          freeRegisters.remove(register);
+          // We have just established that there is an overlap between the live range of the
+          // current argument and the live range we need to find a register for. Therefore, if
+          // the argument is wide, and the current register corresponds to the low register of the
+          // argument, we know that the subsequent register will not work either.
+          if (register == argumentLiveIntervals.getRegister()
+              && argumentLiveIntervals.getType().isWide()) {
+            freeRegisters.remove(register + 1);
+          }
+          return false;
+        }
+        // The next argument live interval may also use the register, if it is a wide register pair.
+        argumentLiveIntervals = argumentLiveIntervals.getNextConsecutive();
+      } while (argumentLiveIntervals != null
+          && argumentLiveIntervals.usesRegister(register, intervals.getType().isWide()));
+    }
+
+    // Check for overlap with inactive intervals.
+    LiveIntervals overlapsInactiveIntervals = null;
+    for (LiveIntervals inactiveIntervals : inactive) {
+      if (inactiveIntervals.usesRegister(register, intervals.getType().isWide())
+          && intervals.overlaps(inactiveIntervals)) {
+        overlapsInactiveIntervals = inactiveIntervals;
+        break;
+      }
+    }
+    if (overlapsInactiveIntervals != null) {
+      // Remove so that next invocation of getFreeConsecutiveRegisters does not consider this.
+      freeRegisters.remove(register);
+      if (register == overlapsInactiveIntervals.getRegister()
+          && overlapsInactiveIntervals.getType().isWide()) {
+        freeRegisters.remove(register + 1);
+      }
+      return false;
+    }
+
+    // Check for overlap with the move exception interval.
+    boolean overlapsMoveExceptionInterval =
+        hasDedicatedMoveExceptionRegister()
+            && (register == getMoveExceptionRegister()
+                || (intervals.getType().isWide() && register + 1 == getMoveExceptionRegister()))
+            && overlapsMoveExceptionInterval(intervals);
+    if (overlapsMoveExceptionInterval) {
+      // Remove so that next invocation of getFreeConsecutiveRegisters does not consider this.
+      freeRegisters.remove(register);
+      return false;
+    }
+
+    return true;
+  }
+
   private int toInstructionPosition(int position) {
     return position % 2 == 0 ? position : position + 1;
   }
@@ -1496,7 +1635,7 @@
       // of finding another candidate to spill via allocateBlockedRegister.
       if (!unhandledInterval.getUses().first().hasConstraint()) {
         int nextConstrainedPosition = unhandledInterval.firstUseWithConstraint().getPosition();
-        int register = getSpillRegister(unhandledInterval);
+        int register = getSpillRegister(unhandledInterval, null);
         LiveIntervals split = unhandledInterval.splitBefore(nextConstrainedPosition);
         assignFreeRegisterToUnhandledInterval(unhandledInterval, register);
         unhandled.add(split);
@@ -1839,7 +1978,8 @@
       int splitPosition = unhandledInterval.getFirstUse();
       LiveIntervals split = unhandledInterval.splitBefore(splitPosition);
       assert split != unhandledInterval;
-      int registerNumber = getSpillRegister(unhandledInterval);
+      // Experiments show that it has a positive impact on code size to use a fresh register here.
+      int registerNumber = getNewSpillRegister(unhandledInterval);
       assignFreeRegisterToUnhandledInterval(unhandledInterval, registerNumber);
       unhandledInterval.setSpilled(true);
       unhandled.add(split);
@@ -1926,6 +2066,18 @@
       LiveIntervals unhandledInterval, int candidate, boolean candidateIsWide) {
     assert unhandledInterval.getRegister() == NO_REGISTER;
     assert atLeastOneOfRegistersAreTaken(candidate, candidateIsWide);
+    // Registers that we cannot choose for spilling.
+    IntList excludedRegisters = new IntArrayList(candidateIsWide ? 2 : 1);
+    excludedRegisters.add(candidate);
+    if (candidateIsWide) {
+      excludedRegisters.add(candidate + 1);
+    }
+    if (unhandledInterval.isArgumentInterval()
+        && unhandledInterval != unhandledInterval.getSplitParent()) {
+      // This live interval will become active in its original argument register and in the
+      // candidate register simultaneously.
+      unhandledInterval.getSplitParent().forEachRegister(excludedRegisters::add);
+    }
     // Spill overlapping active intervals.
     List<LiveIntervals> newActive = new ArrayList<>();
     Iterator<LiveIntervals> activeIterator = active.iterator();
@@ -1934,7 +2086,7 @@
       assert registersForIntervalsAreTaken(intervals);
       if (intervals.usesRegister(candidate, candidateIsWide)) {
         activeIterator.remove();
-        int registerNumber = getSpillRegister(intervals);
+        int registerNumber = getSpillRegister(intervals, excludedRegisters);
         // Important not to free the registers for intervals before finding a spill register,
         // because we might otherwise end up spilling to the current registers of intervals,
         // depending on getSpillRegister.
@@ -2662,8 +2814,33 @@
   }
 
   private int getFreeConsecutiveRegisters(int numberOfRegisters) {
+    return getFreeConsecutiveRegisters(numberOfRegisters, false);
+  }
+
+  private int getFreeConsecutiveRegisters(int numberOfRegisters, boolean prioritizeSmallRegisters) {
     int oldMaxRegisterNumber = maxRegisterNumber;
-    Iterator<Integer> freeRegistersIterator = freeRegisters.iterator();
+    TreeSet<Integer> freeRegistersWithDesiredOrdering = this.freeRegisters;
+    if (prioritizeSmallRegisters) {
+      freeRegistersWithDesiredOrdering =
+          new TreeSet<>(
+              (Integer x, Integer y) -> {
+                boolean xIsArgument = x < numberOfArgumentRegisters;
+                boolean yIsArgument = y < numberOfArgumentRegisters;
+                // If x is an argument and y is not, then prioritize y.
+                if (xIsArgument && !yIsArgument) {
+                  return 1;
+                }
+                // If x is not an argument and y is, then prioritize x.
+                if (!xIsArgument && yIsArgument) {
+                  return -1;
+                }
+                // Otherwise use their normal ordering.
+                return x - y;
+              });
+      freeRegistersWithDesiredOrdering.addAll(this.freeRegisters);
+    }
+
+    Iterator<Integer> freeRegistersIterator = freeRegistersWithDesiredOrdering.iterator();
     int first = getNextFreeRegister(freeRegistersIterator);
     int current = first;
     while (current - first + 1 != numberOfRegisters) {
@@ -2692,6 +2869,22 @@
     return first;
   }
 
+  private boolean registersAreFreeAndConsecutive(int register, boolean registerIsWide) {
+    if (!freeRegisters.contains(register)) {
+      return false;
+    }
+    if (registerIsWide) {
+      if (!freeRegisters.contains(register + 1)) {
+        return false;
+      }
+      if (register == numberOfArgumentRegisters - 1) {
+        // Will not be consecutive after reordering the arguments and temporaries.
+        return false;
+      }
+    }
+    return true;
+  }
+
   private int getNextFreeRegister(Iterator<Integer> freeRegistersIterator) {
     if (freeRegistersIterator.hasNext()) {
       return freeRegistersIterator.next();
diff --git a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
index 7a25e1a..6537667 100644
--- a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
@@ -31,6 +31,7 @@
 import com.android.tools.r8.graph.DexValue.DexValueString;
 import com.android.tools.r8.graph.DexValue.DexValueType;
 import com.android.tools.r8.graph.DexValue.UnknownDexValue;
+import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.graph.InnerClassAttribute;
 import com.android.tools.r8.graph.JarClassFileReader;
 import com.android.tools.r8.graph.ParameterAnnotationsList;
@@ -61,6 +62,7 @@
   private static final boolean PRINT_CF = false;
 
   private final DexApplication application;
+  private final GraphLense graphLense;
   private final NamingLens namingLens;
   private final InternalOptions options;
 
@@ -72,10 +74,12 @@
       DexApplication application,
       InternalOptions options,
       String deadCode,
+      GraphLense graphLense,
       NamingLens namingLens,
       String proguardSeedsData,
       ProguardMapSupplier proguardMapSupplier) {
     this.application = application;
+    this.graphLense = graphLense;
     this.namingLens = namingLens;
     this.options = options;
     this.proguardMapSupplier = proguardMapSupplier;
@@ -102,7 +106,13 @@
       }
     }
     ApplicationWriter.supplyAdditionalConsumers(
-        application, namingLens, options, deadCode, proguardMapSupplier, proguardSeedsData);
+        application,
+        graphLense,
+        namingLens,
+        options,
+        deadCode,
+        proguardMapSupplier,
+        proguardSeedsData);
   }
 
   private void writeClass(DexProgramClass clazz, ClassFileConsumer consumer) throws IOException {
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
index 54b90b2..7526e3f 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
@@ -56,7 +56,7 @@
     private Position keepParameterNamesOptionPosition;
     private final ProguardClassFilter.Builder adaptClassStrings = ProguardClassFilter.builder();
     private final ProguardPathFilter.Builder adaptResourceFilenames = ProguardPathFilter.builder();
-    private final ProguardPathFilter.Builder adaptResourceFilecontents =
+    private final ProguardPathFilter.Builder adaptResourceFileContents =
         ProguardPathFilter.builder();
     private final ProguardPathFilter.Builder keepDirectories = ProguardPathFilter.builder();
     private boolean forceProguardCompatibility = false;
@@ -235,8 +235,8 @@
       adaptResourceFilenames.addPattern(pattern);
     }
 
-    public void addAdaptResourceFilecontents(ProguardPathList pattern) {
-      adaptResourceFilecontents.addPattern(pattern);
+    public void addAdaptResourceFileContents(ProguardPathList pattern) {
+      adaptResourceFileContents.addPattern(pattern);
     }
 
     public void addKeepDirectories(ProguardPathList pattern) {
@@ -288,7 +288,7 @@
           keepParameterNames,
           adaptClassStrings.build(),
           adaptResourceFilenames.build(),
-          adaptResourceFilecontents.build(),
+          adaptResourceFileContents.build(),
           keepDirectories.build());
 
       reporter.failIfPendingErrors();
@@ -357,7 +357,7 @@
   private final boolean keepParameterNames;
   private final ProguardClassFilter adaptClassStrings;
   private final ProguardPathFilter adaptResourceFilenames;
-  private final ProguardPathFilter adaptResourceFilecontents;
+  private final ProguardPathFilter adaptResourceFileContents;
   private final ProguardPathFilter keepDirectories;
 
   private ProguardConfiguration(
@@ -395,7 +395,7 @@
       boolean keepParameterNames,
       ProguardClassFilter adaptClassStrings,
       ProguardPathFilter adaptResourceFilenames,
-      ProguardPathFilter adaptResourceFilecontents,
+      ProguardPathFilter adaptResourceFileContents,
       ProguardPathFilter keepDirectories) {
     this.parsedConfiguration = parsedConfiguration;
     this.dexItemFactory = factory;
@@ -431,7 +431,7 @@
     this.keepParameterNames = keepParameterNames;
     this.adaptClassStrings = adaptClassStrings;
     this.adaptResourceFilenames = adaptResourceFilenames;
-    this.adaptResourceFilecontents = adaptResourceFilecontents;
+    this.adaptResourceFileContents = adaptResourceFileContents;
     this.keepDirectories = keepDirectories;
   }
 
@@ -575,8 +575,8 @@
     return adaptResourceFilenames;
   }
 
-  public ProguardPathFilter getAdaptResourceFilecontents() {
-    return adaptResourceFilecontents;
+  public ProguardPathFilter getAdaptResourceFileContents() {
+    return adaptResourceFileContents;
   }
 
   public ProguardPathFilter getKeepDirectories() {
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index e070db9..b9c3012 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -374,7 +374,7 @@
         if (failOnPartiallyImplementedOptions) {
           failPartiallyImplementedOption("-adaptresourcefilecontents", optionStart);
         }
-        parsePathFilter(configurationBuilder::addAdaptResourceFilecontents);
+        parsePathFilter(configurationBuilder::addAdaptResourceFileContents);
       } else if (acceptString("identifiernamestring")) {
         configurationBuilder.addRule(parseIdentifierNameStringRule(optionStart));
       } else if (acceptString("if")) {
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 44b491e..afd407e 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -14,6 +14,7 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.shaking.FilteredClassPath;
 import com.android.tools.r8.shaking.ProguardConfiguration;
@@ -1609,6 +1610,7 @@
         Executors.newSingleThreadExecutor(),
         application,
         null,
+        GraphLense.getIdentityLense(),
         NamingLens.getIdentityLens(),
         null,
         options,
diff --git a/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java b/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
index ead9175..3b12cc4 100644
--- a/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
+++ b/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
@@ -22,6 +22,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DexTypeList;
 import com.android.tools.r8.graph.DirectMappedDexApplication;
+import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ParameterAnnotationsList;
 import com.android.tools.r8.naming.NamingLens;
@@ -135,7 +136,14 @@
     options.programConsumer = consumer;
     ApplicationWriter writer =
         new ApplicationWriter(
-            application, options, null, null, NamingLens.getIdentityLens(), null, null);
+            application,
+            options,
+            null,
+            null,
+            GraphLense.getIdentityLense(),
+            NamingLens.getIdentityLens(),
+            null,
+            null);
     ExecutorService executorService = ThreadUtils.getExecutorService(options);
     writer.write(executorService);
     List<Set<String>> generatedDescriptors = consumer.getDescriptors();
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index 0df78bc..d56c0e7 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -678,7 +678,14 @@
     DirectMappedDexApplication application = builder.build().toDirect();
     ApplicationWriter writer =
         new ApplicationWriter(
-            application, options, null, null, NamingLens.getIdentityLens(), null, null);
+            application,
+            options,
+            null,
+            null,
+            GraphLense.getIdentityLense(),
+            NamingLens.getIdentityLens(),
+            null,
+            null);
     ExecutorService executor = ThreadUtils.getExecutorService(options);
     AndroidAppConsumers compatSink = new AndroidAppConsumers(options);
     try {
diff --git a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
index 7325be3..b410183 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -1234,7 +1234,7 @@
         "-keepdirectories"
     ));
     checkFileFilterMatchAnything(config.getAdaptResourceFilenames());
-    checkFileFilterMatchAnything(config.getAdaptResourceFilecontents());
+    checkFileFilterMatchAnything(config.getAdaptResourceFileContents());
     checkFileFilterMatchAnything(config.getKeepDirectories());
   }
 
@@ -1247,7 +1247,7 @@
         "-adaptresourcefilecontents"
     ));
     checkFileFilterMatchAnything(config.getAdaptResourceFilenames());
-    checkFileFilterMatchAnything(config.getAdaptResourceFilecontents());
+    checkFileFilterMatchAnything(config.getAdaptResourceFileContents());
     checkFileFilterMatchAnything(config.getKeepDirectories());
   }
 
@@ -1260,7 +1260,7 @@
         "-adaptresourcefilenames"
     ));
     checkFileFilterMatchAnything(config.getAdaptResourceFilenames());
-    checkFileFilterMatchAnything(config.getAdaptResourceFilecontents());
+    checkFileFilterMatchAnything(config.getAdaptResourceFileContents());
     checkFileFilterMatchAnything(config.getKeepDirectories());
   }
 
@@ -1282,7 +1282,7 @@
         "-keepdirectories " + FILE_FILTER_SINGLE
     ));
     checkFileFilterSingle(config.getAdaptResourceFilenames());
-    checkFileFilterSingle(config.getAdaptResourceFilecontents());
+    checkFileFilterSingle(config.getAdaptResourceFileContents());
     checkFileFilterSingle(config.getKeepDirectories());
   }
 
@@ -1315,7 +1315,7 @@
         "-keepdirectories " + FILE_FILTER_MULTIPLE
     ));
     checkFileFilterMultiple(config.getAdaptResourceFilenames());
-    checkFileFilterMultiple(config.getAdaptResourceFilecontents());
+    checkFileFilterMultiple(config.getAdaptResourceFileContents());
     checkFileFilterMultiple(config.getKeepDirectories());
   }
 
diff --git a/src/test/java/com/android/tools/r8/utils/Smali.java b/src/test/java/com/android/tools/r8/utils/Smali.java
index 68de752..ac46dfc 100644
--- a/src/test/java/com/android/tools/r8/utils/Smali.java
+++ b/src/test/java/com/android/tools/r8/utils/Smali.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.dex.ApplicationReader;
 import com.android.tools.r8.dex.ApplicationWriter;
 import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.origin.Origin;
 import com.google.common.collect.ImmutableList;
@@ -110,7 +111,14 @@
           app, options, new Timing("smali")).read(executor);
       ApplicationWriter writer =
           new ApplicationWriter(
-              dexApp, options, null, null, NamingLens.getIdentityLens(), null, null);
+              dexApp,
+              options,
+              null,
+              null,
+              GraphLense.getIdentityLense(),
+              NamingLens.getIdentityLens(),
+              null,
+              null);
       writer.write(executor);
       return consumer.contents;
     } finally {