Merge "Revert "Always parse debug info for reachability sensitive methods in R8.""
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 3ed662f..6906161 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -237,12 +237,6 @@
if (options.quiet) {
System.setOut(new PrintStream(ByteStreams.nullOutputStream()));
}
- // TODO(b/65390962): Remove this warning once the CF backend is complete.
- if (options.isGeneratingClassFiles() && !options.testing.suppressExperimentalCfBackendWarning) {
- options.reporter.warning(new StringDiagnostic(
- "R8 support for generating Java classfiles is incomplete and experimental. "
- + "Even if R8 appears to succeed, the generated output is likely incorrect."));
- }
try {
AndroidApiLevel oLevel = AndroidApiLevel.O;
if (options.minApiLevel >= oLevel.getLevel()
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 3798c3f..bdbf44f 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
// This field is accessed from release scripts using simple pattern matching.
// Therefore, changing this field could break our release scripts.
- public static final String LABEL = "1.4.10-dev";
+ public static final String LABEL = "1.4.11-dev";
private Version() {
}
diff --git a/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java b/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java
index 64395de..16a03e2 100644
--- a/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java
+++ b/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java
@@ -10,17 +10,21 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.Argument;
+import com.android.tools.r8.ir.code.ConstNumber;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionIterator;
import com.android.tools.r8.ir.code.NewInstance;
+import com.android.tools.r8.ir.code.Phi;
import com.android.tools.r8.ir.code.StackValue;
import com.android.tools.r8.ir.code.Value;
import com.google.common.collect.ImmutableSet;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@@ -221,6 +225,7 @@
public Map<Value, TypeInfo> computeVerificationTypes() {
computingVerificationTypes = true;
types = new HashMap<>();
+ List<ConstNumber> nullsUsedInPhis = new ArrayList<>();
Set<Value> worklist = new HashSet<>();
{
InstructionIterator it = code.instructionIterator();
@@ -261,6 +266,12 @@
} else if (instruction.outType().isObject()) {
Value outValue = instruction.outValue();
if (instruction.hasInvariantOutType()) {
+ if (instruction.isConstNumber()) {
+ assert instruction.asConstNumber().isZero();
+ if (outValue.numberOfAllUsers() == outValue.numberOfPhiUsers()) {
+ nullsUsedInPhis.add(instruction.asConstNumber());
+ }
+ }
DexType type = instruction.computeVerificationType(this);
types.put(outValue, createInitializedType(type));
addUsers(outValue, worklist);
@@ -284,6 +295,20 @@
}
}
computingVerificationTypes = false;
+ for (ConstNumber instruction : nullsUsedInPhis) {
+ TypeInfo refinedType = null;
+ for (Phi phi : instruction.outValue().uniquePhiUsers()) {
+ if (refinedType == null) {
+ refinedType = types.get(phi);
+ } else if (refinedType.getDexType() != types.get(phi).getDexType()) {
+ refinedType = null;
+ break;
+ }
+ }
+ if (refinedType != null) {
+ types.put(instruction.outValue(), refinedType);
+ }
+ }
return types;
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
index f3b58db..a658474 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
@@ -346,10 +346,12 @@
previousFallthrough = fallthrough;
} while (block != null);
// TODO(mkroghj) Move computation of stack-height to CF instructions.
- CfLabel endLabel = ensureLabel();
- for (LocalVariableInfo info : openLocalVariables.values()) {
- info.setEnd(endLabel);
- localVariablesTable.add(info);
+ if (!openLocalVariables.isEmpty()) {
+ CfLabel endLabel = ensureLabel();
+ for (LocalVariableInfo info : openLocalVariables.values()) {
+ info.setEnd(endLabel);
+ localVariablesTable.add(info);
+ }
}
return new CfCode(
method.method,
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 05fd603..6288eaa 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,6 +36,7 @@
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;
@@ -93,6 +94,7 @@
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 {
@@ -1241,20 +1243,116 @@
}
}
+ /**
+ * 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::isMaterializingInstructionOnArtArmVersionM);
- if (needsInstructionBeforeLongOperation(firstMaterializing)) {
- ensureInstructionBefore(code, firstMaterializing, it);
+ 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;
+ }
}
}
}
+ 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.
@@ -1273,33 +1371,6 @@
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/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 41463fa..a3c805f 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -483,7 +483,6 @@
public boolean forceJumboStringProcessing = false;
public boolean nondeterministicCycleElimination = false;
public Set<Inliner.Reason> validInliningReasons = null;
- public boolean suppressExperimentalCfBackendWarning = false;
}
private boolean hasMinApi(AndroidApiLevel level) {
diff --git a/src/test/java/com/android/tools/r8/DXTestBuilder.java b/src/test/java/com/android/tools/r8/DXTestBuilder.java
index 8312729..190db23 100644
--- a/src/test/java/com/android/tools/r8/DXTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/DXTestBuilder.java
@@ -67,6 +67,11 @@
}
@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 4e0bedf..6feb460 100644
--- a/src/test/java/com/android/tools/r8/JvmTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/JvmTestBuilder.java
@@ -147,6 +147,12 @@
"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 28ce1e6..fa4c41c 100644
--- a/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
@@ -184,6 +184,12 @@
}
@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 4977d94..7f200c1 100644
--- a/src/test/java/com/android/tools/r8/TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestBuilder.java
@@ -39,6 +39,12 @@
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 12d1990..bf704ea 100644
--- a/src/test/java/com/android/tools/r8/TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/TestCompileResult.java
@@ -6,6 +6,7 @@
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;
@@ -98,4 +99,17 @@
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 810d292..9452a63 100644
--- a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -5,6 +5,7 @@
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;
@@ -113,6 +114,14 @@
}
@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();
@@ -124,4 +133,9 @@
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 46dc4cc..8b6461f 100644
--- a/src/test/java/com/android/tools/r8/TestRunResult.java
+++ b/src/test/java/com/android/tools/r8/TestRunResult.java
@@ -26,6 +26,14 @@
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 d4639a1..70be34e 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -1438,39 +1438,42 @@
}
public static void runDex2Oat(Path file, Path outFile) throws IOException {
- DexVm vm = getDexVm();
+ 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());
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));
+ command.add("--android-root=" + getProductPath(vm) + "/system");
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());
- 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);
- }
+ return runProcess(builder);
}
public static ProcessResult runProguardRaw(
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 095d7e9..bfd3b76 100644
--- a/src/test/java/com/android/tools/r8/naming/AdaptResourceFileNamesTest.java
+++ b/src/test/java/com/android/tools/r8/naming/AdaptResourceFileNamesTest.java
@@ -265,7 +265,6 @@
options -> {
options.dataResourceConsumer = dataResourceConsumer;
options.proguardMapConsumer = proguardMapConsumer;
- options.testing.suppressExperimentalCfBackendWarning = true;
});
}
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 c3311a4..410ae0a 100644
--- a/src/test/java/com/android/tools/r8/naming/MinifierClassSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/naming/MinifierClassSignatureTest.java
@@ -325,10 +325,7 @@
.setProgramConsumer(emptyConsumer(backend))
.addLibraryFiles(runtimeJar(backend))
.setProguardMapConsumer(StringConsumer.emptyConsumer())
- .build(),
- options -> {
- options.testing.suppressExperimentalCfBackendWarning = true;
- }));
+ .build()));
// All classes are kept, and renamed.
assertThat(inspector.clazz("Simple"), isRenamed());
assertThat(inspector.clazz("Base"), isRenamed());
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 6877953..1c4e31b 100644
--- a/src/test/java/com/android/tools/r8/naming/MinifierFieldSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/naming/MinifierFieldSignatureTest.java
@@ -190,10 +190,7 @@
.setProgramConsumer(emptyConsumer(backend))
.addLibraryFiles(runtimeJar(backend))
.setProguardMapConsumer(StringConsumer.emptyConsumer())
- .build(),
- options -> {
- options.testing.suppressExperimentalCfBackendWarning = true;
- }));
+ .build()));
// All classes are kept, and renamed.
ClassSubject clazz = inspector.clazz("Fields");
assertThat(clazz, isRenamed());
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 706bdd4..3c74a5b 100644
--- a/src/test/java/com/android/tools/r8/naming/MinifierMethodSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/naming/MinifierMethodSignatureTest.java
@@ -212,10 +212,7 @@
.setProgramConsumer(emptyConsumer(backend))
.addLibraryFiles(runtimeJar(backend))
.setProguardMapConsumer(StringConsumer.emptyConsumer())
- .build(),
- options -> {
- options.testing.suppressExperimentalCfBackendWarning = true;
- }));
+ .build()));
// All classes are kept, and renamed.
ClassSubject clazz = inspector.clazz("Methods");
assertThat(clazz, isRenamed());
diff --git a/src/test/java/com/android/tools/r8/naming/WarnReflectiveAccessTest.java b/src/test/java/com/android/tools/r8/naming/WarnReflectiveAccessTest.java
index 9ebb6cc..74e6471 100644
--- a/src/test/java/com/android/tools/r8/naming/WarnReflectiveAccessTest.java
+++ b/src/test/java/com/android/tools/r8/naming/WarnReflectiveAccessTest.java
@@ -123,7 +123,6 @@
o -> {
o.enableInlining = false;
o.forceProguardCompatibility = forceProguardCompatibility;
- o.testing.suppressExperimentalCfBackendWarning = true;
});
}
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
new file mode 100644
index 0000000..12bd452
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/regress/b118075510/Regress118075510Runner.java
@@ -0,0 +1,54 @@
+// 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
new file mode 100644
index 0000000..cc4dece
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/regress/b118075510/Regress118075510Test.java
@@ -0,0 +1,38 @@
+// 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 cbc6e1b..3ab3467 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,29 +5,20 @@
import com.android.tools.r8.AsmTestBase;
import com.android.tools.r8.CompilationFailedException;
-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 com.android.tools.r8.utils.AndroidApiLevel;
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 {
-
- 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);
+ testForD8()
+ .addProgramClassFileData(Regress77842465Dump.dump())
+ .noDesugaring()
+ .setMinApi(AndroidApiLevel.M)
+ .compile()
+ .runDex2Oat()
+ .assertSuccess();
}
}
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 1e21552..98bb8d0 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,8 +5,10 @@
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 {
@@ -40,4 +42,8 @@
public abstract LineNumberTable getLineNumberTable();
public abstract boolean hasLocalVariableTable();
+
+ public Stream<InstructionSubject> streamInstructions() {
+ return Streams.stream(iterateInstructions());
+ }
}