Rewrite Float.hashCode to Float.floatToIntBits

Test: tools/test.py --dex_vm all --no-internal -v *Backport*Test*
Test: tools/test.py --no-internal -v *GenerateBackportMethods*
Change-Id: I5c35b420c0f54a6a4d43d84fa73c422c9006b3db
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 cbc2c64..730a743 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
@@ -31,6 +31,7 @@
 import com.android.tools.r8.ir.conversion.IRConverter;
 import com.android.tools.r8.ir.desugar.backports.BackportedMethods;
 import com.android.tools.r8.ir.desugar.backports.BooleanMethodRewrites;
+import com.android.tools.r8.ir.desugar.backports.FloatMethodRewrites;
 import com.android.tools.r8.ir.desugar.backports.ListMethodRewrites;
 import com.android.tools.r8.ir.desugar.backports.LongMethodRewrites;
 import com.android.tools.r8.ir.desugar.backports.NumericMethodRewrites;
@@ -481,7 +482,7 @@
       name = factory.createString("hashCode");
       proto = factory.createProto(factory.intType, factory.floatType);
       method = factory.createMethod(type, proto, name);
-      addProvider(new MethodGenerator(method, BackportedMethods::FloatMethods_hashCode));
+      addProvider(new InvokeRewriter(method, FloatMethodRewrites::rewriteHashCode));
 
       // float Float.max(float a, float b)
       name = factory.createString("max");
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 5046c2f..d9beda9 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
@@ -712,31 +712,6 @@
         ImmutableList.of());
   }
 
-  public static CfCode FloatMethods_hashCode(
-      InternalOptions options, DexMethod method, String name) {
-    CfLabel label0 = new CfLabel();
-    CfLabel label1 = new CfLabel();
-    return new CfCode(
-        method.holder,
-        1,
-        1,
-        ImmutableList.of(
-            label0,
-            new CfLoad(ValueType.FLOAT, 0),
-            new CfInvoke(
-                184,
-                options.itemFactory.createMethod(
-                    options.itemFactory.createType("Ljava/lang/Float;"),
-                    options.itemFactory.createProto(
-                        options.itemFactory.createType("I"), options.itemFactory.createType("F")),
-                    options.itemFactory.createString("floatToIntBits")),
-                false),
-            new CfReturn(ValueType.INT),
-            label1),
-        ImmutableList.of(),
-        ImmutableList.of());
-  }
-
   public static CfCode FloatMethods_isFinite(
       InternalOptions options, DexMethod method, String name) {
     CfLabel label0 = new CfLabel();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/FloatMethodRewrites.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/FloatMethodRewrites.java
new file mode 100644
index 0000000..9a4ef45
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/FloatMethodRewrites.java
@@ -0,0 +1,23 @@
+// 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.DexItemFactory;
+import com.android.tools.r8.ir.code.InstructionListIterator;
+import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.code.InvokeStatic;
+
+public final class FloatMethodRewrites {
+
+  private FloatMethodRewrites() {}
+
+  public static void rewriteHashCode(
+      InvokeMethod invoke, InstructionListIterator iterator, DexItemFactory factory) {
+    InvokeStatic mathInvoke = new InvokeStatic(
+        factory.createMethod(factory.boxedFloatType, invoke.getInvokedMethod().proto,
+            "floatToIntBits"), invoke.outValue(), invoke.inValues(), false);
+    iterator.replaceCurrentInstruction(mathInvoke);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/AbstractBackportTest.java b/src/test/java/com/android/tools/r8/desugar/backports/AbstractBackportTest.java
index c61433b..6cd2bdf 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/AbstractBackportTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/AbstractBackportTest.java
@@ -19,8 +19,10 @@
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import java.io.IOException;
 import java.nio.file.Path;
+import java.util.HashSet;
 import java.util.List;
 import java.util.NavigableMap;
+import java.util.Set;
 import java.util.TreeMap;
 import org.junit.Assert;
 import org.junit.Test;
@@ -32,6 +34,7 @@
   private final Path testJar;
   private final String testClassName;
   private final NavigableMap<AndroidApiLevel, Integer> invokeStaticCounts = new TreeMap<>();
+  private final Set<String> ignoredInvokes = new HashSet<>();
 
   AbstractBackportTest(TestParameters parameters, Class<?> targetClass,
       Class<?> testClass) {
@@ -68,6 +71,10 @@
     invokeStaticCounts.put(apiLevel, invokeStaticCount);
   }
 
+  void ignoreInvokes(String methodName) {
+    ignoredInvokes.add(methodName);
+  }
+
   private void configureProgram(TestBuilder<?, ?> builder) throws IOException {
     builder.addProgramClasses(MiniAssert.class, IgnoreInvokes.class);
     if (testClass != null) {
@@ -106,6 +113,8 @@
         .flatMap(MethodSubject::streamInstructions)
         .filter(InstructionSubject::isInvoke)
         .filter(is -> is.getMethod().holder.toSourceString().equals(targetClass.getName()))
+        // Do not count invokes if explicitly ignored.
+        .filter(is -> !ignoredInvokes.contains(is.getMethod().name.toString()))
         .collect(toList());
 
     AndroidApiLevel apiLevel = parameters.getRuntime().asDex().getMinApiLevel();
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/FloatBackportTest.java b/src/test/java/com/android/tools/r8/desugar/backports/FloatBackportTest.java
index d20122b..d8c1f8d 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/FloatBackportTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/FloatBackportTest.java
@@ -20,6 +20,7 @@
   public FloatBackportTest(TestParameters parameters) {
     super(parameters, Float.class, Main.class);
     registerTarget(AndroidApiLevel.N, 10);
+    ignoreInvokes("floatToIntBits"); // Available in API 1, used to backport hashCode.
   }
 
   static final class Main extends MiniAssert {
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/FloatMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/FloatMethods.java
index 3b4932f..a452fea 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/backports/FloatMethods.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/FloatMethods.java
@@ -6,10 +6,6 @@
 
 public final class FloatMethods {
 
-  public static int hashCode(float f) {
-    return Float.floatToIntBits(f);
-  }
-
   public static boolean isFinite(float f) {
     return !Float.isInfinite(f) && !Float.isNaN(f);
   }