Backport Set.of factories

Test: tools/test.py --dex_vm all --no-internal -v *Backport*Test*
Test: tools/test.py --no-internal -v *GenerateBackportMethods*
Change-Id: I7c351021c1bcb420e197f664aeea832d1c5aaeca
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index 36e4cc8..9c08a90 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -214,6 +214,7 @@
   public final DexString proxyDescriptor = createString("Ljava/lang/reflect/Proxy;");
   public final DexString serviceLoaderDescriptor = createString("Ljava/util/ServiceLoader;");
   public final DexString listDescriptor = createString("Ljava/util/List;");
+  public final DexString setDescriptor = createString("Ljava/util/Set;");
   public final DexString comparatorDescriptor = createString("Ljava/util/Comparator;");
   public final DexString callableDescriptor = createString("Ljava/util/concurrent/Callable;");
   public final DexString supplierDescriptor = createString("Ljava/util/function/Supplier;");
@@ -302,6 +303,7 @@
   public final DexType proxyType = createType(proxyDescriptor);
   public final DexType serviceLoaderType = createType(serviceLoaderDescriptor);
   public final DexType listType = createType(listDescriptor);
+  public final DexType setType = createType(setDescriptor);
   public final DexType comparatorType = createType(comparatorDescriptor);
   public final DexType callableType = createType(callableDescriptor);
   public final DexType supplierType = createType(supplierDescriptor);
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 0e13782..13c599e 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,9 +31,9 @@
 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.CollectionMethodGenerators;
+import com.android.tools.r8.ir.desugar.backports.CollectionMethodRewrites;
 import com.android.tools.r8.ir.desugar.backports.FloatMethodRewrites;
-import com.android.tools.r8.ir.desugar.backports.ListMethodGenerators;
-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;
 import com.android.tools.r8.ir.desugar.backports.ObjectsMethodRewrites;
@@ -1003,15 +1003,38 @@
         method = factory.createMethod(type, proto, name);
         addProvider(
             i == 0
-                ? new InvokeRewriter(method, ListMethodRewrites::rewriteEmptyOf)
+                ? new InvokeRewriter(method, CollectionMethodRewrites::rewriteListOfEmpty)
                 : new MethodGenerator(
                     method,
                     (options, methodArg, ignored) ->
-                        ListMethodGenerators.generateListOf(options, methodArg, formalCount)));
+                        CollectionMethodGenerators.generateListOf(options, methodArg, formalCount)));
       }
       proto = factory.createProto(factory.listType, factory.objectArrayType);
       method = factory.createMethod(type, proto, name);
-      addProvider(new MethodGenerator(method, BackportedMethods::ListMethods_ofArray, "ofArray"));
+      addProvider(
+          new MethodGenerator(
+              method, BackportedMethods::CollectionMethods_listOfArray, "ofArray"));
+
+      // Set<E> Set.of(<args>) for 0 to 10 arguments and Set.of(E[])
+      type = factory.setType;
+      name = factory.createString("of");
+      for (int i = 0; i <= 10; i++) {
+        final int formalCount = i;
+        proto = factory.createProto(factory.setType, Collections.nCopies(i, factory.objectType));
+        method = factory.createMethod(type, proto, name);
+        addProvider(
+            i == 0
+                ? new InvokeRewriter(method, CollectionMethodRewrites::rewriteSetOfEmpty)
+                : new MethodGenerator(
+                    method,
+                    (options, methodArg, ignored) ->
+                        CollectionMethodGenerators.generateSetOf(options, methodArg, formalCount)));
+      }
+      proto = factory.createProto(factory.setType, factory.objectArrayType);
+      method = factory.createMethod(type, proto, name);
+      addProvider(
+          new MethodGenerator(
+              method, BackportedMethods::CollectionMethods_setOfArray, "ofArray"));
     }
 
     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 fb025c9..5d81f7b 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
@@ -518,6 +518,229 @@
         ImmutableList.of());
   }
 
