Revert "Combine Long.compare/Objects.requireNonNull with Java 8 rewriter"
This reverts commit 237112500c62bdce32d0cdb2832007bfdedab5d0.
Reason for revert: Unrelated tests asserting generated types fail as a result of new Java 7 deugaring technique
Change-Id: I166f60abac36b1b28333b2dda9e6f515158593a5
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index be60042..801d6f8 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.ir.desugar.BackportedMethodRewriter;
+import com.android.tools.r8.ir.desugar.Java8MethodRewriter;
import com.android.tools.r8.ir.desugar.NestBasedAccessDesugaring;
import com.android.tools.r8.ir.desugar.TwrCloseResourceRewriter;
import com.android.tools.r8.naming.NamingLens;
@@ -250,7 +250,7 @@
|| name.contains(OutlineOptions.CLASS_NAME)
|| name.contains(TwrCloseResourceRewriter.UTILITY_CLASS_NAME)
|| name.contains(NestBasedAccessDesugaring.NEST_CONSTRUCTOR_NAME)
- || name.contains(BackportedMethodRewriter.UTILITY_CLASS_NAME_PREFIX);
+ || name.contains(Java8MethodRewriter.UTILITY_CLASS_NAME_PREFIX);
}
public boolean isProgramType(DexDefinitionSupplier definitions) {
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 f0f1613..c6c1ba8 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
@@ -42,7 +42,7 @@
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.desugar.CovariantReturnTypeAnnotationTransformer;
import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
-import com.android.tools.r8.ir.desugar.BackportedMethodRewriter;
+import com.android.tools.r8.ir.desugar.Java8MethodRewriter;
import com.android.tools.r8.ir.desugar.LambdaRewriter;
import com.android.tools.r8.ir.desugar.NestBasedAccessDesugaringRewriter;
import com.android.tools.r8.ir.desugar.StringConcatRewriter;
@@ -123,7 +123,7 @@
private final NestBasedAccessDesugaringRewriter nestBasedAccessDesugaringRewriter;
private final InterfaceMethodRewriter interfaceMethodRewriter;
private final TwrCloseResourceRewriter twrCloseResourceRewriter;
- private final BackportedMethodRewriter backportedMethodRewriter;
+ private final Java8MethodRewriter java8MethodRewriter;
private final LambdaMerger lambdaMerger;
private final ClassInliner classInliner;
private final ClassStaticizer classStaticizer;
@@ -180,9 +180,9 @@
(options.enableDesugaring && enableTwrCloseResourceDesugaring())
? new TwrCloseResourceRewriter(appView, this)
: null;
- this.backportedMethodRewriter =
+ this.java8MethodRewriter =
options.enableDesugaring
- ? new BackportedMethodRewriter(appView, this)
+ ? new Java8MethodRewriter(appView, this)
: null;
this.lambdaMerger = options.enableLambdaMerging ? new LambdaMerger(appView) : null;
this.covariantReturnTypeAnnotationTransformer =
@@ -344,8 +344,8 @@
private void synthesizeJava8UtilityClass(
Builder<?> builder, ExecutorService executorService) throws ExecutionException {
- if (backportedMethodRewriter != null) {
- backportedMethodRewriter.synthesizeUtilityClass(builder, executorService, options);
+ if (java8MethodRewriter != null) {
+ java8MethodRewriter.synthesizeUtilityClass(builder, executorService, options);
}
}
@@ -983,6 +983,7 @@
assert code.verifyTypes(appView);
codeRewriter.removeTrivialCheckCastAndInstanceOfInstructions(code);
+ codeRewriter.rewriteLongCompareAndRequireNonNull(code, options);
codeRewriter.commonSubexpressionElimination(code);
codeRewriter.simplifyArrayConstruction(code);
codeRewriter.rewriteMoveResult(code);
@@ -1024,8 +1025,8 @@
if (options.enableDesugaring && enableTryWithResourcesDesugaring()) {
codeRewriter.rewriteThrowableAddAndGetSuppressed(code);
}
- if (backportedMethodRewriter != null) {
- backportedMethodRewriter.desugar(code);
+ if (java8MethodRewriter != null) {
+ java8MethodRewriter.desugar(code);
}
stringConcatRewriter.desugarStringConcats(method.method, code);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
index ff03181..b949b72 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
@@ -154,7 +154,7 @@
InvokeStatic invokeStatic = instruction.asInvokeStatic();
DexMethod method = invokeStatic.getInvokedMethod();
DexClass clazz = appInfo.definitionFor(method.holder);
- if (BackportedMethodRewriter.hasRewrittenMethodPrefix(method.holder)) {
+ if (Java8MethodRewriter.hasJava8MethodRewritePrefix(method.holder)) {
// We did not create this code yet, but it will not require rewriting.
continue;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java
similarity index 85%
rename from src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
rename to src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java
index ac911f2..69d0b48 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java
@@ -27,7 +27,7 @@
import com.android.tools.r8.ir.code.InstructionIterator;
import com.android.tools.r8.ir.code.InvokeStatic;
import com.android.tools.r8.ir.conversion.IRConverter;
-import com.android.tools.r8.ir.desugar.BackportedMethodRewriter.RewritableMethods.MethodGenerator;
+import com.android.tools.r8.ir.desugar.Java8MethodRewriter.RewritableMethods.MethodGenerator;
import com.android.tools.r8.ir.synthetic.TemplateMethodCode;
import com.android.tools.r8.origin.SynthesizedOrigin;
import com.android.tools.r8.utils.DescriptorUtils;
@@ -43,9 +43,9 @@
import java.util.concurrent.ExecutorService;
import java.util.function.BiFunction;
-public final class BackportedMethodRewriter {
- public static final String UTILITY_CLASS_NAME_PREFIX = "$r8$backportedMethods$utility";
- private static final String UTILITY_CLASS_DESCRIPTOR_PREFIX = "L" + UTILITY_CLASS_NAME_PREFIX;
+public final class Java8MethodRewriter {
+ public static final String UTILITY_CLASS_NAME_PREFIX = "$r8$java8methods$utility";
+ private static final String UTILITY_CLASS_DESCRIPTOR_PREFIX = "L$r8$java8methods$utility";
private final Set<DexType> holders = Sets.newConcurrentHashSet();
private final AppView<?> appView;
@@ -55,7 +55,7 @@
private Map<DexMethod, MethodGenerator> methodGenerators = new ConcurrentHashMap<>();
- public BackportedMethodRewriter(AppView<?> appView, IRConverter converter) {
+ public Java8MethodRewriter(AppView<?> appView, IRConverter converter) {
this.appView = appView;
this.converter = converter;
this.factory = appView.dexItemFactory();
@@ -96,7 +96,7 @@
return null;
}
- public static boolean hasRewrittenMethodPrefix(DexType clazz) {
+ public static boolean hasJava8MethodRewritePrefix(DexType clazz) {
return clazz.descriptor.toString().startsWith(UTILITY_CLASS_DESCRIPTOR_PREFIX);
}
@@ -173,17 +173,9 @@
return new ByteMethods(options, method, "hashCodeImpl");
}
- public static ByteMethods compareCode(InternalOptions options, DexMethod method) {
- return new ByteMethods(options, method, "compareImpl");
- }
-
public static int hashCodeImpl(byte i) {
return Byte.valueOf(i).hashCode();
}
-
- public static int compareImpl(byte a, byte b) {
- return Byte.valueOf(a).compareTo(Byte.valueOf(b));
- }
}
@@ -196,17 +188,9 @@
return new ShortMethods(options, method, "hashCodeImpl");
}
- public static ShortMethods compareCode(InternalOptions options, DexMethod method) {
- return new ShortMethods(options, method, "compareImpl");
- }
-
public static int hashCodeImpl(short i) {
return Short.valueOf(i).hashCode();
}
-
- public static int compareImpl(short a, short b) {
- return Short.valueOf(a).compareTo(Short.valueOf(b));
- }
}
private static final class IntegerMethods extends TemplateMethodCode {
@@ -218,10 +202,6 @@
return new IntegerMethods(options, method, "hashCodeImpl");
}
- public static IntegerMethods compareCode(InternalOptions options, DexMethod method) {
- return new IntegerMethods(options, method, "compareImpl");
- }
-
public static IntegerMethods maxCode(InternalOptions options, DexMethod method) {
return new IntegerMethods(options, method, "maxImpl");
}
@@ -250,10 +230,6 @@
return Integer.valueOf(i).hashCode();
}
- public static int compareImpl(int a, int b) {
- return Integer.valueOf(a).compareTo(Integer.valueOf(b));
- }
-
public static int maxImpl(int a, int b) {
return java.lang.Math.max(a, b);
}
@@ -388,10 +364,6 @@
return new BooleanMethods(options, method, "hashCodeImpl");
}
- public static BooleanMethods compareCode(InternalOptions options, DexMethod method) {
- return new BooleanMethods(options, method, "compareImpl");
- }
-
public static BooleanMethods logicalAndCode(InternalOptions options, DexMethod method) {
return new BooleanMethods(options, method, "logicalAndImpl");
}
@@ -408,10 +380,6 @@
return Boolean.valueOf(b).hashCode();
}
- public static int compareImpl(boolean a, boolean b) {
- return Boolean.valueOf(a).compareTo(Boolean.valueOf(b));
- }
-
public static boolean logicalAndImpl(boolean a, boolean b) {
return a && b;
}
@@ -434,10 +402,6 @@
return new LongMethods(options, method, "hashCodeImpl");
}
- public static LongMethods compareCode(InternalOptions options, DexMethod method) {
- return new LongMethods(options, method, "compareImpl");
- }
-
public static LongMethods maxCode(InternalOptions options, DexMethod method) {
return new LongMethods(options, method, "maxImpl");
}
@@ -466,10 +430,6 @@
return Long.valueOf(i).hashCode();
}
- public static int compareImpl(long a, long b) {
- return Long.valueOf(a).compareTo(Long.valueOf(b));
- }
-
public static long maxImpl(long a, long b) {
return java.lang.Math.max(a, b);
}
@@ -570,34 +530,9 @@
return new CharacterMethods(options, method, "hashCodeImpl");
}
- public static CharacterMethods compareCode(InternalOptions options, DexMethod method) {
- return new CharacterMethods(options, method, "compareImpl");
- }
-
public static int hashCodeImpl(char i) {
return Character.valueOf(i).hashCode();
}
-
- public static int compareImpl(char a, char b) {
- return Character.valueOf(a).compareTo(Character.valueOf(b));
- }
- }
-
- private static final class ObjectMethods extends TemplateMethodCode {
- ObjectMethods(InternalOptions options, DexMethod method, String methodName) {
- super(options, method, methodName, method.proto.toDescriptorString());
- }
-
- public static ObjectMethods requireNonNullCode(InternalOptions options, DexMethod method) {
- // Rewrite calls to Objects.requireNonNull(Object) because Javac 9 started to use it for
- // synthesized null checks.
- return new ObjectMethods(options, method, "requireNonNullImpl");
- }
-
- public static Object requireNonNullImpl(Object a) {
- a.getClass();
- return a;
- }
}
public static final class RewritableMethods {
@@ -606,9 +541,6 @@
new HashMap<>();
public RewritableMethods(DexItemFactory factory, InternalOptions options) {
- if (!options.canUseJava7CompareAndObjectsOperations()) {
- initializeJava7CompareOperations(factory);
- }
if (!options.canUseJava8SignedOperations()) {
initializeJava8SignedOperations(factory);
}
@@ -621,64 +553,6 @@
return rewritable.isEmpty();
}
- private void initializeJava7CompareOperations(DexItemFactory factory) {
- // Byte
- DexString clazz = factory.boxedByteDescriptor;
- // int Byte.compare(byte a, byte b)
- DexString method = factory.createString("compare");
- DexProto proto = factory.createProto(factory.intType, factory.byteType, factory.byteType);
- addOrGetMethod(clazz, method)
- .put(proto, new MethodGenerator(ByteMethods::compareCode, clazz, method, proto));
-
- // Short
- clazz = factory.boxedShortDescriptor;
- // int Short.compare(short a, short b)
- method = factory.createString("compare");
- proto = factory.createProto(factory.intType, factory.shortType, factory.shortType);
- addOrGetMethod(clazz, method)
- .put(proto, new MethodGenerator(ShortMethods::compareCode, clazz, method, proto));
-
- // Integer
- clazz = factory.boxedIntDescriptor;
- // int Integer.compare(int a, int b)
- method = factory.createString("compare");
- proto = factory.createProto(factory.intType, factory.intType, factory.intType);
- addOrGetMethod(clazz, method)
- .put(proto, new MethodGenerator(IntegerMethods::compareCode, clazz, method, proto));
-
- // Boolean
- clazz = factory.boxedBooleanDescriptor;
- // int Boolean.compare(boolean a, boolean b)
- method = factory.createString("compare");
- proto = factory.createProto(factory.intType, factory.booleanType, factory.booleanType);
- addOrGetMethod(clazz, method)
- .put(proto, new MethodGenerator(BooleanMethods::compareCode, clazz, method, proto));
-
- // Long
- clazz = factory.boxedLongDescriptor;
- // int Long.compare(long a, long b)
- method = factory.createString("compare");
- proto = factory.createProto(factory.intType, factory.longType, factory.longType);
- addOrGetMethod(clazz, method)
- .put(proto, new MethodGenerator(LongMethods::compareCode, clazz, method, proto));
-
- // Character
- clazz = factory.boxedCharDescriptor;
- // int Character.compare(char a, char b)
- method = factory.createString("compare");
- proto = factory.createProto(factory.intType, factory.charType, factory.charType);
- addOrGetMethod(clazz, method)
- .put(proto, new MethodGenerator(CharacterMethods::compareCode, clazz, method, proto));
-
- // Object
- clazz = factory.objectsDescriptor;
- // Object Objects.requireNonNull(Object a)
- method = factory.createString("requireNonNull");
- proto = factory.createProto(factory.objectType, factory.objectType);
- addOrGetMethod(clazz, method)
- .put(proto, new MethodGenerator(ObjectMethods::requireNonNullCode, clazz, method, proto));
- }
-
private void initializeJava8SignedOperations(DexItemFactory factory) {
// Byte
DexString clazz = factory.boxedByteDescriptor;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index 48b81ae..87c28bf 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -43,6 +43,8 @@
import com.android.tools.r8.ir.code.Binop;
import com.android.tools.r8.ir.code.CatchHandlers;
import com.android.tools.r8.ir.code.CheckCast;
+import com.android.tools.r8.ir.code.Cmp;
+import com.android.tools.r8.ir.code.Cmp.Bias;
import com.android.tools.r8.ir.code.ConstInstruction;
import com.android.tools.r8.ir.code.ConstNumber;
import com.android.tools.r8.ir.code.ConstString;
@@ -3507,6 +3509,39 @@
return true;
}
+ public void rewriteLongCompareAndRequireNonNull(IRCode code, InternalOptions options) {
+ if (options.canUseLongCompareAndObjectsNonNull()) {
+ return;
+ }
+
+ InstructionIterator iterator = code.instructionIterator();
+ while (iterator.hasNext()) {
+ Instruction current = iterator.next();
+ if (current.isInvokeMethod()) {
+ DexMethod invokedMethod = current.asInvokeMethod().getInvokedMethod();
+ if (invokedMethod == dexItemFactory.longMethods.compare) {
+ // Rewrite calls to Long.compare for sdk versions that do not have that method.
+ List<Value> inValues = current.inValues();
+ assert inValues.size() == 2;
+ iterator.replaceCurrentInstruction(
+ new Cmp(NumericType.LONG, Bias.NONE, current.outValue(), inValues.get(0),
+ inValues.get(1)));
+ } else if (invokedMethod == dexItemFactory.objectsMethods.requireNonNull) {
+ // Rewrite calls to Objects.requireNonNull(Object) because Javac 9 start to use it for
+ // synthesized null checks.
+ InvokeVirtual callToGetClass = new InvokeVirtual(dexItemFactory.objectMethods.getClass,
+ null, current.inValues());
+ if (current.outValue() != null) {
+ current.outValue().replaceUsers(current.inValues().get(0));
+ current.setOutValue(null);
+ }
+ iterator.replaceCurrentInstruction(callToGetClass);
+ }
+ }
+ }
+ assert code.isConsistentSSA();
+ }
+
/**
* Remove moves that are not actually used by instructions in exiting paths. These moves can arise
* due to debug local info needing a particular value and the live-interval for it then moves it
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 99eb7ea..7fafc4b 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -719,7 +719,7 @@
return intermediate || hasMinApi(AndroidApiLevel.L);
}
- public boolean canUseJava7CompareAndObjectsOperations() {
+ public boolean canUseLongCompareAndObjectsNonNull() {
return isGeneratingClassFiles() || hasMinApi(AndroidApiLevel.K);
}
diff --git a/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java b/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
index edc1873..1cf61c0 100644
--- a/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
+++ b/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
-import com.android.tools.r8.ir.desugar.BackportedMethodRewriter;
+import com.android.tools.r8.ir.desugar.Java8MethodRewriter;
import com.android.tools.r8.ir.desugar.LambdaRewriter;
import com.android.tools.r8.ir.desugar.TwrCloseResourceRewriter;
import java.util.List;
@@ -69,7 +69,7 @@
private static boolean assumeClassesAreEqual(DexProgramClass a) {
return LambdaRewriter.hasLambdaClassPrefix(a.type)
- || BackportedMethodRewriter.hasRewrittenMethodPrefix(a.type)
+ || Java8MethodRewriter.hasJava8MethodRewritePrefix(a.type)
|| InterfaceMethodRewriter.hasDispatchClassSuffix(a.type)
|| a.type.descriptor.toString().equals(TwrCloseResourceRewriter.UTILITY_CLASS_DESCRIPTOR);
}
diff --git a/src/test/examples/rewrite/LongCompare.java b/src/test/examples/rewrite/LongCompare.java
new file mode 100644
index 0000000..7c96c10
--- /dev/null
+++ b/src/test/examples/rewrite/LongCompare.java
@@ -0,0 +1,40 @@
+// Copyright (c) 2017, 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 rewrite;
+
+public class LongCompare {
+
+ public static int simpleCompare(long l1, long l2) {
+ try {
+ return Long.compare(l1, l2);
+ } catch (Throwable t) {
+ System.out.println(t);
+ }
+ return 2;
+ }
+
+ public static long getValue1() {
+ return 123456789L;
+ }
+
+ public static long getValue2() {
+ return 0;
+ }
+
+ public static boolean complexCompare(long l1, long l2) {
+ return Long.compare(getValue1(), l1) == 0 && Long.compare(l2, getValue2()) > 0;
+ }
+
+ public static void main(String[] args) {
+ System.out.println(simpleCompare(123456789L, 987654321L));
+ System.out.println(simpleCompare(Long.MAX_VALUE, 0L));
+ System.out.println(simpleCompare(Long.MIN_VALUE, 0L));
+ System.out.println(simpleCompare(Long.MAX_VALUE, Long.MAX_VALUE));
+
+ System.out.println(complexCompare(123456789L, 1));
+ System.out.println(complexCompare(123456789L, -1));
+ System.out.println(complexCompare(1234567890L, 1));
+ System.out.println(complexCompare(1234567890L, -1));
+ }
+}
diff --git a/src/test/examples/rewrite/RequireNonNull.java b/src/test/examples/rewrite/RequireNonNull.java
new file mode 100644
index 0000000..d8868bf
--- /dev/null
+++ b/src/test/examples/rewrite/RequireNonNull.java
@@ -0,0 +1,39 @@
+// Copyright (c) 2017, 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 rewrite;
+
+import java.util.Objects;
+
+public class RequireNonNull {
+
+ public static void main(String[] args) {
+ RequireNonNull o = new RequireNonNull();
+ System.out.println(o.nonnullRemove().toString());
+ System.out.println(o.nonnullRemove(o).toString());
+ o.nonnullWithPhiInstruction(true, o);
+ o.nonnullWithPhiInstruction(false, o);
+ }
+
+ private Object nonnullRemove() {
+ return Objects.requireNonNull(this);
+ }
+
+ private Object nonnullRemove(Object o) {
+ Objects.requireNonNull(o);
+ return o;
+ }
+
+ private void nonnullWithPhiInstruction(boolean b, Object input) {
+ Object o = null;
+ if (b) {
+ o = Objects.requireNonNull(input);
+ }
+ System.out.println(o);
+ }
+
+ @Override
+ public String toString() {
+ return "toString";
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/BackportedMethodRewriterTest.java b/src/test/java/com/android/tools/r8/desugar/Java8MethodsTest.java
similarity index 74%
rename from src/test/java/com/android/tools/r8/desugar/BackportedMethodRewriterTest.java
rename to src/test/java/com/android/tools/r8/desugar/Java8MethodsTest.java
index a130c0f..cb4c9b7 100644
--- a/src/test/java/com/android/tools/r8/desugar/BackportedMethodRewriterTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/Java8MethodsTest.java
@@ -16,58 +16,56 @@
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.nio.file.Path;
import java.util.List;
-import java.util.Objects;
import org.junit.Before;
import org.junit.Test;
-public class BackportedMethodRewriterTest extends TestBase {
+public class Java8MethodsTest extends TestBase {
static String expectedOutput = "";
@Before
public void testJvm() throws Exception {
expectedOutput = testForJvm()
.addTestClasspath()
- .run(TestMethods.class).getStdOut();
+ .run(Java8Methods.class).getStdOut();
}
@Test
public void testD8() throws Exception {
testForD8()
- .addProgramClasses(TestMethods.class)
- .run(TestMethods.class)
+ .addProgramClasses(Java8Methods.class)
+ .run(Java8Methods.class)
.assertSuccessWithOutput(expectedOutput);
- assertDesugaring(AndroidApiLevel.O, 39);
- assertDesugaring(AndroidApiLevel.N, 33);
- assertDesugaring(AndroidApiLevel.K, 8);
- assertDesugaring(AndroidApiLevel.J_MR2, 0);
+ assertDesugaring(AndroidApiLevel.O, 31);
+ assertDesugaring(AndroidApiLevel.N, 25);
+ assertDesugaring(AndroidApiLevel.M, 0);
}
- private void assertDesugaring(AndroidApiLevel apiLevel, int expectedJavaInvokeStatics)
+ private void assertDesugaring(AndroidApiLevel apilevel, int expectedJavaLangInvokeStatics)
throws Exception {
D8TestCompileResult runResult = testForD8()
- .addProgramClasses(TestMethods.class)
- .setMinApi(apiLevel)
+ .addProgramClasses(Java8Methods.class)
+ .setMinApi(apilevel)
.compile();
MethodSubject mainMethod = runResult.inspector()
- .clazz(TestMethods.class)
+ .clazz(Java8Methods.class)
.mainMethod();
assertThat(mainMethod, isPresent());
- List<InstructionSubject> javaInvokeStatics = mainMethod
+ List<InstructionSubject> javaLangInvokeStatics = mainMethod
.streamInstructions()
.filter(InstructionSubject::isInvokeStatic)
- .filter(is -> is.getMethod().holder.toDescriptorString().startsWith("Ljava/"))
+ .filter(is -> is.getMethod().holder.toDescriptorString().startsWith("Ljava/lang/"))
.collect(toList());
- int actualJavaInvokeStatics = javaInvokeStatics.size();
+ int actualJavaLangInvokeStatics = javaLangInvokeStatics.size();
assertEquals("Expected "
- + expectedJavaInvokeStatics
- + " invoke-static on java/*/<Type> but found "
- + actualJavaInvokeStatics
+ + expectedJavaLangInvokeStatics
+ + " invoke-static on java/lang/<Type> but found "
+ + actualJavaLangInvokeStatics
+ ": "
- + javaInvokeStatics, expectedJavaInvokeStatics, actualJavaInvokeStatics);
+ + javaLangInvokeStatics, expectedJavaLangInvokeStatics, actualJavaLangInvokeStatics);
}
@Test
@@ -124,29 +122,16 @@
}
}
- static class TestMethods {
- // Defined as a static method on this class to avoid affecting invoke-static counts in main().
- private static int signum(int value) {
- return (int) Math.signum(value);
- }
-
+ static class Java8Methods {
public static void main(String[] args) {
byte[] aBytes = new byte[]{42, 1, -1, Byte.MAX_VALUE, Byte.MIN_VALUE};
for (byte aByte : aBytes) {
System.out.println(Byte.hashCode(aByte));
- for (byte bByte : aBytes) {
- // Normalize comparison to [-1, 1] since the values differ across versions but signs match
- System.out.println(signum(Byte.compare(aByte, bByte)));
- }
}
short[] aShorts = new short[]{42, 1, -1, Short.MAX_VALUE, Short.MIN_VALUE};
for (short aShort : aShorts) {
System.out.println(Short.hashCode(aShort));
- for (short bShort : aShorts) {
- // Normalize comparison to [-1, 1] since the values differ across versions but signs match
- System.out.println(signum(Short.compare(aShort, bShort)));
- }
}
int[] aInts = new int[]{42, 1, -1, Integer.MAX_VALUE, Integer.MIN_VALUE};
@@ -154,7 +139,6 @@
for (int aInt : aInts) {
System.out.println(Integer.hashCode(aInt));
for (int bInt : bInts) {
- System.out.println(Integer.compare(aInt, bInt));
System.out.println(Integer.max(aInt, bInt));
System.out.println(Integer.min(aInt, bInt));
System.out.println(Integer.sum(aInt, bInt));
@@ -199,7 +183,6 @@
for (boolean aBoolean : new boolean[]{true, false}) {
System.out.println(Boolean.hashCode(aBoolean));
for (boolean bBoolean : new boolean[]{true, false}) {
- System.out.println(Boolean.compare(aBoolean, bBoolean));
System.out.println(Boolean.logicalAnd(aBoolean, bBoolean));
System.out.println(Boolean.logicalOr(aBoolean, bBoolean));
System.out.println(Boolean.logicalXor(aBoolean, bBoolean));
@@ -213,7 +196,6 @@
for (long aLong : aLongs) {
System.out.println(Long.hashCode(aLong));
for (long bLong : bLongs) {
- System.out.println(Long.compare(aLong, bLong));
System.out.println(Long.max(aLong, bLong));
System.out.println(Long.min(aLong, bLong));
System.out.println(Long.sum(aLong, bLong));
@@ -226,21 +208,6 @@
char[] aChars = new char[]{'s', 'u', 'p', Character.MAX_VALUE, Character.MIN_VALUE};
for (char aChar : aChars) {
System.out.println(Character.hashCode(aChar));
- for (char bChar : aChars) {
- System.out.println(Character.compare(aChar, bChar));
- }
- }
-
- // Use a runtime conditional so nullability analysis doesn't remove the requireNonNull call.
- String nonNullString = args.length < Integer.MAX_VALUE ? "non-null string" : null;
- System.out.println(Objects.requireNonNull(nonNullString));
-
- try {
- // Use a runtime conditional so nullability analysis doesn't remove the requireNonNull call.
- String nullString = args.length == 0 ? null : "non-null string";
- throw new AssertionError(Objects.requireNonNull(nullString));
- } catch (NullPointerException expected) {
- System.out.println("null");
}
}
}
diff --git a/src/test/java/com/android/tools/r8/rewrite/longcompare/LongCompare.java b/src/test/java/com/android/tools/r8/rewrite/longcompare/LongCompare.java
new file mode 100644
index 0000000..16b7922
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/longcompare/LongCompare.java
@@ -0,0 +1,80 @@
+// Copyright (c) 2017, 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.rewrite.longcompare;
+
+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.ToolHelper.ArtCommandBuilder;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.android.tools.r8.utils.codeinspector.InvokeInstructionSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Iterator;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+/**
+ * Tests checking that Long.compare() is always rewritten into long compare instruction.
+ */
+public class LongCompare {
+
+ @Rule
+ public TemporaryFolder tmpOutputDir = ToolHelper.getTemporaryFolderForTest();
+
+ void compileWithD8(Path intputPath, Path outputPath)
+ throws IOException, CompilationFailedException {
+ D8.run(
+ D8Command.builder()
+ .addProgramFiles(intputPath)
+ .setOutput(outputPath, OutputMode.DexIndexed)
+ .build());
+ }
+
+ void runTest(Path dexFile) {
+ ArtCommandBuilder builder = new ArtCommandBuilder(ToolHelper.getDexVm());
+ builder.appendClasspath(dexFile.toString());
+ builder.setMainClass("rewrite.LongCompare");
+ try {
+ String output = ToolHelper.runArt(builder);
+ Assert
+ .assertEquals(StringUtils.lines("-1", "1", "-1", "0", "true", "false", "false", "false"),
+ output);
+ } catch (IOException e) {
+ Assert.fail();
+ }
+ }
+
+ @Test
+ public void testLongCompareIsRewritten() throws Exception {
+ final Path inputPath = Paths.get(ToolHelper.EXAMPLES_BUILD_DIR + "/rewrite.jar");
+ Path outputPath = tmpOutputDir.newFolder().toPath();
+
+ compileWithD8(inputPath, outputPath);
+
+ Path dexPath = outputPath.resolve("classes.dex");
+
+ CodeInspector codeInspector = new CodeInspector(dexPath);
+ ClassSubject classSubject = codeInspector.clazz("rewrite.LongCompare");
+ MethodSubject methodSubject = classSubject
+ .method("int", "simpleCompare", Arrays.asList("long", "long"));
+ // Check that exception handler is removed since it is no longer needed.
+ Assert.assertFalse(methodSubject.getMethod().getCode().asDexCode().usesExceptionHandling());
+ Iterator<InvokeInstructionSubject> iterator =
+ methodSubject.iterateInstructions(InstructionSubject::isInvoke);
+ Assert.assertFalse(iterator.hasNext());
+
+ runTest(dexPath);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/rewrite/longcompare/RequireNonNullRewriteTest.java b/src/test/java/com/android/tools/r8/rewrite/longcompare/RequireNonNullRewriteTest.java
new file mode 100644
index 0000000..278bc8b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/longcompare/RequireNonNullRewriteTest.java
@@ -0,0 +1,91 @@
+// Copyright (c) 2017, 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.rewrite.longcompare;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.CompilationMode;
+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.ToolHelper.ArtCommandBuilder;
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.android.tools.r8.utils.codeinspector.InvokeInstructionSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.concurrent.ExecutionException;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+public class RequireNonNullRewriteTest {
+
+ @Rule
+ public TemporaryFolder tmpOutputDir = ToolHelper.getTemporaryFolderForTest();
+
+ void compileWithD8(Path intputPath, Path outputPath, CompilationMode mode)
+ throws IOException, CompilationFailedException {
+ D8.run(
+ D8Command.builder()
+ .setMode(mode)
+ .addProgramFiles(intputPath)
+ .setOutput(outputPath, OutputMode.DexIndexed)
+ .build());
+ }
+
+ void runTest(Path jarFile, Path dexFile) {
+ String mainClass = "rewrite.RequireNonNull";
+ ArtCommandBuilder builder = new ArtCommandBuilder(ToolHelper.getDexVm());
+ builder.appendClasspath(dexFile.toString());
+ builder.setMainClass(mainClass);
+ try {
+ String output = ToolHelper.runArt(builder);
+ ProcessResult javaResult = ToolHelper.runJava(jarFile, mainClass);
+ Assert.assertEquals(javaResult.stdout, output);
+ } catch (IOException e) {
+ Assert.fail();
+ }
+ }
+
+ @Test
+ public void testDebugRequireNonNullIsRewritten() throws Exception {
+ runTest(CompilationMode.DEBUG);
+ }
+
+ @Test
+ public void testReleaseRequireNonNullIsRewritten() throws Exception {
+ runTest(CompilationMode.RELEASE);
+ }
+
+ private void runTest(CompilationMode mode)
+ throws IOException, ExecutionException, CompilationFailedException {
+ final Path inputPath = Paths.get(ToolHelper.EXAMPLES_BUILD_DIR + "/rewrite.jar");
+ Path outputPath = tmpOutputDir.newFolder().toPath();
+
+ compileWithD8(inputPath, outputPath, mode);
+
+ Path dexPath = outputPath.resolve("classes.dex");
+
+ CodeInspector codeInspector = new CodeInspector(dexPath);
+ ClassSubject classSubject = codeInspector.clazz("rewrite.RequireNonNull");
+ MethodSubject methodSubject = classSubject
+ .method("java.lang.Object", "nonnullRemove", Collections.emptyList());
+
+ Iterator<InvokeInstructionSubject> iterator =
+ methodSubject.iterateInstructions(InstructionSubject::isInvoke);
+ Assert.assertTrue(iterator.hasNext());
+ Assert.assertEquals("getClass", iterator.next().invokedMethod().name.toString());
+ Assert.assertFalse(iterator.hasNext());
+
+ runTest(inputPath, dexPath);
+ }
+}