Remove uninstantiated type optimization pass

Change-Id: I4514f4d8342f4951683f5ee0db01b80d90903926
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 1f87898..0c8c20d 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -52,11 +52,8 @@
 import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.ir.desugar.records.RecordRewriter;
 import com.android.tools.r8.ir.optimize.AssertionsRewriter;
-import com.android.tools.r8.ir.optimize.MethodPoolCollection;
 import com.android.tools.r8.ir.optimize.NestReducer;
 import com.android.tools.r8.ir.optimize.SwitchMapCollector;
-import com.android.tools.r8.ir.optimize.UninstantiatedTypeOptimization;
-import com.android.tools.r8.ir.optimize.UninstantiatedTypeOptimization.UninstantiatedTypeOptimizationGraphLens;
 import com.android.tools.r8.ir.optimize.enums.EnumUnboxingCfMethods;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
 import com.android.tools.r8.ir.optimize.templates.CfUtilityMethodsForCodeOptimizations;
@@ -510,17 +507,6 @@
         }
         assert appView.verticallyMergedClasses() != null;
 
-        if (options.enableUninstantiatedTypeOptimization) {
-          timing.begin("UninstantiatedTypeOptimization");
-          UninstantiatedTypeOptimizationGraphLens lens =
-              new UninstantiatedTypeOptimization(appViewWithLiveness)
-                  .strenghtenOptimizationInfo()
-                  .run(new MethodPoolCollection(appViewWithLiveness), executorService, timing);
-          assert lens == null || getDirectApp(appView).verifyNothingToRewrite(appView, lens);
-          appView.rewriteWithLens(lens);
-          timing.end();
-        }
-
         HorizontalClassMerger.createForInitialClassMerging(appViewWithLiveness)
             .runIfNecessary(runtimeTypeCheckInfo, executorService, timing);
       }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java b/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
index c6bb8a7..04ba47d 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
@@ -223,7 +223,7 @@
 
       // We can exploit that a catch handler must be dead if its guard is never instantiated
       // directly or indirectly.