+  public static CfCode CollectionMethods_listOfArray(
+      InternalOptions options, DexMethod method, String name) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    CfLabel label5 = new CfLabel();
+    CfLabel label6 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        3,
+        6,
+        ImmutableList.of(
+            label0,
+            new CfNew(options.itemFactory.createType("Ljava/util/ArrayList;")),
+            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfArrayLength(),
+            new CfInvoke(
+                183,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/ArrayList;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("V"), options.itemFactory.createType("I")),
+                    options.itemFactory.createString("<init>")),
+                false),
+            new CfStore(ValueType.OBJECT, 1),
+            label1,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfStore(ValueType.OBJECT, 2),
+            new CfLoad(ValueType.OBJECT, 2),
+            new CfArrayLength(),
+            new CfStore(ValueType.INT, 3),
+            new CfConstNumber(0, ValueType.INT),
+            new CfStore(ValueType.INT, 4),
+            label2,
+            new CfLoad(ValueType.INT, 4),
+            new CfLoad(ValueType.INT, 3),
+            new CfIfCmp(If.Type.GE, ValueType.INT, label5),
+            new CfLoad(ValueType.OBJECT, 2),
+            new CfLoad(ValueType.INT, 4),
+            new CfArrayLoad(MemberType.OBJECT),
+            new CfStore(ValueType.OBJECT, 5),
+            label3,
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 5),
+            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(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/ArrayList;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Z"),
+                        options.itemFactory.createType("Ljava/lang/Object;")),
+                    options.itemFactory.createString("add")),
+                false),
+            new CfStackInstruction(CfStackInstruction.Opcode.Pop),
+            label4,
+            new CfIinc(4, 1),
+            new CfGoto(label2),
+            label5,
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfInvoke(
+                184,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Collections;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/util/List;"),
+                        options.itemFactory.createType("Ljava/util/List;")),
+                    options.itemFactory.createString("unmodifiableList")),
+                false),
+            new CfReturn(ValueType.OBJECT),
+            label6),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode CollectionMethods_setOfArray(
+      InternalOptions options, DexMethod method, String name) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    CfLabel label5 = new CfLabel();
+    CfLabel label6 = new CfLabel();
+    CfLabel label7 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        4,
+        6,
+        ImmutableList.of(
+            label0,
+            new CfNew(options.itemFactory.createType("Ljava/util/HashSet;")),
+            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfArrayLength(),
+            new CfInvoke(
+                183,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/HashSet;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("V"), options.itemFactory.createType("I")),
+                    options.itemFactory.createString("<init>")),
+                false),
+            new CfStore(ValueType.OBJECT, 1),
+            label1,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfStore(ValueType.OBJECT, 2),
+            new CfLoad(ValueType.OBJECT, 2),
+            new CfArrayLength(),
+            new CfStore(ValueType.INT, 3),
+            new CfConstNumber(0, ValueType.INT),
+            new CfStore(ValueType.INT, 4),
+            label2,
+            new CfLoad(ValueType.INT, 4),
+            new CfLoad(ValueType.INT, 3),
+            new CfIfCmp(If.Type.GE, ValueType.INT, label6),
+            new CfLoad(ValueType.OBJECT, 2),
+            new CfLoad(ValueType.INT, 4),
+            new CfArrayLoad(MemberType.OBJECT),
+            new CfStore(ValueType.OBJECT, 5),
+            label3,
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 5),
+            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(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/HashSet;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Z"),
+                        options.itemFactory.createType("Ljava/lang/Object;")),
+                    options.itemFactory.createString("add")),
+                false),
+            new CfIf(If.Type.NE, ValueType.INT, label5),
+            label4,
+            new CfNew(options.itemFactory.createType("Ljava/lang/IllegalArgumentException;")),
+            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+            new CfNew(options.itemFactory.createType("Ljava/lang/StringBuilder;")),
+            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+            new CfInvoke(
+                183,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/lang/StringBuilder;"),
+                    options.itemFactory.createProto(options.itemFactory.createType("V")),
+                    options.itemFactory.createString("<init>")),
+                false),
+            new CfConstString(options.itemFactory.createString("duplicate element: ")),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/lang/StringBuilder;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/lang/StringBuilder;"),
+                        options.itemFactory.createType("Ljava/lang/String;")),
+                    options.itemFactory.createString("append")),
+                false),
+            new CfLoad(ValueType.OBJECT, 5),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/lang/StringBuilder;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/lang/StringBuilder;"),
+                        options.itemFactory.createType("Ljava/lang/Object;")),
+                    options.itemFactory.createString("append")),
+                false),
+            new CfInvoke(
+                182,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/lang/StringBuilder;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/lang/String;")),
+                    options.itemFactory.createString("toString")),
+                false),
+            new CfInvoke(
+                183,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/lang/IllegalArgumentException;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("V"),
+                        options.itemFactory.createType("Ljava/lang/String;")),
+                    options.itemFactory.createString("<init>")),
+                false),
+            new CfThrow(),
+            label5,
+            new CfIinc(4, 1),
+            new CfGoto(label2),
+            label6,
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfInvoke(
+                184,
+                options.itemFactory.createMethod(
+                    options.itemFactory.createType("Ljava/util/Collections;"),
+                    options.itemFactory.createProto(
+                        options.itemFactory.createType("Ljava/util/Set;"),
+                        options.itemFactory.createType("Ljava/util/Set;")),
+                    options.itemFactory.createString("unmodifiableSet")),
+                false),
+            new CfReturn(ValueType.OBJECT),
+            label7),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
   public static CfCode CollectionsMethods_emptyEnumeration(
       InternalOptions options, DexMethod method, String name) {
     CfLabel label0 = new CfLabel();
@@ -1142,91 +1365,6 @@
         ImmutableList.of());
   }
 
