Revert "Revised workaround for Android 6.0 dex2oat divergence issue."

This reverts commit cf110979123d03ab2405d04b7c0ce9d0ea1539bf.

Reason for revert: CL leads to NPE during register allocation in internal tests.

Change-Id: I0a65d7516ea1bd08232f1f9418e0b50948a78682
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 6288eaa..05fd603 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -36,7 +36,6 @@
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionListIterator;
 import com.android.tools.r8.ir.code.InvokeMethod;
-import com.android.tools.r8.ir.code.InvokeStatic;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.desugar.CovariantReturnTypeAnnotationTransformer;
 import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
@@ -94,7 +93,6 @@
 import java.util.function.BiConsumer;
 import java.util.function.Function;
 import java.util.function.Predicate;
-import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
 public class IRConverter {
@@ -1243,116 +1241,20 @@
     }
   }
 
-  /**
-   * For each block, we look to see if the header matches:
-   *
-   * <pre>
-   *   pseudo-instructions*
-   *   v2 <- long-{mul,div} v0 v1
-   *   pseudo-instructions*
-   *   v5 <- long-{add,sub} v3 v4
-   * </pre>
-   *
-   * where v2 ~=~ v3 or v2 ~=~ v4 (with ~=~ being equal or an alias of) and the block is not a
-   * fallthrough target.
-   */
   private void materializeInstructionBeforeLongOperationsWorkaround(IRCode code) {
     if (!options.canHaveDex2OatLinkedListBug()) {
       return;
     }
-    DexItemFactory factory = options.itemFactory;
-    final Supplier<DexMethod> javaLangLangSignum =
-        Suppliers.memoize(
-            () ->
-                factory.createMethod(
-                    factory.createString("Ljava/lang/Long;"),
-                    factory.createString("signum"),
-                    factory.intDescriptor,
-                    new DexString[] {factory.longDescriptor}));
     for (BasicBlock block : code.blocks) {
       InstructionListIterator it = block.listIterator();
-      Instruction firstMaterializing = it.nextUntil(IRConverter::isNotPseudoInstruction);
-      if (!isLongMulOrDiv(firstMaterializing)) {
-        continue;
-      }
-      Instruction secondMaterializing = it.nextUntil(IRConverter::isNotPseudoInstruction);
-      if (!isLongAddOrSub(secondMaterializing)) {
-        continue;
-      }
-      if (isFallthoughTarget(block)) {
-        continue;
-      }
-      Value outOfMulOrDiv = firstMaterializing.outValue();
-      for (Value inOfAddOrSub : secondMaterializing.inValues()) {
-        if (isAliasOf(inOfAddOrSub, outOfMulOrDiv)) {
-          it = block.listIterator();
-          it.nextUntil(i -> i == firstMaterializing);
-          Value longValue = firstMaterializing.inValues().get(0);
-          InvokeStatic invokeLongSignum =
-              new InvokeStatic(
-                  javaLangLangSignum.get(), null, Collections.singletonList(longValue));
-          ensureThrowingInstructionBefore(code, firstMaterializing, it, invokeLongSignum);
-          return;
-        }
+      Instruction firstMaterializing =
+          it.nextUntil(IRConverter::isMaterializingInstructionOnArtArmVersionM);
+      if (needsInstructionBeforeLongOperation(firstMaterializing)) {
+        ensureInstructionBefore(code, firstMaterializing, it);
       }
     }
   }
 
-  private static boolean isAliasOf(Value usedValue, Value definingValue) {
-    while (true) {
-      if (usedValue == definingValue) {
-        return true;
-      }
-      Instruction definition = usedValue.definition;
-      if (definition == null || !definition.isMove()) {
-        return false;
-      }
-      usedValue = definition.asMove().src();
-    }
-  }
-
-  private static boolean isNotPseudoInstruction(Instruction instruction) {
-    return !(instruction.isDebugInstruction() || instruction.isMove());
-  }
-
-  private static boolean isLongMulOrDiv(Instruction instruction) {
-    return instruction != null
-        && instruction.outValue() != null
-        && instruction.outValue().getTypeLattice().isLong()
-        && (instruction.isMul() || instruction.isDiv());
-  }
-
-  private static boolean isLongAddOrSub(Instruction instruction) {
-    return instruction != null
-        && instruction.outValue() != null
-        && instruction.outValue().getTypeLattice().isLong()
-        && (instruction.isAdd() || instruction.isSub());
-  }
-
-  private static boolean isFallthoughTarget(BasicBlock block) {
-    for (BasicBlock pred : block.getPredecessors()) {
-      if (pred.exit().fallthroughBlock() == block) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  private void ensureThrowingInstructionBefore(
-      IRCode code, Instruction addBefore, InstructionListIterator it, Instruction instruction) {
-    Instruction check = it.previous();
-    assert addBefore == check;
-    BasicBlock block = check.getBlock();
-    if (block.hasCatchHandlers()) {
-      // Split the block and copy back catch handlers to the header block.
-      BasicBlock split = it.split(code);
-      block.copyCatchHandlers(code, code.listIterator(code.blocks.size()), split);
-      it = block.listIterator(block.getInstructions().size() - 1);
-    }
-    instruction.setPosition(addBefore.getPosition());
-    it.add(instruction);
-  }
-
   private static void ensureInstructionBefore(
       IRCode code, Instruction addBefore, InstructionListIterator it) {
     // Force materialize a constant-zero before the long operation.
@@ -1371,6 +1273,33 @@
     it.add(fixitUser);
   }
 
+  private static boolean needsInstructionBeforeLongOperation(Instruction instruction) {
+    // The cortex fixup will only trigger on long sub and long add instructions.
+    if (!((instruction.isAdd() || instruction.isSub()) && instruction.outType().isWide())) {
+      return false;
+    }
+    // If the block with the instruction is a fallthrough block, then it can't end up being
+    // preceded by the incorrectly linked prologue/epilogue..
+    BasicBlock block = instruction.getBlock();
+    for (BasicBlock pred : block.getPredecessors()) {
+      if (pred.exit().fallthroughBlock() == block) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  private static boolean isMaterializingInstructionOnArtArmVersionM(Instruction instruction) {
+    return !instruction.isDebugInstruction()
+        && !instruction.isMove()
+        && !isPossiblyNonMaterializingLongOperationOnArtArmVersionM(instruction);
+  }
+
+  private static boolean isPossiblyNonMaterializingLongOperationOnArtArmVersionM(
+      Instruction instruction) {
+    return (instruction.isMul() || instruction.isDiv()) && instruction.outType().isWide();
+  }
+
   private void printC1VisualizerHeader(DexEncodedMethod method) {
     if (printer != null) {
       printer.begin("compilation");
diff --git a/src/test/java/com/android/tools/r8/DXTestBuilder.java b/src/test/java/com/android/tools/r8/DXTestBuilder.java
index 190db23..8312729 100644
--- a/src/test/java/com/android/tools/r8/DXTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/DXTestBuilder.java
@@ -67,11 +67,6 @@
   }
 
   @Override
-  public DXTestBuilder addProgramClassFileData(Collection<byte[]> classes) {
-    throw new Unimplemented("No support for adding classfile data directly");
-  }
-
-  @Override
   public DXTestBuilder addProgramFiles(Collection<Path> files) {
     injars.addAll(files);
     return self();
diff --git a/src/test/java/com/android/tools/r8/JvmTestBuilder.java b/src/test/java/com/android/tools/r8/JvmTestBuilder.java
index 6feb460..4e0bedf 100644
--- a/src/test/java/com/android/tools/r8/JvmTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/JvmTestBuilder.java
@@ -147,12 +147,6 @@
         "No support for adding paths directly (we need to compute the descriptor)");
   }
 
-  @Override
-  public JvmTestBuilder addProgramClassFileData(Collection<byte[]> files) {
-    throw new Unimplemented(
-        "No support for adding classfile data directly (we need to compute the descriptor)");
-  }
-
   public JvmTestBuilder addClasspath(Path... paths) {
     return addClasspath(Arrays.asList(paths));
   }
diff --git a/src/test/java/com/android/tools/r8/ProguardTestBuilder.java b/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
index fa4c41c..28ce1e6 100644
--- a/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
@@ -184,12 +184,6 @@
   }
 
   @Override
-  public ProguardTestBuilder addProgramClassFileData(Collection<byte[]> classes) {
-    throw new Unimplemented(
-        "No support for adding classfile data directly (we need to compute the descriptor)");
-  }
-
-  @Override
   public ProguardTestBuilder addKeepRules(Collection<String> rules) {
     config.addAll(rules);
     return self();
diff --git a/src/test/java/com/android/tools/r8/TestBuilder.java b/src/test/java/com/android/tools/r8/TestBuilder.java
index 7f200c1..4977d94 100644
--- a/src/test/java/com/android/tools/r8/TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestBuilder.java
@@ -39,12 +39,6 @@
 
   public abstract T addProgramFiles(Collection<Path> files);
 
-  public abstract T addProgramClassFileData(Collection<byte[]> classes);
-
-  public T addProgramClassFileData(byte[]... classes) {
-    return addProgramClassFileData(Arrays.asList(classes));
-  }
-
   public T addProgramClasses(Class<?>... classes) {
     return addProgramClasses(Arrays.asList(classes));
   }
diff --git a/src/test/java/com/android/tools/r8/TestCompileResult.java b/src/test/java/com/android/tools/r8/TestCompileResult.java
index bf704ea..12d1990 100644
--- a/src/test/java/com/android/tools/r8/TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/TestCompileResult.java
@@ -6,7 +6,6 @@
 import static com.android.tools.r8.TestBase.Backend.DEX;
 
 import com.android.tools.r8.TestBase.Backend;
-import com.android.tools.r8.ToolHelper.DexVm;
 import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.debug.CfDebugTestConfig;
 import com.android.tools.r8.debug.DebugTestConfig;
@@ -99,17 +98,4 @@
     ProcessResult result = ToolHelper.runArtRaw(out.toString(), mainClass);
     return createRunResult(app, result);
   }
-
-  public TestRunResult runDex2Oat() throws IOException {
-    return runDex2Oat(ToolHelper.getDexVm());
-  }
-
-  public TestRunResult runDex2Oat(DexVm vm) throws IOException {
-    assert getBackend() == DEX;
-    Path tmp = state.getNewTempFolder();
-    Path jarFile = tmp.resolve("out.jar");
-    Path oatFile = tmp.resolve("out.oat");
-    app.writeToZip(jarFile, OutputMode.DexIndexed);
-    return new TestRunResult(app, ToolHelper.runDex2OatRaw(jarFile, oatFile, vm));
-  }
 }
diff --git a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
index 9452a63..810d292 100644
--- a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -5,7 +5,6 @@
 
 import com.android.tools.r8.TestBase.Backend;
 import com.android.tools.r8.debug.DebugTestConfig;
-import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.AndroidAppConsumers;
@@ -114,14 +113,6 @@
   }
 
   @Override
-  public T addProgramClassFileData(Collection<byte[]> classes) {
-    for (byte[] clazz : classes) {
-      builder.addClassProgramData(clazz, Origin.unknown());
-    }
-    return self();
-  }
-
-  @Override
   public T addProgramFiles(Collection<Path> files) {
     builder.addProgramFiles(files);
     return self();
@@ -133,9 +124,4 @@
     builder.addLibraryFiles(files);
     return self();
   }
-
-  public T noDesugaring() {
-    builder.setDisableDesugaring(true);
-    return self();
-  }
 }
diff --git a/src/test/java/com/android/tools/r8/TestRunResult.java b/src/test/java/com/android/tools/r8/TestRunResult.java
index 8b6461f..46dc4cc 100644
--- a/src/test/java/com/android/tools/r8/TestRunResult.java
+++ b/src/test/java/com/android/tools/r8/TestRunResult.java
@@ -26,14 +26,6 @@
     this.result = result;
   }
 