-      if (appInfoWithLiveness != null && appView.options().enableUninstantiatedTypeOptimization) {
+      if (appInfoWithLiveness != null) {
         DexProgramClass clazz = asProgramClassOrNull(appView.definitionFor(guard));
         if (clazz != null && !appInfoWithLiveness.isInstantiatedDirectlyOrIndirectly(clazz)) {
           builder.add(new CatchHandler<>(guard, target));
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MethodPoolCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/MethodPoolCollection.java
index 2b439a6..652c185 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MethodPoolCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MethodPoolCollection.java
@@ -34,10 +34,6 @@
 
   private final Predicate<DexEncodedMethod> methodTester;
 
-  public MethodPoolCollection(AppView<AppInfoWithLiveness> appView) {
-    this(appView, appView.appInfo().computeSubtypingInfo());
-  }
-
   public MethodPoolCollection(AppView<AppInfoWithLiveness> appView, SubtypingInfo subtypingInfo) {
     this(appView, subtypingInfo, Predicates.alwaysTrue());
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
deleted file mode 100644
index df7eeb3..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
+++ /dev/null
@@ -1,331 +0,0 @@
-// Copyright (c) 2018, 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.optimize.UninstantiatedTypeOptimization.Strategy.ALLOW_ARGUMENT_REMOVAL;
-import static com.android.tools.r8.ir.optimize.UninstantiatedTypeOptimization.Strategy.DISALLOW_ARGUMENT_REMOVAL;
-
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexProto;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.NestedGraphLens;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
-import com.android.tools.r8.graph.TopDownClassHierarchyTraversal;
-import com.android.tools.r8.ir.analysis.value.AbstractValue;
-import com.android.tools.r8.ir.optimize.MemberPoolCollection.MemberPool;
-import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
-import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.MethodSignatureEquivalence;
-import com.android.tools.r8.utils.Timing;
-import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
-import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap;
-import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap;
-import com.google.common.base.Equivalence.Wrapper;
-import com.google.common.collect.BiMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.IdentityHashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ExecutorService;
-
-public class UninstantiatedTypeOptimization {
-
-  enum Strategy {
-    ALLOW_ARGUMENT_REMOVAL,
-    DISALLOW_ARGUMENT_REMOVAL
-  }
-
-  public static class UninstantiatedTypeOptimizationGraphLens extends NestedGraphLens {
-
-    private final Map<DexMethod, ArgumentInfoCollection> removedArgumentsInfoPerMethod;
-
-    UninstantiatedTypeOptimizationGraphLens(
-        BidirectionalOneToOneMap<DexMethod, DexMethod> methodMap,
-        Map<DexMethod, ArgumentInfoCollection> removedArgumentsInfoPerMethod,
-        AppView<?> appView) {
-      super(appView, EMPTY_FIELD_MAP, methodMap, EMPTY_TYPE_MAP);
-      this.removedArgumentsInfoPerMethod = removedArgumentsInfoPerMethod;
-    }
-
-    @Override
-    protected RewrittenPrototypeDescription internalDescribePrototypeChanges(
-        RewrittenPrototypeDescription prototypeChanges, DexMethod method) {
-      DexMethod previous = internalGetPreviousMethodSignature(method);
-      if (previous == method) {
-        assert !removedArgumentsInfoPerMethod.containsKey(method);
-        return prototypeChanges;
-      }
-      if (method.getReturnType().isVoidType() && !previous.getReturnType().isVoidType()) {
-        prototypeChanges =
-            prototypeChanges.withConstantReturn(previous.getReturnType(), dexItemFactory());
-      }
-      return prototypeChanges.withRemovedArguments(
-          removedArgumentsInfoPerMethod.getOrDefault(method, ArgumentInfoCollection.empty()));
-    }
-  }
-
-  private static final MethodSignatureEquivalence equivalence = MethodSignatureEquivalence.get();
-
-  private final AppView<AppInfoWithLiveness> appView;
-
-  public UninstantiatedTypeOptimization(AppView<AppInfoWithLiveness> appView) {
-    this.appView = appView;
-  }
-
-  public UninstantiatedTypeOptimization strenghtenOptimizationInfo() {
-    OptimizationFeedback feedback = OptimizationFeedbackSimple.getInstance();
-    AbstractValue nullValue = appView.abstractValueFactory().createSingleNumberValue(0);
-    for (DexProgramClass clazz : appView.appInfo().classes()) {
-      clazz.forEachField(
-          field -> {
-            if (field.type().isAlwaysNull(appView)) {
-              feedback.recordFieldHasAbstractValue(field, appView, nullValue);
-            }
-          });
-      clazz.forEachMethod(
-          method -> {
-            if (method.returnType().isAlwaysNull(appView)) {
-              feedback.methodReturnsAbstractValue(method, appView, nullValue);
-            }
-          });
-    }
-    return this;
-  }
-
-  public UninstantiatedTypeOptimizationGraphLens run(
-      MethodPoolCollection methodPoolCollection, ExecutorService executorService, Timing timing) {
-    try {
-      methodPoolCollection.buildAll(executorService, timing);
-    } catch (Exception e) {
-      throw new RuntimeException(e);
-    }
-
-    Map<Wrapper<DexMethod>, Set<DexType>> changedVirtualMethods = new HashMap<>();
-    MutableBidirectionalOneToOneMap<DexMethod, DexMethod> methodMapping =
-        new BidirectionalOneToOneHashMap<>();
-    Map<DexMethod, ArgumentInfoCollection> removedArgumentsInfoPerMethod = new IdentityHashMap<>();
-
-    TopDownClassHierarchyTraversal.forProgramClasses(appView)
-        .visit(
-            appView.appInfo().classes(),
-            clazz ->
-                processClass(
-                    clazz,
-                    changedVirtualMethods,
-                    methodMapping.getForwardMap(),
-                    methodPoolCollection,
-                    removedArgumentsInfoPerMethod));
-
-    if (!methodMapping.isEmpty()) {
-      return new UninstantiatedTypeOptimizationGraphLens(
-          methodMapping, removedArgumentsInfoPerMethod, appView);
-    }
-    return null;
-  }
-
-  private void processClass(
-      DexProgramClass clazz,
-      Map<Wrapper<DexMethod>, Set<DexType>> changedVirtualMethods,
-      BiMap<DexMethod, DexMethod> methodMapping,
-      MethodPoolCollection methodPoolCollection,
-      Map<DexMethod, ArgumentInfoCollection> removedArgumentsInfoPerMethod) {
-    MemberPool<DexMethod> methodPool = methodPoolCollection.get(clazz);
-
-    if (clazz.isInterface()) {
-      // Do not allow changing the prototype of methods that override an interface method.
-      // This achieved by faking that there is already a method with the given signature.
-      for (DexEncodedMethod virtualMethod : clazz.virtualMethods()) {
-        RewrittenPrototypeDescription prototypeChanges =
-            RewrittenPrototypeDescription.createForUninstantiatedTypes(
-                virtualMethod.getReference(),
-                appView,
-                getRemovedArgumentsInfo(virtualMethod, ALLOW_ARGUMENT_REMOVAL));
-        if (!prototypeChanges.isEmpty()) {
-          DexMethod newMethod = getNewMethodSignature(virtualMethod, prototypeChanges);
-          Wrapper<DexMethod> wrapper = equivalence.wrap(newMethod);
-          if (!methodPool.hasSeenDirectly(wrapper)) {
-            methodPool.seen(wrapper);
-          }
-        }
-      }
-      return;
-    }
-
-    Map<DexEncodedMethod, RewrittenPrototypeDescription> prototypeChangesPerMethod =
-        new IdentityHashMap<>();
-    for (DexEncodedMethod directMethod : clazz.directMethods()) {
-      RewrittenPrototypeDescription prototypeChanges =
-          getPrototypeChanges(directMethod, ALLOW_ARGUMENT_REMOVAL);
-      if (!prototypeChanges.isEmpty()) {
-        prototypeChangesPerMethod.put(directMethod, prototypeChanges);
-      }
-    }
-
-    // Reserve all signatures which are known to not be touched below.
-    Set<Wrapper<DexMethod>> usedSignatures = new HashSet<>();
-    for (DexEncodedMethod method : clazz.methods()) {
-      if (!prototypeChangesPerMethod.containsKey(method)) {
-        usedSignatures.add(equivalence.wrap(method.getReference()));
-      }
-    }
-
-    // Change the return type of direct methods that return an uninstantiated type to void.
-    clazz
-        .getMethodCollection()
-        .replaceDirectMethods(
-            encodedMethod -> {
-              DexMethod method = encodedMethod.getReference();
-              RewrittenPrototypeDescription prototypeChanges =
-                  prototypeChangesPerMethod.getOrDefault(
-                      encodedMethod, RewrittenPrototypeDescription.none());
-              ArgumentInfoCollection removedArgumentsInfo =
-                  prototypeChanges.getArgumentInfoCollection();
-              DexMethod newMethod = getNewMethodSignature(encodedMethod, prototypeChanges);
-              if (newMethod != method) {
-                Wrapper<DexMethod> wrapper = equivalence.wrap(newMethod);
-
-                // TODO(b/110806787): Can be extended to handle collisions by renaming the given
-                // method.
-                if (usedSignatures.add(wrapper)) {
-                  methodMapping.put(method, newMethod);
-                  if (removedArgumentsInfo.hasRemovedArguments()) {
-                    removedArgumentsInfoPerMethod.put(newMethod, removedArgumentsInfo);
-                  }
-                  return encodedMethod.toTypeSubstitutedMethod(
-                      newMethod,
-                      removedArgumentsInfo.createParameterAnnotationsRemover(encodedMethod));
-                }
-              }
-              return encodedMethod;
-            });
-
-    // Change the return type of virtual methods that return an uninstantiated type to void.
-    // This is done in two steps. First we change the return type of all methods that override
-    // a method whose return type has already been changed to void previously. Note that
-    // all supertypes of the current class are always visited prior to the current class.
-    // This is important to ensure that a method that used to override a method in its super
-    // class will continue to do so after this optimization.
-    clazz
-        .getMethodCollection()
-        .replaceVirtualMethods(
-            encodedMethod -> {
-              DexMethod method = encodedMethod.getReference();
-              RewrittenPrototypeDescription prototypeChanges =
-                  getPrototypeChanges(encodedMethod, DISALLOW_ARGUMENT_REMOVAL);
-              ArgumentInfoCollection removedArgumentsInfo =
-                  prototypeChanges.getArgumentInfoCollection();
-              DexMethod newMethod = getNewMethodSignature(encodedMethod, prototypeChanges);
-              if (newMethod != method) {
-                Wrapper<DexMethod> wrapper = equivalence.wrap(newMethod);
-
-                boolean isOverrideOfPreviouslyChangedMethodInSuperClass =
-                    changedVirtualMethods
-                        .getOrDefault(equivalence.wrap(method), ImmutableSet.of())
-                        .stream()
-                        .anyMatch(other -> appView.appInfo().isSubtype(clazz.type, other));
-                if (isOverrideOfPreviouslyChangedMethodInSuperClass) {
-                  assert methodPool.hasSeen(wrapper);
-
-                  boolean signatureIsAvailable = usedSignatures.add(wrapper);
-                  assert signatureIsAvailable;
-
-                  methodMapping.put(method, newMethod);
-                  return encodedMethod.toTypeSubstitutedMethod(
-                      newMethod,
-                      removedArgumentsInfo.createParameterAnnotationsRemover(encodedMethod));
-                }
-              }
-              return encodedMethod;
-            });
-    clazz
-        .getMethodCollection()
-        .replaceVirtualMethods(
-            encodedMethod -> {
-              DexMethod method = encodedMethod.getReference();
-              RewrittenPrototypeDescription prototypeChanges =
-                  getPrototypeChanges(encodedMethod, DISALLOW_ARGUMENT_REMOVAL);
-              ArgumentInfoCollection removedArgumentsInfo =
-                  prototypeChanges.getArgumentInfoCollection();
-              DexMethod newMethod = getNewMethodSignature(encodedMethod, prototypeChanges);
-              if (newMethod != method) {
-                Wrapper<DexMethod> wrapper = equivalence.wrap(newMethod);
-
-                // TODO(b/110806787): Can be extended to handle collisions by renaming the given
-                //  method. Note that this also requires renaming all of the methods that override
-                // this
-                //  method, though.
-                if (!methodPool.hasSeen(wrapper) && usedSignatures.add(wrapper)) {
-                  methodPool.seen(wrapper);
-
-                  methodMapping.put(method, newMethod);
-
-                  boolean added =
-                      changedVirtualMethods
-                          .computeIfAbsent(
-                              equivalence.wrap(method), key -> Sets.newIdentityHashSet())
-                          .add(clazz.type);
-                  assert added;
-
-                  return encodedMethod.toTypeSubstitutedMethod(
-                      newMethod,
-                      removedArgumentsInfo.createParameterAnnotationsRemover(encodedMethod));
-                }
-              }
-              return encodedMethod;
-            });
-  }
-
-  private RewrittenPrototypeDescription getPrototypeChanges(
-      DexEncodedMethod encodedMethod, Strategy strategy) {
-    if (ArgumentRemovalUtils.isPinned(encodedMethod, appView)
-        || appView.appInfo().isKeepConstantArgumentsMethod(encodedMethod.getReference())) {
-      return RewrittenPrototypeDescription.none();
-    }
-    return RewrittenPrototypeDescription.createForUninstantiatedTypes(
-        encodedMethod.getReference(), appView, getRemovedArgumentsInfo(encodedMethod, strategy));
-  }
-
-  private ArgumentInfoCollection getRemovedArgumentsInfo(
-      DexEncodedMethod encodedMethod, Strategy strategy) {
-    if (strategy == DISALLOW_ARGUMENT_REMOVAL) {
-      return ArgumentInfoCollection.empty();
-    }
-
-    ArgumentInfoCollection.Builder argInfosBuilder = ArgumentInfoCollection.builder();
-    DexProto proto = encodedMethod.getReference().proto;
-    int offset = encodedMethod.getFirstNonReceiverArgumentIndex();
-    for (int i = 0; i < proto.parameters.size(); ++i) {
-      DexType type = proto.parameters.values[i];
-      if (type.isAlwaysNull(appView)) {
-        RemovedArgumentInfo removedArg =
-            RemovedArgumentInfo.builder()
-                .setSingleValue(appView.abstractValueFactory().createNullValue())
-                .setType(type)
-                .build();
-        argInfosBuilder.addArgumentInfo(i + offset, removedArg);
-      }
-    }
-    return argInfosBuilder.build();
-  }
-
-  private DexMethod getNewMethodSignature(
-      DexEncodedMethod encodedMethod, RewrittenPrototypeDescription prototypeChanges) {
-    DexItemFactory dexItemFactory = appView.dexItemFactory();
-    DexMethod method = encodedMethod.getReference();
-    DexProto newProto = prototypeChanges.rewriteProto(encodedMethod, dexItemFactory);
-
-    return dexItemFactory.createMethod(method.holder, newProto, method.name);
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/BooleanMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/BooleanMethodOptimizer.java
index 2c93f77..b0b64ee 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/BooleanMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/BooleanMethodOptimizer.java
@@ -10,6 +10,8 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
 import com.android.tools.r8.ir.code.ConstString;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
@@ -37,10 +39,12 @@
   @Override
   public void optimize(
       IRCode code,
+      BasicBlockIterator blockIterator,
       InstructionListIterator instructionIterator,
       InvokeMethod invoke,
       DexClassAndMethod singleTarget,
-      Set<Value> affectedValues) {
+      Set<Value> affectedValues,
+      Set<BasicBlock> blocksToRemove) {
     if (singleTarget.getReference() == dexItemFactory.booleanMembers.booleanValue) {
       optimizeBooleanValue(code, instructionIterator, invoke);
     } else if (singleTarget.getReference() == dexItemFactory.booleanMembers.parseBoolean) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/ByteMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/ByteMethodOptimizer.java
index 5fb3d05..952d7cc 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/ByteMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/ByteMethodOptimizer.java
@@ -8,6 +8,8 @@
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionListIterator;
@@ -33,10 +35,12 @@
   @Override
   public void optimize(
       IRCode code,
+      BasicBlockIterator blockIterator,
       InstructionListIterator instructionIterator,
       InvokeMethod invoke,
       DexClassAndMethod singleTarget,
-      Set<Value> affectedValues) {
+      Set<Value> affectedValues,
+      Set<BasicBlock> blocksToRemove) {
     if (singleTarget.getReference() == dexItemFactory.byteMembers.byteValue) {
       optimizeByteValue(instructionIterator, invoke);
     }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/EnumMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/EnumMethodOptimizer.java
index 5ee7017..167a528 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/EnumMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/EnumMethodOptimizer.java
@@ -12,6 +12,8 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.code.Assume;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.InstructionListIterator;
 import com.android.tools.r8.ir.code.InvokeMethod;
@@ -35,10 +37,12 @@
   @Override
   public void optimize(
       IRCode code,
+      BasicBlockIterator blockIterator,
       InstructionListIterator instructionIterator,
       InvokeMethod invoke,
       DexClassAndMethod singleTarget,
-      Set<Value> affectedValues) {
+      Set<Value> affectedValues,
+      Set<BasicBlock> blocksToRemove) {
     if (singleTarget.getReference() == appView.dexItemFactory().enumMembers.valueOf
         && invoke.inValues().get(0).isConstClass()) {
       insertAssumeDynamicType(code, instructionIterator, invoke);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMemberOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMemberOptimizer.java
index 1ce2493..935e869 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMemberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMemberOptimizer.java
@@ -12,6 +12,8 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionListIterator;
@@ -115,48 +117,62 @@
       MethodProcessor methodProcessor,
       MethodProcessingContext methodProcessingContext) {
     Set<Value> affectedValues = Sets.newIdentityHashSet();
-    InstructionListIterator instructionIterator = code.instructionListIterator();
-    Map<LibraryMethodModelCollection<?>, LibraryMethodModelCollection.State> optimizationStates =
-        new IdentityHashMap<>();
-    while (instructionIterator.hasNext()) {
-      Instruction instruction = instructionIterator.next();
-      if (!instruction.isInvokeMethod()) {
+    BasicBlockIterator blockIterator = code.listIterator();
+    Set<BasicBlock> blocksToRemove = Sets.newIdentityHashSet();
+    while (blockIterator.hasNext()) {
+      BasicBlock block = blockIterator.next();
+      if (blocksToRemove.contains(block)) {
         continue;
       }
 
-      InvokeMethod invoke = instruction.asInvokeMethod();
-      DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, code.context());
-      if (singleTarget == null) {
-        continue;
-      }
+      InstructionListIterator instructionIterator = block.listIterator(code);
+      Map<LibraryMethodModelCollection<?>, LibraryMethodModelCollection.State> optimizationStates =
+          new IdentityHashMap<>();
+      while (instructionIterator.hasNext()) {
+        Instruction instruction = instructionIterator.next();
+        if (!instruction.isInvokeMethod()) {
+          continue;
+        }
 
-      LibraryMethodModelCollection<?> optimizer =
-          libraryMethodModelCollections.get(singleTarget.getHolderType());
-      if (optimizer == null) {
-        continue;
-      }
+        InvokeMethod invoke = instruction.asInvokeMethod();
+        DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, code.context());
+        if (singleTarget == null) {
+          continue;
+        }
 
-      if (invoke.hasUnusedOutValue()
-          && !singleTarget.getDefinition().isInstanceInitializer()
-          && !invoke.instructionMayHaveSideEffects(appView, code.context())) {
-        instructionIterator.removeOrReplaceByDebugLocalRead();
-        continue;
-      }
+        LibraryMethodModelCollection<?> optimizer =
+            libraryMethodModelCollections.get(singleTarget.getHolderType());
+        if (optimizer == null) {
+          continue;
+        }
 
-      LibraryMethodModelCollection.State optimizationState =
-          optimizationStates.computeIfAbsent(
-              optimizer,
-              libraryMethodModelCollection ->
-                  libraryMethodModelCollection.createInitialState(methodProcessor));
-      optimizer.optimize(
-          code,
-          instructionIterator,
-          invoke,
-          singleTarget,
-          affectedValues,
-          optimizationState,
-          methodProcessingContext);
+        if (invoke.hasUnusedOutValue()
+            && !singleTarget.getDefinition().isInstanceInitializer()
+            && !invoke.instructionMayHaveSideEffects(appView, code.context())) {
+          instructionIterator.removeOrReplaceByDebugLocalRead();
+          continue;
+        }
+
+        LibraryMethodModelCollection.State optimizationState =
+            optimizationStates.computeIfAbsent(
+                optimizer,
+                libraryMethodModelCollection ->
+                    libraryMethodModelCollection.createInitialState(methodProcessor));
+        optimizer.optimize(
+            code,
+            blockIterator,
+            instructionIterator,
+            invoke,
+            singleTarget,
+            affectedValues,
+            blocksToRemove,
+            optimizationState,
+            methodProcessingContext);
+      }
     }
+
+    code.removeBlocks(blocksToRemove);
+
     if (!affectedValues.isEmpty()) {
       new TypeAnalysis(appView).narrowing(affectedValues);
     }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMethodModelCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMethodModelCollection.java
index da38111..dbc5b0b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMethodModelCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMethodModelCollection.java
@@ -7,6 +7,8 @@
 import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.InstructionListIterator;
 import com.android.tools.r8.ir.code.InvokeMethod;
@@ -34,28 +36,34 @@
    */
   void optimize(
       IRCode code,
+      BasicBlockIterator blockIterator,
       InstructionListIterator instructionIterator,
       InvokeMethod invoke,
       DexClassAndMethod singleTarget,
       Set<Value> affectedValues,
+      Set<BasicBlock> blocksToRemove,
       T state,
       MethodProcessingContext methodProcessingContext);
 
   @SuppressWarnings("unchecked")
   default void optimize(
       IRCode code,
+      BasicBlockIterator blockIterator,
       InstructionListIterator instructionIterator,
       InvokeMethod invoke,
       DexClassAndMethod singleTarget,
       Set<Value> affectedValues,
+      Set<BasicBlock> blocksToRemove,
       Object state,
       MethodProcessingContext methodProcessingContext) {
     optimize(
         code,
+        blockIterator,
         instructionIterator,
         invoke,
         singleTarget,
         affectedValues,
+        blocksToRemove,
         (T) state,
         methodProcessingContext);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/LogMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/LogMethodOptimizer.java
index aa93f3c..37ca53d 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/LogMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/LogMethodOptimizer.java
@@ -9,6 +9,8 @@
 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.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionListIterator;
@@ -102,10 +104,12 @@
   @Override
   public void optimize(
       IRCode code,
+      BasicBlockIterator blockIterator,
       InstructionListIterator instructionIterator,
       InvokeMethod invoke,
       DexClassAndMethod singleTarget,
-      Set<Value> affectedValues) {
+      Set<Value> affectedValues,
+      Set<BasicBlock> blocksToRemove) {
     int maxRemovedAndroidLogLevel =
         appView.options().getProguardConfiguration().getMaxRemovedAndroidLogLevel();
     if (singleTarget.getReference() == isLoggableMethod) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/NopLibraryMethodModelCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/library/NopLibraryMethodModelCollection.java
index 2eeb165..e545164 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/NopLibraryMethodModelCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/NopLibraryMethodModelCollection.java
@@ -7,6 +7,8 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.InstructionListIterator;
 import com.android.tools.r8.ir.code.InvokeMethod;
@@ -32,8 +34,10 @@
   @Override
   public void optimize(
       IRCode code,
+      BasicBlockIterator blockIterator,
       InstructionListIterator instructionIterator,
       InvokeMethod invoke,
       DexClassAndMethod singleTarget,
-      Set<Value> affectedValues) {}
+      Set<Value> affectedValues,
+      Set<BasicBlock> blocksToRemove) {}
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectMethodOptimizer.java
index c325500..98e0014 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectMethodOptimizer.java
@@ -8,6 +8,8 @@
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.InstructionListIterator;
 import com.android.tools.r8.ir.code.InvokeMethod;
@@ -30,10 +32,12 @@
   @Override
   public void optimize(
       IRCode code,
+      BasicBlockIterator blockIterator,
       InstructionListIterator instructionIterator,
       InvokeMethod invoke,
       DexClassAndMethod singleTarget,
-      Set<Value> affectedValues) {
+      Set<Value> affectedValues,
+      Set<BasicBlock> blocksToRemove) {
     if (singleTarget.getReference() == dexItemFactory.objectMembers.getClass) {
       optimizeGetClass(instructionIterator, invoke);
     }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java
index 1e518d6..7e55ce3 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java
@@ -11,6 +11,8 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.InstructionListIterator;
 import com.android.tools.r8.ir.code.InvokeMethod;
@@ -44,10 +46,12 @@
   @Override
   public void optimize(
       IRCode code,
+      BasicBlockIterator blockIterator,
       InstructionListIterator instructionIterator,
       InvokeMethod invoke,
       DexClassAndMethod singleTarget,
-      Set<Value> affectedValues) {
+      Set<Value> affectedValues,
+      Set<BasicBlock> blocksToRemove) {
     DexMethod singleTargetReference = singleTarget.getReference();
     switch (singleTargetReference.getName().byteAt(0)) {
       case 'e':
@@ -72,7 +76,14 @@
         break;
       case 'r':
         if (objectsMethods.isRequireNonNullMethod(singleTargetReference)) {
-          optimizeRequireNonNull(instructionIterator, invoke, affectedValues, singleTarget);
+          optimizeRequireNonNull(
+              code,
+              blockIterator,
+              instructionIterator,
+              invoke,
+              affectedValues,
+              blocksToRemove,
+              singleTarget);
         }
         break;
       case 't':
@@ -159,9 +170,12 @@
   }
 
   private void optimizeRequireNonNull(
+      IRCode code,
+      BasicBlockIterator blockIterator,
       InstructionListIterator instructionIterator,
       InvokeMethod invoke,
       Set<Value> affectedValues,
+      Set<BasicBlock> blocksToRemove,
       DexClassAndMethod singleTarget) {
     if (invoke.hasOutValue() && invoke.outValue().hasLocalInfo()) {
       // Replacing the out-value with an in-value would change debug info.
@@ -176,7 +190,13 @@
       }
       instructionIterator.removeOrReplaceByDebugLocalRead();
     } else if (inValue.isAlwaysNull(appView)) {
-      if (singleTarget.getReference() == objectsMethods.requireNonNullElse) {
+      if (singleTarget.getReference() == objectsMethods.requireNonNull) {
+        // Optimize Objects.requireNonNull(null) into throw null.
+        if (appView.hasClassHierarchy()) {
+          instructionIterator.replaceCurrentInstructionWithThrowNull(
+              appView.withClassHierarchy(), code, blockIterator, blocksToRemove, affectedValues);
+        }
+      } else if (singleTarget.getReference() == objectsMethods.requireNonNullElse) {
         // Optimize Objects.requireNonNullElse(null, defaultObj) into defaultObj if defaultObj
         // is never null.
         if (invoke.getLastArgument().isNeverNull()) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/StatelessLibraryMethodModelCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/library/StatelessLibraryMethodModelCollection.java
index df15197..520c27a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/StatelessLibraryMethodModelCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/StatelessLibraryMethodModelCollection.java
@@ -6,6 +6,8 @@
 
 import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
 import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.InstructionListIterator;
 import com.android.tools.r8.ir.code.InvokeMethod;
@@ -24,22 +26,33 @@
 
   public abstract void optimize(
       IRCode code,
-      InstructionListIterator instructionIterator,
-      InvokeMethod invoke,
-      DexClassAndMethod singleTarget,
-      Set<Value> affectedValues);
-
-  @Override
-  public final void optimize(
-      IRCode code,
+      BasicBlockIterator blockIterator,
       InstructionListIterator instructionIterator,
       InvokeMethod invoke,
       DexClassAndMethod singleTarget,
       Set<Value> affectedValues,
+      Set<BasicBlock> blocksToRemove);
+
+  @Override
+  public final void optimize(
+      IRCode code,
+      BasicBlockIterator blockIterator,
+      InstructionListIterator instructionIterator,
+      InvokeMethod invoke,
+      DexClassAndMethod singleTarget,
+      Set<Value> affectedValues,
+      Set<BasicBlock> blocksToRemove,
       State state,
       MethodProcessingContext methodProcessingContext) {
     assert state == null;
-    optimize(code, instructionIterator, invoke, singleTarget, affectedValues);
+    optimize(
+        code,
+        blockIterator,
+        instructionIterator,
+        invoke,
+        singleTarget,
+        affectedValues,
+        blocksToRemove);
   }
 
   static class State implements LibraryMethodModelCollection.State {}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/StringBuilderMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/StringBuilderMethodOptimizer.java
index 07ab344..8e03c61 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/StringBuilderMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/StringBuilderMethodOptimizer.java
@@ -18,6 +18,8 @@
 import com.android.tools.r8.graph.DexItemFactory.StringBuildingMethods;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionListIterator;
@@ -67,10 +69,12 @@
   @Override
   public void optimize(
       IRCode code,
+      BasicBlockIterator blockIterator,
       InstructionListIterator instructionIterator,
       InvokeMethod invoke,
       DexClassAndMethod singleTarget,
       Set<Value> affectedValues,
+      Set<BasicBlock> blocksToRemove,
       State state,
       MethodProcessingContext methodProcessingContext) {
     if (invoke.isInvokeMethodWithReceiver()) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/StringMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/StringMethodOptimizer.java
index 8c62340..e5483db 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/StringMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/StringMethodOptimizer.java
@@ -12,6 +12,8 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.BasicBlockIterator;
 import com.android.tools.r8.ir.code.DexItemBasedConstString;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
@@ -40,10 +42,12 @@
   @Override
   public void optimize(
       IRCode code,
+      BasicBlockIterator blockIterator,
       InstructionListIterator instructionIterator,
       InvokeMethod invoke,
       DexClassAndMethod singleTarget,
-      Set<Value> affectedValues) {
+      Set<Value> affectedValues,
+      Set<BasicBlock> blocksToRemove) {
     DexMethod singleTargetReference = singleTarget.getReference();
     if (singleTargetReference == dexItemFactory.stringMembers.equals) {
       optimizeEquals(code, instructionIterator, invoke.asInvokeVirtual());
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 308862a..b5235d2 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -220,7 +220,6 @@
     enableDevirtualization = false;
     enableVerticalClassMerging = false;
     enableEnumUnboxing = false;
-    enableUninstantiatedTypeOptimization = false;
     outline.enabled = false;
     enableEnumValueOptimization = false;
     enableValuePropagation = false;
@@ -329,7 +328,6 @@
   public boolean enableInitializedClassesInInstanceMethodsAnalysis = true;
   public boolean enableRedundantFieldLoadElimination = true;
   public boolean enableValuePropagation = true;
-  public boolean enableUninstantiatedTypeOptimization = true;
   // Currently disabled, see b/146957343.
   public boolean enableUninstantiatedTypeOptimizationForInterfaces = false;
   // TODO(b/138917494): Disable until we have numbers on potential performance penalties.
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/ObjectsRequireNonNullTest.java b/src/test/java/com/android/tools/r8/ir/optimize/ObjectsRequireNonNullTest.java
index ca64a9f..77da418 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/ObjectsRequireNonNullTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/ObjectsRequireNonNullTest.java
@@ -140,9 +140,7 @@
             .setMinApi(parameters.getApiLevel())
             .run(parameters.getRuntime(), MAIN)
             .assertSuccessWithOutput(JAVA_OUTPUT);
-    // TODO(b/157427150): would be able to remove the call to requireNonNull() if we knew that it
-    //  throws an NullPointerException that does not have a message.
-    test(result, 0, 1);
+    test(result, 0, 0);
   }
 
   static class ObjectsRequireNonNullTestMain {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
index f699bd7..615aa20 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
@@ -399,7 +399,6 @@
 
   private void configure(InternalOptions options) {
     options.enableClassInlining = false;
-    options.enableUninstantiatedTypeOptimization = false;
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithReceiverOptimizationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithReceiverOptimizationTest.java
index 06aae25..eca11f0 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithReceiverOptimizationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InvokeMethodWithReceiverOptimizationTest.java
@@ -64,10 +64,8 @@
             .addKeepMainRule(TestClass.class)
             .enableInliningAnnotations()
             .addOptionsModification(
-                options -> {
-                  options.enableUninstantiatedTypeOptimization = enableArgumentPropagation;
-                  options.callSiteOptimizationOptions().setEnabled(enableArgumentPropagation);
-                })
+                options ->
+                    options.callSiteOptimizationOptions().setEnabled(enableArgumentPropagation))
             // TODO(b/120764902): The calls to getOriginalName() below does not work in presence of
             //  argument removal.
             .noMinification()