Merge "Avoid tree shaking of fields that are read or written"
diff --git a/src/main/java/com/android/tools/r8/ir/code/ValueType.java b/src/main/java/com/android/tools/r8/ir/code/ValueType.java
index c414342..69618b3 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ValueType.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ValueType.java
@@ -48,6 +48,10 @@
     if (other == INT_OR_FLOAT_OR_NULL) {
       return other.meet(this);
     }
+    if (isPreciseType() && other.isPreciseType()) {
+      // Precise types must be identical, hitting the first check above.
+      throw new CompilationError("Cannot compute meet of types: " + this + " and " + other);
+    }
     switch (this) {
       case OBJECT:
         {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index 98b4502..3612944 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -87,6 +87,7 @@
 import com.android.tools.r8.utils.Pair;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
 import it.unimi.dsi.fastutil.ints.IntArrayList;
 import it.unimi.dsi.fastutil.ints.IntArraySet;
@@ -309,6 +310,7 @@
   // Basic blocks. Added after processing from the worklist.
   private final LinkedList<BasicBlock> blocks = new LinkedList<>();
 
+  private BasicBlock entryBlock = null;
   private BasicBlock currentBlock = null;
   final private ValueNumberGenerator valueNumberGenerator;
   private final DexEncodedMethod method;
@@ -324,6 +326,9 @@
   private Value previousLocalValue = null;
   private final List<Value> debugLocalReads = new ArrayList<>();
 
+  // Lazily populated list of local values that are referenced without being actually defined.
+  private Int2ReferenceMap<List<Value>> uninitializedDebugLocalValues = null;
+
   private int nextBlockNumber = 0;
 
   // Flag indicating if the instructions define values with imprecise types.
@@ -420,6 +425,7 @@
     processedInstructions = null;
 
     setCurrentBlock(targets.get(INITIAL_BLOCK_OFFSET).block);
+    entryBlock = currentBlock;
     source.buildPrelude(this);
 
     // Process normal blocks reachable from the entry block using a worklist of reachable
@@ -438,6 +444,21 @@
     // Insert debug positions so all position changes are marked by an explicit instruction.
     boolean hasDebugPositions = insertDebugPositions();
 
+    // Insert definitions for all uninitialized local values.
+    if (uninitializedDebugLocalValues != null) {
+      InstructionListIterator it = entryBlock.listIterator();
+      it.nextUntil(i -> !i.isArgument());
+      it.previous();
+      for (List<Value> values : uninitializedDebugLocalValues.values()) {
+        for (Value value : values) {
+          Instruction def = new DebugLocalUninitialized(value);
+          def.setBlock(entryBlock);
+          def.setPosition(Position.none());
+          it.add(def);
+        }
+      }
+    }
+
     // Clear all reaching definitions to free up memory (and avoid invalid use).
     for (BasicBlock block : blocks) {
       block.clearCurrentDefinitions();
@@ -648,15 +669,6 @@
     addInstruction(new Argument(value));
   }
 
-  public void addDebugUninitialized(int register, ValueType type) {
-    if (!options.debug) {
-      return;
-    }
-    Value value = writeRegister(register, type, ThrowingInfo.NO_THROW, null);
-    assert !value.hasLocalInfo();
-    addInstruction(new DebugLocalUninitialized(value));
-  }
-
   private void addDebugLocalWrite(ValueType type, int dest, Value in) {
     assert options.debug;
     Value out = writeRegister(dest, type, ThrowingInfo.NO_THROW);
@@ -670,7 +682,7 @@
     assert local != null;
     assert local == getIncomingLocal(register);
     ValueType valueType = ValueType.fromDexType(local.type);
-    return readRegisterIgnoreLocal(register, valueType);
+    return readRegisterIgnoreLocal(register, valueType, local);
   }
 
   private static boolean isValidFor(Value value, DebugLocalInfo local) {
@@ -697,7 +709,7 @@
     assert local == getOutgoingLocal(register);
     ValueType valueType = ValueType.fromDexType(local.type);
     // TODO(mathiasr): Here we create a Phi with type based on debug info. That's just wrong!
-    Value incomingValue = readRegisterIgnoreLocal(register, valueType);
+    Value incomingValue = readRegisterIgnoreLocal(register, valueType, local);
 
     // TODO(mathiasr): This can be simplified once trivial phi removal is local-info aware.
     if (incomingValue.isPhi() || incomingValue.getLocalInfo() != local) {
@@ -1672,8 +1684,7 @@
     return value;
   }
 
-  private Value readRegisterIgnoreLocal(int register, ValueType type) {
-    DebugLocalInfo local = getIncomingLocal(register);
+  private Value readRegisterIgnoreLocal(int register, ValueType type, DebugLocalInfo local) {
     return readRegister(register, type, currentBlock, EdgeType.NON_EDGE, local);
   }
 
@@ -1707,7 +1718,14 @@
     }
     // If the register still has unknown value create a phi value for it.
     if (value == null) {
-      if (!block.isSealed()) {
+      if (block == entryBlock && local != null) {
+        assert block.getPredecessors().isEmpty();
+        // If a debug-local is referenced at the entry block, lazily introduce an SSA value for it.
+        // This value must *not* be added to the entry blocks current definitions since
+        // uninitialized debug-locals may be referenced at the same register/local-index yet be of
+        // different types (eg, int in one part of the CFG and float in a disjoint part).
+        value = getUninitializedDebugLocalValue(register, type, local);
+      } else if (!block.isSealed()) {
         assert !blocks.isEmpty() : "No write to " + register;
         Phi phi = new Phi(valueNumberGenerator.next(), block, type, local);
         block.addIncompletePhi(register, phi, readingEdge);
@@ -1734,6 +1752,31 @@
     return value;
   }
 
+  private Value getUninitializedDebugLocalValue(
+      int register, ValueType type, DebugLocalInfo local) {
+    assert type == ValueType.fromDexType(local.type);
+    if (uninitializedDebugLocalValues == null) {
+      uninitializedDebugLocalValues = new Int2ReferenceOpenHashMap<>();
+    }
+    List<Value> values = uninitializedDebugLocalValues.get(register);
+    if (values != null) {
+      for (Value value : values) {
+        if (value.outType() == type) {
+          return value;
+        }
+      }
+    } else {
+      values = new ArrayList<>(2);
+      uninitializedDebugLocalValues.put(register, values);
+    }
+    // Create a new SSA value for the uninitialized local value.
+    // Note that the uninitialized local value must not itself have local information, so that it
+    // does not contribute to the visible/live-range of the local variable.
+    Value value = new Value(valueNumberGenerator.next(), type, null);
+    values.add(value);
+    return value;
+  }
+
   public Value readNumericRegister(int register, NumericType type) {
     return readRegister(register, ValueType.fromNumericType(type));
   }
@@ -1785,7 +1828,7 @@
     previousLocalValue =
         (incomingLocal == null || incomingLocal != outgoingLocal)
             ? null
-            : readRegisterIgnoreLocal(register, type);
+            : readRegisterIgnoreLocal(register, type, incomingLocal);
     return writeRegister(register, type, throwing, outgoingLocal);
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
index 85a0f99..01c4dd0 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
@@ -29,7 +29,6 @@
 import com.android.tools.r8.ir.conversion.JarState.Slot;
 import com.android.tools.r8.logging.Log;
 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.Int2ReferenceSortedMap;
 import java.io.PrintWriter;
@@ -275,7 +274,6 @@
     // Record types for arguments.
     Int2ReferenceMap<ValueType> argumentLocals = recordArgumentTypes();
     Int2ReferenceMap<ValueType> initializedLocals = new Int2ReferenceOpenHashMap<>(argumentLocals);
-    Int2ReferenceMap<ValueType> uninitializedLocals = new Int2ReferenceOpenHashMap<>();
     // Initialize all non-argument locals to ensure safe insertion of debug-local instructions.
     for (Object o : node.localVariables) {
       LocalVariableNode local = (LocalVariableNode) o;
@@ -320,11 +318,9 @@
       int localRegister = state.getLocalRegister(local.index, localType);
       ValueType existingLocalType = initializedLocals.get(localRegister);
       if (existingLocalType == null) {
-        // For uninitialized entries write the local to ensure it exists in the local state.
         int writeRegister = state.writeLocal(local.index, localType);
         assert writeRegister == localRegister;
         initializedLocals.put(localRegister, localValueType);
-        uninitializedLocals.put(localRegister, localValueType);
       }
     }
 
@@ -335,10 +331,6 @@
     // for arguments.
     buildArgumentInstructions(builder);
 
-    for (Entry<ValueType> entry : uninitializedLocals.int2ReferenceEntrySet()) {
-      builder.addDebugUninitialized(entry.getIntKey(), entry.getValue());
-    }
-
     // Add debug information for all locals at the initial label.
     for (Local local : state.getLocalsToOpen()) {
       if (!argumentLocals.containsKey(local.slot.register)) {
diff --git a/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java b/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
index 0f3cadc..11ad12b 100644
--- a/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
@@ -11,12 +11,14 @@
 import com.android.tools.r8.utils.TestDescriptionWatcher;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
@@ -89,6 +91,11 @@
       // This list is currently empty!
   );
 
+  private Set<String> failingOnX8 = ImmutableSet.of(
+      // Contains use of register as both an int and a float.
+      "regression/33336471"
+  );
+
   @Rule
   public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
 
@@ -161,6 +168,10 @@
         .addLibraryFiles(ToolHelper.getDefaultAndroidJar())
             .setOutput(Paths.get(outputPath), OutputMode.DexIndexed);
     ToolHelper.getAppBuilder(builder).addProgramFiles(originalDexFile);
+
+    if (failingOnX8.contains(directoryName)) {
+      thrown.expect(CompilationFailedException.class);
+    }
     R8.run(builder.build());
 
     if (!ToolHelper.artSupported()) {
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index d6abe44..bb2db07 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -151,19 +151,19 @@
     return builder.build();
   }
 
-  protected static AndroidApp readClassesAndAndriodJar(List<Class> programClasses)
-      throws IOException {
-    return readClassesAndAndriodJar(programClasses, ToolHelper.getMinApiLevelForDexVm());
-  }
-
-  protected static AndroidApp readClassesAndAndriodJar(
-      List<Class> programClasses, AndroidApiLevel androidLibrary)
+  protected static AndroidApp readClassesAndRuntimeJar(List<Class> programClasses, Backend backend)
       throws IOException {
     AndroidApp.Builder builder = AndroidApp.builder();
     for (Class clazz : programClasses) {
       builder.addProgramFiles(ToolHelper.getClassFileForTestClass(clazz));
     }
-    builder.addLibraryFiles(ToolHelper.getAndroidJar(androidLibrary));
+    if (backend == Backend.DEX) {
+      AndroidApiLevel androidLibrary = ToolHelper.getMinApiLevelForDexVm();
+      builder.addLibraryFiles(ToolHelper.getAndroidJar(androidLibrary));
+    } else {
+      assert backend == Backend.CF;
+      builder.addLibraryFiles(ToolHelper.getJava8RuntimeJar());
+    }
     return builder.build();
   }
 
@@ -721,4 +721,22 @@
       return this != NONE;
     }
   }
+
+  public static ProgramConsumer emptyConsumer(Backend backend) {
+    if (backend == Backend.DEX) {
+      return DexIndexedConsumer.emptyConsumer();
+    } else {
+      assert backend == Backend.CF;
+      return ClassFileConsumer.emptyConsumer();
+    }
+  }
+
+  public static Path runtimeJar(Backend backend) {
+    if (backend == Backend.DEX) {
+      return ToolHelper.getDefaultAndroidJar();
+    } else {
+      assert backend == Backend.CF;
+      return ToolHelper.getJava8RuntimeJar();
+    }
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/movestringconstants/MoveStringConstantsTest.java b/src/test/java/com/android/tools/r8/movestringconstants/MoveStringConstantsTest.java
index d7d0538..6dd02c6 100644
--- a/src/test/java/com/android/tools/r8/movestringconstants/MoveStringConstantsTest.java
+++ b/src/test/java/com/android/tools/r8/movestringconstants/MoveStringConstantsTest.java
@@ -6,9 +6,7 @@
 
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.ClassFileConsumer;
 import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.ToolHelper;
@@ -45,15 +43,8 @@
     R8Command.Builder builder = R8Command.builder();
     builder.addProgramFiles(ToolHelper.getClassFileForTestClass(TestClass.class));
     builder.addProgramFiles(ToolHelper.getClassFileForTestClass(Utils.class));
-    builder.addLibraryFiles(
-        backend == Backend.DEX
-            ? ToolHelper.getDefaultAndroidJar()
-            : ToolHelper.getJava8RuntimeJar());
-    assert (backend == Backend.CF || backend == Backend.DEX);
-    builder.setProgramConsumer(
-        backend == Backend.DEX
-            ? DexIndexedConsumer.emptyConsumer()
-            : ClassFileConsumer.emptyConsumer());
+    builder.addLibraryFiles(runtimeJar(backend));
+    builder.setProgramConsumer(emptyConsumer(backend));
     builder.setMode(CompilationMode.RELEASE);
     builder.addProguardConfiguration(
         ImmutableList.of(
@@ -82,6 +73,7 @@
       // Run on Art to check generated code against verifier.
       runOnArt(app, TestClass.class);
     } else {
+      assert backend == Backend.CF;
       runOnJava(app, TestClass.class);
     }
   }
diff --git a/src/test/java/com/android/tools/r8/naming/AdaptResourceFileContentsTest.java b/src/test/java/com/android/tools/r8/naming/AdaptResourceFileContentsTest.java
index 2f59f6d..413a511 100644
--- a/src/test/java/com/android/tools/r8/naming/AdaptResourceFileContentsTest.java
+++ b/src/test/java/com/android/tools/r8/naming/AdaptResourceFileContentsTest.java
@@ -11,13 +11,11 @@
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.ClassFileConsumer;
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.DataDirectoryResource;
 import com.android.tools.r8.DataEntryResource;
 import com.android.tools.r8.DataResourceConsumer;
 import com.android.tools.r8.DataResourceProvider.Visitor;
-import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.DiagnosticsHandler;
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.ToolHelper;
@@ -319,19 +317,11 @@
 
   private AndroidApp compileWithR8(String proguardConfig, DataResourceConsumer dataResourceConsumer)
       throws CompilationFailedException, IOException {
-    assert backend == Backend.DEX || backend == Backend.CF;
     R8Command command =
         ToolHelper.allowTestProguardOptions(
-                ToolHelper.prepareR8CommandBuilder(
-                        getAndroidApp(),
-                        backend == Backend.DEX
-                            ? DexIndexedConsumer.emptyConsumer()
-                            : ClassFileConsumer.emptyConsumer())
+                ToolHelper.prepareR8CommandBuilder(getAndroidApp(), emptyConsumer(backend))
                     .addProguardConfiguration(ImmutableList.of(proguardConfig), Origin.unknown()))
-            .addLibraryFiles(
-                backend == Backend.DEX
-                    ? ToolHelper.getDefaultAndroidJar()
-                    : ToolHelper.getJava8RuntimeJar())
+            .addLibraryFiles(runtimeJar(backend))
             .build();
     return ToolHelper.runR8(
         command,
diff --git a/src/test/java/com/android/tools/r8/naming/AdaptResourceFileNamesTest.java b/src/test/java/com/android/tools/r8/naming/AdaptResourceFileNamesTest.java
index 51201df..9ffb4f2 100644
--- a/src/test/java/com/android/tools/r8/naming/AdaptResourceFileNamesTest.java
+++ b/src/test/java/com/android/tools/r8/naming/AdaptResourceFileNamesTest.java
@@ -11,13 +11,11 @@
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.ClassFileConsumer;
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.DataDirectoryResource;
 import com.android.tools.r8.DataEntryResource;
 import com.android.tools.r8.DataResourceConsumer;
 import com.android.tools.r8.DataResourceProvider.Visitor;
-import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.DiagnosticsHandler;
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.StringConsumer;
@@ -256,20 +254,12 @@
       StringConsumer proguardMapConsumer,
       List<DataEntryResource> dataResources)
       throws CompilationFailedException, IOException {
-    assert backend == Backend.DEX || backend == Backend.CF;
     R8Command command =
         ToolHelper.allowTestProguardOptions(
                 ToolHelper.prepareR8CommandBuilder(
-                        getAndroidApp(dataResources),
-                        backend == Backend.DEX
-                            ? DexIndexedConsumer.emptyConsumer()
-                            : ClassFileConsumer.emptyConsumer(),
-                        diagnosticsHandler)
+                        getAndroidApp(dataResources), emptyConsumer(backend), diagnosticsHandler)
                     .addProguardConfiguration(ImmutableList.of(proguardConfig), Origin.unknown()))
-            .addLibraryFiles(
-                backend == Backend.DEX
-                    ? ToolHelper.getDefaultAndroidJar()
-                    : ToolHelper.getJava8RuntimeJar())
+            .addLibraryFiles(runtimeJar(backend))
             .build();
     return ToolHelper.runR8(
         command,
diff --git a/src/test/java/com/android/tools/r8/naming/MinifierClassSignatureTest.java b/src/test/java/com/android/tools/r8/naming/MinifierClassSignatureTest.java
index a5bbdf6..3240365 100644
--- a/src/test/java/com/android/tools/r8/naming/MinifierClassSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/naming/MinifierClassSignatureTest.java
@@ -20,8 +20,6 @@
 import static org.objectweb.asm.Opcodes.RETURN;
 import static org.objectweb.asm.Opcodes.V1_8;
 
-import com.android.tools.r8.ClassFileConsumer;
-import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.DiagnosticsChecker;
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.StringConsumer;
@@ -306,7 +304,6 @@
       Consumer<CodeInspector> inspect)
       throws Exception {
     DiagnosticsChecker checker = new DiagnosticsChecker();
-    assert (backend == Backend.CF || backend == Backend.DEX);
     CodeInspector inspector =
         new CodeInspector(
             ToolHelper.runR8(
@@ -327,10 +324,8 @@
                             "-keepattributes InnerClasses,EnclosingMethod,Signature",
                             "-keep,allowobfuscation class **"),
                         Origin.unknown())
-                    .setProgramConsumer(
-                        backend == Backend.DEX
-                            ? DexIndexedConsumer.emptyConsumer()
-                            : ClassFileConsumer.emptyConsumer())
+                    .setProgramConsumer(emptyConsumer(backend))
+                    .addLibraryFiles(runtimeJar(backend))
                     .setProguardMapConsumer(StringConsumer.emptyConsumer())
                     .build(),
                 options -> {
diff --git a/src/test/java/com/android/tools/r8/naming/MinifierFieldSignatureTest.java b/src/test/java/com/android/tools/r8/naming/MinifierFieldSignatureTest.java
index c470661..4c81632 100644
--- a/src/test/java/com/android/tools/r8/naming/MinifierFieldSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/naming/MinifierFieldSignatureTest.java
@@ -21,8 +21,6 @@
 import static org.objectweb.asm.Opcodes.RETURN;
 import static org.objectweb.asm.Opcodes.V1_8;
 
-import com.android.tools.r8.ClassFileConsumer;
-import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.DiagnosticsChecker;
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.StringConsumer;
@@ -180,7 +178,6 @@
       Consumer<CodeInspector> inspect)
       throws Exception {
     DiagnosticsChecker checker = new DiagnosticsChecker();
-    assert (backend == Backend.CF || backend == Backend.DEX);
     CodeInspector inspector =
         new CodeInspector(
             ToolHelper.runR8(
@@ -192,10 +189,8 @@
                             "-keepattributes InnerClasses,EnclosingMethod,Signature",
                             "-keep,allowobfuscation class ** { *; }"),
                         Origin.unknown())
-                    .setProgramConsumer(
-                        backend == Backend.DEX
-                            ? DexIndexedConsumer.emptyConsumer()
-                            : ClassFileConsumer.emptyConsumer())
+                    .setProgramConsumer(emptyConsumer(backend))
+                    .addLibraryFiles(runtimeJar(backend))
                     .setProguardMapConsumer(StringConsumer.emptyConsumer())
                     .build(),
                 options -> {
diff --git a/src/test/java/com/android/tools/r8/naming/MinifierMethodSignatureTest.java b/src/test/java/com/android/tools/r8/naming/MinifierMethodSignatureTest.java
index aa5307d..a1ab483 100644
--- a/src/test/java/com/android/tools/r8/naming/MinifierMethodSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/naming/MinifierMethodSignatureTest.java
@@ -24,8 +24,6 @@
 import static org.objectweb.asm.Opcodes.RETURN;
 import static org.objectweb.asm.Opcodes.V1_8;
 
-import com.android.tools.r8.ClassFileConsumer;
-import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.DiagnosticsChecker;
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.StringConsumer;
@@ -202,7 +200,6 @@
       Consumer<CodeInspector> inspect)
       throws Exception {
     DiagnosticsChecker checker = new DiagnosticsChecker();
-    assert (backend == Backend.CF || backend == Backend.DEX);
     CodeInspector inspector =
         new CodeInspector(
             ToolHelper.runR8(
@@ -214,10 +211,8 @@
                             "-keepattributes InnerClasses,EnclosingMethod,Signature",
                             "-keep,allowobfuscation class ** { *; }"),
                         Origin.unknown())
-                    .setProgramConsumer(
-                        backend == Backend.DEX
-                            ? DexIndexedConsumer.emptyConsumer()
-                            : ClassFileConsumer.emptyConsumer())
+                    .setProgramConsumer(emptyConsumer(backend))
+                    .addLibraryFiles(runtimeJar(backend))
                     .setProguardMapConsumer(StringConsumer.emptyConsumer())
                     .build(),
                 options -> {
diff --git a/src/test/java/com/android/tools/r8/naming/b80083341/B80083341.java b/src/test/java/com/android/tools/r8/naming/b80083341/B80083341.java
index 9791142..c4c3801 100644
--- a/src/test/java/com/android/tools/r8/naming/b80083341/B80083341.java
+++ b/src/test/java/com/android/tools/r8/naming/b80083341/B80083341.java
@@ -35,10 +35,16 @@
         "-keep,allowobfuscation class " + mainClass.getCanonicalName() + " {",
         "}"
     );
-    AndroidApp app = readClassesAndAndriodJar(ImmutableList.of(
-        mainClass, TestClass.class, AnotherClass.class,
-        PackagePrivateClass.class, PackagePrivateClass.Itf.class, PackagePrivateClass.Impl.class
-    ));
+    AndroidApp app =
+        readClassesAndRuntimeJar(
+            ImmutableList.of(
+                mainClass,
+                TestClass.class,
+                AnotherClass.class,
+                PackagePrivateClass.class,
+                PackagePrivateClass.Itf.class,
+                PackagePrivateClass.Impl.class),
+            Backend.DEX);
     AndroidApp processedApp = compileWithR8(app, String.join(System.lineSeparator(), config));
     CodeInspector inspector = new CodeInspector(processedApp);
     ClassSubject mainSubject = inspector.clazz(mainClass);
diff --git a/src/test/java/com/android/tools/r8/neverreturnsnormally/NeverReturnsNormallyTest.java b/src/test/java/com/android/tools/r8/neverreturnsnormally/NeverReturnsNormallyTest.java
index 73dcdb3..f401f6a 100644
--- a/src/test/java/com/android/tools/r8/neverreturnsnormally/NeverReturnsNormallyTest.java
+++ b/src/test/java/com/android/tools/r8/neverreturnsnormally/NeverReturnsNormallyTest.java
@@ -7,9 +7,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.ClassFileConsumer;
 import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.ToolHelper;
@@ -53,15 +51,8 @@
       boolean enableClassInliner, CompilationMode mode) throws Exception {
     R8Command.Builder builder = R8Command.builder();
     builder.addProgramFiles(ToolHelper.getClassFileForTestClass(TestClass.class));
-    assert (backend == Backend.DEX || backend == Backend.CF);
-    builder.setProgramConsumer(
-        backend == Backend.DEX
-            ? DexIndexedConsumer.emptyConsumer()
-            : ClassFileConsumer.emptyConsumer());
-    builder.addLibraryFiles(
-        backend == Backend.DEX
-            ? ToolHelper.getDefaultAndroidJar()
-            : ToolHelper.getJava8RuntimeJar());
+    builder.setProgramConsumer(emptyConsumer(backend));
+    builder.addLibraryFiles(runtimeJar(backend));
     builder.setMode(mode);
     builder.addProguardConfiguration(
         ImmutableList.of(
@@ -93,6 +84,7 @@
       // Run on Art to check generated code against verifier.
       runOnArt(app, TestClass.class);
     } else {
+      assert backend == Backend.CF;
       runOnJava(app, TestClass.class);
     }
   }
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ProguardCompatibilityTestBase.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ProguardCompatibilityTestBase.java
index 24f64c9..f10395e 100644
--- a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ProguardCompatibilityTestBase.java
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ProguardCompatibilityTestBase.java
@@ -78,9 +78,9 @@
   }
 
   protected CodeInspector inspectAfterShrinking(
-      Shrinker mode, List<Class> programClasses, List<String> proguadConfigs) throws Exception {
+      Shrinker mode, List<Class> programClasses, List<String> proguardConfigs) throws Exception {
     return inspectAfterShrinking(
-        mode, programClasses, String.join(System.lineSeparator(), proguadConfigs));
+        mode, programClasses, String.join(System.lineSeparator(), proguardConfigs));
   }
 
   protected CodeInspector inspectAfterShrinking(
@@ -115,18 +115,8 @@
       Consumer<InternalOptions> configure,
       Backend backend)
       throws Exception {
-    assert backend == Backend.DEX || backend == Backend.CF;
-    AndroidApp app = readClassesAndAndriodJar(programClasses);
-    R8Command.Builder builder =
-        ToolHelper.prepareR8CommandBuilder(
-                app,
-                backend == Backend.DEX
-                    ? DexIndexedConsumer.emptyConsumer()
-                    : ClassFileConsumer.emptyConsumer())
-            .addLibraryFiles(
-                backend == Backend.DEX
-                    ? ToolHelper.getDefaultAndroidJar()
-                    : ToolHelper.getJava8RuntimeJar());
+    AndroidApp app = readClassesAndRuntimeJar(programClasses, backend);
+    R8Command.Builder builder = ToolHelper.prepareR8CommandBuilder(app, emptyConsumer(backend));
     ToolHelper.allowTestProguardOptions(builder);
     builder.addProguardConfiguration(ImmutableList.of(proguardConfig), Origin.unknown());
     return ToolHelper.runR8(builder.build(), configure);
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnAccessModifierTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnAccessModifierTest.java
index 23aad75..af9cfdf 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnAccessModifierTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnAccessModifierTest.java
@@ -11,6 +11,7 @@
 
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
 import com.android.tools.r8.shaking.forceproguardcompatibility.ProguardCompatibilityTestBase;
+import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
@@ -40,7 +41,14 @@
 
   @Parameters(name = "shrinker: {0}")
   public static Collection<Object> data() {
-    return ImmutableList.of(Shrinker.PROGUARD6, Shrinker.R8);
+    return ImmutableList.of(Shrinker.R8_CF, Shrinker.PROGUARD6, Shrinker.R8);
+  }
+
+  @Override
+  protected AndroidApp runR8(List<Class> programClasses, String proguardConfig, Backend backend)
+      throws Exception {
+    // Disable inlining, otherwise classes can be pruned away if all their methods are inlined.
+    return runR8(programClasses, proguardConfig, o -> o.enableInlining = false, backend);
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/smali/RemoveWriteOfUnusedFieldsTest.java b/src/test/java/com/android/tools/r8/smali/RemoveWriteOfUnusedFieldsTest.java
index 9c9991e..0261af6 100644
--- a/src/test/java/com/android/tools/r8/smali/RemoveWriteOfUnusedFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/smali/RemoveWriteOfUnusedFieldsTest.java
@@ -8,7 +8,6 @@
 
 import com.android.tools.r8.OutputMode;
 import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.DexVm;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApp;
@@ -37,28 +36,23 @@
     builder.addStaticField("stringField", "Ljava/lang/String;");
     builder.addStaticField("testField", "LTest;");
 
-    boolean isDalvik = ToolHelper.getDexVm().isOlderThanOrEqual(DexVm.ART_4_4_4_HOST);
-    String additionalConstZero = isDalvik ? "const v0, 0" : "";
-    String additionalConstZeroWide = isDalvik ? "const-wide v0, 0" : "";
-
     builder.addStaticMethod("void", "test", ImmutableList.of(),
         2,
-        "const               v0, 0",
+        "const               v0, 0", // single non-float typed zero (ie, int type)
         "sput-boolean        v0, LTest;->booleanField:Z",
         "sput-byte           v0, LTest;->byteField:B",
+        "sput-char           v0, LTest;->charField:C",
         "sput-short          v0, LTest;->shortField:S",
         "sput                v0, LTest;->intField:I",
-        // Dalvik 4.x. does not require a new const 0 here.
+        "const               v0, 0", // float typed zero
         "sput                v0, LTest;->floatField:F",
-        additionalConstZero,  // Required for Dalvik 4.x.
-        "sput-char           v0, LTest;->charField:C",
-        "const               v0, 0",
+        "const               v0, 0", // reference typed null
         "sput-object         v0, LTest;->objectField:Ljava/lang/Object;",
         "sput-object         v0, LTest;->stringField:Ljava/lang/String;",
         "sput-object         v0, LTest;->testField:LTest;",
-        "const-wide          v0, 0",
+        "const-wide          v0, 0", // wide typed long
         "sput-wide           v0, LTest;->longField:J",
-        additionalConstZeroWide,  // Required for Dalvik 4.x.
+        "const-wide          v0, 0", // wide typed double
         "sput-wide           v0, LTest;->doubleField:D",
         "return-void");
 
@@ -103,28 +97,23 @@
     builder.addInstanceField("stringField", "Ljava/lang/String;");
     builder.addInstanceField("testField", "LTest;");
 
-    boolean isDalvik = ToolHelper.getDexVm().isOlderThanOrEqual(DexVm.ART_4_4_4_HOST);
-    String additionalConstZero = isDalvik ? "const v0, 0" : "";
-    String additionalConstZeroWide = isDalvik ? "const-wide v0, 0" : "";
-
     builder.addInstanceMethod("void", "test", ImmutableList.of(),
         2,
         "const               v0, 0",
         "iput-boolean        v0, p0, LTest;->booleanField:Z",
         "iput-byte           v0, p0, LTest;->byteField:B",
+        "iput-char           v0, p0, LTest;->charField:C",
         "iput-short          v0, p0, LTest;->shortField:S",
         "iput                v0, p0, LTest;->intField:I",
-        // Dalvik 4.x. does not require a new const 0 here.
+        "const               v0, 0",
         "iput                v0, p0, LTest;->floatField:F",
-        additionalConstZero,  // Required for Dalvik 4.x.
-        "iput-char           v0, p0, LTest;->charField:C",
         "const               v0, 0",
         "iput-object         v0, p0, LTest;->objectField:Ljava/lang/Object;",
         "iput-object         v0, p0, LTest;->stringField:Ljava/lang/String;",
         "iput-object         v0, p0, LTest;->testField:LTest;",
         "const-wide          v0, 0",
         "iput-wide           v0, p0, LTest;->longField:J",
-        additionalConstZeroWide,  // Required for Dalvik 4.x.
+        "const-wide          v0, 0",
         "iput-wide           v0, p0, LTest;->doubleField:D",
         "return-void");