-  public String getStdOut() {
-    return result.stdout;
-  }
-
-  public String getStdErr() {
-    return result.stderr;
-  }
-
   public TestRunResult assertSuccess() {
     assertEquals(errorMessage("Expected run to succeed."), 0, result.exitCode);
     return this;
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 70be34e..d4639a1 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -1438,42 +1438,39 @@
   }
 
   public static void runDex2Oat(Path file, Path outFile) throws IOException {
-    runDex2Oat(file, outFile, getDexVm());
-  }
-
-  public static void runDex2Oat(Path file, Path outFile, DexVm vm) throws IOException {
-    ProcessResult result = runDex2OatRaw(file, outFile, vm);
-    if (result.exitCode != 0) {
-      fail("dex2oat failed, exit code " + result.exitCode + ", stderr:\n" + result.stderr);
-    }
-    if (result.stderr != null && result.stderr.contains("Verification error")) {
-      fail("Verification error: \n" + result.stderr);
-    }
-  }
-
-  public static ProcessResult runDex2OatRaw(Path file, Path outFile, DexVm vm) throws IOException {
-    Assume.assumeTrue(ToolHelper.isDex2OatSupported());
+    DexVm vm = getDexVm();
     if (vm.isOlderThanOrEqual(DexVm.ART_5_1_1_HOST)) {
       // TODO(b/79191363): Support running dex2oat for past android versions.
       // Run default dex2oat for tests on old runtimes.
       vm = DexVm.ART_DEFAULT;
     }
+    runDex2Oat(file, outFile, vm);
+  }
+
+  public static void runDex2Oat(Path file, Path outFile, DexVm vm) throws IOException {
+    Assume.assumeTrue(ToolHelper.isDex2OatSupported());
     // TODO(jmhenaff): find a way to run this on windows (push dex and run on device/emulator?)
     Assume.assumeTrue(!ToolHelper.isWindows());
     assert Files.exists(file);
     assert ByteStreams.toByteArray(Files.newInputStream(file)).length > 0;
     List<String> command = new ArrayList<>();
     command.add(getDex2OatPath(vm).toString());
-    command.add("--android-root=" + getProductPath(vm) + "/system");
+    command.add("--android-root=" + getProductPath(vm));
     command.add("--runtime-arg");
     command.add("-Xnorelocate");
+    command.add("--boot-image=" + getProductBootImagePath(vm));
     command.add("--dex-file=" + file.toAbsolutePath());
     command.add("--oat-file=" + outFile.toAbsolutePath());
-    // TODO(zerny): Create a proper interface for invoking dex2oat. Hardcoding arm64 here is a hack!
     command.add("--instruction-set=arm64");
     ProcessBuilder builder = new ProcessBuilder(command);
     builder.environment().put("LD_LIBRARY_PATH", getDexVmLibPath(vm).toString());
-    return runProcess(builder);
+    ProcessResult result = runProcess(builder);
+    if (result.exitCode != 0) {
+      fail("dex2oat failed, exit code " + result.exitCode + ", stderr:\n" + result.stderr);
+    }
+    if (result.stderr.contains("Verification error")) {
+      fail("Verification error: \n" + result.stderr);
+    }
   }
 
   public static ProcessResult runProguardRaw(
diff --git a/src/test/java/com/android/tools/r8/regress/b118075510/Regress118075510Runner.java b/src/test/java/com/android/tools/r8/regress/b118075510/Regress118075510Runner.java
deleted file mode 100644
index 12bd452..0000000
--- a/src/test/java/com/android/tools/r8/regress/b118075510/Regress118075510Runner.java
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.regress.b118075510;
-
-import com.android.tools.r8.AsmTestBase;
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.D8TestCompileResult;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.StringUtils;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.io.IOException;
-import java.util.concurrent.ExecutionException;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class Regress118075510Runner extends AsmTestBase {
-
-  public static final Class<?> CLASS = Regress118075510Test.class;
-  public static final String EXPECTED = StringUtils.lines("0", "0");
-
-  @Test
-  public void test()
-      throws CompilationFailedException, IOException, ExecutionException, NoSuchMethodException {
-    testForJvm().addTestClasspath().run(CLASS).assertSuccessWithOutput(EXPECTED);
-
-    D8TestCompileResult d8Result =
-        testForD8().addProgramClasses(CLASS).setMinApi(AndroidApiLevel.M).release().compile();
-
-    CodeInspector inspector = d8Result.inspector();
-    checkMethodContainsLongSignum(inspector, "fooNoTryCatch");
-    checkMethodContainsLongSignum(inspector, "fooWithTryCatch");
-    // Check the program runs on ART/Dalvik
-    d8Result.run(CLASS).assertSuccessWithOutput(EXPECTED);
-    // Check the program can be dex2oat compiled to arm64. This will diverge without the fixup.
-    d8Result.runDex2Oat().assertSuccess();
-  }
-
-  private void checkMethodContainsLongSignum(CodeInspector inspector, String methodName)
-      throws NoSuchMethodException {
-    MethodSubject method = inspector.method(CLASS.getMethod(methodName, long.class, long.class));
-    Assert.assertTrue(
-        "Did not contain Long.signum workaround in "
-            + methodName
-            + ":\n"
-            + method.getMethod().codeToString(),
-        method
-            .streamInstructions()
-            .anyMatch(
-                i ->
-                    i.isInvoke() && i.getMethod().qualifiedName().equals("java.lang.Long.signum")));
-  }
-}
diff --git a/src/test/java/com/android/tools/r8/regress/b118075510/Regress118075510Test.java b/src/test/java/com/android/tools/r8/regress/b118075510/Regress118075510Test.java
deleted file mode 100644
index cc4dece..0000000
--- a/src/test/java/com/android/tools/r8/regress/b118075510/Regress118075510Test.java
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.regress.b118075510;
-
-public class Regress118075510Test {
-
-  public static void fooNoTryCatch(long a, long b) {
-    // Call a method on the runner class that will not be on the classpath at runtime.
-    // This causes the optimizing 6.0.1 compiler to delegate to the old quick compiler.
-    if (a == b) Regress118075510Runner.class.getMethods();
-    // The else branch of the conditional here ends up with an invalid previous pointer at its
-    // block header (ie, previous of mul-long (2addr) points to epilogue-end which is self-linked.
-    System.out.println(a < b ? 0 : a * b + b);
-  }
-
-  public static void fooWithTryCatch(long a, long b) {
-    // Call a method on the runner class that will not be on the classpath at runtime.
-    // This causes the optimizing 6.0.1 compiler to delegate to the old quick compiler.
-    if (a == b) Regress118075510Runner.class.getMethods();
-    // The else branch of the conditional here ends up with an invalid previous pointer at its
-    // block header (ie, previous of mul-long (2addr) points to epilogue-end which is self-linked.
-    try {
-      if (a < b) {
-        System.out.println((long) 0);
-      } else {
-        System.out.println(a * b + b);
-      }
-    } catch (RuntimeException e) {
-      e.printStackTrace();
-    }
-  }
-
-  public static void main(String[] args) {
-    fooNoTryCatch(args.length, 456);
-    fooWithTryCatch(456, args.length);
-  }
-}
diff --git a/src/test/java/com/android/tools/r8/regress/b77842465/Regress77842465.java b/src/test/java/com/android/tools/r8/regress/b77842465/Regress77842465.java
index 3ab3467..cbc6e1b 100644
--- a/src/test/java/com/android/tools/r8/regress/b77842465/Regress77842465.java
+++ b/src/test/java/com/android/tools/r8/regress/b77842465/Regress77842465.java
@@ -5,20 +5,29 @@
 
 import com.android.tools.r8.AsmTestBase;
 import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.D8;
+import com.android.tools.r8.D8Command;
+import com.android.tools.r8.OutputMode;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.origin.Origin;
 import java.io.IOException;
+import java.nio.file.Path;
 import org.junit.Test;
 
 public class Regress77842465 extends AsmTestBase {
 
   @Test
   public void test() throws CompilationFailedException, IOException {
-    testForD8()
-        .addProgramClassFileData(Regress77842465Dump.dump())
-        .noDesugaring()
-        .setMinApi(AndroidApiLevel.M)
-        .compile()
-        .runDex2Oat()
-        .assertSuccess();
+
+    Path dexOut = temp.getRoot().toPath().resolve("out.jar");
+    Path oatOut = temp.getRoot().toPath().resolve("out.odex");
+
+    D8.run(D8Command.builder()
+        .addClassProgramData(Regress77842465Dump.dump(), Origin.unknown())
+        .setOutput(dexOut, OutputMode.DexIndexed)
+        .setDisableDesugaring(true)
+        .build());
+
+    ToolHelper.runDex2Oat(dexOut, oatOut);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
index 98bb8d0..1e21552 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
@@ -5,10 +5,8 @@
 package com.android.tools.r8.utils.codeinspector;
 
 import com.android.tools.r8.graph.DexEncodedMethod;
-import com.google.common.collect.Streams;
 import java.util.Iterator;
 import java.util.function.Predicate;
-import java.util.stream.Stream;
 
 public abstract class MethodSubject extends MemberSubject {
 
@@ -42,8 +40,4 @@
   public abstract LineNumberTable getLineNumberTable();
 
   public abstract boolean hasLocalVariableTable();
-
-  public Stream<InstructionSubject> streamInstructions() {
-    return Streams.stream(iterateInstructions());
-  }
 }