Revert "Rewrite of ServiceLoader.load to NewInstance when possible"

This reverts commit b027e3c0b123bd4a9397ff210e40293c1381d1a8.

Reason for revert: Failing kotlinreflecttest

Change-Id: I09c2c405b1a309f607aaaaca624447b16365e08a
diff --git a/src/main/java/com/android/tools/r8/graph/AppServices.java b/src/main/java/com/android/tools/r8/graph/AppServices.java
index 0122834..fab313f 100644
--- a/src/main/java/com/android/tools/r8/graph/AppServices.java
+++ b/src/main/java/com/android/tools/r8/graph/AppServices.java
@@ -13,15 +13,13 @@
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.StringDiagnostic;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.io.ByteStreams;
 import java.io.IOException;
 import java.nio.charset.Charset;
 import java.util.Arrays;
-import java.util.HashSet;
 import java.util.IdentityHashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
@@ -35,9 +33,9 @@
   private final AppView<? extends AppInfo> appView;
 
   // Mapping from service types to service implementation types.
-  private final Map<DexType, List<DexType>> services;
+  private final Map<DexType, Set<DexType>> services;
 
-  private AppServices(AppView<? extends AppInfo> appView, Map<DexType, List<DexType>> services) {
+  private AppServices(AppView<? extends AppInfo> appView, Map<DexType, Set<DexType>> services) {
     this.appView = appView;
     this.services = services;
   }
@@ -47,25 +45,25 @@
     return services.keySet();
   }
 
