Math/StrictMath JDK Tests

- Add JDK tests for Math/StrictMath
- Add support for multiplyExact,
  floorDiv, floorMod with longxint
  parameters.
- Add Java 9 tests for the 3 new methods
- Fix BackportedMethodRewriter to support
  Backported methods calling each other

Bug:136717060
Change-Id: I2ae7dad3fd9ddfde496203f08c81211bb68d17e6
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 430c38a..7a830e8 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
@@ -6,7 +6,6 @@
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ClassAccessFlags;
 import com.android.tools.r8.graph.DexAnnotationSet;
@@ -141,6 +140,7 @@
     if (holders.isEmpty()) {
       return;
     }
+    // Compute referencing classes ignoring references in-between utility classes.
     Set<DexProgramClass> referencingClasses = Sets.newConcurrentHashSet();
     for (DexType holder : holders) {
       DexClass definitionFor = appView.definitionFor(holder);
@@ -152,15 +152,22 @@
         referencingClasses.add(definitionFor.asProgramClass());
       }
     }
+
     MethodAccessFlags flags = MethodAccessFlags.fromSharedAccessFlags(
         Constants.ACC_PUBLIC | Constants.ACC_STATIC | Constants.ACC_SYNTHETIC, false);
     ClassAccessFlags classAccessFlags =
         ClassAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC);
-
-    for (MethodProvider provider : methodProviders.values()) {
+    // Generate the utility classes in a loop since utility classes can require the
+    // the creation of other utility classes.
+    // Function multiplyExact(long int) calls multiplyExact(long long) for example.
+    while (!methodProviders.isEmpty()) {
+      DexMethod key = methodProviders.keySet().iterator().next();
+      MethodProvider provider = methodProviders.get(key);
+      methodProviders.remove(key);
       assert provider.requiresGenerationOfCode();
       DexMethod method = provider.provideMethod(factory);
-      // The utility class could have been synthesized, e.g., running R8 then D8.
+      // The utility class could have been synthesized, e.g., running R8 then D8,
+      // or if already processed in this while loop.
       if (appView.definitionFor(method.holder) != null) {
         continue;
       }
@@ -189,12 +196,13 @@
               factory.getSkipNameValidationForTesting(),
               referencingClasses);
       code.setUpContext(utilityClass);
-      AppInfo appInfo = appView.appInfo();
       boolean addToMainDexList =
-          referencingClasses.stream().anyMatch(clazz -> appInfo.isInMainDexList(clazz.type));
-      appInfo.addSynthesizedClass(utilityClass);
-      converter.optimizeSynthesizedClass(utilityClass, executorService);
+          referencingClasses.stream()
+              .anyMatch(clazz -> appView.appInfo().isInMainDexList(clazz.type));
+      appView.appInfo().addSynthesizedClass(utilityClass);
       builder.addSynthesizedClass(utilityClass, addToMainDexList);
+      // The following may add elements to methodsProviders.
+      converter.optimizeSynthesizedClass(utilityClass, executorService);
     }
   }
 
@@ -231,6 +239,9 @@
       if (!options.canUseJava9UnsignedOperations()) {
         initializeJava9UnsignedOperations(factory);
       }
