Add support for backporting List.of(E...)

Test: tools/test.py --no-internal -v *ListBackportJava9Test*
Change-Id: I2cc66c3f299f86694118f2426c60d4f245354d92
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 aeb1dd5..b47dced 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
@@ -925,18 +925,17 @@
       method = factory.createMethod(type, proto, name);
       addProvider(new MethodGenerator(method, ObjectsMethods::new));
 
-      // List of
+      // List<E> List.of(<args>) for 0 to 10 arguments and List.of(E[])
       type = factory.listType;
       name = factory.createString("of");
-
-      // From 0 to 10 arguments.
-      ArrayList<DexType> parameters = new ArrayList<>();
       for (int i = 0; i <= 10; i++) {
-        proto = factory.createProto(factory.listType, parameters);
+        proto = factory.createProto(factory.listType, Collections.nCopies(i, factory.objectType));
         method = factory.createMethod(type, proto, name);
         addProvider(new MethodGenerator(method, ListMethods::new));
-        parameters.add(factory.objectType);
       }
+      proto = factory.createProto(factory.listType, factory.objectArrayType);
+      method = factory.createMethod(type, proto, name);
+      addProvider(new MethodGenerator(method, ListMethods::new, "ofArray"));
     }
 
     private void initializeJava11MethodProviders(DexItemFactory factory) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/ListMethods.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/ListMethods.java
index 9aec5f0..736a476 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/backports/ListMethods.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/ListMethods.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.ir.synthetic.TemplateMethodCode;
 import com.android.tools.r8.utils.InternalOptions;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
@@ -140,4 +141,14 @@
             Objects.requireNonNull(e9),
             Objects.requireNonNull(e10)));
   }
+
+  public static <E> List<E> ofArray(E[] elements) {
+    // TODO(140709356): The other overloads should call into this method to ensure consistent
+    //  behavior, but we cannot link against List.of(E[]) because it's only available in Java 9.
+    ArrayList<E> list = new ArrayList<>(elements.length);
+    for (E element : elements) {
+      list.add(Objects.requireNonNull(element));
+    }
+    return Collections.unmodifiableList(list);
+  }
 }
diff --git a/src/test/examplesJava9/backport/ListBackportJava9Main.java b/src/test/examplesJava9/backport/ListBackportJava9Main.java
index 88d20ab..4c8ae88 100644
--- a/src/test/examplesJava9/backport/ListBackportJava9Main.java
+++ b/src/test/examplesJava9/backport/ListBackportJava9Main.java
@@ -13,6 +13,7 @@
     testOf1();
     testOf2();
     testOf10();
+    testOfVarargs();
   }
 
   private static void testOf0() {
@@ -103,6 +104,45 @@
     }
   }
 
+  private static void testOfVarargs() {
+    Object anObject0 = new Object();
+    Object anObject6 = new Object();
+    Object anObject10 = new Object();
+    List<Object> ofObject =
+        List.of(anObject0, new Object(), new Object(), new Object(), new Object(), new Object(),
+            anObject6, new Object(), new Object(), new Object(), anObject10);
+    assertEquals(11, ofObject.size());
+    assertSame(anObject0, ofObject.get(0));
+    assertSame(anObject6, ofObject.get(6));
+    assertSame(anObject10, ofObject.get(10));
+    assertMutationNotAllowed(ofObject);
+
+    List<Integer> ofInteger = List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+    assertEquals(11, ofInteger.size());
+    assertEquals(0, ofInteger.get(0));
+    assertEquals(6, ofInteger.get(6));
+    assertEquals(10, ofInteger.get(10));
+
+    List<Object> ofMixed = List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, anObject10);
+    assertEquals(11, ofMixed.size());
+    assertEquals(0, ofMixed.get(0));
+    assertEquals(6, ofMixed.get(6));
+    assertSame(anObject10, ofMixed.get(10));
+    assertMutationNotAllowed(ofMixed);
+
+    // Ensure the supplied mutable array is not used directly since it is mutable.
+    Object[] mutableArray = { anObject0 };
+    List<Object> ofMutableArray = List.of(mutableArray);
+    mutableArray[0] = anObject10;
+    assertSame(anObject0, ofMutableArray.get(0));
+
+    try {
+      List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, null);
+      throw new AssertionError();
+    } catch (NullPointerException expected) {
+    }
+  }
+
   private static void assertMutationNotAllowed(List<Object> ofObject) {
     try {
       ofObject.add(new Object());