Migrate Integer and Long backport/desugar tests
Test: tools/test.py --dex_vm all --no-internal -v *Backport*
Change-Id: I0bab4bcafbbe2b30e0d6e59cbfe865da669c96f3
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
index 1636a89..26fcb1c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -33,6 +33,8 @@
import com.android.tools.r8.ir.desugar.backports.CharacterMethods;
import com.android.tools.r8.ir.desugar.backports.DoubleMethods;
import com.android.tools.r8.ir.desugar.backports.FloatMethods;
+import com.android.tools.r8.ir.desugar.backports.IntegerMethods;
+import com.android.tools.r8.ir.desugar.backports.LongMethods;
import com.android.tools.r8.ir.desugar.backports.MathMethods;
import com.android.tools.r8.ir.desugar.backports.ObjectsMethods;
import com.android.tools.r8.ir.desugar.backports.ShortMethods;
@@ -193,154 +195,6 @@
original.holder.descriptor, original.name, original.proto);
}
- private static final class IntegerMethods extends TemplateMethodCode {
- IntegerMethods(InternalOptions options, DexMethod method, String methodName) {
- super(options, method, methodName, method.proto.toDescriptorString());
- }
-
- public static int hashCode(int i) {
- return Integer.valueOf(i).hashCode();
- }
-
- public static int compare(int a, int b) {
- return Integer.valueOf(a).compareTo(Integer.valueOf(b));
- }
-
- public static int max(int a, int b) {
- return java.lang.Math.max(a, b);
- }
-
- public static int min(int a, int b) {
- return java.lang.Math.min(a, b);
- }
-
- public static int sum(int a, int b) {
- return a + b;
- }
-
- public static int divideUnsigned(int dividend, int divisor) {
- long dividendLong = dividend & 0xffffffffL;
- long divisorLong = divisor & 0xffffffffL;
- return (int) (dividendLong / divisorLong);
- }
-
- public static int remainderUnsigned(int dividend, int divisor) {
- long dividendLong = dividend & 0xffffffffL;
- long divisorLong = divisor & 0xffffffffL;
- return (int) (dividendLong % divisorLong);
- }
-
- public static int compareUnsigned(int a, int b) {
- int aFlipped = a ^ Integer.MIN_VALUE;
- int bFlipped = b ^ Integer.MIN_VALUE;
- return Integer.compare(aFlipped, bFlipped);
- }
-
- public static long toUnsignedLong(int value) {
- return value & 0xffffffffL;
- }
- }
-
- private static final class LongMethods extends TemplateMethodCode {
- LongMethods(InternalOptions options, DexMethod method, String methodName) {
- super(options, method, methodName, method.proto.toDescriptorString());
- }
-
- public static int hashCode(long i) {
- return Long.valueOf(i).hashCode();
- }
-
- public static long max(long a, long b) {
- return java.lang.Math.max(a, b);
- }
-
- public static long min(long a, long b) {
- return java.lang.Math.min(a, b);
- }
-
- public static long sum(long a, long b) {
- return a + b;
- }
-
- public static long divideUnsigned(long dividend, long divisor) {
- // This implementation is adapted from Guava's UnsignedLongs.java and Longs.java.
-
- if (divisor < 0) { // i.e., divisor >= 2^63:
- // Reference implementation calls UnsignedLongs.compare(dividend, divisor) whose
- // implementation is Longs.compare(UnsignedLong.flip(a), UnsignedLong.flip(b)). The
- // implementations of flip() and compare() are inlined here instead.
- long dividendFlipped = dividend ^ Long.MIN_VALUE;
- long divisorFlipped = divisor ^ Long.MIN_VALUE;
- if (dividendFlipped < divisorFlipped) {
- return 0; // dividend < divisor
- } else {
- return 1; // dividend >= divisor
- }
- }
-
- // Optimization - use signed division if dividend < 2^63
- if (dividend >= 0) {
- return dividend / divisor;
- }
-
- // Otherwise, approximate the quotient, check, and correct if necessary. Our approximation is
- // guaranteed to be either exact or one less than the correct value. This follows from the
- // fact that floor(floor(x)/i) == floor(x/i) for any real x and integer i != 0. The proof is
- // not quite trivial.
- long quotient = ((dividend >>> 1) / divisor) << 1;
- long rem = dividend - quotient * divisor;
-
- // Reference implementation calls UnsignedLongs.compare(rem, divisor) whose
- // implementation is Longs.compare(UnsignedLong.flip(a), UnsignedLong.flip(b)). The
- // implementations of flip() and compare() are inlined here instead.
- long remFlipped = rem ^ Long.MIN_VALUE;
- long divisorFlipped = divisor ^ Long.MIN_VALUE;
- return quotient + (remFlipped >= divisorFlipped ? 1 : 0);
- }
-
- public static long remainderUnsigned(long dividend, long divisor) {
- // This implementation is adapted from Guava's UnsignedLongs.java and Longs.java.
-
- if (divisor < 0) { // i.e., divisor >= 2^63:
- // Reference implementation calls UnsignedLongs.compare(dividend, divisor) whose
- // implementation is Longs.compare(UnsignedLong.flip(a), UnsignedLong.flip(b)). The
- // implementations of flip() and compare() are inlined here instead.
- long dividendFlipped = dividend ^ Long.MIN_VALUE;
- long divisorFlipped = divisor ^ Long.MIN_VALUE;
- if (dividendFlipped < divisorFlipped) {
- return dividend; // dividend < divisor
- } else {
- return dividend - divisor; // dividend >= divisor
- }
- }
-
- // Optimization - use signed modulus if dividend < 2^63
- if (dividend >= 0) {
- return dividend % divisor;
- }
-
- // Otherwise, approximate the quotient, check, and correct if necessary. Our approximation is
- // guaranteed to be either exact or one less than the correct value. This follows from the
- // fact that floor(floor(x)/i) == floor(x/i) for any real x and integer i != 0. The proof is
- // not quite trivial.
- long quotient = ((dividend >>> 1) / divisor) << 1;
- long rem = dividend - quotient * divisor;
-
- // Reference implementation calls UnsignedLongs.compare(rem, divisor) whose
- // implementation is Longs.compare(UnsignedLong.flip(a), UnsignedLong.flip(b)). The
- // implementations of flip() and compare() are inlined here instead.
- long remFlipped = rem ^ Long.MIN_VALUE;
- long divisorFlipped = divisor ^ Long.MIN_VALUE;
- return rem - (remFlipped >= divisorFlipped ? divisor : 0);
- }
-
- public static int compareUnsigned(long a, long b) {
- long aFlipped = a ^ Long.MIN_VALUE;
- long bFlipped = b ^ Long.MIN_VALUE;
- return Long.compare(aFlipped, bFlipped);
- }
- }
-
public static final class RewritableMethods {
// Map class, method, proto to a generator for creating the code and method.
private final Map<DexString, Map<DexString, Map<DexProto, MethodGenerator>>> rewritable =
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/IntegerMethods.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/IntegerMethods.java
new file mode 100644
index 0000000..3803667
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/IntegerMethods.java
@@ -0,0 +1,57 @@
+// Copyright (c) 2019, 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.ir.desugar.backports;
+
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.ir.synthetic.TemplateMethodCode;
+import com.android.tools.r8.utils.InternalOptions;
+
+public final class IntegerMethods extends TemplateMethodCode {
+ public IntegerMethods(InternalOptions options, DexMethod method, String methodName) {
+ super(options, method, methodName, method.proto.toDescriptorString());
+ }
+
+ public static int hashCode(int i) {
+ return Integer.valueOf(i).hashCode();
+ }
+
+ public static int compare(int a, int b) {
+ return Integer.valueOf(a).compareTo(Integer.valueOf(b));
+ }
+
+ public static int max(int a, int b) {
+ return Math.max(a, b);
+ }
+
+ public static int min(int a, int b) {
+ return Math.min(a, b);
+ }
+
+ public static int sum(int a, int b) {
+ return a + b;
+ }
+
+ public static int divideUnsigned(int dividend, int divisor) {
+ long dividendLong = dividend & 0xffffffffL;
+ long divisorLong = divisor & 0xffffffffL;
+ return (int) (dividendLong / divisorLong);
+ }
+
+ public static int remainderUnsigned(int dividend, int divisor) {
+ long dividendLong = dividend & 0xffffffffL;
+ long divisorLong = divisor & 0xffffffffL;
+ return (int) (dividendLong % divisorLong);
+ }
+
+ public static int compareUnsigned(int a, int b) {
+ int aFlipped = a ^ Integer.MIN_VALUE;
+ int bFlipped = b ^ Integer.MIN_VALUE;
+ return Integer.compare(aFlipped, bFlipped);
+ }
+
+ public static long toUnsignedLong(int value) {
+ return value & 0xffffffffL;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/LongMethods.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/LongMethods.java
new file mode 100644
index 0000000..d868664
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/LongMethods.java
@@ -0,0 +1,109 @@
+// Copyright (c) 2019, 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.ir.desugar.backports;
+
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.ir.synthetic.TemplateMethodCode;
+import com.android.tools.r8.utils.InternalOptions;
+
+public final class LongMethods extends TemplateMethodCode {
+ public LongMethods(InternalOptions options, DexMethod method, String methodName) {
+ super(options, method, methodName, method.proto.toDescriptorString());
+ }
+
+ public static int hashCode(long i) {
+ return Long.valueOf(i).hashCode();
+ }
+
+ public static long max(long a, long b) {
+ return Math.max(a, b);
+ }
+
+ public static long min(long a, long b) {
+ return Math.min(a, b);
+ }
+
+ public static long sum(long a, long b) {
+ return a + b;
+ }
+
+ public static long divideUnsigned(long dividend, long divisor) {
+ // This implementation is adapted from Guava's UnsignedLongs.java and Longs.java.
+
+ if (divisor < 0) { // i.e., divisor >= 2^63:
+ // Reference implementation calls UnsignedLongs.compare(dividend, divisor) whose
+ // implementation is Longs.compare(UnsignedLong.flip(a), UnsignedLong.flip(b)). The
+ // implementations of flip() and compare() are inlined here instead.
+ long dividendFlipped = dividend ^ Long.MIN_VALUE;
+ long divisorFlipped = divisor ^ Long.MIN_VALUE;
+ if (dividendFlipped < divisorFlipped) {
+ return 0; // dividend < divisor
+ } else {
+ return 1; // dividend >= divisor
+ }
+ }
+
+ // Optimization - use signed division if dividend < 2^63
+ if (dividend >= 0) {
+ return dividend / divisor;
+ }
+
+ // Otherwise, approximate the quotient, check, and correct if necessary. Our approximation is
+ // guaranteed to be either exact or one less than the correct value. This follows from the
+ // fact that floor(floor(x)/i) == floor(x/i) for any real x and integer i != 0. The proof is
+ // not quite trivial.
+ long quotient = ((dividend >>> 1) / divisor) << 1;
+ long rem = dividend - quotient * divisor;
+
+ // Reference implementation calls UnsignedLongs.compare(rem, divisor) whose
+ // implementation is Longs.compare(UnsignedLong.flip(a), UnsignedLong.flip(b)). The
+ // implementations of flip() and compare() are inlined here instead.
+ long remFlipped = rem ^ Long.MIN_VALUE;
+ long divisorFlipped = divisor ^ Long.MIN_VALUE;
+ return quotient + (remFlipped >= divisorFlipped ? 1 : 0);
+ }
+
+ public static long remainderUnsigned(long dividend, long divisor) {
+ // This implementation is adapted from Guava's UnsignedLongs.java and Longs.java.
+
+ if (divisor < 0) { // i.e., divisor >= 2^63:
+ // Reference implementation calls UnsignedLongs.compare(dividend, divisor) whose
+ // implementation is Longs.compare(UnsignedLong.flip(a), UnsignedLong.flip(b)). The
+ // implementations of flip() and compare() are inlined here instead.
+ long dividendFlipped = dividend ^ Long.MIN_VALUE;
+ long divisorFlipped = divisor ^ Long.MIN_VALUE;
+ if (dividendFlipped < divisorFlipped) {
+ return dividend; // dividend < divisor
+ } else {
+ return dividend - divisor; // dividend >= divisor
+ }
+ }
+
+ // Optimization - use signed modulus if dividend < 2^63
+ if (dividend >= 0) {
+ return dividend % divisor;
+ }
+
+ // Otherwise, approximate the quotient, check, and correct if necessary. Our approximation is
+ // guaranteed to be either exact or one less than the correct value. This follows from the
+ // fact that floor(floor(x)/i) == floor(x/i) for any real x and integer i != 0. The proof is
+ // not quite trivial.
+ long quotient = ((dividend >>> 1) / divisor) << 1;
+ long rem = dividend - quotient * divisor;
+
+ // Reference implementation calls UnsignedLongs.compare(rem, divisor) whose
+ // implementation is Longs.compare(UnsignedLong.flip(a), UnsignedLong.flip(b)). The
+ // implementations of flip() and compare() are inlined here instead.
+ long remFlipped = rem ^ Long.MIN_VALUE;
+ long divisorFlipped = divisor ^ Long.MIN_VALUE;
+ return rem - (remFlipped >= divisorFlipped ? divisor : 0);
+ }
+
+ public static int compareUnsigned(long a, long b) {
+ long aFlipped = a ^ Long.MIN_VALUE;
+ long bFlipped = b ^ Long.MIN_VALUE;
+ return Long.compare(aFlipped, bFlipped);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/BackportedMethodMergeTest.java b/src/test/java/com/android/tools/r8/desugar/BackportedMethodMergeTest.java
new file mode 100644
index 0000000..44f32ee
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/BackportedMethodMergeTest.java
@@ -0,0 +1,65 @@
+// Copyright (c) 2019, 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.desugar;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.nio.file.Path;
+import org.junit.Test;
+
+public class BackportedMethodMergeTest extends TestBase {
+ @Test
+ public void testD8Merge() throws Exception {
+ String jvmOutput = testForJvm()
+ .addTestClasspath()
+ .run(MergeRun.class).getStdOut();
+ // See b/123242448
+ Path zip1 = temp.newFile("first.zip").toPath();
+ Path zip2 = temp.newFile("second.zip").toPath();
+
+ testForD8()
+ .setMinApi(AndroidApiLevel.L)
+ .addProgramClasses(MergeRun.class, MergeInputB.class)
+ .compile()
+ .assertNoMessages()
+ .writeToZip(zip1);
+ testForD8()
+ .setMinApi(AndroidApiLevel.L)
+ .addProgramClasses(MergeInputA.class)
+ .compile()
+ .assertNoMessages()
+ .writeToZip(zip2);
+ testForD8()
+ .addProgramFiles(zip1, zip2)
+ .setMinApi(AndroidApiLevel.L)
+ .compile()
+ .assertNoMessages()
+ .run(MergeRun.class)
+ .assertSuccessWithOutput(jvmOutput);
+ }
+
+ static class MergeInputA {
+ public void foo() {
+ System.out.println(Integer.hashCode(42));
+ System.out.println(Double.hashCode(42.0));
+ }
+ }
+
+ static class MergeInputB {
+ public void foo() {
+ System.out.println(Integer.hashCode(43));
+ System.out.println(Double.hashCode(43.0));
+ }
+ }
+
+ static class MergeRun {
+ public static void main(String[] args) {
+ MergeInputA a = new MergeInputA();
+ MergeInputB b = new MergeInputB();
+ a.foo();
+ b.foo();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/BackportedMethodRewriterTest.java b/src/test/java/com/android/tools/r8/desugar/BackportedMethodRewriterTest.java
deleted file mode 100644
index ab3e7a9..0000000
--- a/src/test/java/com/android/tools/r8/desugar/BackportedMethodRewriterTest.java
+++ /dev/null
@@ -1,171 +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.desugar;
-
-import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static java.util.stream.Collectors.toList;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
-
-import com.android.tools.r8.D8TestCompileResult;
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.desugar.backports.BooleanBackportTest;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.codeinspector.InstructionSubject;
-import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.nio.file.Path;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Objects;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * @deprecated New tests should follow the pattern of {@link BooleanBackportTest}.
- */
-@Deprecated
-public class BackportedMethodRewriterTest extends TestBase {
- static String expectedOutput = "";
-
- @Before
- public void testJvm() throws Exception {
- expectedOutput = testForJvm()
- .addTestClasspath()
- .run(TestMethods.class).getStdOut();
- }
-
- @Test
- public void testD8() throws Exception {
- testForD8()
- .addProgramClasses(TestMethods.class)
- .run(TestMethods.class)
- .assertSuccessWithOutput(expectedOutput);
-
- assertDesugaring(AndroidApiLevel.O, 17);
- assertDesugaring(AndroidApiLevel.N, 10);
- assertDesugaring(AndroidApiLevel.K, 2);
- assertDesugaring(AndroidApiLevel.J_MR2, 0);
- }
-
- private void assertDesugaring(AndroidApiLevel apiLevel, int expectedJavaInvokeStatics)
- throws Exception {
- D8TestCompileResult runResult = testForD8()
- .addProgramClasses(TestMethods.class)
- .setMinApi(apiLevel)
- .compile();
-
- MethodSubject mainMethod = runResult.inspector()
- .clazz(TestMethods.class)
- .mainMethod();
- assertThat(mainMethod, isPresent());
-
- List<InstructionSubject> javaInvokeStatics = mainMethod
- .streamInstructions()
- .filter(InstructionSubject::isInvokeStatic)
- .filter(is -> is.getMethod().holder.toDescriptorString().startsWith("Ljava/"))
- .collect(toList());
-
- int actualJavaInvokeStatics = javaInvokeStatics.size();
- assertEquals("Expected "
- + expectedJavaInvokeStatics
- + " invoke-static on java/*/<Type> but found "
- + actualJavaInvokeStatics
- + ": "
- + javaInvokeStatics, expectedJavaInvokeStatics, actualJavaInvokeStatics);
- }
-
- @Test
- public void testD8Merge() throws Exception {
- String jvmOutput = testForJvm()
- .addTestClasspath()
- .run(MergeRun.class).getStdOut();
- // See b/123242448
- Path zip1 = temp.newFile("first.zip").toPath();
- Path zip2 = temp.newFile("second.zip").toPath();
-
- testForD8()
- .setMinApi(AndroidApiLevel.L)
- .addProgramClasses(MergeRun.class, MergeInputB.class)
- .compile()
- .assertNoMessages()
- .writeToZip(zip1);
- testForD8()
- .setMinApi(AndroidApiLevel.L)
- .addProgramClasses(MergeInputA.class)
- .compile()
- .assertNoMessages()
- .writeToZip(zip2);
- testForD8()
- .addProgramFiles(zip1, zip2)
- .setMinApi(AndroidApiLevel.L)
- .compile()
- .assertNoMessages()
- .run(MergeRun.class)
- .assertSuccessWithOutput(jvmOutput);
- }
-
-
- static class MergeInputA {
- public void foo() {
- System.out.println(Integer.hashCode(42));
- System.out.println(Double.hashCode(42.0));
- }
- }
-
- static class MergeInputB {
- public void foo() {
- System.out.println(Integer.hashCode(43));
- System.out.println(Double.hashCode(43.0));
- }
- }
-
- static class MergeRun {
- public static void main(String[] args) {
- MergeInputA a = new MergeInputA();
- MergeInputB b = new MergeInputB();
- a.foo();
- b.foo();
- }
- }
-
- static class TestMethods {
- public static void main(String[] args) {
- int[] aInts = new int[]{42, 1, -1, Integer.MAX_VALUE, Integer.MIN_VALUE};
- int[] bInts = new int[]{43, 1, -1, Integer.MAX_VALUE, Integer.MIN_VALUE};
- for (int aInt : aInts) {
- System.out.println(Integer.hashCode(aInt));
- System.out.println(Integer.toUnsignedLong(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));
- System.out.println(Integer.divideUnsigned(aInt, bInt));
- System.out.println(Integer.remainderUnsigned(aInt, bInt));
- System.out.println(Integer.compareUnsigned(aInt, bInt));
- }
- }
-
- long[] aLongs = new long[]{42L, 1L, -1L, Integer.MIN_VALUE, Integer.MAX_VALUE,
- Long.MAX_VALUE, Long.MIN_VALUE};
- long[] bLongs = new long[]{43L, 2L, -2L, Integer.MIN_VALUE, Integer.MAX_VALUE,
- Long.MAX_VALUE, Long.MIN_VALUE};
- 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));
- System.out.println(Long.divideUnsigned(aLong, bLong));
- System.out.println(Long.remainderUnsigned(aLong, bLong));
- System.out.println(Long.compareUnsigned(aLong, bLong));
- }
- }
- }
- }
-}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/IntegerBackportTest.java b/src/test/java/com/android/tools/r8/desugar/backports/IntegerBackportTest.java
new file mode 100644
index 0000000..952c7cd
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/IntegerBackportTest.java
@@ -0,0 +1,157 @@
+// Copyright (c) 2019, 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.desugar.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.math.BigInteger;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public final class IntegerBackportTest extends AbstractBackportTest {
+ @Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ return getTestParameters().withDexRuntimes().build();
+ }
+
+ public IntegerBackportTest(TestParameters parameters) {
+ super(parameters, Integer.class, Main.class);
+ registerTarget(AndroidApiLevel.O, 35);
+ registerTarget(AndroidApiLevel.N, 11);
+ registerTarget(AndroidApiLevel.K, 7);
+ }
+
+ static final class Main extends MiniAssert {
+ private static final int[] interestingValues = {
+ Integer.MIN_VALUE, Integer.MAX_VALUE,
+ Short.MIN_VALUE, Short.MAX_VALUE,
+ Byte.MIN_VALUE, Byte.MAX_VALUE,
+ 0,
+ -1, 1,
+ -42, 42
+ };
+
+ public static void main(String[] args) {
+ testHashCode();
+ testToUnsignedLong();
+ testCompare();
+ testMax();
+ testMin();
+ testSum();
+ testCompareUnsigned();
+ testDivideUnsigned();
+ testRemainderUnsigned();
+ }
+
+ private static void testHashCode() {
+ for (int value : interestingValues) {
+ assertEquals(value, Integer.hashCode(value));
+ }
+ }
+
+ private static void testToUnsignedLong() {
+ assertEquals(0L, Integer.toUnsignedLong(0));
+ assertEquals(2_147_483_647L, Integer.toUnsignedLong(Integer.MAX_VALUE));
+ assertEquals(2_147_483_648L, Integer.toUnsignedLong(Integer.MIN_VALUE));
+ assertEquals(4_294_967_295L, Integer.toUnsignedLong(-1));
+ }
+
+ private static void testCompare() {
+ assertEquals(1, Integer.compare(1, 0));
+ assertEquals(0, Integer.compare(0, 0));
+ assertEquals(-1, Integer.compare(0, 1));
+ assertEquals(-1, Integer.compare(Integer.MIN_VALUE, Integer.MAX_VALUE));
+ assertEquals(1, Integer.compare(Integer.MAX_VALUE, Integer.MIN_VALUE));
+ assertEquals(0, Integer.compare(Integer.MIN_VALUE, Integer.MIN_VALUE));
+ assertEquals(0, Integer.compare(Integer.MAX_VALUE, Integer.MAX_VALUE));
+ }
+
+ private static void testMax() {
+ for (int x : interestingValues) {
+ for (int y : interestingValues) {
+ assertEquals(Math.max(x, y), Integer.max(x, y));
+ }
+ }
+ }
+
+ private static void testMin() {
+ for (int x : interestingValues) {
+ for (int y : interestingValues) {
+ assertEquals(Math.min(x, y), Integer.min(x, y));
+ }
+ }
+ }
+
+ private static void testSum() {
+ for (int x : interestingValues) {
+ for (int y : interestingValues) {
+ assertEquals(x + y, Integer.sum(x, y));
+ }
+ }
+ }
+
+ private static void testCompareUnsigned() {
+ assertEquals(0, Integer.compareUnsigned(0, 0));
+ assertEquals(-1, Integer.compareUnsigned(0, Integer.MAX_VALUE));
+ assertEquals(-1, Integer.compareUnsigned(0, Integer.MIN_VALUE));
+ assertEquals(-1, Integer.compareUnsigned(0, -1));
+
+ assertEquals(1, Integer.compareUnsigned(Integer.MAX_VALUE, 0));
+ assertEquals(0, Integer.compareUnsigned(Integer.MAX_VALUE, Integer.MAX_VALUE));
+ assertEquals(-1, Integer.compareUnsigned(Integer.MAX_VALUE, Integer.MIN_VALUE));
+ assertEquals(-1, Integer.compareUnsigned(Integer.MAX_VALUE, -1));
+
+ assertEquals(1, Integer.compareUnsigned(Integer.MIN_VALUE, 0));
+ assertEquals(1, Integer.compareUnsigned(Integer.MIN_VALUE, Integer.MAX_VALUE));
+ assertEquals(0, Integer.compareUnsigned(Integer.MIN_VALUE, Integer.MIN_VALUE));
+ assertEquals(-1, Integer.compareUnsigned(Integer.MIN_VALUE, -1));
+
+ assertEquals(1, Integer.compareUnsigned(-1, 0));
+ assertEquals(1, Integer.compareUnsigned(-1, Integer.MAX_VALUE));
+ assertEquals(1, Integer.compareUnsigned(-1, Integer.MIN_VALUE));
+ assertEquals(0, Integer.compareUnsigned(-1, -1));
+ }
+
+ private static void testDivideUnsigned() {
+ for (int x : interestingValues) {
+ for (int y : interestingValues) {
+ if (y == 0) continue;
+
+ BigInteger xUnsigned = BigInteger.valueOf(x & 0xffffffffL);
+ BigInteger yUnsigned = BigInteger.valueOf(y & 0xffffffffL);
+ int expected = xUnsigned.divide(yUnsigned).intValue();
+
+ assertEquals(expected, Integer.divideUnsigned(x, y));
+ }
+ }
+
+ try {
+ throw new AssertionError(Integer.divideUnsigned(1, 0));
+ } catch (ArithmeticException expected) {
+ }
+ }
+
+ private static void testRemainderUnsigned() {
+ for (int x : interestingValues) {
+ for (int y : interestingValues) {
+ if (y == 0) continue;
+
+ BigInteger xUnsigned = BigInteger.valueOf(x & 0xffffffffL);
+ BigInteger yUnsigned = BigInteger.valueOf(y & 0xffffffffL);
+ int expected = xUnsigned.remainder(yUnsigned).intValue();
+
+ assertEquals(expected, Integer.remainderUnsigned(x, y));
+ }
+ }
+
+ try {
+ throw new AssertionError(Integer.divideUnsigned(1, 0));
+ } catch (ArithmeticException expected) {
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/LongBackportTest.java b/src/test/java/com/android/tools/r8/desugar/backports/LongBackportTest.java
new file mode 100644
index 0000000..469e652
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/LongBackportTest.java
@@ -0,0 +1,163 @@
+// Copyright (c) 2019, 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.desugar.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.math.BigInteger;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public final class LongBackportTest extends AbstractBackportTest {
+ @Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ return getTestParameters().withDexRuntimes().build();
+ }
+
+ public LongBackportTest(TestParameters parameters) {
+ super(parameters, Long.class, Main.class);
+ registerTarget(AndroidApiLevel.O, 31);
+ registerTarget(AndroidApiLevel.N, 11);
+ registerTarget(AndroidApiLevel.K, 7);
+ }
+
+ static final class Main extends MiniAssert {
+ private static final long[] interestingValues = {
+ Long.MIN_VALUE, Long.MAX_VALUE,
+ Long.MIN_VALUE, Long.MAX_VALUE,
+ Short.MIN_VALUE, Short.MAX_VALUE,
+ Byte.MIN_VALUE, Byte.MAX_VALUE,
+ 0L,
+ -1L, 1L,
+ -42L, 42L
+ };
+
+ public static void main(String[] args) {
+ testHashCode();
+ testCompare();
+ testMax();
+ testMin();
+ testSum();
+ testCompareUnsigned();
+ testDivideUnsigned();
+ testRemainderUnsigned();
+ }
+
+ private static void testHashCode() {
+ for (long value : interestingValues) {
+ assertEquals(expectedHashCode(value), Long.hashCode(value));
+ }
+ }
+
+ private static void testCompare() {
+ assertEquals(1, Long.compare(1, 0));
+ assertEquals(0, Long.compare(0, 0));
+ assertEquals(-1, Long.compare(0, 1));
+ assertEquals(-1, Long.compare(Long.MIN_VALUE, Long.MAX_VALUE));
+ assertEquals(1, Long.compare(Long.MAX_VALUE, Long.MIN_VALUE));
+ assertEquals(0, Long.compare(Long.MIN_VALUE, Long.MIN_VALUE));
+ assertEquals(0, Long.compare(Long.MAX_VALUE, Long.MAX_VALUE));
+ }
+
+ private static void testMax() {
+ for (long x : interestingValues) {
+ for (long y : interestingValues) {
+ assertEquals(Math.max(x, y), Long.max(x, y));
+ }
+ }
+ }
+
+ private static void testMin() {
+ for (long x : interestingValues) {
+ for (long y : interestingValues) {
+ assertEquals(Math.min(x, y), Long.min(x, y));
+ }
+ }
+ }
+
+ private static void testSum() {
+ for (long x : interestingValues) {
+ for (long y : interestingValues) {
+ assertEquals(x + y, Long.sum(x, y));
+ }
+ }
+ }
+
+ private static void testCompareUnsigned() {
+ assertEquals(0, Long.compareUnsigned(0, 0));
+ assertEquals(-1, Long.compareUnsigned(0, Long.MAX_VALUE));
+ assertEquals(-1, Long.compareUnsigned(0, Long.MIN_VALUE));
+ assertEquals(-1, Long.compareUnsigned(0, -1));
+
+ assertEquals(1, Long.compareUnsigned(Long.MAX_VALUE, 0));
+ assertEquals(0, Long.compareUnsigned(Long.MAX_VALUE, Long.MAX_VALUE));
+ assertEquals(-1, Long.compareUnsigned(Long.MAX_VALUE, Long.MIN_VALUE));
+ assertEquals(-1, Long.compareUnsigned(Long.MAX_VALUE, -1));
+
+ assertEquals(1, Long.compareUnsigned(Long.MIN_VALUE, 0));
+ assertEquals(1, Long.compareUnsigned(Long.MIN_VALUE, Long.MAX_VALUE));
+ assertEquals(0, Long.compareUnsigned(Long.MIN_VALUE, Long.MIN_VALUE));
+ assertEquals(-1, Long.compareUnsigned(Long.MIN_VALUE, -1));
+
+ assertEquals(1, Long.compareUnsigned(-1, 0));
+ assertEquals(1, Long.compareUnsigned(-1, Long.MAX_VALUE));
+ assertEquals(1, Long.compareUnsigned(-1, Long.MIN_VALUE));
+ assertEquals(0, Long.compareUnsigned(-1, -1));
+ }
+
+ private static void testDivideUnsigned() {
+ for (long x : interestingValues) {
+ for (long y : interestingValues) {
+ if (y == 0L) continue;
+
+ BigInteger xUnsigned = longToBigInteger(x);
+ BigInteger yUnsigned = longToBigInteger(y);
+ long expected = xUnsigned.divide(yUnsigned).longValue();
+
+ assertEquals(expected, Long.divideUnsigned(x, y));
+ }
+ }
+
+ try {
+ throw new AssertionError(Long.divideUnsigned(1L, 0L));
+ } catch (ArithmeticException expected) {
+ }
+ }
+
+ private static void testRemainderUnsigned() {
+ for (long x : interestingValues) {
+ for (long y : interestingValues) {
+ if (y == 0L) continue;
+
+ BigInteger xUnsigned = longToBigInteger(x);
+ BigInteger yUnsigned = longToBigInteger(y);
+ long expected = xUnsigned.remainder(yUnsigned).longValue();
+
+ assertEquals(expected, Long.remainderUnsigned(x, y));
+ }
+ }
+
+ try {
+ throw new AssertionError(Long.remainderUnsigned(1L, 0L));
+ } catch (ArithmeticException expected) {
+ }
+ }
+
+ @IgnoreInvokes
+ private static int expectedHashCode(long value) {
+ return Long.valueOf(value).hashCode();
+ }
+
+ private static BigInteger longToBigInteger(long value) {
+ BigInteger bigInt = BigInteger.valueOf(value & 0x7fffffffffffffffL);
+ if (value < 0) {
+ bigInt = bigInt.setBit(Long.SIZE - 1);
+ }
+ return bigInt;
+ }
+ }
+}