+      if (!options.canUseJava9SignedOperations()) {
+        initializeJava9SignedOperations(factory);
+      }
       // interface method desugaring also toggles library emulation.
       if (options.isInterfaceMethodDesugaringEnabled()) {
         initializeRetargetCoreLibraryMembers(appView);
@@ -528,7 +539,7 @@
         proto = factory.createProto(factory.intType, factory.intType, factory.intType);
         addProvider(new MethodGenerator(clazz, method, proto, MathMethods::new, "floorDivInt"));
 
-        // long {Math,StrictMath}.floorDiv(long)
+        // long {Math,StrictMath}.floorDiv(long, long)
         method = factory.createString("floorDiv");
         proto = factory.createProto(factory.longType, factory.longType, factory.longType);
         addProvider(new MethodGenerator(clazz, method, proto, MathMethods::new, "floorDivLong"));
@@ -538,7 +549,7 @@
         proto = factory.createProto(factory.intType, factory.intType, factory.intType);
         addProvider(new MethodGenerator(clazz, method, proto, MathMethods::new, "floorModInt"));
 
-        // long {Math,StrictMath}.floorMod(long)
+        // long {Math,StrictMath}.floorMod(long, long)
         method = factory.createString("floorMod");
         proto = factory.createProto(factory.longType, factory.longType, factory.longType);
         addProvider(new MethodGenerator(clazz, method, proto, MathMethods::new, "floorModLong"));
@@ -549,7 +560,7 @@
         addProvider(
             new MethodGenerator(clazz, method, proto, MathMethods::new, "multiplyExactInt"));
 
-        // long {Math,StrictMath}.multiplyExact(long)
+        // long {Math,StrictMath}.multiplyExact(long, long)
         method = factory.createString("multiplyExact");
         proto = factory.createProto(factory.longType, factory.longType, factory.longType);
         addProvider(
@@ -677,8 +688,9 @@
       // int Integer.parseUnsignedInt(String value, int radix)
       method = factory.createString("parseUnsignedInt");
       proto = factory.createProto(factory.intType, factory.stringType, factory.intType);
-      addProvider(new MethodGenerator(clazz, method, proto, IntegerMethods::new,
-          "parseUnsignedIntWithRadix"));
+      addProvider(
+          new MethodGenerator(
+              clazz, method, proto, IntegerMethods::new, "parseUnsignedIntWithRadix"));
 
       // String Integer.toUnsignedString(int value)
       method = factory.createString("toUnsignedString");
@@ -688,8 +700,9 @@
       // String Integer.toUnsignedString(int value, int radix)
       method = factory.createString("toUnsignedString");
       proto = factory.createProto(factory.stringType, factory.intType, factory.intType);
-      addProvider(new MethodGenerator(clazz, method, proto, IntegerMethods::new,
-          "toUnsignedStringWithRadix"));
+      addProvider(
+          new MethodGenerator(
+              clazz, method, proto, IntegerMethods::new, "toUnsignedStringWithRadix"));
 
       // Long
       clazz = factory.boxedLongDescriptor;
@@ -717,8 +730,9 @@
       // long Long.parseUnsignedLong(String value, int radix)
       method = factory.createString("parseUnsignedLong");
       proto = factory.createProto(factory.longType, factory.stringType, factory.intType);
-      addProvider(new MethodGenerator(clazz, method, proto, LongMethods::new,
-          "parseUnsignedLongWithRadix"));
+      addProvider(
+          new MethodGenerator(
+              clazz, method, proto, LongMethods::new, "parseUnsignedLongWithRadix"));
 
       // String Long.toUnsignedString(long value)
       method = factory.createString("toUnsignedString");
@@ -728,8 +742,8 @@
       // String Long.toUnsignedString(long value, int radix)
       method = factory.createString("toUnsignedString");
       proto = factory.createProto(factory.stringType, factory.longType, factory.intType);
-      addProvider(new MethodGenerator(clazz, method, proto, LongMethods::new,
-          "toUnsignedStringWithRadix"));
+      addProvider(
+          new MethodGenerator(clazz, method, proto, LongMethods::new, "toUnsignedStringWithRadix"));
 
       // String
       clazz = factory.stringDescriptor;
@@ -747,6 +761,29 @@
       addProvider(new MethodGenerator(clazz, method, proto, StringMethods::new, "joinIterable"));
     }
 
+    private void initializeJava9SignedOperations(DexItemFactory factory) {
+      DexString[] mathClasses = {factory.mathDescriptor, factory.strictMathDescriptor};
+      for (DexString mathClass : mathClasses) {
+        DexString clazz = mathClass;
+
+        // long {Math,StrictMath}.multiplyExact(long, int)
+        DexString method = factory.createString("multiplyExact");
+        DexProto proto = factory.createProto(factory.longType, factory.longType, factory.intType);
+        addProvider(
+            new MethodGenerator(clazz, method, proto, MathMethods::new, "multiplyExactLongInt"));
+
+        // long {Math,StrictMath}.floorDiv(long, int)
+        method = factory.createString("floorDiv");
+        proto = factory.createProto(factory.longType, factory.longType, factory.intType);
+        addProvider(new MethodGenerator(clazz, method, proto, MathMethods::new, "floorDivLongInt"));
+
+        // int {Math,StrictMath}.floorMod(long, int)
+        method = factory.createString("floorMod");
+        proto = factory.createProto(factory.intType, factory.longType, factory.intType);
+        addProvider(new MethodGenerator(clazz, method, proto, MathMethods::new, "floorModLongInt"));
+      }
+    }
+
     private void initializeJava9UnsignedOperations(DexItemFactory factory) {
       // Byte
       DexString clazz = factory.boxedByteDescriptor;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/MathMethods.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/MathMethods.java
index fc5458f..394823f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/backports/MathMethods.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/MathMethods.java
@@ -72,6 +72,10 @@
     return signum < 0L ? div - 1L : div;
   }
 
+  public static long floorDivLongInt(long dividend, int divisor) {
+    return Math.floorDiv(dividend, (long) divisor);
+  }
+
   public static int floorModInt(int dividend, int divisor) {
     int rem = dividend % divisor;
     if (rem == 0) {
@@ -98,6 +102,10 @@
     return signum > 0L ? rem : rem + divisor;
   }
 
+  public static int floorModLongInt(long dividend, int divisor) {
+    return (int) Math.floorMod(dividend, (long) divisor);
+  }
+
   public static int incrementExactInt(int value) {
     if (value == Integer.MAX_VALUE) {
       throw new ArithmeticException();
@@ -149,6 +157,10 @@
     throw new ArithmeticException();
   }
 
+  public static long multiplyExactLongInt(long x, int y) {
+    return Math.multiplyExact(x, (long) y);
+  }
+
   public static int negateExactInt(int value) {
     if (value == Integer.MIN_VALUE) {
       throw new ArithmeticException();
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 81ace3c..731fcfa 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1002,6 +1002,11 @@
     return false;
   }
 
+  public boolean canUseJava9SignedOperations() {
+    assert isGeneratingDex();
+    return false;
+  }
+
   public boolean canUsePrivateInterfaceMethods() {
     return isGeneratingClassFiles() || hasMinApi(AndroidApiLevel.N);
   }
diff --git a/src/test/examplesJava9/backport/MathBackportJava9Main.java b/src/test/examplesJava9/backport/MathBackportJava9Main.java
new file mode 100644
index 0000000..5eefb65
--- /dev/null
+++ b/src/test/examplesJava9/backport/MathBackportJava9Main.java
@@ -0,0 +1,67 @@
+// 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 backport;
+
+public class MathBackportJava9Main {
+
+  public static void main(String[] args) {
+    testMultiplyExactLongInt();
+    testFloorDivLongInt();
+    testFloorModLongInt();
+  }
+
+  public static void testMultiplyExactLongInt() {
+    assertEquals(8L, Math.multiplyExact(2L, 4));
+    assertEquals(Long.MAX_VALUE, Math.multiplyExact(Long.MAX_VALUE, 1));
+    assertEquals(Long.MIN_VALUE, Math.multiplyExact(Long.MIN_VALUE / 2L, 2));
+    try {
+      throw new AssertionError(Math.multiplyExact(Long.MAX_VALUE, 2));
+    } catch (ArithmeticException expected) {
+    }
+    try {
+      throw new AssertionError(Math.multiplyExact(Long.MIN_VALUE, 2));
+    } catch (ArithmeticException expected) {
+    }
+  }
+
+  public static void testFloorDivLongInt() {
+    assertEquals(1L, Math.floorDiv(4L, 4));
+    assertEquals(1L, Math.floorDiv(-4L, -4));
+    assertEquals(-1L, Math.floorDiv(-4L, 4));
+    assertEquals(-1L, Math.floorDiv(4L, -4));
+
+    assertEquals(1L, Math.floorDiv(4L, 3));
+    assertEquals(1L, Math.floorDiv(-4L, -3));
+    assertEquals(-2L, Math.floorDiv(-4L, 3));
+    assertEquals(-2L, Math.floorDiv(4L, -3));
+
+    // Spec edge case: result is actually MAX_VALUE+1 which becomes MIN_VALUE.
+    assertEquals(Long.MIN_VALUE, Math.floorDiv(Long.MIN_VALUE, -1));
+  }
+
+  public static void testFloorModLongInt() {
+    assertEquals(0, Math.floorMod(4L, 4));
+    assertEquals(0, Math.floorMod(-4L, -4));
+    assertEquals(0, Math.floorMod(-4L, 4));
+    assertEquals(0, Math.floorMod(4L, -4));
+
+    assertEquals(1, Math.floorMod(4L, 3));
+    assertEquals(-1, Math.floorMod(-4L, -3));
+    assertEquals(2, Math.floorMod(-4L, 3));
+    assertEquals(-2, Math.floorMod(4L, -3));
+  }
+
+  private static void assertEquals(int expected, int actual) {
+    if (expected != actual) {
+      throw new AssertionError("Expected <" + expected + "> but was <" + actual + '>');
+    }
+  }
+
+  private static void assertEquals(long expected, long actual) {
+    if (expected != actual) {
+      throw new AssertionError("Expected <" + expected + "> but was <" + actual + '>');
+    }
+  }
+}
diff --git a/src/test/examplesJava9/backport/StrictMathBackportJava9Main.java b/src/test/examplesJava9/backport/StrictMathBackportJava9Main.java
new file mode 100644
index 0000000..b711539
--- /dev/null
+++ b/src/test/examplesJava9/backport/StrictMathBackportJava9Main.java
@@ -0,0 +1,67 @@
+// 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 backport;
+
+public class StrictMathBackportJava9Main {
+
+  public static void main(String[] args) {
+    testMultiplyExactLongInt();
+    testFloorDivLongInt();
+    testFloorModLongInt();
+  }
+
+  public static void testMultiplyExactLongInt() {
+    assertEquals(8L, StrictMath.multiplyExact(2L, 4));
+    assertEquals(Long.MAX_VALUE, StrictMath.multiplyExact(Long.MAX_VALUE, 1));
+    assertEquals(Long.MIN_VALUE, StrictMath.multiplyExact(Long.MIN_VALUE / 2L, 2));
+    try {
+      throw new AssertionError(StrictMath.multiplyExact(Long.MAX_VALUE, 2));
+    } catch (ArithmeticException expected) {
+    }
+    try {
+      throw new AssertionError(StrictMath.multiplyExact(Long.MIN_VALUE, 2));
+    } catch (ArithmeticException expected) {
+    }
+  }
+
+  public static void testFloorDivLongInt() {
+    assertEquals(1L, StrictMath.floorDiv(4L, 4));
+    assertEquals(1L, StrictMath.floorDiv(-4L, -4));
+    assertEquals(-1L, StrictMath.floorDiv(-4L, 4));
+    assertEquals(-1L, StrictMath.floorDiv(4L, -4));
+
+    assertEquals(1L, StrictMath.floorDiv(4L, 3));
+    assertEquals(1L, StrictMath.floorDiv(-4L, -3));
+    assertEquals(-2L, StrictMath.floorDiv(-4L, 3));
+    assertEquals(-2L, StrictMath.floorDiv(4L, -3));
+
+    // Spec edge case: result is actually MAX_VALUE+1 which becomes MIN_VALUE.
+    assertEquals(Long.MIN_VALUE, StrictMath.floorDiv(Long.MIN_VALUE, -1));
+  }
+
+  public static void testFloorModLongInt() {
+    assertEquals(0, StrictMath.floorMod(4L, 4));
+    assertEquals(0, StrictMath.floorMod(-4L, -4));
+    assertEquals(0, StrictMath.floorMod(-4L, 4));
+    assertEquals(0, StrictMath.floorMod(4L, -4));
+
+    assertEquals(1, StrictMath.floorMod(4L, 3));
+    assertEquals(-1, StrictMath.floorMod(-4L, -3));
+    assertEquals(2, StrictMath.floorMod(-4L, 3));
+    assertEquals(-2, StrictMath.floorMod(4L, -3));
+  }
+
+  private static void assertEquals(int expected, int actual) {
+    if (expected != actual) {
+      throw new AssertionError("Expected <" + expected + "> but was <" + actual + '>');
+    }
+  }
+
+  private static void assertEquals(long expected, long actual) {
+    if (expected != actual) {
+      throw new AssertionError("Expected <" + expected + "> but was <" + actual + '>');
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 03e199e..62ada86 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -107,6 +107,7 @@
   public static final String GENERATED_PROTO_BUILD_DIR = GENERATED_TEST_BUILD_DIR + "proto/";
   public static final String SMALI_DIR = TESTS_DIR + "smali/";
   public static final String SMALI_BUILD_DIR = TESTS_BUILD_DIR + "smali/";
+  public static final String JAVA_CLASSES_DIR = BUILD_DIR + "classes/java/";
 
   public static final String LINE_SEPARATOR = StringUtils.LINE_SEPARATOR;
   public static final String CLASSPATH_SEPARATOR = File.pathSeparator;
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/MathBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/MathBackportJava9Test.java
new file mode 100644
index 0000000..27e34ab
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/MathBackportJava9Test.java
@@ -0,0 +1,31 @@
+// 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 static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public final class MathBackportJava9Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters().withDexRuntimes().build();
+  }
+
+  private static final Path TEST_JAR =
+      Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+  public MathBackportJava9Test(TestParameters parameters) {
+    super(parameters, Math.class, TEST_JAR, "backport.MathBackportJava9Main");
+    // TODO Once shipped in an actual API level, migrate to MathBackportTest
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/StrictMathBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/StrictMathBackportJava9Test.java
new file mode 100644
index 0000000..f4274c0
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/StrictMathBackportJava9Test.java
@@ -0,0 +1,31 @@
+// 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 static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public final class StrictMathBackportJava9Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters().withDexRuntimes().build();
+  }
+
+  private static final Path TEST_JAR =
+      Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+  public StrictMathBackportJava9Test(TestParameters parameters) {
+    super(parameters, Math.class, TEST_JAR, "backport.StrictMathBackportJava9Main");
+    // TODO Once shipped in an actual API level, migrate to MathBackportTest
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/corelibjdktests/Jdk11MathTests.java b/src/test/java/com/android/tools/r8/desugar/corelib/corelibjdktests/Jdk11MathTests.java
new file mode 100644
index 0000000..6e4aa4e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/corelibjdktests/Jdk11MathTests.java
@@ -0,0 +1,111 @@
+// 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.corelib.corelibjdktests;
+
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class Jdk11MathTests extends TestBase {
+
+  private static final Path JDK_11_MATH_TESTS_DIR =
+      Paths.get(ToolHelper.JAVA_CLASSES_DIR + "jdk11MathTests");
+  private static final Path JDK_11_STRICT_MATH_TESTS_DIR =
+      Paths.get(ToolHelper.JAVA_CLASSES_DIR + "jdk11StrictMathTests");
+  private static final String DIVMOD = "DivModTests";
+  private static final String EXACTARITH = "ExactArithTests";
+  private static final String CLASS_SUFFIX = ".class";
+  private static final Path[] JDK_11_MATH_TEST_CLASS_FILES =
+      new Path[] {
+        JDK_11_MATH_TESTS_DIR.resolve(DIVMOD + CLASS_SUFFIX),
+        JDK_11_MATH_TESTS_DIR.resolve(EXACTARITH + CLASS_SUFFIX)
+      };
+  private static final Path[] JDK_11_STRICT_MATH_TEST_CLASS_FILES =
+      new Path[] {JDK_11_STRICT_MATH_TESTS_DIR.resolve(EXACTARITH + CLASS_SUFFIX)};
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withDexRuntimes().withCfRuntime(CfVm.JDK11).build();
+  }
+
+  public Jdk11MathTests(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testD8MathExactArith() throws Exception {
+    Assume.assumeTrue(parameters.isDexRuntime());
+    testForD8()
+        .addProgramFiles(JDK_11_MATH_TEST_CLASS_FILES)
+        .setMinApi(parameters.getRuntime())
+        .run(parameters.getRuntime(), EXACTARITH)
+        .assertSuccessWithOutput("");
+  }
+
+  @Test
+  public void testD8MathDivMod() throws Exception {
+    Assume.assumeTrue(parameters.isDexRuntime());
+    testForD8()
+        .addProgramFiles(JDK_11_MATH_TEST_CLASS_FILES)
+        .setMinApi(parameters.getRuntime())
+        .run(parameters.getRuntime(), DIVMOD)
+        .assertSuccessWithOutput("");
+  }
+
+  @Test
+  public void testD8StrictMathExactArith() throws Exception {
+    Assume.assumeTrue(parameters.isDexRuntime());
+    testForD8()
+        .addProgramFiles(JDK_11_STRICT_MATH_TEST_CLASS_FILES)
+        .setMinApi(parameters.getRuntime())
+        .run(parameters.getRuntime(), EXACTARITH)
+        .assertSuccessWithOutput("");
+  }
+
+  @Test
+  public void testR8MathExactArith() throws Exception {
+    testForR8(parameters.getBackend())
+        .addKeepMainRule(DIVMOD)
+        .addKeepMainRule(EXACTARITH)
+        .addProgramFiles(JDK_11_MATH_TEST_CLASS_FILES)
+        .setMinApi(parameters.getRuntime())
+        .run(parameters.getRuntime(), EXACTARITH)
+        .assertSuccessWithOutput("");
+  }
+
+  @Test
+  public void testR8MathDivMod() throws Exception {
+    testForR8(parameters.getBackend())
+        .addKeepMainRule(DIVMOD)
+        .addKeepMainRule(EXACTARITH)
+        .addProgramFiles(JDK_11_MATH_TEST_CLASS_FILES)
+        .setMinApi(parameters.getRuntime())
+        .run(parameters.getRuntime(), DIVMOD)
+        .assertSuccessWithOutput("");
+  }
+
+  @Test
+  public void testR8StrictMathExactArith() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramFiles(JDK_11_STRICT_MATH_TEST_CLASS_FILES)
+        .addKeepMainRule(EXACTARITH)
+        .setMinApi(parameters.getRuntime())
+        .run(parameters.getRuntime(), EXACTARITH)
+        .assertSuccessWithOutput("");
+  }
+}