BackportedMethods for Android U
- Fix Math.StrictMath missing methods
- Fix Objects methods
- Fix levels at which some desugaring are disabled
RELNOTES: R8 now backports methods of Objects and Math/StrictMath up to Android U.
Change-Id: I289a676af68e74ba34dad1c0a8f08a98451d0cf1
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 3826986..a7771eb 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
@@ -253,18 +253,18 @@
if (typeIsPresentWithoutBackportsFrom(factory.optionalType, AndroidApiLevel.T)) {
initializeAndroidOptionalTMethodProviders(factory);
}
+ if (typeIsPresentWithoutNeverIntroducedBackports(factory.predicateType)) {
+ initializeAndroidTPredicateMethodProviders(factory);
+ }
+ }
+ if (options.getMinApiLevel().isLessThan(AndroidApiLevel.U)) {
+ if (typeIsPresentWithoutNeverIntroducedBackports(factory.streamType)) {
+ initializeAndroidUStreamMethodProviders(factory);
+ }
+ initializeAndroidUMethodProviders(factory);
}
- // These are currently not implemented at any API level in Android.
- if (typeIsPresentWithoutNeverIntroducedBackports(factory.streamType)) {
- initializeStreamMethodProviders(factory);
- }
- if (typeIsPresentWithoutNeverIntroducedBackports(factory.predicateType)) {
- initializePredicateMethodProviders(factory);
- }
- initializeJava9MethodProviders(factory);
- initializeJava10MethodProviders(factory);
- initializeJava11MethodProviders(factory);
+ initializeMethodProvidersUnimplementedOnAndroid(factory);
}
private Map<DexType, AndroidApiLevel> initializeTypeMinApi(DexItemFactory factory) {
@@ -803,9 +803,17 @@
addProvider(new MethodGenerator(method, BackportedMethods::MathMethods_toIntExact));
}
- // Math (APIs which are not mirrored by StrictMath)
- type = factory.mathType;
+ initializeMathExactApis(factory, factory.mathType);
+ }
+ /**
+ * Math APIs which are mirrored by StrictMath in a later Android api level than the one they are
+ * introduced for Math.
+ */
+ private void initializeMathExactApis(DexItemFactory factory, DexType type) {
+ DexMethod method;
+ DexProto proto;
+ DexString name;
// int Math.decrementExact(int)
name = factory.createString("decrementExact");
proto = factory.createProto(factory.intType, factory.intType);
@@ -1590,15 +1598,57 @@
}
}
- private void initializeJava9MethodProviders(DexItemFactory factory) {
- // Nothing right now.
+ private void initializeAndroidUMethodProviders(DexItemFactory factory) {
+ DexType type;
+ DexString name;
+ DexProto proto;
+ DexMethod method;
+
+ // Objects
+ type = factory.objectsType;
+
+ // long Objects.checkIndex(long, long)
+ name = factory.createString("checkIndex");
+ proto = factory.createProto(factory.longType, factory.longType, factory.longType);
+ method = factory.createMethod(type, proto, name);
+ addProvider(new MethodGenerator(method, BackportedMethods::ObjectsMethods_checkIndexLong));
+
+ // long Objects.checkFromToIndex(long, long, long)
+ name = factory.createString("checkFromToIndex");
+ proto =
+ factory.createProto(
+ factory.longType, factory.longType, factory.longType, factory.longType);
+ method = factory.createMethod(type, proto, name);
+ addProvider(
+ new MethodGenerator(method, BackportedMethods::ObjectsMethods_checkFromToIndexLong));
+
+ // long Objects.checkFromIndexSize(long, long, long)
+ name = factory.createString("checkFromIndexSize");
+ proto =
+ factory.createProto(
+ factory.longType, factory.longType, factory.longType, factory.longType);
+ method = factory.createMethod(type, proto, name);
+ addProvider(
+ new MethodGenerator(method, BackportedMethods::ObjectsMethods_checkFromIndexSizeLong));
+
+ DexType[] mathTypes = {factory.mathType, factory.strictMathType};
+ for (DexType mathType : mathTypes) {
+ // int {StrictMath.Math}.absExact(int)
+ // long {StrictMath.Math}.absExact(long)
+ name = factory.createString("absExact");
+ proto = factory.createProto(factory.intType, factory.intType);
+ method = factory.createMethod(mathType, proto, name);
+ addProvider(new MethodGenerator(method, BackportedMethods::MathMethods_absExact));
+
+ proto = factory.createProto(factory.longType, factory.longType);
+ method = factory.createMethod(mathType, proto, name);
+ addProvider(new MethodGenerator(method, BackportedMethods::MathMethods_absExactLong));
+ }
+
+ initializeMathExactApis(factory, factory.strictMathType);
}
- private void initializeJava10MethodProviders(DexItemFactory factory) {
- // Nothing right now.
- }
-
- private void initializeJava11MethodProviders(DexItemFactory factory) {
+ private void initializeMethodProvidersUnimplementedOnAndroid(DexItemFactory factory) {
// Character
DexType type = factory.boxedCharType;
@@ -1622,7 +1672,7 @@
new MethodGenerator(method, BackportedMethods::CharSequenceMethods_compare, "compare"));
}
- private void initializeStreamMethodProviders(DexItemFactory factory) {
+ private void initializeAndroidUStreamMethodProviders(DexItemFactory factory) {
// Stream
DexType streamType = factory.streamType;
@@ -1634,7 +1684,7 @@
new MethodGenerator(method, BackportedMethods::StreamMethods_ofNullable, "ofNullable"));
}
- private void initializePredicateMethodProviders(DexItemFactory factory) {
+ private void initializeAndroidTPredicateMethodProviders(DexItemFactory factory) {
// Predicate
DexType predicateType = factory.predicateType;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
index d2efd78..2fdebe0 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
@@ -4171,6 +4171,97 @@
ImmutableList.of());
}
+ public static CfCode MathMethods_absExact(DexItemFactory factory, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ CfLabel label3 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 3,
+ 1,
+ ImmutableList.of(
+ label0,
+ new CfLoad(ValueType.INT, 0),
+ new CfConstNumber(-2147483648, ValueType.INT),
+ new CfIfCmp(If.Type.NE, ValueType.INT, label2),
+ label1,
+ new CfNew(factory.createType("Ljava/lang/ArithmeticException;")),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfConstString(
+ factory.createString("Overflow to represent absolute value of Integer.MIN_VALUE")),
+ new CfInvoke(
+ 183,
+ factory.createMethod(
+ factory.createType("Ljava/lang/ArithmeticException;"),
+ factory.createProto(factory.voidType, factory.stringType),
+ factory.createString("<init>")),
+ false),
+ new CfThrow(),
+ label2,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(new int[] {0}, new FrameType[] {FrameType.intType()})),
+ new CfLoad(ValueType.INT, 0),
+ new CfInvoke(
+ 184,
+ factory.createMethod(
+ factory.createType("Ljava/lang/Math;"),
+ factory.createProto(factory.intType, factory.intType),
+ factory.createString("abs")),
+ false),
+ new CfReturn(ValueType.INT),
+ label3),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
+ public static CfCode MathMethods_absExactLong(DexItemFactory factory, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ CfLabel label3 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 4,
+ 2,
+ ImmutableList.of(
+ label0,
+ new CfLoad(ValueType.LONG, 0),
+ new CfConstNumber(-9223372036854775808L, ValueType.LONG),
+ new CfCmp(Cmp.Bias.NONE, NumericType.LONG),
+ new CfIf(If.Type.NE, ValueType.INT, label2),
+ label1,
+ new CfNew(factory.createType("Ljava/lang/ArithmeticException;")),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfConstString(
+ factory.createString("Overflow to represent absolute value of Long.MIN_VALUE")),
+ new CfInvoke(
+ 183,
+ factory.createMethod(
+ factory.createType("Ljava/lang/ArithmeticException;"),
+ factory.createProto(factory.voidType, factory.stringType),
+ factory.createString("<init>")),
+ false),
+ new CfThrow(),
+ label2,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1},
+ new FrameType[] {FrameType.longType(), FrameType.longHighType()})),
+ new CfLoad(ValueType.LONG, 0),
+ new CfInvoke(
+ 184,
+ factory.createMethod(
+ factory.createType("Ljava/lang/Math;"),
+ factory.createProto(factory.longType, factory.longType),
+ factory.createString("abs")),
+ false),
+ new CfReturn(ValueType.LONG),
+ label3),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
public static CfCode MathMethods_addExactInt(DexItemFactory factory, DexMethod method) {
CfLabel label0 = new CfLabel();
CfLabel label1 = new CfLabel();
@@ -5819,6 +5910,157 @@
ImmutableList.of());
}
+ public static CfCode ObjectsMethods_checkFromIndexSizeLong(
+ DexItemFactory factory, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ CfLabel label3 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 6,
+ 6,
+ ImmutableList.of(
+ label0,
+ new CfLoad(ValueType.LONG, 0),
+ new CfConstNumber(0, ValueType.LONG),
+ new CfCmp(Cmp.Bias.NONE, NumericType.LONG),
+ new CfIf(If.Type.LT, ValueType.INT, label1),
+ new CfLoad(ValueType.LONG, 2),
+ new CfConstNumber(0, ValueType.LONG),
+ new CfCmp(Cmp.Bias.NONE, NumericType.LONG),
+ new CfIf(If.Type.LT, ValueType.INT, label1),
+ new CfLoad(ValueType.LONG, 4),
+ new CfConstNumber(0, ValueType.LONG),
+ new CfCmp(Cmp.Bias.NONE, NumericType.LONG),
+ new CfIf(If.Type.LT, ValueType.INT, label1),
+ new CfLoad(ValueType.LONG, 0),
+ new CfLoad(ValueType.LONG, 4),
+ new CfLoad(ValueType.LONG, 2),
+ new CfArithmeticBinop(CfArithmeticBinop.Opcode.Sub, NumericType.LONG),
+ new CfCmp(Cmp.Bias.NONE, NumericType.LONG),
+ new CfIf(If.Type.LE, ValueType.INT, label2),
+ label1,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3, 4, 5},
+ new FrameType[] {
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType()
+ })),
+ new CfNew(factory.createType("Ljava/lang/IndexOutOfBoundsException;")),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfNew(factory.stringBuilderType),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfInvoke(
+ 183,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.voidType),
+ factory.createString("<init>")),
+ false),
+ new CfConstString(factory.createString("Range [")),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringBuilderType, factory.stringType),
+ factory.createString("append")),
+ false),
+ new CfLoad(ValueType.LONG, 0),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringBuilderType, factory.longType),
+ factory.createString("append")),
+ false),
+ new CfConstString(factory.createString(", ")),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringBuilderType, factory.stringType),
+ factory.createString("append")),
+ false),
+ new CfLoad(ValueType.LONG, 0),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringBuilderType, factory.longType),
+ factory.createString("append")),
+ false),
+ new CfConstString(factory.createString(" + ")),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringBuilderType, factory.stringType),
+ factory.createString("append")),
+ false),
+ new CfLoad(ValueType.LONG, 2),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringBuilderType, factory.longType),
+ factory.createString("append")),
+ false),
+ new CfConstString(factory.createString(") out of bounds for length ")),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringBuilderType, factory.stringType),
+ factory.createString("append")),
+ false),
+ new CfLoad(ValueType.LONG, 4),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringBuilderType, factory.longType),
+ factory.createString("append")),
+ false),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringType),
+ factory.createString("toString")),
+ false),
+ new CfInvoke(
+ 183,
+ factory.createMethod(
+ factory.createType("Ljava/lang/IndexOutOfBoundsException;"),
+ factory.createProto(factory.voidType, factory.stringType),
+ factory.createString("<init>")),
+ false),
+ new CfThrow(),
+ label2,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3, 4, 5},
+ new FrameType[] {
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType()
+ })),
+ new CfLoad(ValueType.LONG, 0),
+ new CfReturn(ValueType.LONG),
+ label3),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
public static CfCode ObjectsMethods_checkFromToIndex(DexItemFactory factory, DexMethod method) {
CfLabel label0 = new CfLabel();
CfLabel label1 = new CfLabel();
@@ -5933,6 +6175,135 @@
ImmutableList.of());
}
+ public static CfCode ObjectsMethods_checkFromToIndexLong(
+ DexItemFactory factory, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ CfLabel label3 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 5,
+ 6,
+ ImmutableList.of(
+ label0,
+ new CfLoad(ValueType.LONG, 0),
+ new CfConstNumber(0, ValueType.LONG),
+ new CfCmp(Cmp.Bias.NONE, NumericType.LONG),
+ new CfIf(If.Type.LT, ValueType.INT, label1),
+ new CfLoad(ValueType.LONG, 0),
+ new CfLoad(ValueType.LONG, 2),
+ new CfCmp(Cmp.Bias.NONE, NumericType.LONG),
+ new CfIf(If.Type.GT, ValueType.INT, label1),
+ new CfLoad(ValueType.LONG, 2),
+ new CfLoad(ValueType.LONG, 4),
+ new CfCmp(Cmp.Bias.NONE, NumericType.LONG),
+ new CfIf(If.Type.LE, ValueType.INT, label2),
+ label1,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3, 4, 5},
+ new FrameType[] {
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType()
+ })),
+ new CfNew(factory.createType("Ljava/lang/IndexOutOfBoundsException;")),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfNew(factory.stringBuilderType),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfInvoke(
+ 183,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.voidType),
+ factory.createString("<init>")),
+ false),
+ new CfConstString(factory.createString("Range [")),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringBuilderType, factory.stringType),
+ factory.createString("append")),
+ false),
+ new CfLoad(ValueType.LONG, 0),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringBuilderType, factory.longType),
+ factory.createString("append")),
+ false),
+ new CfConstString(factory.createString(", ")),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringBuilderType, factory.stringType),
+ factory.createString("append")),
+ false),
+ new CfLoad(ValueType.LONG, 2),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringBuilderType, factory.longType),
+ factory.createString("append")),
+ false),
+ new CfConstString(factory.createString(") out of bounds for length ")),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringBuilderType, factory.stringType),
+ factory.createString("append")),
+ false),
+ new CfLoad(ValueType.LONG, 4),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringBuilderType, factory.longType),
+ factory.createString("append")),
+ false),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringType),
+ factory.createString("toString")),
+ false),
+ new CfInvoke(
+ 183,
+ factory.createMethod(
+ factory.createType("Ljava/lang/IndexOutOfBoundsException;"),
+ factory.createProto(factory.voidType, factory.stringType),
+ factory.createString("<init>")),
+ false),
+ new CfThrow(),
+ label2,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3, 4, 5},
+ new FrameType[] {
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType()
+ })),
+ new CfLoad(ValueType.LONG, 0),
+ new CfReturn(ValueType.LONG),
+ label3),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
public static CfCode ObjectsMethods_checkIndex(DexItemFactory factory, DexMethod method) {
CfLabel label0 = new CfLabel();
CfLabel label1 = new CfLabel();
@@ -6022,6 +6393,110 @@
ImmutableList.of());
}
+ public static CfCode ObjectsMethods_checkIndexLong(DexItemFactory factory, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ CfLabel label3 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 5,
+ 4,
+ ImmutableList.of(
+ label0,
+ new CfLoad(ValueType.LONG, 0),
+ new CfConstNumber(0, ValueType.LONG),
+ new CfCmp(Cmp.Bias.NONE, NumericType.LONG),
+ new CfIf(If.Type.LT, ValueType.INT, label1),
+ new CfLoad(ValueType.LONG, 0),
+ new CfLoad(ValueType.LONG, 2),
+ new CfCmp(Cmp.Bias.NONE, NumericType.LONG),
+ new CfIf(If.Type.LT, ValueType.INT, label2),
+ label1,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3},
+ new FrameType[] {
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType()
+ })),
+ new CfNew(factory.createType("Ljava/lang/IndexOutOfBoundsException;")),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfNew(factory.stringBuilderType),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfInvoke(
+ 183,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.voidType),
+ factory.createString("<init>")),
+ false),
+ new CfConstString(factory.createString("Index ")),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringBuilderType, factory.stringType),
+ factory.createString("append")),
+ false),
+ new CfLoad(ValueType.LONG, 0),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringBuilderType, factory.longType),
+ factory.createString("append")),
+ false),
+ new CfConstString(factory.createString(" out of bounds for length ")),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringBuilderType, factory.stringType),
+ factory.createString("append")),
+ false),
+ new CfLoad(ValueType.LONG, 2),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringBuilderType, factory.longType),
+ factory.createString("append")),
+ false),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringType),
+ factory.createString("toString")),
+ false),
+ new CfInvoke(
+ 183,
+ factory.createMethod(
+ factory.createType("Ljava/lang/IndexOutOfBoundsException;"),
+ factory.createProto(factory.voidType, factory.stringType),
+ factory.createString("<init>")),
+ false),
+ new CfThrow(),
+ label2,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3},
+ new FrameType[] {
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.longType(),
+ FrameType.longHighType()
+ })),
+ new CfLoad(ValueType.LONG, 0),
+ new CfReturn(ValueType.LONG),
+ label3),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
public static CfCode ObjectsMethods_compare(DexItemFactory factory, DexMethod method) {
CfLabel label0 = new CfLabel();
CfLabel label1 = new CfLabel();
diff --git a/src/test/examplesJava17/backport/MathBackportJava17Main.java b/src/test/examplesJava17/backport/MathBackportJava17Main.java
new file mode 100644
index 0000000..7eeed95
--- /dev/null
+++ b/src/test/examplesJava17/backport/MathBackportJava17Main.java
@@ -0,0 +1,48 @@
+// Copyright (c) 2023, 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 MathBackportJava17Main {
+
+ public static void main(String[] args) {
+ // The methods are actually from Java 15, but we can test them from Java 17.
+ testAbsExactInteger();
+ testAbsExactLong();
+ }
+
+ private static void testAbsExactInteger() {
+ assertEquals(42, Math.absExact(42));
+ assertEquals(42, Math.absExact(-42));
+ assertEquals(Integer.MAX_VALUE, Math.absExact(Integer.MAX_VALUE));
+ try {
+ throw new AssertionError(Math.absExact(Integer.MIN_VALUE));
+ } catch (ArithmeticException expected) {
+
+ }
+ }
+
+ private static void testAbsExactLong() {
+ assertEquals(42L, Math.absExact(42L));
+ assertEquals(42L, Math.absExact(-42L));
+ assertEquals(Long.MAX_VALUE, Math.absExact(Long.MAX_VALUE));
+ try {
+ throw new AssertionError(Math.absExact(Long.MIN_VALUE));
+ } catch (ArithmeticException expected) {
+
+ }
+ }
+
+ 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/examplesJava17/backport/ObjectsBackportJava17Main.java b/src/test/examplesJava17/backport/ObjectsBackportJava17Main.java
new file mode 100644
index 0000000..b950c17
--- /dev/null
+++ b/src/test/examplesJava17/backport/ObjectsBackportJava17Main.java
@@ -0,0 +1,116 @@
+// Copyright (c) 2023, 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;
+
+import java.util.Objects;
+
+public class ObjectsBackportJava17Main {
+
+ public static void main(String[] args) {
+ // The methods are actually from Java 16, but we can test them from Java 17.
+ testCheckIndex();
+ testCheckFromToIndex();
+ testCheckFromIndexSize();
+ }
+
+ private static void testCheckIndex() {
+ for (long i = 0L; i < 10L; i++) {
+ assertEquals(i, Objects.checkIndex(i, 10L));
+ }
+
+ try {
+ throw new AssertionError(Objects.checkIndex(-1L, 10L));
+ } catch (IndexOutOfBoundsException expected) {
+ }
+ try {
+ throw new AssertionError(Objects.checkIndex(10L, 0L));
+ } catch (IndexOutOfBoundsException expected) {
+ }
+ try {
+ throw new AssertionError(Objects.checkIndex(0L, 0L));
+ } catch (IndexOutOfBoundsException expected) {
+ }
+ }
+
+ private static void testCheckFromToIndex() {
+ for (long i = 0L; i <= 10L; i++) {
+ for (long j = i; j <= 10L; j++) {
+ assertEquals(i, Objects.checkFromToIndex(i, j, 10L));
+ }
+ }
+ assertEquals(0L, Objects.checkFromToIndex(0L, 0L, 0L));
+
+ try {
+ throw new AssertionError(Objects.checkFromToIndex(4L, 2L, 10L));
+ } catch (IndexOutOfBoundsException expected) {
+ }
+ try {
+ throw new AssertionError(Objects.checkFromToIndex(-1L, 5L, 10L));
+ } catch (IndexOutOfBoundsException expected) {
+ }
+ try {
+ throw new AssertionError(Objects.checkFromToIndex(0L, -1L, 10L));
+ } catch (IndexOutOfBoundsException expected) {
+ }
+ try {
+ throw new AssertionError(Objects.checkFromToIndex(11L, 11L, 10L));
+ } catch (IndexOutOfBoundsException expected) {
+ }
+ try {
+ throw new AssertionError(Objects.checkFromToIndex(0L, 1L, 0L));
+ } catch (IndexOutOfBoundsException expected) {
+ }
+ try {
+ throw new AssertionError(Objects.checkFromToIndex(1L, 1L, 0L));
+ } catch (IndexOutOfBoundsException expected) {
+ }
+ }
+
+ private static void testCheckFromIndexSize() {
+ for (long i = 0L; i <= 10L; i++) {
+ for (long j = 10L - i; j >= 0L; j--) {
+ assertEquals(i, Objects.checkFromIndexSize(i, j, 10L));
+ }
+ }
+ assertEquals(0, Objects.checkFromIndexSize(0L, 0L, 0L));
+
+ try {
+ throw new AssertionError(Objects.checkFromIndexSize(8L, 4L, 10L));
+ } catch (IndexOutOfBoundsException expected) {
+ }
+ try {
+ throw new AssertionError(Objects.checkFromIndexSize(-1L, 5L, 10L));
+ } catch (IndexOutOfBoundsException expected) {
+ }
+ try {
+ throw new AssertionError(Objects.checkFromIndexSize(11L, 0L, 10L));
+ } catch (IndexOutOfBoundsException expected) {
+ }
+ try {
+ throw new AssertionError(Objects.checkFromIndexSize(0L, 1L, 0L));
+ } catch (IndexOutOfBoundsException expected) {
+ }
+ try {
+ throw new AssertionError(Objects.checkFromIndexSize(1L, 1L, 0L));
+ } catch (IndexOutOfBoundsException expected) {
+ }
+
+ // Check for cases where overflow might occur producing incorrect results.
+ try {
+ throw new AssertionError(Objects.checkFromIndexSize(Long.MAX_VALUE, 1L, Long.MAX_VALUE));
+ } catch (IndexOutOfBoundsException expected) {
+ }
+ try {
+ throw new AssertionError(Objects.checkFromIndexSize(0L, 1L, Long.MIN_VALUE));
+ } catch (IndexOutOfBoundsException expected) {
+ }
+ }
+
+ private static void assertEquals(long expected, long actual) {
+ if (expected != actual) {
+ throw new AssertionError("Expected <" + expected + "> but was <" + actual + '>');
+ }
+ }
+}
diff --git a/src/test/examplesJava17/backport/StrictMathBackportJava17Main.java b/src/test/examplesJava17/backport/StrictMathBackportJava17Main.java
new file mode 100644
index 0000000..028e24f
--- /dev/null
+++ b/src/test/examplesJava17/backport/StrictMathBackportJava17Main.java
@@ -0,0 +1,119 @@
+// Copyright (c) 2023, 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 StrictMathBackportJava17Main {
+
+ public static void main(String[] args) {
+ // The methods are actually from Java 15, but we can test them from Java 17.
+ testAbsExactInteger();
+ testAbsExactLong();
+ // The methods are actually from Java 14, but we can test them from Java 17.
+ testDecrementExactInteger();
+ testDecrementExactLong();
+ testIncrementExactInteger();
+ testIncrementExactLong();
+ testNegateExactInteger();
+ testNegateExactLong();
+ }
+
+ private static void testAbsExactInteger() {
+ assertEquals(42, StrictMath.absExact(42));
+ assertEquals(42, StrictMath.absExact(-42));
+ assertEquals(Integer.MAX_VALUE, StrictMath.absExact(Integer.MAX_VALUE));
+ try {
+ throw new AssertionError(StrictMath.absExact(Integer.MIN_VALUE));
+ } catch (ArithmeticException expected) {
+
+ }
+ }
+
+ private static void testAbsExactLong() {
+ assertEquals(42L, StrictMath.absExact(42L));
+ assertEquals(42L, StrictMath.absExact(-42L));
+ assertEquals(Long.MAX_VALUE, StrictMath.absExact(Long.MAX_VALUE));
+ try {
+ throw new AssertionError(StrictMath.absExact(Long.MIN_VALUE));
+ } catch (ArithmeticException expected) {
+
+ }
+ }
+
+ private static void testDecrementExactInteger() {
+ assertEquals(-1, StrictMath.decrementExact(0));
+ assertEquals(Integer.MIN_VALUE, StrictMath.decrementExact(Integer.MIN_VALUE + 1));
+
+ try {
+ throw new AssertionError(StrictMath.decrementExact(Integer.MIN_VALUE));
+ } catch (ArithmeticException expected) {
+ }
+ }
+
+ private static void testDecrementExactLong() {
+ assertEquals(-1L, StrictMath.decrementExact(0L));
+ assertEquals(Long.MIN_VALUE, StrictMath.decrementExact(Long.MIN_VALUE + 1L));
+
+ try {
+ throw new AssertionError(StrictMath.decrementExact(Long.MIN_VALUE));
+ } catch (ArithmeticException expected) {
+ }
+ }
+
+ private static void testIncrementExactInteger() {
+ assertEquals(1, StrictMath.incrementExact(0));
+ assertEquals(Integer.MAX_VALUE, StrictMath.incrementExact(Integer.MAX_VALUE - 1));
+
+ try {
+ throw new AssertionError(StrictMath.incrementExact(Integer.MAX_VALUE));
+ } catch (ArithmeticException expected) {
+ }
+ }
+
+ private static void testIncrementExactLong() {
+ assertEquals(1L, StrictMath.incrementExact(0L));
+ assertEquals(Long.MAX_VALUE, StrictMath.incrementExact(Long.MAX_VALUE - 1L));
+
+ try {
+ throw new AssertionError(StrictMath.incrementExact(Long.MAX_VALUE));
+ } catch (ArithmeticException expected) {
+ }
+ }
+
+ private static void testNegateExactInteger() {
+ assertEquals(0, StrictMath.negateExact(0));
+ assertEquals(-1, StrictMath.negateExact(1));
+ assertEquals(1, StrictMath.negateExact(-1));
+ assertEquals(-2_147_483_647, StrictMath.negateExact(Integer.MAX_VALUE));
+
+ try {
+ throw new AssertionError(StrictMath.negateExact(Integer.MIN_VALUE));
+ } catch (ArithmeticException expected) {
+ }
+ }
+
+ private static void testNegateExactLong() {
+ assertEquals(0L, StrictMath.negateExact(0L));
+ assertEquals(-1L, StrictMath.negateExact(1L));
+ assertEquals(1L, StrictMath.negateExact(-1L));
+ assertEquals(-9_223_372_036_854_775_807L, StrictMath.negateExact(Long.MAX_VALUE));
+
+ try {
+ throw new AssertionError(StrictMath.negateExact(Long.MIN_VALUE));
+ } catch (ArithmeticException expected) {
+ }
+ }
+
+ 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/desugar/backports/MathBackportJava17Test.java b/src/test/java/com/android/tools/r8/desugar/backports/MathBackportJava17Test.java
new file mode 100644
index 0000000..fde89f0
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/MathBackportJava17Test.java
@@ -0,0 +1,40 @@
+// Copyright (c) 2023, 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.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
+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 MathBackportJava17Test extends AbstractBackportTest {
+ @Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ return getTestParameters()
+ .withDexRuntimes()
+ .withAllApiLevels()
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
+ .build();
+ }
+
+ private static final Path TEST_JAR =
+ Paths.get(ToolHelper.TESTS_BUILD_DIR).resolve("examplesJava17/backport" + JAR_EXTENSION);
+
+ public MathBackportJava17Test(TestParameters parameters) {
+ super(parameters, Math.class, TEST_JAR, "backport.MathBackportJava17Main");
+
+ // Math.absExact.
+ // The exact number needs to be updated once we test Android U.
+ registerTarget(AndroidApiLevel.U, 27);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ObjectsBackportJava17Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ObjectsBackportJava17Test.java
new file mode 100644
index 0000000..d54a044
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ObjectsBackportJava17Test.java
@@ -0,0 +1,41 @@
+// Copyright (c) 2023, 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.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Objects;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public final class ObjectsBackportJava17Test extends AbstractBackportTest {
+ @Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ return getTestParameters()
+ .withDexRuntimes()
+ .withAllApiLevels()
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
+ .build();
+ }
+
+ private static final Path TEST_JAR =
+ Paths.get(ToolHelper.TESTS_BUILD_DIR).resolve("examplesJava17/backport" + JAR_EXTENSION);
+ private static final String TEST_CLASS = "backport.ObjectsBackportJava17Main";
+
+ public ObjectsBackportJava17Test(TestParameters parameters) {
+ super(parameters, Objects.class, TEST_JAR, TEST_CLASS);
+ // Objects.checkFromIndexSize, Objects.checkFromToIndex, Objects.checkIndex.
+ // The exact number needs to be updated once we test Android U.
+ registerTarget(AndroidApiLevel.U, 28);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/StrictMathBackportJava17Test.java b/src/test/java/com/android/tools/r8/desugar/backports/StrictMathBackportJava17Test.java
new file mode 100644
index 0000000..3089d40
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/StrictMathBackportJava17Test.java
@@ -0,0 +1,39 @@
+// Copyright (c) 2023, 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.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
+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 StrictMathBackportJava17Test extends AbstractBackportTest {
+
+ @Parameters(name = "{0}")
+ public static Iterable<?> data() {
+ return getTestParameters()
+ .withDexRuntimes()
+ .withAllApiLevels()
+ .withCfRuntimesStartingFromIncluding(CfVm.JDK17)
+ .build();
+ }
+
+ private static final Path TEST_JAR =
+ Paths.get(ToolHelper.TESTS_BUILD_DIR).resolve("examplesJava17/backport" + JAR_EXTENSION);
+
+ public StrictMathBackportJava17Test(TestParameters parameters) {
+ super(parameters, StrictMath.class, TEST_JAR, "backport.StrictMathBackportJava17Main");
+ // The exact number needs to be updated once we test Android U.
+ registerTarget(AndroidApiLevel.U, 75);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/MathMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/MathMethods.java
index a41259d..84b218b 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/backports/MathMethods.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/MathMethods.java
@@ -227,4 +227,18 @@
}
return result;
}
+
+ public static int absExact(int a) {
+ if (a == Integer.MIN_VALUE) {
+ throw new ArithmeticException();
+ }
+ return Math.abs(a);
+ }
+
+ public static long absExactLong(long a) {
+ if (a == Long.MIN_VALUE) {
+ throw new ArithmeticException();
+ }
+ return Math.abs(a);
+ }
}
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/ObjectsMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/ObjectsMethods.java
index 566d8f2..f8e31b0 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/backports/ObjectsMethods.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/ObjectsMethods.java
@@ -131,4 +131,34 @@
}
return fromIndex;
}
+
+ public static long checkIndexLong(long index, long length) {
+ if (index < 0 || index >= length) {
+ throw new IndexOutOfBoundsException("Index " + index + " out of bounds for length " + length);
+ }
+ return index;
+ }
+
+ public static long checkFromToIndexLong(long fromIndex, long toIndex, long length) {
+ if (fromIndex < 0 || fromIndex > toIndex || toIndex > length) {
+ throw new IndexOutOfBoundsException(
+ "Range [" + fromIndex + ", " + toIndex + ") out of bounds for length " + length);
+ }
+ return fromIndex;
+ }
+
+ public static long checkFromIndexSizeLong(long fromIndex, long size, long length) {
+ if (fromIndex < 0 || size < 0 || length < 0 || fromIndex > length - size) {
+ throw new IndexOutOfBoundsException(
+ "Range ["
+ + fromIndex
+ + ", "
+ + fromIndex
+ + " + "
+ + size
+ + ") out of bounds for length "
+ + length);
+ }
+ return fromIndex;
+ }
}