-  public List<DexType> serviceImplementationsFor(DexType serviceType) {
+  public Set<DexType> serviceImplementationsFor(DexType serviceType) {
     assert verifyRewrittenWithLens();
     assert services.containsKey(serviceType);
-    List<DexType> serviceImplementationTypes = services.get(serviceType);
+    Set<DexType> serviceImplementationTypes = services.get(serviceType);
     if (serviceImplementationTypes == null) {
       assert false
           : "Unexpected attempt to get service implementations for non-service type `"
               + serviceType.toSourceString()
               + "`";
-      return ImmutableList.of();
+      return ImmutableSet.of();
     }
     return serviceImplementationTypes;
   }
 
   public AppServices rewrittenWithLens(GraphLense graphLens) {
-    ImmutableMap.Builder<DexType, List<DexType>> rewrittenServices = ImmutableMap.builder();
-    for (Entry<DexType, List<DexType>> entry : services.entrySet()) {
+    ImmutableMap.Builder<DexType, Set<DexType>> rewrittenServices = ImmutableMap.builder();
+    for (Entry<DexType, Set<DexType>> entry : services.entrySet()) {
       DexType rewrittenServiceType = graphLens.lookupType(entry.getKey());
-      ImmutableList.Builder<DexType> rewrittenServiceImplementationTypes = ImmutableList.builder();
+      ImmutableSet.Builder<DexType> rewrittenServiceImplementationTypes = ImmutableSet.builder();
       for (DexType serviceImplementationType : entry.getValue()) {
         rewrittenServiceImplementationTypes.add(graphLens.lookupType(serviceImplementationType));
       }
@@ -75,7 +73,7 @@
   }
 
   private boolean verifyRewrittenWithLens() {
-    for (Entry<DexType, List<DexType>> entry : services.entrySet()) {
+    for (Entry<DexType, Set<DexType>> entry : services.entrySet()) {
       assert entry.getKey() == appView.graphLense().lookupType(entry.getKey());
       for (DexType type : entry.getValue()) {
         assert type == appView.graphLense().lookupType(type);
@@ -91,7 +89,7 @@
   public static class Builder {
 
     private final AppView<? extends AppInfo> appView;
-    private final Map<DexType, List<DexType>> services = new IdentityHashMap<>();
+    private final Map<DexType, Set<DexType>> services = new IdentityHashMap<>();
 
     private Builder(AppView<? extends AppInfo> appView) {
       this.appView = appView;
@@ -139,9 +137,8 @@
         }
       }
 
-      private List<DexType> readServiceImplementationsForService(String contents, Origin origin) {
+      private Set<DexType> readServiceImplementationsForService(String contents, Origin origin) {
         if (contents != null) {
-          Set<DexType> seenTypes = new HashSet<>();
           return Arrays.stream(contents.split(System.lineSeparator()))
               .map(String::trim)
               .map(this::prefixUntilCommentChar)
@@ -164,11 +161,11 @@
                                   origin));
                       return false;
                     }
-                    return seenTypes.add(serviceImplementationType);
+                    return true;
                   })
-              .collect(Collectors.toList());
+              .collect(Collectors.toSet());
         }
-        return ImmutableList.of();
+        return ImmutableSet.of();
       }
 
       private String prefixUntilCommentChar(String line) {
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 4934f4a..61f40c8 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -191,7 +191,6 @@
   public final DexString npeDescriptor = createString("Ljava/lang/NullPointerException;");
   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 intFieldUpdaterDescriptor =
       createString("Ljava/util/concurrent/atomic/AtomicIntegerFieldUpdater;");
@@ -256,7 +255,6 @@
   public final DexType npeType = createType(npeDescriptor);
   public final DexType proxyType = createType(proxyDescriptor);
   public final DexType serviceLoaderType = createType(serviceLoaderDescriptor);
-  public final DexType listType = createType(listDescriptor);
 
   public final StringBuildingMethods stringBuilderMethods =
       new StringBuildingMethods(stringBuilderType);
@@ -266,7 +264,6 @@
   public final ObjectMethods objectMethods = new ObjectMethods();
   public final StringMethods stringMethods = new StringMethods();
   public final LongMethods longMethods = new LongMethods();
-  public final JavaUtilArraysMethods utilArraysMethods = new JavaUtilArraysMethods();
   public final ThrowableMethods throwableMethods = new ThrowableMethods();
   public final ClassMethods classMethods = new ClassMethods();
   public final ConstructorMethods constructorMethods = new ConstructorMethods();
@@ -279,6 +276,7 @@
   public final Kotlin kotlin;
   public final PolymorphicMethods polymorphicMethods = new PolymorphicMethods();
   public final ProxyMethods proxyMethods = new ProxyMethods();
+  public final ServiceLoaderMethods serviceLoaderMethods = new ServiceLoaderMethods();
 
   public final DexString twrCloseResourceMethodName = createString("$closeResource");
   public final DexProto twrCloseResourceMethodProto =
@@ -322,8 +320,6 @@
   public final DexType externalizableType = createType("Ljava/io/Externalizable;");
   public final DexType comparableType = createType("Ljava/lang/Comparable;");
 
-  public final ServiceLoaderMethods serviceLoaderMethods = new ServiceLoaderMethods();
-
   public final DexMethod metafactoryMethod =
       createMethod(
           metafactoryType,
@@ -440,20 +436,6 @@
     }
   }
 
-  public class JavaUtilArraysMethods {
-
-    public final DexMethod asList;
-
-    private JavaUtilArraysMethods() {
-      asList =
-          createMethod(
-              createString("Ljava/util/Arrays;"),
-              createString("asList"),
-              listDescriptor,
-              new DexString[] {objectArrayDescriptor});
-    }
-  }
-
   public class ThrowableMethods {
 
     public final DexMethod addSuppressed;
@@ -905,7 +887,6 @@
     public final DexMethod load;
     public final DexMethod loadWithClassLoader;
     public final DexMethod loadInstalled;
-    public final DexMethod iterator;
 
     private ServiceLoaderMethods() {
       DexString loadName = createString("load");
@@ -920,8 +901,6 @@
               serviceLoaderType,
               createProto(serviceLoaderType, classType),
               createString("loadInstalled"));
-      iterator =
-          createMethod(serviceLoaderType, createProto(iteratorType), createString("iterator"));
     }
 
     public boolean isLoadMethod(DexMethod method) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 2e72732..57562d8 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -59,7 +59,6 @@
 import com.android.tools.r8.ir.optimize.PeepholeOptimizer;
 import com.android.tools.r8.ir.optimize.RedundantFieldLoadElimination;
 import com.android.tools.r8.ir.optimize.ReflectionOptimizer;
-import com.android.tools.r8.ir.optimize.ServiceLoaderRewriter;
 import com.android.tools.r8.ir.optimize.UninstantiatedTypeOptimization;
 import com.android.tools.r8.ir.optimize.classinliner.ClassInliner;
 import com.android.tools.r8.ir.optimize.lambda.LambdaMerger;
@@ -136,7 +135,6 @@
   private final UninstantiatedTypeOptimization uninstantiatedTypeOptimization;
   private final TypeChecker typeChecker;
   private final IdempotentFunctionCallCanonicalizer idempotentFunctionCallCanonicalizer;
-  private final ServiceLoaderRewriter serviceLoaderRewriter;
 
   final DeadCodeRemover deadCodeRemover;
 
@@ -217,8 +215,6 @@
               ? new UninstantiatedTypeOptimization(appViewWithLiveness)
               : null;
       this.typeChecker = new TypeChecker(appView.withLiveness());
-      this.serviceLoaderRewriter =
-          options.enableServiceLoaderRewriting ? new ServiceLoaderRewriter() : null;
     } else {
       this.classInliner = null;
       this.classStaticizer = null;
@@ -230,7 +226,6 @@
       this.devirtualizer = null;
       this.uninstantiatedTypeOptimization = null;
       this.typeChecker = null;
-      this.serviceLoaderRewriter = null;
     }
     this.deadCodeRemover = new DeadCodeRemover(appView, codeRewriter);
     this.idempotentFunctionCallCanonicalizer =
@@ -869,11 +864,6 @@
     // we will return with finalizeEmptyThrowingCode() above.
     assert code.verifyTypes(appView);
 
-    if (serviceLoaderRewriter != null) {
-      assert appView.appInfo().hasLiveness();
-      serviceLoaderRewriter.rewrite(code, appView.withLiveness());
-    }
-
     if (classStaticizer != null) {
       classStaticizer.fixupMethodCode(method, code);
       assert code.isConsistentSSA();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java
deleted file mode 100644
index b19894e..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java
+++ /dev/null
@@ -1,286 +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.optimize;
-
-import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
-
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
-import com.android.tools.r8.ir.code.ArrayPut;
-import com.android.tools.r8.ir.code.ConstClass;
-import com.android.tools.r8.ir.code.ConstNumber;
-import com.android.tools.r8.ir.code.IRCode;
-import com.android.tools.r8.ir.code.Instruction;
-import com.android.tools.r8.ir.code.InstructionIterator;
-import com.android.tools.r8.ir.code.InvokeDirect;
-import com.android.tools.r8.ir.code.InvokeInterface;
-import com.android.tools.r8.ir.code.InvokeStatic;
-import com.android.tools.r8.ir.code.InvokeVirtual;
-import com.android.tools.r8.ir.code.MemberType;
-import com.android.tools.r8.ir.code.NewArrayEmpty;
-import com.android.tools.r8.ir.code.NewInstance;
-import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.google.common.collect.ImmutableList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * ServiceLoaderRewriter will attempt to rewrite calls on the form of: ServiceLoader.load(X.class,
- * X.class.getClassLoader()).iterator() ... to Arrays.asList(new X[] { new Y(), ..., new Z()
- * }).iterator() for classes Y..Z specified in the META-INF/services/X.
- *
- * <p>The reason for this optimization is to not have the ServiceLoader.load on the distributed R8
- * in AGP, since this can potentially conflict with debug versions added to a build.gradle file as:
- * classpath 'com.android.tools:r8:a.b.c' Additionally, it might also result in improved performance
- * because ServiceLoader.load is really slow on Android because it has to do a reflective lookup.
- *
- * <p>A call to ServiceLoader.load(X.class) is implicitly the same as ServiceLoader.load(X.class,
- * Thread.getContextClassLoader()) which can have different behavior in Android if a process host
- * multiple applications:
- *
- * <pre>
- * See <a href="https://stackoverflow.com/questions/13407006/android-class-loader-may-fail-for-
- * processes-that-host-multiple-applications">https://stackoverflow.com/questions/13407006/
- * android-class-loader-may-fail-for-processes-that-host-multiple-applications</a>
- * </pre>
- *
- * We therefore only conservatively rewrite if the invoke is on is on the form
- * ServiceLoader.load(X.class, X.class.getClassLoader()) or ServiceLoader.load(X.class, null).
- */
-public class ServiceLoaderRewriter {
-
-  public static void rewrite(IRCode code, AppView<? extends AppInfoWithLiveness> appView) {
-    DexItemFactory factory = appView.dexItemFactory();
-    InstructionIterator instructionIterator = code.instructionIterator();
-    while (instructionIterator.hasNext()) {
-      Instruction instruction = instructionIterator.next();
-
-      // Check if instruction is an invoke static on the desired form of ServiceLoader.load.
-      if (!instruction.isInvokeStatic()
-          || instruction.asInvokeStatic().getInvokedMethod()
-              != factory.serviceLoaderMethods.loadWithClassLoader) {
-        continue;
-      }
-
-      InvokeStatic serviceLoaderLoad = instruction.asInvokeStatic();
-      Value serviceLoaderLoadOut = serviceLoaderLoad.outValue();
-      if (serviceLoaderLoadOut.numberOfAllUsers() != 1
-          || serviceLoaderLoadOut.numberOfPhiUsers() != 0) {
-        continue;
-      }
-
-      // Check that the only user is a call to iterator().
-      if (serviceLoaderLoadOut.singleUniqueUser().isInvokeVirtual()
-          || serviceLoaderLoadOut.singleUniqueUser().asInvokeVirtual().getInvokedMethod()
-              != factory.serviceLoaderMethods.iterator) {
-        continue;
-      }
-
-      // Check that the first argument is a const class.
-      Value argument = serviceLoaderLoad.inValues().get(0).getAliasedValue();
-      if (argument.isPhi() || !argument.definition.isConstClass()) {
-        continue;
-      }
-
-      ConstClass constClass =
-          serviceLoaderLoad
-              .inValues()
-              .get(0)
-              .getAliasedValue()
-              .getConstInstruction()
-              .asConstClass();
-
-      // Check that the service is not kept.
-      if (appView.appInfo().isPinned(constClass.getValue())) {
-        continue;
-      }
-
-      // Check that the service is configured in the META-INF/services.
-      if (!appView.appServices().allServiceTypes().contains(constClass.getValue())) {
-        // Error already reported in the Enqueuer.
-        continue;
-      }
-
-      // Check that ClassLoader used is the ClassLoader defined for the the service configuration
-      // that we are instantiating or NULL.
-      InvokeVirtual classLoaderInvoke =
-          serviceLoaderLoad.inValues().get(1).definition.asInvokeVirtual();
-      boolean isGetClassLoaderOnConstClassOrNull =
-          serviceLoaderLoad.inValues().get(1).getTypeLattice().isNullType()
-              || (classLoaderInvoke != null
-                  && classLoaderInvoke.inValues().size() == 1
-                  && classLoaderInvoke.getReceiver().getAliasedValue().isConstClass()
-                  && classLoaderInvoke
-                          .getReceiver()
-                          .getAliasedValue()
-                          .getConstInstruction()
-                          .asConstClass()
-                          .getValue()
-                      == constClass.getValue());
-      if (!isGetClassLoaderOnConstClassOrNull) {
-        continue;
-      }
-
-      // We can perform the rewrite of the ServiceLoader.load call.
-      new Rewriter(appView, code, instructionIterator, serviceLoaderLoad)
-          .perform(classLoaderInvoke, constClass.getValue());
-    }
-  }
-
-  /**
-   * Rewriter will look assume that code is on the form:
-   *
-   * <pre>
-   * ConstClass         v1 <- X
-   * ConstClass         v2 <- X
-   * Invoke-Virtual     v3 <- v2; method: java.lang.ClassLoader java.lang.Class.getClassLoader()
-   * Invoke-Static      v4 <- v1, v3; method: java.util.ServiceLoader java.util.ServiceLoader
-   *     .load(java.lang.Class, java.lang.ClassLoader)
-   * Invoke-Virtual     v5 <- v4; method: java.util.Iterator java.util.ServiceLoader.iterator()
-   * </pre>
-   *
-   * and rewrites it to for classes impl(X) defined in META-INF/services/X:
-   *
-   * <pre>
-   * ConstClass         v1 <- X
-   * ConstClass         v2 <- X
-   * ConstNumber        va <-  impl(X).size() (INT)
-   * NewArrayEmpty      vb <- va X[]
-   * for i = 0 to C - 1:
-   *   ConstNumber        vc(i) <-  i (INT)
-   *   NewInstance        vd <-  impl(X).get(i)
-   *   Invoke-Direct      vd; method: void impl(X).get(i).<init>()
-   *   ArrayPut           vb, vc(i), vd
-   * end for
-   * Invoke-Static      ve <- vb; method: java.util.List java.util.Arrays.asList(java.lang.Object[])
-   * Invoke-Interface   v5 <- ve; method: java.util.Iterator java.util.List.iterator()
-   * </pre>
-   *
-   * We rely on the DeadCodeRemover to remove the ConstClasses and any aliased values no longer
-   * used.
-   */
-  private static class Rewriter {
-
-    private final AppView appView;
-    private final DexItemFactory factory;
-    private final IRCode code;
-    private final InvokeStatic serviceLoaderLoad;
-
-    private InstructionIterator iterator;
-    private MemberType memberType;
-    private Value valueArray;
-    private int index = 0;
-
-    public Rewriter(
-        AppView appView,
-        IRCode code,
-        InstructionIterator iterator,
-        InvokeStatic serviceLoaderLoad) {
-      this.appView = appView;
-      this.factory = appView.dexItemFactory();
-      this.iterator = iterator;
-      this.code = code;
-      this.serviceLoaderLoad = serviceLoaderLoad;
-    }
-
-    public void perform(InvokeVirtual classLoaderInvoke, DexType dexType) {
-      assert valueArray == null;
-      assert memberType == null;
-
-      // Remove the ClassLoader call since this can throw and will not be removed otherwise.
-      if (classLoaderInvoke != null) {
-        clearGetClassLoader(classLoaderInvoke);
-        iterator.nextUntil(i -> i == serviceLoaderLoad);
-      }
-
-      // Remove the ServiceLoader.load call.
-      InvokeVirtual serviceLoaderIterator =
-          serviceLoaderLoad.outValue().singleUniqueUser().asInvokeVirtual();
-      iterator.replaceCurrentInstruction(code.createConstNull());
-
-      List<DexType> dexTypes = appView.appServices().serviceImplementationsFor(dexType);
-
-      // Build the array for the "loaded" classes.
-      ConstNumber arrayLength = code.createIntConstant(dexTypes.size());
-      arrayLength.setPosition(serviceLoaderLoad.getPosition());
-      iterator.add(arrayLength);
-
-      DexType arrayType = factory.createArrayType(1, dexType);
-      TypeLatticeElement arrayLatticeElement =
-          TypeLatticeElement.fromDexType(arrayType, definitelyNotNull(), appView);
-      valueArray = code.createValue(arrayLatticeElement);
-      NewArrayEmpty newArrayEmpty =
-          new NewArrayEmpty(valueArray, arrayLength.outValue(), arrayType);
-      newArrayEmpty.setPosition(serviceLoaderLoad.getPosition());
-      iterator.add(newArrayEmpty);
-
-      this.memberType = MemberType.fromDexType(dexType);
-
-      // Add all new instances to the array.
-      dexTypes.forEach(this::addNewServiceAndPutInArray);
-
-      // Build the Arrays.asList(...) instruction.
-      Value vArrayAsList =
-          code.createValue(
-              TypeLatticeElement.fromDexType(factory.listType, definitelyNotNull(), appView));
-      InvokeStatic arraysAsList =
-          new InvokeStatic(
-              factory.utilArraysMethods.asList, vArrayAsList, ImmutableList.of(valueArray));
-      arraysAsList.setPosition(serviceLoaderLoad.getPosition());
-      iterator.add(arraysAsList);
-
-      // Find the iterator instruction and replace it.
-      iterator.nextUntil(x -> x == serviceLoaderIterator);
-
-      DexMethod method =
-          factory.createMethod(
-              factory.listType, factory.createProto(factory.iteratorType), "iterator");
-      InvokeInterface arrayIterator =
-          new InvokeInterface(
-              method, serviceLoaderIterator.outValue(), ImmutableList.of(vArrayAsList));
-      iterator.replaceCurrentInstruction(arrayIterator);
-    }
-
-    private void addNewServiceAndPutInArray(DexType clazz) {
-      ConstNumber indexInArray = code.createIntConstant(index++);
-      indexInArray.setPosition(serviceLoaderLoad.getPosition());
-      iterator.add(indexInArray);
-
-      TypeLatticeElement clazzLatticeElement =
-          TypeLatticeElement.fromDexType(clazz, definitelyNotNull(), appView);
-      Value vInstance = code.createValue(clazzLatticeElement);
-      NewInstance newInstance = new NewInstance(clazz, vInstance);
-      newInstance.setPosition(serviceLoaderLoad.getPosition());
-      iterator.add(newInstance);
-
-      DexClass clazzDefinition = appView.definitionFor(clazz);
-      DexMethod method = clazzDefinition.getDefaultInitializer().method;
-      assert method.getArity() == 0;
-      InvokeDirect invokeDirect =
-          new InvokeDirect(method, null, Collections.singletonList(vInstance));
-      invokeDirect.setPosition(serviceLoaderLoad.getPosition());
-      iterator.add(invokeDirect);
-
-      ArrayPut put = new ArrayPut(memberType, valueArray, indexInArray.outValue(), vInstance);
-      put.setPosition(serviceLoaderLoad.getPosition());
-      iterator.add(put);
-    }
-
-    private void clearGetClassLoader(InvokeVirtual classLoaderInvoke) {
-      while (iterator.hasPrevious()) {
-        Instruction instruction = iterator.previous();
-        if (instruction == classLoaderInvoke) {
-          iterator.replaceCurrentInstruction(code.createConstNull());
-          break;
-        }
-      }
-    }
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 98cd095..b1e074a 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -2175,7 +2175,7 @@
   private void handleServiceInstantiation(DexType serviceType, KeepReason reason) {
     instantiatedAppServices.add(serviceType);
 
-    List<DexType> serviceImplementationTypes =
+    Set<DexType> serviceImplementationTypes =
         appView.appServices().serviceImplementationsFor(serviceType);
     for (DexType serviceImplementationType : serviceImplementationTypes) {
       if (!serviceImplementationType.isClassType()) {
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index d07f025..bca5d8f 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -142,7 +142,6 @@
   public boolean enableClassStaticizer = true;
   public boolean enableInitializedClassesAnalysis = true;
   public boolean enableSideEffectAnalysis = true;
-  public boolean enableServiceLoaderRewriting = true;
   // TODO(b/120138731): Enable this when it is worthwhile, e.g., combined with Class#forName.
   public boolean enableNameReflectionOptimization = false;
   public int classInliningInstructionLimit = 50;
diff --git a/src/test/java/com/android/tools/r8/rewrite/ServiceLoaderRewritingTest.java b/src/test/java/com/android/tools/r8/rewrite/ServiceLoaderRewritingTest.java
deleted file mode 100644
index 6daef42..0000000
--- a/src/test/java/com/android/tools/r8/rewrite/ServiceLoaderRewritingTest.java
+++ /dev/null
@@ -1,280 +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.rewrite;
-
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.assertNull;
-import static junit.framework.TestCase.assertTrue;
-
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.DataEntryResource;
-import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.R8TestRunResult;
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.utils.StringUtils;
-import com.android.tools.r8.utils.codeinspector.ClassSubject;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import com.android.tools.r8.utils.codeinspector.InstructionSubject;
-import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.ServiceLoader;
-import java.util.concurrent.ExecutionException;
-import java.util.zip.ZipFile;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-@RunWith(Parameterized.class)
-public class ServiceLoaderRewritingTest extends TestBase {
-
-  private final TestParameters parameters;
-  private final String EXPECTED_OUTPUT =
-      StringUtils.lines("Hello World!", "Hello World!", "Hello World!");
-
-  public interface Service {
-
-    void print();
-  }
-
-  public static class ServiceImpl implements Service {
-
-    @Override
-    public void print() {
-      System.out.println("Hello World!");
-    }
-  }
-
-  public static class MainRunner {
-
-    public static void main(String[] args) {
-      ServiceLoader.load(Service.class, Service.class.getClassLoader()).iterator().next().print();
-      ServiceLoader.load(Service.class, null).iterator().next().print();
-      for (Service x : ServiceLoader.load(Service.class, Service.class.getClassLoader())) {
-        x.print();
-      }
-      // TODO(b/120436373) The stream API for ServiceLoader was added in Java 9. When we can model
-      //   streams correctly, uncomment the lines below and adjust EXPECTED_OUTPUT.
-      // ServiceLoader.load(Service.class, Service.class.getClassLoader())
-      //   .stream().forEach(x -> x.get().print());
-    }
-  }
-
-  public static class OtherRunner {
-
-    public static void main(String[] args) {
-      ServiceLoader.load(Service.class).iterator().next().print();
-      ServiceLoader.load(Service.class, Thread.currentThread().getContextClassLoader())
-          .iterator()
-          .next()
-          .print();
-      ServiceLoader.load(Service.class, OtherRunner.class.getClassLoader())
-          .iterator()
-          .next()
-          .print();
-    }
-  }
-
-  public static class EscapingRunner {
-
-    public ServiceLoader<Service> serviceImplementations;
-
-    @NeverInline
-    public ServiceLoader<Service> getServices() {
-      return ServiceLoader.load(Service.class, Thread.currentThread().getContextClassLoader());
-    }
-
-    @NeverInline
-    public void printServices() {
-      print(ServiceLoader.load(Service.class, Thread.currentThread().getContextClassLoader()));
-    }
-
-    @NeverInline
-    public void print(ServiceLoader<Service> loader) {
-      loader.iterator().next().print();
-    }
-
-    @NeverInline
-    public void assignServicesField() {
-      serviceImplementations =
-          ServiceLoader.load(Service.class, Thread.currentThread().getContextClassLoader());
-    }
-
-    public static void main(String[] args) {
-      EscapingRunner escapingRunner = new EscapingRunner();
-      escapingRunner.getServices().iterator().next().print();
-      escapingRunner.printServices();
-      escapingRunner.assignServicesField();
-      escapingRunner.print(escapingRunner.serviceImplementations);
-    }
-  }
-
-  @Parameterized.Parameters(name = "{0}")
-  public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimes().build();
-  }
-
-  public ServiceLoaderRewritingTest(TestParameters parameters) {
-    this.parameters = parameters;
-  }
-
-  @Test
-  public void testRewritings() throws IOException, CompilationFailedException, ExecutionException {
-    Path path = temp.newFile("out.zip").toPath();
-    R8TestRunResult inspect =
-        testForR8(parameters.getBackend())
-            .addInnerClasses(ServiceLoaderRewritingTest.class)
-            .addKeepMainRule(MainRunner.class)
-            .setMinApi(parameters.getRuntime())
-            .addDataEntryResources(
-                DataEntryResource.fromBytes(
-                    StringUtils.lines(ServiceImpl.class.getTypeName()).getBytes(),
-                    "META-INF/services/" + Service.class.getTypeName(),
-                    Origin.unknown()))
-            .compile()
-            .writeToZip(path)
-            .run(parameters.getRuntime(), MainRunner.class)
-            .assertSuccessWithOutput(EXPECTED_OUTPUT)
-            .inspect(
-                inspector -> {
-                  // Check that we have actually rewritten the calls to ServiceLoader.load.
-                  ClassSubject clazz = inspector.clazz(MainRunner.class);
-                  assertTrue(clazz.isPresent());
-                  MethodSubject main = clazz.uniqueMethodWithName("main");
-                  assertTrue(main.isPresent());
-                  assertTrue(
-                      main.streamInstructions()
-                          .noneMatch(ServiceLoaderRewritingTest::isServiceLoaderLoad));
-                });
-
-    // Check that we have removed the service configuration from META-INF/services.
-    ZipFile zip = new ZipFile(path.toFile());
-    assertNull(zip.getEntry("META-INF/services"));
-  }
-
-  @Test
-  public void testDoNoRewrite() throws IOException, CompilationFailedException, ExecutionException {
-    Path path = temp.newFile("out.zip").toPath();
-    CodeInspector inspector =
-        testForR8(parameters.getBackend())
-            .addInnerClasses(ServiceLoaderRewritingTest.class)
-            .addKeepMainRule(OtherRunner.class)
-            .setMinApi(parameters.getRuntime())
-            .addDataEntryResources(
-                DataEntryResource.fromBytes(
-                    StringUtils.lines(ServiceImpl.class.getTypeName()).getBytes(),
-                    "META-INF/services/" + Service.class.getTypeName(),
-                    Origin.unknown()))
-            .compile()
-            .writeToZip(path)
-            .run(parameters.getRuntime(), OtherRunner.class)
-            .assertSuccessWithOutput(EXPECTED_OUTPUT)
-            .inspector();
-
-    // Check that we have not rewritten the calls to ServiceLoader.load.
-    ClassSubject clazz = inspector.clazz(OtherRunner.class);
-    assertTrue(clazz.isPresent());
-    MethodSubject main = clazz.uniqueMethodWithName("main");
-    assertTrue(main.isPresent());
-    assertEquals(
-        3,
-        main.streamInstructions().filter(ServiceLoaderRewritingTest::isServiceLoaderLoad).count());
-
-    // Check that we have not removed the service configuration from META-INF/services.
-    ZipFile zip = new ZipFile(path.toFile());
-    ClassSubject serviceImpl = inspector.clazz(ServiceImpl.class);
-    assertTrue(serviceImpl.isPresent());
-    assertNotNull(zip.getEntry("META-INF/services/" + serviceImpl.getFinalName()));
-  }
-
-  @Test
-  public void testDoNoRewriteWhenEscaping()
-      throws IOException, CompilationFailedException, ExecutionException {
-    Path path = temp.newFile("out.zip").toPath();
-    CodeInspector inspector =
-        testForR8(parameters.getBackend())
-            .addInnerClasses(ServiceLoaderRewritingTest.class)
-            .addKeepMainRule(EscapingRunner.class)
-            .enableInliningAnnotations()
-            .setMinApi(parameters.getRuntime())
-            .noMinification()
-            .addDataEntryResources(
-                DataEntryResource.fromBytes(
-                    StringUtils.lines(ServiceImpl.class.getTypeName()).getBytes(),
-                    "META-INF/services/" + Service.class.getTypeName(),
-                    Origin.unknown()))
-            .compile()
-            .writeToZip(path)
-            .run(parameters.getRuntime(), EscapingRunner.class)
-            .assertSuccessWithOutput(EXPECTED_OUTPUT)
-            .inspector();
-
-    // Check that we have not rewritten the calls to ServiceLoader.load.
-    ClassSubject clazz = inspector.clazz(EscapingRunner.class);
-    assertTrue(clazz.isPresent());
-    int allServiceLoaders =
-        clazz.allMethods().stream()
-            .mapToInt(
-                method ->
-                    (int)
-                        method
-                            .streamInstructions()
-                            .filter(ServiceLoaderRewritingTest::isServiceLoaderLoad)
-                            .count())
-            .sum();
-    assertEquals(3, allServiceLoaders);
-    // Check that we have not removed the service configuration from META-INF/services.
-    ZipFile zip = new ZipFile(path.toFile());
-    ClassSubject serviceImpl = inspector.clazz(ServiceImpl.class);
-    assertTrue(serviceImpl.isPresent());
-    assertNotNull(zip.getEntry("META-INF/services/" + serviceImpl.getFinalName()));
-  }
-
-  @Test
-  public void testKeepAsOriginal()
-      throws IOException, CompilationFailedException, ExecutionException {
-    Path path = temp.newFile("out.zip").toPath();
-    CodeInspector inspector =
-        testForR8(parameters.getBackend())
-            .addInnerClasses(ServiceLoaderRewritingTest.class)
-            .addKeepMainRule(MainRunner.class)
-            .addKeepClassRules(Service.class)
-            .setMinApi(parameters.getRuntime())
-            .addDataEntryResources(
-                DataEntryResource.fromBytes(
-                    StringUtils.lines(ServiceImpl.class.getTypeName()).getBytes(),
-                    "META-INF/services/" + Service.class.getTypeName(),
-                    Origin.unknown()))
-            .compile()
-            .writeToZip(path)
-            .run(parameters.getRuntime(), MainRunner.class)
-            .assertSuccessWithOutput(EXPECTED_OUTPUT)
-            .inspector();
-
-    // Check that we have not rewritten the calls to ServiceLoader.load.
-    ClassSubject clazz = inspector.clazz(MainRunner.class);
-    assertTrue(clazz.isPresent());
-    MethodSubject main = clazz.uniqueMethodWithName("main");
-    assertTrue(main.isPresent());
-    assertEquals(
-        3,
-        main.streamInstructions().filter(ServiceLoaderRewritingTest::isServiceLoaderLoad).count());
-
-    // Check that we have not removed the service configuration from META-INF/services.
-    ZipFile zip = new ZipFile(path.toFile());
-    ClassSubject service = inspector.clazz(Service.class);
-    assertTrue(service.isPresent());
-    assertNotNull(zip.getEntry("META-INF/services/" + service.getFinalName()));
-  }
-
-  private static boolean isServiceLoaderLoad(InstructionSubject instruction) {
-    return instruction.isInvokeStatic()
-        && instruction.getMethod().qualifiedName().contains("ServiceLoader.load");
-  }
-}