Merge "Ensure that dual nullable TypeLattice is synchronized."
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index bdbf44f..29d54b4 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.11-dev";
+ public static final String LABEL = "1.4.12-dev";
private Version() {
}
diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
index 0773237..a25bae0 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -167,6 +167,7 @@
private final List<DexEncodedMethod> directMethods = new ArrayList<>();
private final List<DexEncodedMethod> virtualMethods = new ArrayList<>();
private final Set<Wrapper<DexMethod>> methodSignatures = new HashSet<>();
+ private boolean hasReachabilitySensitiveMethod = false;
public CreateDexClassVisitor(
Origin origin,
@@ -301,6 +302,7 @@
addAnnotation(DexAnnotation.createAnnotationDefaultAnnotation(
type, defaultAnnotations, application.getFactory()));
}
+ checkReachabilitySensitivity();
DexClass clazz =
classKind.create(
type,
@@ -325,6 +327,45 @@
classConsumer.accept(clazz);
}
+ // If anything is marked reachability sensitive, all methods need to be parsed including
+ // locals information. This propagates the reachability sensitivity bit so that if any field
+ // or method is annotated, all methods get parsed with locals information.
+ private void checkReachabilitySensitivity() {
+ if (hasReachabilitySensitiveMethod || hasReachabilitySensitiveField()) {
+ for (DexEncodedMethod method : directMethods) {
+ Code code = method.getCode();
+ if (code != null && code.isJarCode()) {
+ code.asJarCode().markReachabilitySensitive();
+ }
+ }
+ for (DexEncodedMethod method : virtualMethods) {
+ Code code = method.getCode();
+ if (code != null && code.isJarCode()) {
+ code.asJarCode().markReachabilitySensitive();
+ }
+ }
+ }
+ }
+
+ private boolean hasReachabilitySensitiveField() {
+ DexType reachabilitySensitive = application.getFactory().annotationReachabilitySensitive;
+ for (DexEncodedField field : instanceFields) {
+ for (DexAnnotation annotation : field.annotations.annotations) {
+ if (annotation.annotation.type == reachabilitySensitive) {
+ return true;
+ }
+ }
+ }
+ for (DexEncodedField field : staticFields) {
+ for (DexAnnotation annotation : field.annotations.annotations) {
+ if (annotation.annotation.type == reachabilitySensitive) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
private void addDefaultAnnotation(String name, DexValue value) {
if (defaultAnnotations == null) {
defaultAnnotations = new ArrayList<>();
@@ -626,6 +667,7 @@
parent.version);
Wrapper<DexMethod> signature = MethodSignatureEquivalence.get().wrap(method);
if (parent.methodSignatures.add(signature)) {
+ parent.hasReachabilitySensitiveMethod |= isReachabilitySensitive();
if (flags.isStatic() || flags.isConstructor() || flags.isPrivate()) {
parent.directMethods.add(dexMethod);
} else {
@@ -644,6 +686,17 @@
}
}
+ private boolean isReachabilitySensitive() {
+ DexType reachabilitySensitive =
+ parent.application.getFactory().annotationReachabilitySensitive;
+ for (DexAnnotation annotation : getAnnotations()) {
+ if (annotation.annotation.type == reachabilitySensitive) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private List<DexAnnotation> getAnnotations() {
if (annotations == null) {
annotations = new ArrayList<>();
diff --git a/src/main/java/com/android/tools/r8/graph/JarCode.java b/src/main/java/com/android/tools/r8/graph/JarCode.java
index c2f4943..57a4c78 100644
--- a/src/main/java/com/android/tools/r8/graph/JarCode.java
+++ b/src/main/java/com/android/tools/r8/graph/JarCode.java
@@ -52,8 +52,8 @@
private final Origin origin;
private MethodNode node;
protected ReparseContext context;
-
protected final JarApplicationReader application;
+ private boolean reachabilitySensitive = false;
public JarCode(
DexMethod method, Origin origin, ReparseContext context, JarApplicationReader application) {
@@ -64,6 +64,13 @@
context.codeList.add(this);
}
+ public void markReachabilitySensitive() {
+ // We need to mark before we have reparsed so that the method code is reparsed
+ // including debug information.
+ assert context != null;
+ this.reachabilitySensitive = true;
+ }
+
public MethodNode getNode() {
triggerDelayedParsingIfNeccessary();
return node;
@@ -271,9 +278,16 @@
private void parseCode(ReparseContext context, boolean useJsrInliner) {
// If the keep attributes do not specify keeping LocalVariableTable, LocalVariableTypeTable or
// LineNumberTable, then we can skip parsing all the debug related attributes during code read.
+ // If the method is reachability sensitive we have to include debug information in order
+ // to get locals information which we need to extend the live ranges of locals for their
+ // entire scope.
int parsingOptions = ClassReader.SKIP_FRAMES;
ProguardKeepAttributes keep = application.options.proguardConfiguration.getKeepAttributes();
- if (!keep.localVariableTable && !keep.localVariableTypeTable && !keep.lineNumberTable) {
+
+ if (!keep.localVariableTable
+ && !keep.localVariableTypeTable
+ && !keep.lineNumberTable
+ && !reachabilitySensitive) {
parsingOptions |= ClassReader.SKIP_DEBUG;
}
SecondVisitor classVisitor = new SecondVisitor(createCodeLocator(context), useJsrInliner);
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..f0d5d7b 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 {
@@ -1163,9 +1161,11 @@
}
private void markProcessed(DexEncodedMethod method, IRCode code, OptimizationFeedback feedback) {
- // After all the optimizations have take place, we compute whether method should be inlinedex.
+ // After all the optimizations have take place, we compute whether method should be inlined.
ConstraintWithTarget state;
- if (!options.enableInlining || inliner == null) {
+ if (!options.enableInlining
+ || inliner == null
+ || method.getOptimizationInfo().isReachabilitySensitive()) {
state = ConstraintWithTarget.NEVER;
} else {
state = inliner.computeInliningConstraint(code, method);
@@ -1243,116 +1243,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 +1275,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/D8TestRunResult.java b/src/test/java/com/android/tools/r8/D8TestRunResult.java
index d14f12d..1aa095a 100644
--- a/src/test/java/com/android/tools/r8/D8TestRunResult.java
+++ b/src/test/java/com/android/tools/r8/D8TestRunResult.java
@@ -7,9 +7,14 @@
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.utils.AndroidApp;
-public class D8TestRunResult extends TestRunResult {
+public class D8TestRunResult extends TestRunResult<D8TestRunResult> {
public D8TestRunResult(AndroidApp app, ProcessResult result) {
super(app, result);
}
+
+ @Override
+ protected D8TestRunResult self() {
+ return this;
+ }
}
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/DXTestRunResult.java b/src/test/java/com/android/tools/r8/DXTestRunResult.java
index c1df193..830cbd8 100644
--- a/src/test/java/com/android/tools/r8/DXTestRunResult.java
+++ b/src/test/java/com/android/tools/r8/DXTestRunResult.java
@@ -7,9 +7,14 @@
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.utils.AndroidApp;
-public class DXTestRunResult extends TestRunResult {
+public class DXTestRunResult extends TestRunResult<DXTestRunResult> {
public DXTestRunResult(AndroidApp app, ProcessResult result) {
super(app, result);
}
+
+ @Override
+ protected DXTestRunResult self() {
+ return this;
+ }
}
diff --git a/src/test/java/com/android/tools/r8/JvmTestBuilder.java b/src/test/java/com/android/tools/r8/JvmTestBuilder.java
index 6feb460..44a3bed 100644
--- a/src/test/java/com/android/tools/r8/JvmTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/JvmTestBuilder.java
@@ -24,7 +24,7 @@
import java.util.List;
import java.util.Set;
-public class JvmTestBuilder extends TestBuilder<JvmTestBuilder> {
+public class JvmTestBuilder extends TestBuilder<JvmTestRunResult, JvmTestBuilder> {
private static class ClassFileResource implements ProgramResource {
@@ -107,9 +107,9 @@
}
@Override
- public TestRunResult run(String mainClass) throws IOException {
+ public JvmTestRunResult run(String mainClass) throws IOException {
ProcessResult result = ToolHelper.runJava(classpath, mainClass);
- return new TestRunResult(builder.build(), result);
+ return new JvmTestRunResult(builder.build(), result);
}
@Override
@@ -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/JvmTestRunResult.java b/src/test/java/com/android/tools/r8/JvmTestRunResult.java
new file mode 100644
index 0000000..b7a71fd
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/JvmTestRunResult.java
@@ -0,0 +1,20 @@
+// 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;
+
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.utils.AndroidApp;
+
+public class JvmTestRunResult extends TestRunResult<JvmTestRunResult> {
+
+ public JvmTestRunResult(AndroidApp app, ProcessResult result) {
+ super(app, result);
+ }
+
+ @Override
+ protected JvmTestRunResult self() {
+ return this;
+ }
+}
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/ProguardTestRunResult.java b/src/test/java/com/android/tools/r8/ProguardTestRunResult.java
index 9e0d875..e242a38 100644
--- a/src/test/java/com/android/tools/r8/ProguardTestRunResult.java
+++ b/src/test/java/com/android/tools/r8/ProguardTestRunResult.java
@@ -12,7 +12,7 @@
import java.io.IOException;
import java.util.concurrent.ExecutionException;
-public class ProguardTestRunResult extends TestRunResult {
+public class ProguardTestRunResult extends TestRunResult<ProguardTestRunResult> {
private final String proguardMap;
@@ -22,6 +22,11 @@
}
@Override
+ protected ProguardTestRunResult self() {
+ return this;
+ }
+
+ @Override
public CodeInspector inspector() throws IOException, ExecutionException {
// See comment in base class.
assertSuccess();
diff --git a/src/test/java/com/android/tools/r8/R8TestRunResult.java b/src/test/java/com/android/tools/r8/R8TestRunResult.java
index 2c42b95..ddea062 100644
--- a/src/test/java/com/android/tools/r8/R8TestRunResult.java
+++ b/src/test/java/com/android/tools/r8/R8TestRunResult.java
@@ -12,7 +12,7 @@
import java.io.IOException;
import java.util.concurrent.ExecutionException;
-public class R8TestRunResult extends TestRunResult {
+public class R8TestRunResult extends TestRunResult<R8TestRunResult> {
private final String proguardMap;
@@ -22,10 +22,19 @@
}
@Override
+ protected R8TestRunResult self() {
+ return this;
+ }
+
+ @Override
public CodeInspector inspector() throws IOException, ExecutionException {
// See comment in base class.
assertSuccess();
assertNotNull(app);
return new CodeInspector(app, proguardMap);
}
+
+ public String proguardMap() {
+ return proguardMap;
+ }
}
diff --git a/src/test/java/com/android/tools/r8/TestBuilder.java b/src/test/java/com/android/tools/r8/TestBuilder.java
index 7f200c1..0675118 100644
--- a/src/test/java/com/android/tools/r8/TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestBuilder.java
@@ -14,7 +14,7 @@
import java.util.HashSet;
import java.util.Set;
-public abstract class TestBuilder<T extends TestBuilder<T>> {
+public abstract class TestBuilder<RR extends TestRunResult, T extends TestBuilder<RR, T>> {
private final TestState state;
@@ -28,10 +28,10 @@
abstract T self();
- public abstract TestRunResult run(String mainClass)
+ public abstract RR run(String mainClass)
throws IOException, CompilationFailedException;
- public TestRunResult run(Class mainClass) throws IOException, CompilationFailedException {
+ public RR run(Class mainClass) throws IOException, CompilationFailedException {
return run(mainClass.getTypeName());
}
@@ -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..f60db7f 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;
@@ -23,7 +22,7 @@
CR extends TestCompileResult<RR>,
RR extends TestRunResult,
T extends TestCompilerBuilder<C, B, CR, RR, T>>
- extends TestBuilder<T> {
+ extends TestBuilder<RR, T> {
public static final Consumer<InternalOptions> DEFAULT_OPTIONS =
new Consumer<InternalOptions>() {
@@ -72,7 +71,7 @@
}
@Override
- public TestRunResult run(String mainClass) throws IOException, CompilationFailedException {
+ public RR run(String mainClass) throws IOException, CompilationFailedException {
return compile().run(mainClass);
}
@@ -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..f3ec339 100644
--- a/src/test/java/com/android/tools/r8/TestRunResult.java
+++ b/src/test/java/com/android/tools/r8/TestRunResult.java
@@ -15,9 +15,10 @@
import java.io.IOException;
import java.io.PrintStream;
import java.util.concurrent.ExecutionException;
+import java.util.function.Function;
import org.hamcrest.Matcher;
-public class TestRunResult {
+public abstract class TestRunResult<RR extends TestRunResult<?>> {
protected final AndroidApp app;
private final ProcessResult result;
@@ -26,6 +27,8 @@
this.result = result;
}
+ abstract RR self();
+
public String getStdOut() {
return result.stdout;
}
@@ -34,33 +37,41 @@
return result.stderr;
}
- public TestRunResult assertSuccess() {
+ public int getExitCode() {
+ return result.exitCode;
+ }
+
+ public RR assertSuccess() {
assertEquals(errorMessage("Expected run to succeed."), 0, result.exitCode);
- return this;
+ return self();
}
- public TestRunResult assertFailure() {
+ public RR assertFailure() {
assertNotEquals(errorMessage("Expected run to fail."), 0, result.exitCode);
- return this;
+ return self();
}
- public TestRunResult assertFailureWithOutput(String expected) {
+ public RR assertFailureWithOutput(String expected) {
assertFailure();
assertEquals(errorMessage("Run stdout incorrect.", expected), expected, result.stdout);
- return this;
+ return self();
}
- public TestRunResult assertFailureWithErrorThatMatches(Matcher<String> matcher) {
+ public RR assertFailureWithErrorThatMatches(Matcher<String> matcher) {
assertFailure();
assertThat(
errorMessage("Run stderr incorrect.", matcher.toString()), result.stderr, matcher);
- return this;
+ return self();
}
- public TestRunResult assertSuccessWithOutput(String expected) {
+ public RR assertSuccessWithOutput(String expected) {
assertSuccess();
assertEquals(errorMessage("Run stdout incorrect.", expected), expected, result.stdout);
- return this;
+ return self();
+ }
+
+ public <R> R map(Function<RR, R> mapper) {
+ return mapper.apply(self());
}
public CodeInspector inspector() throws IOException, ExecutionException {
@@ -71,10 +82,10 @@
return new CodeInspector(app);
}
- public TestRunResult inspect(Consumer<CodeInspector> consumer)
+ public RR inspect(Consumer<CodeInspector> consumer)
throws IOException, ExecutionException {
consumer.accept(inspector());
- return this;
+ return self();
}
private String errorMessage(String message) {
@@ -110,24 +121,24 @@
builder.append("COMMAND: ").append(result.command).append('\n').append(result);
}
- public TestRunResult writeInfo(PrintStream ps) {
+ public RR writeInfo(PrintStream ps) {
StringBuilder sb = new StringBuilder();
appendInfo(sb);
ps.println(sb.toString());
- return this;
+ return self();
}
- public TestRunResult writeApplicaion(PrintStream ps) {
+ public RR writeApplicaion(PrintStream ps) {
StringBuilder sb = new StringBuilder();
appendApplication(sb);
ps.println(sb.toString());
- return this;
+ return self();
}
- public TestRunResult writeProcessResult(PrintStream ps) {
+ public RR writeProcessResult(PrintStream ps) {
StringBuilder sb = new StringBuilder();
appendProcessResult(sb);
ps.println(sb.toString());
- return this;
+ return self();
}
}
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 70be34e..caeebd9 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -475,7 +475,7 @@
.put(DexVm.ART_8_1_0_HOST, "marlin")
.put(DexVm.ART_7_0_0_HOST, "angler")
.put(DexVm.ART_6_0_1_HOST, "angler")
- .put(DexVm.ART_5_1_1_HOST, "<missing>")
+ .put(DexVm.ART_5_1_1_HOST, "mako")
.put(DexVm.ART_4_4_4_HOST, "<missing>")
.put(DexVm.ART_4_0_4_HOST, "<missing>");
PRODUCT = builder.build();
@@ -504,6 +504,10 @@
return getDexVmPath(vm).resolve("product").resolve(PRODUCT.get(vm));
}
+ private static String getArchString(DexVm vm) {
+ return vm.isOlderThanOrEqual(DexVm.ART_5_1_1_HOST) ? "arm" : "arm64";
+ }
+
private static Path getProductBootImagePath(DexVm vm) {
return getProductPath(vm).resolve("system").resolve("framework").resolve("boot.art");
}
@@ -1452,14 +1456,12 @@
}
public static ProcessResult runDex2OatRaw(Path file, Path outFile, DexVm vm) throws IOException {
+ // TODO(jmhenaff): find a way to run this on windows (push dex and run on device/emulator?)
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.
+ if (vm.isOlderThanOrEqual(DexVm.ART_4_4_4_HOST)) {
+ // Run default dex2oat for tests on dalvik runtimes.
vm = DexVm.ART_DEFAULT;
}
- // 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<>();
@@ -1469,8 +1471,8 @@
command.add("-Xnorelocate");
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");
+ // TODO(zerny): Create a proper interface for invoking dex2oat. Hardcoding arch here is a hack!
+ command.add("--instruction-set=" + getArchString(vm));
ProcessBuilder builder = new ProcessBuilder(command);
builder.environment().put("LD_LIBRARY_PATH", getDexVmLibPath(vm).toString());
return runProcess(builder);
diff --git a/src/test/java/com/android/tools/r8/d8/IncompatiblePrimitiveTypesTest.java b/src/test/java/com/android/tools/r8/d8/IncompatiblePrimitiveTypesTest.java
index 010f903..a9eef53 100644
--- a/src/test/java/com/android/tools/r8/d8/IncompatiblePrimitiveTypesTest.java
+++ b/src/test/java/com/android/tools/r8/d8/IncompatiblePrimitiveTypesTest.java
@@ -64,8 +64,8 @@
@Test
public void dexTest() throws Exception {
- TestRunResult d8Result = testForD8().addProgramFiles(inputJar).run("TestClass");
- TestRunResult dxResult = testForDX().addProgramFiles(inputJar).run("TestClass");
+ TestRunResult<?> d8Result = testForD8().addProgramFiles(inputJar).run("TestClass");
+ TestRunResult<?> dxResult = testForDX().addProgramFiles(inputJar).run("TestClass");
if (ToolHelper.getDexVm().getVersion().isNewerThan(Version.V4_4_4)) {
d8Result.assertSuccessWithOutput(expectedOutput);
dxResult.assertSuccessWithOutput(expectedOutput);
diff --git a/src/test/java/com/android/tools/r8/reachabilitysensitive/ReachabilitySensitiveTest.java b/src/test/java/com/android/tools/r8/reachabilitysensitive/ReachabilitySensitiveTest.java
index edd6fd6..4c2fedc 100644
--- a/src/test/java/com/android/tools/r8/reachabilitysensitive/ReachabilitySensitiveTest.java
+++ b/src/test/java/com/android/tools/r8/reachabilitysensitive/ReachabilitySensitiveTest.java
@@ -10,7 +10,6 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.R8;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.code.AddIntLit8;
import com.android.tools.r8.code.Const4;
@@ -29,7 +28,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
class TestClass {
@@ -124,7 +122,8 @@
private void checkNoLocals(DexCode code) {
// Even if we preserve live range of locals, we do not output locals information
// as this is a release build.
- assertTrue(Arrays.stream(code.getDebugInfo().events)
+ assertTrue((code.getDebugInfo() == null) ||
+ Arrays.stream(code.getDebugInfo().events)
.allMatch(event -> !(event instanceof StartLocal)));
}
@@ -171,10 +170,10 @@
.addKeepRules(keepRules)
// Keep the annotation class.
.addKeepRules("-keep class dalvik.annotation.optimization.ReachabilitySensitive")
- // Keep the annotation and debug information which is needed for debug mode to actually
- // keep things alive.
- .addKeepRules("-keepattributes *Annotations*,LineNumberTable," +
- "LocalVariableTable,LocalVariableTypeTable")
+ // Keep the annotation so R8 can find it and honor it. It also needs to be available
+ // at runtime so that the Art runtime can honor it as well, so if it is not kept we
+ // do not have to honor it as the runtime will not know to do so in any case.
+ .addKeepRules("-keepattributes RuntimeVisibleAnnotations")
.compile()
.inspector();
}
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/shaking/InvalidTypesTest.java b/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
index 2e065ed..5362c38 100644
--- a/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
@@ -126,15 +126,15 @@
jasminBuilder.writeJar(inputJar);
if (backend == Backend.CF) {
- TestRunResult jvmResult = testForJvm().addClasspath(inputJar).run(mainClass.name);
+ TestRunResult<?> jvmResult = testForJvm().addClasspath(inputJar).run(mainClass.name);
checkTestRunResult(jvmResult, false);
} else {
assert backend == Backend.DEX;
- TestRunResult dxResult = testForDX().addProgramFiles(inputJar).run(mainClass.name);
+ TestRunResult<?> dxResult = testForDX().addProgramFiles(inputJar).run(mainClass.name);
checkTestRunResult(dxResult, false);
- TestRunResult d8Result = testForD8().addProgramFiles(inputJar).run(mainClass.name);
+ TestRunResult<?> d8Result = testForD8().addProgramFiles(inputJar).run(mainClass.name);
checkTestRunResult(d8Result, false);
}
@@ -147,7 +147,7 @@
checkTestRunResult(r8Result, true);
}
- private void checkTestRunResult(TestRunResult result, boolean isR8) {
+ private void checkTestRunResult(TestRunResult<?> result, boolean isR8) {
switch (mode) {
case NO_INVOKE:
result.assertSuccessWithOutput(getExpectedOutput(isR8));
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());
- }
}
diff --git a/tools/dex2oat.py b/tools/dex2oat.py
index eab424f..1e2cffd 100755
--- a/tools/dex2oat.py
+++ b/tools/dex2oat.py
@@ -16,8 +16,7 @@
'default',
'7.0.0',
'6.0.1',
- # TODO(b/79191363): Build a boot image for 5.1.1 dex2oat.
- # '5.1.1',
+ '5.1.1',
]
DIRS = {
@@ -34,6 +33,13 @@
'5.1.1': 'mako',
}
+ARCHS = {
+ 'default': 'arm64',
+ '7.0.0': 'arm64',
+ '6.0.1': 'arm64',
+ '5.1.1': 'arm',
+}
+
def ParseOptions():
parser = optparse.OptionParser()
parser.add_option('--version',
@@ -74,15 +80,15 @@
oatfile = os.path.join(temp, "out.oat")
base = os.path.join(LINUX_DIR, DIRS[version])
product = PRODUCTS[version]
+ arch = ARCHS[version]
cmd = [
os.path.join(base, 'bin', 'dex2oat'),
- '--android-root=' + os.path.join(base, 'product', product),
+ '--android-root=' + os.path.join(base, 'product', product, 'system'),
'--runtime-arg',
'-Xnorelocate',
- '--boot-image=' + os.path.join(base, 'product', product, 'system', 'framework', 'boot.art'),
'--dex-file=' + dexfile,
'--oat-file=' + oatfile,
- '--instruction-set=arm64',
+ '--instruction-set=' + arch,
]
env = {"LD_LIBRARY_PATH": os.path.join(base, 'lib')}
utils.PrintCmd(cmd)
diff --git a/tools/linux/art-5.1.1.tar.gz.sha1 b/tools/linux/art-5.1.1.tar.gz.sha1
index 2b6f07a..d7f86b0 100644
--- a/tools/linux/art-5.1.1.tar.gz.sha1
+++ b/tools/linux/art-5.1.1.tar.gz.sha1
@@ -1 +1 @@
-737072daed9a7cd4ef046b7ea8a60aa7b1b6c65d
\ No newline at end of file
+7c1b10e333a5a028db7f74a989d9edfe168900bf
\ No newline at end of file