Backport Java 9 Map.entry factory

Test: tools/test.py --dex_vm all --no-internal -v *Backport*Test*
Test: tools/test.py --no-internal -v *GenerateBackportMethods*
Change-Id: Ieffa2fbc7e93d51a54209c8f5f1c208963136f13
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 b796600..f6f34e6 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
@@ -1056,6 +1056,12 @@
       addProvider(
           new MethodGenerator(
               method, BackportedMethods::CollectionMethods_mapOfEntries, "ofEntries"));
+
+      // Map.Entry<K, V> Map.entry(K, V)
+      type = factory.mapType;
+      proto = factory.createProto(factory.mapEntryType, factory.objectType, factory.objectType);
+      method = factory.createMethod(type, proto, "entry");
+      addProvider(new MethodGenerator(method, BackportedMethods::CollectionMethods_mapEntry));
     }
 
     private void initializeJava11MethodProviders(DexItemFactory factory) {
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 aadf9e5..864099b 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
@@ -597,6 +597,60 @@
         ImmutableList.of());
   }
 
+  public static CfCode CollectionMethods_mapEntry(InternalOptions options, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        4,
+        2,
+        ImmutableList.of(
+            label0,
+            new CfNew(
+                options.itemFactory.createType("Ljava/util/AbstractMap$SimpleImmutableEntry;")),
+            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+            new CfLoad(ValueType.OBJECT, 0),
+            label1,
+            new CfInvoke(
+                184,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Objects;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/lang/Object;"),
+                        options.itemFactory.createType("Ljava/lang/Object;")),
+                    options.itemFactory.createString("requireNonNull")),
+                false),
+            new CfLoad(ValueType.OBJECT, 1),
+            label2,
+            new CfInvoke(
+                184,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Objects;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/lang/Object;"),
+                        options.itemFactory.createType("Ljava/lang/Object;")),
+                    options.itemFactory.createString("requireNonNull")),
+                false),
+            new CfInvoke(
+                183,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/AbstractMap$SimpleImmutableEntry;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("V"),
+                        options.itemFactory.createType("Ljava/lang/Object;"),
+                        options.itemFactory.createType("Ljava/lang/Object;")),
+                    options.itemFactory.createString("<init>")),
+                false),
+            label3,
+            new CfReturn(ValueType.OBJECT),
+            label4),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
   public static CfCode CollectionMethods_mapOfEntries(InternalOptions options, DexMethod method) {
     CfLabel label0 = new CfLabel();
     CfLabel label1 = new CfLabel();
diff --git a/src/test/examplesJava9/backport/MapBackportJava9Main.java b/src/test/examplesJava9/backport/MapBackportJava9Main.java
index 2aa5cfd..442fd9b 100644
--- a/src/test/examplesJava9/backport/MapBackportJava9Main.java
+++ b/src/test/examplesJava9/backport/MapBackportJava9Main.java
@@ -15,6 +15,7 @@
     testOf2();
     testOf10();
     testOfEntries();
+    testEntry();
   }
 
   private static void testOf0() {
@@ -218,6 +219,31 @@
     }
   }
 
+  private static void testEntry() {
+    Object key = new Object();
+    Object value = new Object();
+    Map.Entry<Object, Object> entry = Map.entry(key, value);
+    assertSame(key, entry.getKey());
+    assertSame(value, entry.getValue());
+
+    try {
+      entry.setValue(new Object());
+      throw new AssertionError();
+    } catch (UnsupportedOperationException expected) {
+    }
+
+    try {
+      Map.entry(null, value);
+      throw new AssertionError();
+    } catch (NullPointerException expected) {
+    }
+    try {
+      Map.entry(key, null);
+      throw new AssertionError();
+    } catch (NullPointerException expected) {
+    }
+  }
+
   private static void assertMutationNotAllowed(Map<Object, Object> ofObject) {
     try {
       ofObject.put(new Object(), new Object());
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/CollectionMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/CollectionMethods.java
index 0dd1a53..ae3aef1 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/backports/CollectionMethods.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/CollectionMethods.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.ir.desugar.backports;
 
+import java.util.AbstractMap;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -44,4 +45,10 @@
     }
     return Collections.unmodifiableMap(map);
   }
+
+  public static <K, V> Map.Entry<K, V> mapEntry(K key, V value) {
+    return new AbstractMap.SimpleImmutableEntry<>(
+        Objects.requireNonNull(key),
+        Objects.requireNonNull(value));
+  }
 }