Fix a few state issues in the bisect command.

There appears to still be issues in the internal command iteration, but
the external did work to bisect issue b/134694194. Follow-up work should
simply replace the internal run to always do a full read, build and write.

Change-Id: If17fb671d8c61212f3dd582cc9e8a07001ce150c
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 ca6b334..6b386c5 100644
--- a/src/main/java/com/android/tools/r8/bisect/Bisect.java
+++ b/src/main/java/com/android/tools/r8/bisect/Bisect.java
@@ -4,6 +4,8 @@
 package com.android.tools.r8.bisect;
 
 import com.android.tools.r8.OutputMode;
+import com.android.tools.r8.ProgramConsumer;
+import com.android.tools.r8.StringConsumer;
 import com.android.tools.r8.bisect.BisectOptions.Result;
 import com.android.tools.r8.dex.ApplicationReader;
 import com.android.tools.r8.dex.ApplicationWriter;
@@ -15,6 +17,7 @@
 import com.android.tools.r8.utils.AndroidAppConsumers;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.Timing;
+import com.google.common.collect.ImmutableList;
 import com.google.common.io.CharStreams;
 import java.io.IOException;
 import java.io.InputStream;
@@ -84,6 +87,7 @@
         return null;
       }
       state.setPreviousResult(command.apply(app));
+      app.options.itemFactory.resetSortedIndices();
     }
   }
 
@@ -98,8 +102,9 @@
 
     ExecutorService executor = Executors.newWorkStealingPool();
     try {
-      DexApplication goodApp = readApp(options.goodBuild, executor);
-      DexApplication badApp = readApp(options.badBuild, executor);
+      InternalOptions internal = new InternalOptions();
+      DexApplication goodApp = readApp(options.goodBuild, internal, executor);
+      DexApplication badApp = readApp(options.badBuild, internal, executor);
 
       Path stateFile =
           options.stateFile != null ? options.stateFile : output.resolve("bisect.state");
@@ -118,10 +123,11 @@
       // Setup post-build command.
       Command command = null;
       if (options.command != null) {
-        command = (application) -> {
-          writeApp(application, output, executor);
-          return runCommand(output);
-        };
+        command =
+            (application) -> {
+              writeApp(application, output, executor);
+              return runCommand(options.command, options.goodBuild, options.badBuild, output);
+            };
       }
 
       // Run bisection.
@@ -131,11 +137,13 @@
     }
   }
 
-  private Result runCommand(Path output) throws IOException {
+  private static Result runCommand(Path command, Path good, Path bad, Path output)
+      throws IOException {
     List<String> args = new ArrayList<>();
     args.add("/bin/bash");
-    args.add(options.command.toString());
-    args.add(output.toString());
+    args.add(command.toString());
+    args.addAll(ImmutableList.of(good.toString(), bad.toString(), output.toString()));
+    System.out.println("Running cmd: " + String.join(" ", args));
     ProcessBuilder builder = new ProcessBuilder(args);
     Process process = builder.start();
     StreamReader stdoutReader = new StreamReader(process.getInputStream());
@@ -151,6 +159,8 @@
     } catch (InterruptedException e) {
       throw new RuntimeException("Execution interrupted", e);
     }
+    System.out.print("OUT:\n" + stdoutReader.getResult());
+    System.out.print("ERR:\n" + stderrReader.getResult());
     int result = process.exitValue();
     if (result == 0) {
       return Result.GOOD;
@@ -159,20 +169,21 @@
     }
     System.out.println("Failed to run command " + args);
     System.out.println("Exit code: " + result + " (expected 0 for good, 1 for bad)");
-    System.out.println("Std out:\n" + stdoutReader.getResult());
-    System.out.println("Std err:\n" + stderrReader.getResult());
     throw new CompilationError("Failed to run command " + args);
   }
 
-  private DexApplication readApp(Path apk, ExecutorService executor)
+  private DexApplication readApp(Path apk, InternalOptions options, ExecutorService executor)
       throws IOException, ExecutionException {
     AndroidApp app = AndroidApp.builder().addProgramFiles(apk).build();
-    return new ApplicationReader(app, new InternalOptions(), timing).read(executor);
+    return new ApplicationReader(app, options, timing).read(executor);
   }
 
   private static void writeApp(DexApplication app, Path output, ExecutorService executor)
       throws IOException, ExecutionException {
-    InternalOptions options = new InternalOptions();
+    InternalOptions options = app.options;
+    // Save the original consumers so they can be unwrapped after write.
+    ProgramConsumer programConsumer = options.programConsumer;
+    StringConsumer proguardMapConsumer = options.proguardMapConsumer;
     AndroidAppConsumers compatSink = new AndroidAppConsumers(options);
     ApplicationWriter writer =
         new ApplicationWriter(
@@ -180,6 +191,9 @@
     writer.write(executor);
     options.signalFinishedToConsumers();
     compatSink.build().writeToDirectory(output, OutputMode.DexIndexed);
+    // Restore original consumers.
+    options.programConsumer = programConsumer;
+    options.proguardMapConsumer = proguardMapConsumer;
   }
 
   public static DexProgramClass run(BisectOptions options) throws Exception {
diff --git a/src/test/java/com/android/tools/r8/bisect/BisectTest.java b/src/test/java/com/android/tools/r8/bisect/BisectTest.java
index dd47a3e..02f6b35 100644
--- a/src/test/java/com/android/tools/r8/bisect/BisectTest.java
+++ b/src/test/java/com/android/tools/r8/bisect/BisectTest.java
@@ -5,7 +5,10 @@
 
 import static org.junit.Assert.assertEquals;
 
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersBuilder;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.bisect.BisectOptions.Result;
 import com.android.tools.r8.dex.ApplicationReader;
 import com.android.tools.r8.graph.DexApplication;
@@ -21,11 +24,24 @@
 import java.nio.file.Path;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
-import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
 
-public class BisectTest {
+@RunWith(Parameterized.class)
+public class BisectTest extends TestBase {
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection parameters() {
+    return TestParametersBuilder.builder().withNoneRuntime().build();
+  }
+
+  private final TestParameters parameters;
+
+  public BisectTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
 
   private final String[] CLASSES = {"A", "B", "C", "D", "E", "F", "G", "H"};
   private final String ERRONEOUS_CLASS = "F";
@@ -35,9 +51,6 @@
   // Set during build to more easily inspect later.
   private MethodSignature erroneousMethodSignature = null;
 
-  @Rule
-  public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
-
   // Build "good" application with no method in "F".
   AndroidApp buildGood() throws Exception {
     SmaliBuilder builderGood = new SmaliBuilder();