Version 1.4.88

Cherry pick: Add desugaring of Java 8 Long and Character methods
CL: https://r8-review.googlesource.com/c/r8/+/36620

Bug:  129730297
Change-Id: I3ac7df7277dfea4d49b0633ba7d05c5a4241e03b
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 4cf066b..18c648d 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
 
   // This field is accessed from release scripts using simple pattern matching.
   // Therefore, changing this field could break our release scripts.
-  public static final String LABEL = "1.4.87";
+  public static final String LABEL = "1.4.88";
 
   private Version() {
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java
index e930bcf..e52b73f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java
@@ -351,6 +351,58 @@
     }
   }
 
+  private static final class LongMethods extends TemplateMethodCode {
+    LongMethods(InternalOptions options, DexMethod method, String methodName) {
+      super(options, method, methodName, method.proto.toDescriptorString());
+    }
+
+    public static LongMethods hashCodeCode(InternalOptions options, DexMethod method) {
+      return new LongMethods(options, method, "hashCodeImpl");
+    }
+
+    public static LongMethods maxCode(InternalOptions options, DexMethod method) {
+      return new LongMethods(options, method, "maxImpl");
+    }
+
+    public static LongMethods minCode(InternalOptions options, DexMethod method) {
+      return new LongMethods(options, method, "minImpl");
+    }
+
+    public static LongMethods sumCode(InternalOptions options, DexMethod method) {
+      return new LongMethods(options, method, "sumImpl");
+    }
+
+    public static int hashCodeImpl(long i) {
+      return Long.valueOf(i).hashCode();
+    }
+
+    public static long maxImpl(long a, long b) {
+      return java.lang.Math.max(a, b);
+    }
+
+    public static long minImpl(long a, long b) {
+      return java.lang.Math.min(a, b);
+    }
+
+    public static long sumImpl(long a, long b) {
+      return a + b;
+    }
+  }
+
+  private static final class CharacterMethods extends TemplateMethodCode {
+    CharacterMethods(InternalOptions options, DexMethod method, String methodName) {
+      super(options, method, methodName, method.proto.toDescriptorString());
+    }
+
+    public static CharacterMethods hashCodeCode(InternalOptions options, DexMethod method) {
+      return new CharacterMethods(options, method, "hashCodeImpl");
+    }
+
+    public static int hashCodeImpl(char i) {
+      return Character.valueOf(i).hashCode();
+    }
+  }
+
   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;
@@ -493,6 +545,42 @@
       proto = factory.createProto(factory.booleanType, factory.booleanType, factory.booleanType);
       addOrGetMethod(clazz, method)
           .put(proto, new MethodGenerator(BooleanMethods::logicalXorCode, clazz, method, proto));
+
+      // Long
+      clazz = factory.boxedLongDescriptor;
+
+      // int Long.hashCode(long i)
+      method = factory.createString("hashCode");
+      proto = factory.createProto(factory.intType, factory.longType);
+      addOrGetMethod(clazz, method)
+          .put(proto, new MethodGenerator(LongMethods::hashCodeCode, clazz, method, proto));
+
+      // long Long.max(long a, long b)
+      method = factory.createString("max");
+      proto = factory.createProto(factory.longType, factory.longType, factory.longType);
+      addOrGetMethod(clazz, method)
+          .put(proto, new MethodGenerator(LongMethods::maxCode, clazz, method, proto));
+
+      // long Long.min(long a, long b)
+      method = factory.createString("min");
+      proto = factory.createProto(factory.longType, factory.longType, factory.longType);
+      addOrGetMethod(clazz, method)
+          .put(proto, new MethodGenerator(LongMethods::minCode, clazz, method, proto));
+
+      // long Long.sum(long a, long b)
+      method = factory.createString("sum");
+      proto = factory.createProto(factory.longType, factory.longType, factory.longType);
+      addOrGetMethod(clazz, method)
+          .put(proto, new MethodGenerator(LongMethods::sumCode, clazz, method, proto));
+
+      // Character
+      clazz = factory.boxedCharDescriptor;
+
+      // int Character.hashCode(char i)
+      method = factory.createString("hashCode");
+      proto = factory.createProto(factory.intType, factory.charType);
+      addOrGetMethod(clazz, method)
+          .put(proto, new MethodGenerator(CharacterMethods::hashCodeCode, clazz, method, proto));
     }
 
     private Map<DexString, Map<DexProto, MethodGenerator>> addOrGetClass(DexString clazz) {
diff --git a/src/test/java/com/android/tools/r8/desugar/Java8MethodsTest.java b/src/test/java/com/android/tools/r8/desugar/Java8MethodsTest.java
index 4d5ade8..e8fc973 100644
--- a/src/test/java/com/android/tools/r8/desugar/Java8MethodsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/Java8MethodsTest.java
@@ -145,6 +145,22 @@
           System.out.println(Boolean.logicalXor(aBoolean, bBoolean));
         }
       }
+
+      long[] aLongs = new long[]{42L, 1L, -1L, Long.MAX_VALUE, Long.MIN_VALUE};
+      long[] bLongs = new long[]{43L, 2L, -2L, Long.MAX_VALUE, Long.MIN_VALUE};
+      for (long aLong : aLongs) {
+        System.out.println(Long.hashCode(aLong));
+        for (long bLong : bLongs) {
+          System.out.println(Long.max(aLong, bLong));
+          System.out.println(Long.min(aLong, bLong));
+          System.out.println(Long.sum(aLong, bLong));
+        }
+      }
+
+      char[] aChars = new char[]{'s', 'u', 'p', Character.MAX_VALUE, Character.MIN_VALUE};
+      for (char aChar : aChars) {
+        System.out.println(Character.hashCode(aChar));
+      }
     }
   }
 }