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();