-  public static CfCode ListMethods_ofArray(InternalOptions options, DexMethod method, String name) {
-    CfLabel label0 = new CfLabel();
-    CfLabel label1 = new CfLabel();
-    CfLabel label2 = new CfLabel();
-    CfLabel label3 = new CfLabel();
-    CfLabel label4 = new CfLabel();
-    CfLabel label5 = new CfLabel();
-    CfLabel label6 = new CfLabel();
-    return new CfCode(
-        method.holder,
-        3,
-        6,
-        ImmutableList.of(
-            label0,
-            new CfNew(options.itemFactory.createType("Ljava/util/ArrayList;")),
-            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
-            new CfLoad(ValueType.OBJECT, 0),
-            new CfArrayLength(),
-            new CfInvoke(
-                183,
-                options.itemFactory.createMethod(
-                    options.itemFactory.createType("Ljava/util/ArrayList;"),
-                    options.itemFactory.createProto(
-                        options.itemFactory.createType("V"), options.itemFactory.createType("I")),
-                    options.itemFactory.createString("<init>")),
-                false),
-            new CfStore(ValueType.OBJECT, 1),
-            label1,
-            new CfLoad(ValueType.OBJECT, 0),
-            new CfStore(ValueType.OBJECT, 2),
-            new CfLoad(ValueType.OBJECT, 2),
-            new CfArrayLength(),
-            new CfStore(ValueType.INT, 3),
-            new CfConstNumber(0, ValueType.INT),
-            new CfStore(ValueType.INT, 4),
-            label2,
-            new CfLoad(ValueType.INT, 4),
-            new CfLoad(ValueType.INT, 3),
-            new CfIfCmp(If.Type.GE, ValueType.INT, label5),
-            new CfLoad(ValueType.OBJECT, 2),
-            new CfLoad(ValueType.INT, 4),
-            new CfArrayLoad(MemberType.OBJECT),
-            new CfStore(ValueType.OBJECT, 5),
-            label3,
-            new CfLoad(ValueType.OBJECT, 1),
-            new CfLoad(ValueType.OBJECT, 5),
-            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(
-                182,
-                options.itemFactory.createMethod(
-                    options.itemFactory.createType("Ljava/util/ArrayList;"),
-                    options.itemFactory.createProto(
-                        options.itemFactory.createType("Z"),
-                        options.itemFactory.createType("Ljava/lang/Object;")),
-                    options.itemFactory.createString("add")),
-                false),
-            new CfStackInstruction(CfStackInstruction.Opcode.Pop),
-            label4,
-            new CfIinc(4, 1),
-            new CfGoto(label2),
-            label5,
-            new CfLoad(ValueType.OBJECT, 1),
-            new CfInvoke(
-                184,
-                options.itemFactory.createMethod(
-                    options.itemFactory.createType("Ljava/util/Collections;"),
-                    options.itemFactory.createProto(
-                        options.itemFactory.createType("Ljava/util/List;"),
-                        options.itemFactory.createType("Ljava/util/List;")),
-                    options.itemFactory.createString("unmodifiableList")),
-                false),
-            new CfReturn(ValueType.OBJECT),
-            label6),
-        ImmutableList.of(),
-        ImmutableList.of());
-  }
-
   public static CfCode LongMethods_compareUnsigned(
       InternalOptions options, DexMethod method, String name) {
     CfLabel label0 = new CfLabel();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/ListMethodGenerators.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/CollectionMethodGenerators.java
similarity index 74%
rename from src/main/java/com/android/tools/r8/ir/desugar/backports/ListMethodGenerators.java
rename to src/main/java/com/android/tools/r8/ir/desugar/backports/CollectionMethodGenerators.java
index 1319752..040e133 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/backports/ListMethodGenerators.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/CollectionMethodGenerators.java
@@ -13,6 +13,7 @@
 import com.android.tools.r8.cf.code.CfStackInstruction;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.code.MemberType;
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.utils.InternalOptions;
@@ -20,11 +21,20 @@
 import com.google.common.collect.ImmutableList.Builder;
 import org.objectweb.asm.Opcodes;
 
-public final class ListMethodGenerators {
+public final class CollectionMethodGenerators {
 
-  private ListMethodGenerators() {}
+  private CollectionMethodGenerators() {}
 
   public static CfCode generateListOf(InternalOptions options, DexMethod method, int formalCount) {
+    return generateFixedMethods(options, method, formalCount, options.itemFactory.listType);
+  }
+
+  public static CfCode generateSetOf(InternalOptions options, DexMethod method, int formalCount) {
+    return generateFixedMethods(options, method, formalCount, options.itemFactory.setType);
+  }
+
+  private static CfCode generateFixedMethods(
+      InternalOptions options, DexMethod method, int formalCount, DexType returnType) {
     Builder<CfInstruction> builder = ImmutableList.builder();
     builder.add(
         new CfConstNumber(formalCount, ValueType.INT),
@@ -42,9 +52,8 @@
         new CfInvoke(
             Opcodes.INVOKESTATIC,
             options.itemFactory.createMethod(
-                options.itemFactory.listType,
-                options.itemFactory.createProto(
-                    options.itemFactory.listType, options.itemFactory.objectArrayType),
+                returnType,
+                options.itemFactory.createProto(returnType, options.itemFactory.objectArrayType),
                 options.itemFactory.createString("of")),
             false),
         new CfReturn(ValueType.OBJECT));
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/ListMethodRewrites.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/CollectionMethodRewrites.java
similarity index 61%
rename from src/main/java/com/android/tools/r8/ir/desugar/backports/ListMethodRewrites.java
rename to src/main/java/com/android/tools/r8/ir/desugar/backports/CollectionMethodRewrites.java
index c3245d8..ce159be 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/backports/ListMethodRewrites.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/CollectionMethodRewrites.java
@@ -11,16 +11,26 @@
 import com.android.tools.r8.ir.code.InvokeStatic;
 import java.util.Collections;
 
-public final class ListMethodRewrites {
+public final class CollectionMethodRewrites {
 
-  private ListMethodRewrites() {}
+  private CollectionMethodRewrites() {}
 
-  public static void rewriteEmptyOf(
+  public static void rewriteListOfEmpty(
       InvokeMethod invoke, InstructionListIterator iterator, DexItemFactory factory) {
+    rewriteToCollectionMethod(invoke, iterator, factory, "emptyList");
+  }
+
+  public static void rewriteSetOfEmpty(
+      InvokeMethod invoke, InstructionListIterator iterator, DexItemFactory factory) {
+    rewriteToCollectionMethod(invoke, iterator, factory, "emptySet");
+  }
+
+  private static void rewriteToCollectionMethod(InvokeMethod invoke,
+      InstructionListIterator iterator, DexItemFactory factory, String methodName) {
     assert invoke.inValues().isEmpty();
 
     DexMethod collectionsEmptyList =
-        factory.createMethod(factory.collectionsType, invoke.getInvokedMethod().proto, "emptyList");
+        factory.createMethod(factory.collectionsType, invoke.getInvokedMethod().proto, methodName);
     InvokeStatic newInvoke =
         new InvokeStatic(collectionsEmptyList, invoke.outValue(), Collections.emptyList());
     iterator.replaceCurrentInstruction(newInvoke);
diff --git a/src/test/examplesJava9/backport/SetBackportJava9Main.java b/src/test/examplesJava9/backport/SetBackportJava9Main.java
new file mode 100644
index 0000000..d824bd0
--- /dev/null
+++ b/src/test/examplesJava9/backport/SetBackportJava9Main.java
@@ -0,0 +1,207 @@
+// 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 backport;
+
+import java.util.Set;
+
+public class SetBackportJava9Main {
+
+  public static void main(String[] args) {
+    testOf0();
+    testOf1();
+    testOf2();
+    testOf10();
+    testOfVarargs();
+  }
+
+  private static void testOf0() {
+    Set<Object> ofObject = Set.of();
+    assertEquals(0, ofObject.size());
+    assertFalse(ofObject.contains(new Object()));
+    assertMutationNotAllowed(ofObject);
+
+    Set<Integer> ofInteger = Set.of();
+    assertEquals(0, ofInteger.size());
+    assertFalse(ofInteger.contains(0));
+  }
+
+  private static void testOf1() {
+    Object anObject = new Object();
+    Set<Object> ofObject = Set.of(anObject);
+    assertEquals(1, ofObject.size());
+    assertTrue(ofObject.contains(anObject));
+    assertFalse(ofObject.contains(new Object()));
+    assertMutationNotAllowed(ofObject);
+
+    Set<Integer> ofInteger = Set.of(1);
+    assertEquals(1, ofInteger.size());
+    assertTrue(ofInteger.contains(1));
+    assertFalse(ofInteger.contains(2));
+
+    try {
+      Set.of((Object) null);
+      throw new AssertionError();
+    } catch (NullPointerException expected) {
+    }
+  }
+
+  private static void testOf2() {
+    Object anObject0 = new Object();
+    Object anObject1 = new Object();
+    Set<Object> ofObject = Set.of(anObject0, anObject1);
+    assertEquals(2, ofObject.size());
+    assertTrue(ofObject.contains(anObject0));
+    assertTrue(ofObject.contains(anObject1));
+    assertFalse(ofObject.contains(new Object()));
+    assertMutationNotAllowed(ofObject);
+
+    Set<Integer> ofInteger = Set.of(1, 2);
+    assertEquals(2, ofInteger.size());
+    assertTrue(ofInteger.contains(1));
+    assertTrue(ofInteger.contains(2));
+    assertFalse(ofInteger.contains(3));
+
+    Set<Object> ofMixed = Set.of(anObject0, 1);
+    assertEquals(2, ofMixed.size());
+    assertTrue(ofMixed.contains(anObject0));
+    assertTrue(ofMixed.contains(1));
+    assertFalse(ofMixed.contains(2));
+    assertFalse(ofMixed.contains(anObject1));
+    assertMutationNotAllowed(ofMixed);
+
+    try {
+      Set.of(1, null);
+      throw new AssertionError();
+    } catch (NullPointerException expected) {
+    }
+
+    try {
+      Set.of(1, 1);
+      throw new AssertionError();
+    } catch (IllegalArgumentException expected) {
+      assertEquals("duplicate element: 1", expected.getMessage());
+    }
+  }
+
+  private static void testOf10() {
+    Object anObject0 = new Object();
+    Object anObject6 = new Object();
+    Object anObject9 = new Object();
+    Set<Object> ofObject =
+        Set.of(anObject0, new Object(), new Object(), new Object(), new Object(), new Object(),
+            anObject6, new Object(), new Object(), anObject9);
+    assertEquals(10, ofObject.size());
+    assertTrue(ofObject.contains(anObject0));
+    assertTrue(ofObject.contains(anObject6));
+    assertTrue(ofObject.contains(anObject9));
+    assertFalse(ofObject.contains(new Object()));
+    assertMutationNotAllowed(ofObject);
+
+    Set<Integer> ofInteger = Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+    assertEquals(10, ofInteger.size());
+    assertTrue(ofInteger.contains(0));
+    assertTrue(ofInteger.contains(6));
+    assertTrue(ofInteger.contains(9));
+    assertFalse(ofInteger.contains(10));
+
+    Set<Object> ofMixed = Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, anObject9);
+    assertEquals(10, ofMixed.size());
+    assertTrue(ofMixed.contains(0));
+    assertTrue(ofMixed.contains(6));
+    assertTrue(ofMixed.contains(anObject9));
+    assertFalse(ofMixed.contains(anObject0));
+    assertMutationNotAllowed(ofMixed);
+
+    try {
+      Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, null);
+      throw new AssertionError();
+    } catch (NullPointerException expected) {
+    }
+
+    try {
+      Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 0);
+      throw new AssertionError();
+    } catch (IllegalArgumentException expected) {
+      assertEquals("duplicate element: 0", expected.getMessage());
+    }
+  }
+
+  private static void testOfVarargs() {
+    Object anObject0 = new Object();
+    Object anObject6 = new Object();
+    Object anObject10 = new Object();
+    Set<Object> ofObject =
+        Set.of(anObject0, new Object(), new Object(), new Object(), new Object(), new Object(),
+            anObject6, new Object(), new Object(), new Object(), anObject10);
+    assertEquals(11, ofObject.size());
+    assertTrue(ofObject.contains(anObject0));
+    assertTrue(ofObject.contains(anObject6));
+    assertTrue(ofObject.contains(anObject10));
+    assertFalse(ofObject.contains(new Object()));
+    assertMutationNotAllowed(ofObject);
+
+    Set<Integer> ofInteger = Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+    assertEquals(11, ofInteger.size());
+    assertTrue(ofInteger.contains(0));
+    assertTrue(ofInteger.contains(6));
+    assertTrue(ofInteger.contains(10));
+    assertFalse(ofInteger.contains(11));
+
+    Set<Object> ofMixed = Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, anObject10);
+    assertEquals(11, ofMixed.size());
+    assertTrue(ofMixed.contains(0));
+    assertTrue(ofMixed.contains(6));
+    assertTrue(ofMixed.contains(anObject10));
+    assertFalse(ofMixed.contains(10));
+    assertFalse(ofMixed.contains(anObject0));
+    assertMutationNotAllowed(ofMixed);
+
+    // Ensure the supplied mutable array is not used directly since it is mutable.
+    Object[] mutableArray = { anObject0 };
+    Set<Object> ofMutableArray = Set.of(mutableArray);
+    mutableArray[0] = anObject10;
+    assertTrue(ofMutableArray.contains(anObject0));
+    assertFalse(ofMutableArray.contains(anObject10));
+
+    try {
+      Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, null);
+      throw new AssertionError();
+    } catch (NullPointerException expected) {
+    }
+
+    try {
+      Set.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
+      throw new AssertionError();
+    } catch (IllegalArgumentException expected) {
+      assertEquals("duplicate element: 0", expected.getMessage());
+    }
+  }
+
+  private static void assertMutationNotAllowed(Set<Object> ofObject) {
+    try {
+      ofObject.add(new Object());
+      throw new AssertionError();
+    } catch (UnsupportedOperationException expected) {
+    }
+  }
+
+  private static void assertTrue(boolean value) {
+    if (!value) {
+      throw new AssertionError("Expected <true> but was <false>");
+    }
+  }
+
+  private static void assertFalse(boolean value) {
+    if (value) {
+      throw new AssertionError("Expected <false> but was <true>");
+    }
+  }
+
+  private static void assertEquals(Object expected, Object actual) {
+    if (expected != actual && !expected.equals(actual)) {
+      throw new AssertionError("Expected <" + expected + "> but was <" + actual + ">");
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java
index b512634..3ff18bc 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ListBackportJava9Test.java
@@ -11,6 +11,7 @@
 import com.android.tools.r8.ToolHelper;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.List;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 import org.junit.runners.Parameterized.Parameters;
@@ -29,7 +30,13 @@
       Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
 
   public ListBackportJava9Test(TestParameters parameters) {
-    super(parameters, Byte.class, TEST_JAR, "backport.ListBackportJava9Main");
-    // TODO Once shipped in an actual API level, migrate to ByteBackportTest
+    super(parameters, List.class, TEST_JAR, "backport.ListBackportJava9Main");
+    // TODO Once shipped in an actual API level, migrate to ListBackportTest
+
+    // Available since API 1 and used to test created lists.
+    ignoreInvokes("add");
+    ignoreInvokes("get");
+    ignoreInvokes("set");
+    ignoreInvokes("size");
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava9Test.java
new file mode 100644
index 0000000..b87816e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/SetBackportJava9Test.java
@@ -0,0 +1,41 @@
+// 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.desugar.backports;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Set;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
+@RunWith(Parameterized.class)
+public class SetBackportJava9Test extends AbstractBackportTest {
+  @Parameters(name = "{0}")
+  public static Iterable<?> data() {
+    return getTestParameters()
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
+        .withDexRuntimes()
+        .build();
+  }
+
+  private static final Path TEST_JAR =
+      Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
+
+  public SetBackportJava9Test(TestParameters parameters) {
+    super(parameters, Set.class, TEST_JAR, "backport.SetBackportJava9Main");
+    // TODO Once shipped in an actual API level, migrate to SetBackportTest
+
+    // Available since API 1 and used to test created sets.
+    ignoreInvokes("add");
+    ignoreInvokes("contains");
+    ignoreInvokes("size");
+  }
+}
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
new file mode 100644
index 0000000..8076224
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/CollectionMethods.java
@@ -0,0 +1,33 @@
+// 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 java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+public class CollectionMethods {
+
+  public static <E> List<E> listOfArray(E[] elements) {
+    ArrayList<E> list = new ArrayList<>(elements.length);
+    for (E element : elements) {
+      list.add(Objects.requireNonNull(element));
+    }
+    return Collections.unmodifiableList(list);
+  }
+
+  public static <E> Set<E> setOfArray(E[] elements) {
+    HashSet<E> set = new HashSet<>(elements.length);
+    for (E element : elements) {
+      if (!set.add(Objects.requireNonNull(element))) {
+        throw new IllegalArgumentException("duplicate element: " + element);
+      }
+    }
+    return Collections.unmodifiableSet(set);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/GenerateBackportMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/GenerateBackportMethods.java
index 2bb7dc3..e210196 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/backports/GenerateBackportMethods.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/GenerateBackportMethods.java
@@ -29,6 +29,7 @@
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -73,11 +74,11 @@
           ByteMethods.class,
           CharacterMethods.class,
           CloseResourceMethod.class,
+          CollectionMethods.class,
           CollectionsMethods.class,
           DoubleMethods.class,
           FloatMethods.class,
           IntegerMethods.class,
-          ListMethods.class,
           LongMethods.class,
           MathMethods.class,
           ObjectsMethods.class,
@@ -99,7 +100,7 @@
   @Test
   public void test() throws Exception {
     ArrayList<Class<?>> sorted = new ArrayList<>(methodTemplateClasses);
-    sorted.sort((a, b) -> a.getTypeName().compareTo(b.getTypeName()));
+    sorted.sort(Comparator.comparing(Class::getTypeName));
     assertEquals("Classes should be listed in sorted order", sorted, methodTemplateClasses);
     assertEquals(
         FileUtils.readTextFile(backportMethodsFile, StandardCharsets.UTF_8),
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/ListMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/ListMethods.java
deleted file mode 100644
index 7d74919..0000000
--- a/src/test/java/com/android/tools/r8/ir/desugar/backports/ListMethods.java
+++ /dev/null
@@ -1,23 +0,0 @@
-// 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 java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
-public class ListMethods {
-
-  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);
-  }
-}