Merge commit '5eddb3987a5140f150bf67a3476b197d9259ed6e' into dev-release
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
index c7b07d3..269dc23 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -112,16 +112,24 @@
 
   private final AppView<? extends AppInfoWithClassHierarchy> appView;
   private final EnumUnboxer enumUnboxer;
-  private final LensCodeRewriterUtils helper;
+  private LensCodeRewriterUtils helper = null;
   private final InternalOptions options;
 
   LensCodeRewriter(AppView<? extends AppInfoWithClassHierarchy> appView, EnumUnboxer enumUnboxer) {
     this.appView = appView;
     this.enumUnboxer = enumUnboxer;
-    this.helper = new LensCodeRewriterUtils(appView);
     this.options = appView.options();
   }
 
+  private LensCodeRewriterUtils getHelper() {
+    // The LensCodeRewriterUtils uses internal caches that are not valid if the graphLens changes.
+    if (helper != null && helper.hasGraphLens(appView.graphLens())) {
+      return helper;
+    }
+    helper = new LensCodeRewriterUtils(appView);
+    return helper;
+  }
+
   private Value makeOutValue(Instruction insn, IRCode code) {
     if (insn.hasOutValue()) {
       TypeElement oldType = insn.getOutType();
@@ -170,7 +178,7 @@
             {
               InvokeCustom invokeCustom = current.asInvokeCustom();
               DexCallSite callSite = invokeCustom.getCallSite();
-              DexCallSite newCallSite = helper.rewriteCallSite(callSite, method);
+              DexCallSite newCallSite = getHelper().rewriteCallSite(callSite, method);
               if (newCallSite != callSite) {
                 Value newOutValue = makeOutValue(invokeCustom, code);
                 InvokeCustom newInvokeCustom =
@@ -187,7 +195,8 @@
             {
               DexMethodHandle handle = current.asConstMethodHandle().getValue();
               DexMethodHandle newHandle =
-                  helper.rewriteDexMethodHandle(handle, NOT_ARGUMENT_TO_LAMBDA_METAFACTORY, method);
+                  getHelper()
+                      .rewriteDexMethodHandle(handle, NOT_ARGUMENT_TO_LAMBDA_METAFACTORY, method);
               if (newHandle != handle) {
                 Value newOutValue = makeOutValue(current, code);
                 iterator.replaceCurrentInstruction(new ConstMethodHandle(newOutValue, newHandle));
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java
index b8a70f9..dd5b328 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java
@@ -17,6 +17,7 @@
 import com.android.tools.r8.graph.DexMethodHandle;
 import com.android.tools.r8.graph.DexMethodHandle.MethodHandleType;
 import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DexValue;
 import com.android.tools.r8.graph.DexValue.DexValueMethodHandle;
@@ -26,6 +27,8 @@
 import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.UseRegistry.MethodHandleUse;
+import com.android.tools.r8.ir.code.Invoke;
+import com.android.tools.r8.ir.desugar.LambdaDescriptor;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -33,7 +36,6 @@
 
 public class LensCodeRewriterUtils {
 
-  private final AppView<?> appView;
   private final DexDefinitionSupplier definitions;
   private final GraphLens graphLens;
 
@@ -44,27 +46,21 @@
   private final Map<DexCallSite, DexCallSite> rewrittenCallSiteCache;
 
   public LensCodeRewriterUtils(AppView<?> appView) {
-    this(appView, false);
+    this(appView, appView.graphLens());
   }
 
   public LensCodeRewriterUtils(AppView<?> appView, boolean enableCallSiteCaching) {
-    this.appView = appView;
     this.definitions = appView;
-    this.graphLens = null;
+    this.graphLens = appView.graphLens();
     this.rewrittenCallSiteCache = enableCallSiteCaching ? new ConcurrentHashMap<>() : null;
   }
 
   public LensCodeRewriterUtils(DexDefinitionSupplier definitions, GraphLens graphLens) {
-    this.appView = null;
     this.definitions = definitions;
     this.graphLens = graphLens;
     this.rewrittenCallSiteCache = null;
   }
 
-  private GraphLens graphLens() {
-    return appView != null ? appView.graphLens() : graphLens;
-  }
-
   public DexCallSite rewriteCallSite(DexCallSite callSite, ProgramMethod context) {
     if (rewrittenCallSiteCache == null) {
       return rewriteCallSiteInternal(callSite, context);
@@ -85,22 +81,41 @@
         isLambdaMetaFactory ? ARGUMENT_TO_LAMBDA_METAFACTORY : NOT_ARGUMENT_TO_LAMBDA_METAFACTORY;
     List<DexValue> newArgs =
         rewriteBootstrapArguments(callSite.bootstrapArgs, methodHandleUse, context);
+    DexString newMethodName = computeNewMethodName(callSite, context, isLambdaMetaFactory);
     if (!newMethodProto.equals(callSite.methodProto)
+        || newMethodName != callSite.methodName
         || newBootstrapMethod != callSite.bootstrapMethod
         || !newArgs.equals(callSite.bootstrapArgs)) {
       return dexItemFactory.createCallSite(
-          callSite.methodName, newMethodProto, newBootstrapMethod, newArgs);
+          newMethodName, newMethodProto, newBootstrapMethod, newArgs);
     }
     return callSite;
   }
 
+  private DexString computeNewMethodName(
+      DexCallSite callSite, ProgramMethod context, boolean isLambdaMetaFactory) {
+    if (!isLambdaMetaFactory) {
+      return callSite.methodName;
+    }
+    assert callSite.getBootstrapArgs().size() > 0;
+    assert callSite.getBootstrapArgs().get(0).isDexValueMethodType();
+    // The targeted method may have been renamed, we need to update the name if that is the case.
+    DexMethod method =
+        LambdaDescriptor.getMainFunctionalInterfaceMethodReference(
+            callSite, definitions.dexItemFactory());
+    return graphLens
+        .lookupMethod(method, context.getReference(), Invoke.Type.INTERFACE)
+        .getReference()
+        .getName();
+  }
+
   public DexMethodHandle rewriteDexMethodHandle(
       DexMethodHandle methodHandle, MethodHandleUse use, ProgramMethod context) {
     if (methodHandle.isMethodHandle()) {
       DexMethod invokedMethod = methodHandle.asMethod();
       MethodHandleType oldType = methodHandle.type;
       MethodLookupResult lensLookup =
-          graphLens().lookupMethod(invokedMethod, context.getReference(), oldType.toInvokeType());
+          graphLens.lookupMethod(invokedMethod, context.getReference(), oldType.toInvokeType());
       DexMethod rewrittenTarget = lensLookup.getReference();
       DexMethod actualTarget;
       MethodHandleType newType;
@@ -120,7 +135,7 @@
             definitions
                 .dexItemFactory()
                 .createMethod(
-                    graphLens().lookupType(invokedMethod.holder),
+                    graphLens.lookupType(invokedMethod.holder),
                     rewrittenTarget.proto,
                     rewrittenTarget.name);
         newType = oldType;
@@ -147,7 +162,7 @@
       }
     } else {
       DexField field = methodHandle.asField();
-      DexField actualField = graphLens().lookupField(field);
+      DexField actualField = graphLens.lookupField(field);
       if (actualField != field) {
         return definitions
             .dexItemFactory()
@@ -192,7 +207,7 @@
         return rewriteDexMethodType(value.asDexValueMethodType());
       case TYPE:
         DexType oldType = value.asDexValueType().value;
-        DexType newType = graphLens().lookupType(oldType);
+        DexType newType = graphLens.lookupType(oldType);
         return newType != oldType ? new DexValueType(newType) : value;
       default:
         return value;
@@ -202,7 +217,7 @@
   public DexProto rewriteProto(DexProto proto) {
     return definitions
         .dexItemFactory()
-        .applyClassMappingToProto(proto, graphLens()::lookupType, protoFixupCache);
+        .applyClassMappingToProto(proto, graphLens::lookupType, protoFixupCache);
   }
 
   private DexValueMethodHandle rewriteDexValueMethodHandle(
@@ -211,4 +226,8 @@
     DexMethodHandle newHandle = rewriteDexMethodHandle(oldHandle, use, context);
     return newHandle != oldHandle ? new DexValueMethodHandle(newHandle) : methodHandle;
   }
+
+  public boolean hasGraphLens(GraphLens graphLens) {
+    return this.graphLens == graphLens;
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java
index ed967ef..bc7a544 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaDescriptor.java
@@ -23,6 +23,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
+import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 
 // Represents the lambda descriptor inferred from calls site.
@@ -182,6 +183,13 @@
     return implHandle.asMethod().getName().startsWith(factory.javacLambdaMethodPrefix);
   }
 
+  public void forEachErasedAndEnforcedTypes(BiConsumer<DexType, DexType> consumer) {
+    consumer.accept(erasedProto.returnType, enforcedProto.returnType);
+    for (int i = 0; i < enforcedProto.getArity(); i++) {
+      consumer.accept(erasedProto.getParameter(i), enforcedProto.getParameter(i));
+    }
+  }
+
   public Iterable<DexType> getReferencedBaseTypes(DexItemFactory dexItemFactory) {
     return enforcedProto.getBaseTypes(dexItemFactory);
   }
@@ -259,6 +267,15 @@
     return descriptor == MATCH_FAILED ? null : descriptor;
   }
 
+  public static DexMethod getMainFunctionalInterfaceMethodReference(
+      DexCallSite callSite, DexItemFactory factory) {
+    DexProto proto = callSite.getBootstrapArgs().get(0).asDexValueMethodType().value;
+    DexProto lambdaFactoryProto = callSite.methodProto;
+    DexType mainInterface = lambdaFactoryProto.returnType;
+    DexString funcMethodName = callSite.methodName;
+    return factory.createMethod(mainInterface, proto, funcMethodName);
+  }
+
   public static boolean isLambdaMetafactoryMethod(
       DexCallSite callSite, DexDefinitionSupplier definitions) {
     return callSite.bootstrapMethod.type.isInvokeStatic()
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
index 40627da..353d8b7 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
@@ -74,6 +74,7 @@
 import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
 import com.android.tools.r8.ir.conversion.MethodProcessor;
 import com.android.tools.r8.ir.conversion.PostMethodProcessor.Builder;
+import com.android.tools.r8.ir.desugar.LambdaDescriptor;
 import com.android.tools.r8.ir.optimize.enums.EnumDataMap.EnumData;
 import com.android.tools.r8.ir.optimize.enums.EnumInstanceFieldData.EnumInstanceFieldKnownData;
 import com.android.tools.r8.ir.optimize.enums.EnumInstanceFieldData.EnumInstanceFieldMappingData;
@@ -265,7 +266,7 @@
             analyzeCheckCast(instruction.asCheckCast(), eligibleEnums);
             break;
           case INVOKE_CUSTOM:
-            analyzeInvokeCustom(instruction.asInvokeCustom(), eligibleEnums);
+            analyzeInvokeCustom(instruction.asInvokeCustom(), eligibleEnums, code.context());
             break;
           case INVOKE_STATIC:
             analyzeInvokeStatic(instruction.asInvokeStatic(), eligibleEnums, code.context());
@@ -303,15 +304,45 @@
     }
   }
 
-  private void analyzeInvokeCustom(InvokeCustom invoke, Set<DexType> eligibleEnums) {
-    Consumer<DexType> typeReferenceConsumer =
-        type -> {
-          DexProgramClass enumClass = getEnumUnboxingCandidateOrNull(type);
-          if (enumClass != null) {
-            eligibleEnums.add(enumClass.getType());
+  private void markEnumEligible(DexType type, Set<DexType> eligibleEnums) {
+    DexProgramClass enumClass = getEnumUnboxingCandidateOrNull(type);
+    if (enumClass != null) {
+      eligibleEnums.add(enumClass.getType());
+    }
+  }
+
+  private void invalidateEnum(DexType type) {
+    DexProgramClass enumClass = getEnumUnboxingCandidateOrNull(type);
+    if (enumClass != null) {
+      markEnumAsUnboxable(Reason.INVALID_INVOKE_CUSTOM, enumClass);
+    }
+  }
+
+  private void analyzeInvokeCustom(
+      InvokeCustom invoke, Set<DexType> eligibleEnums, ProgramMethod context) {
+    invoke.getCallSite().getMethodProto().forEachType(t -> markEnumEligible(t, eligibleEnums));
+    LambdaDescriptor lambdaDescriptor =
+        LambdaDescriptor.tryInfer(invoke.getCallSite(), appView.appInfo(), context);
+    if (lambdaDescriptor == null) {
+      // Based on lambda we can see that enums cannot be unboxed if used in call site bootstrap
+      // arguments, since there might be expectations on overrides. Enums used directly in the
+      // method proto should be fine.
+      analyzeInvokeCustomParameters(invoke, this::invalidateEnum);
+      return;
+    }
+
+    analyzeInvokeCustomParameters(invoke, t -> markEnumEligible(t, eligibleEnums));
+
+    lambdaDescriptor.forEachErasedAndEnforcedTypes(
+        (erasedType, enforcedType) -> {
+          if (erasedType != enforcedType) {
+            invalidateEnum(erasedType);
+            invalidateEnum(enforcedType);
           }
-        };
-    invoke.getCallSite().getMethodProto().forEachType(typeReferenceConsumer);
+        });
+  }
+
+  private void analyzeInvokeCustomParameters(InvokeCustom invoke, Consumer<DexType> nonHolder) {
     invoke
         .getCallSite()
         .getBootstrapArgs()
@@ -322,26 +353,17 @@
                     bootstrapArgument.asDexValueMethodHandle().getValue();
                 if (methodHandle.isMethodHandle()) {
                   DexMethod method = methodHandle.asMethod();
-                  DexProgramClass enumClass =
-                      getEnumUnboxingCandidateOrNull(method.getHolderType());
-                  if (enumClass != null) {
-                    markEnumAsUnboxable(Reason.INVALID_INVOKE_CUSTOM, enumClass);
-                  } else {
-                    method.getProto().forEachType(typeReferenceConsumer);
-                  }
+                  invalidateEnum(method.getHolderType());
+                  method.getProto().forEachType(nonHolder);
                 } else {
                   assert methodHandle.isFieldHandle();
                   DexField field = methodHandle.asField();
-                  DexProgramClass enumClass = getEnumUnboxingCandidateOrNull(field.getHolderType());
-                  if (enumClass != null) {
-                    markEnumAsUnboxable(Reason.INVALID_INVOKE_CUSTOM, enumClass);
-                  } else {
-                    typeReferenceConsumer.accept(field.getType());
-                  }
+                  invalidateEnum(field.getHolderType());
+                  nonHolder.accept(field.type);
                 }
               } else if (bootstrapArgument.isDexValueMethodType()) {
                 DexProto proto = bootstrapArgument.asDexValueMethodType().getValue();
-                proto.forEachType(typeReferenceConsumer);
+                proto.forEachType(nonHolder);
               }
             });
   }
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 494cf92..fb814c6 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -4626,38 +4626,38 @@
       }
 
       DexProgramClass clazz = asProgramClassOrNull(definitionFor(type, method));
-      if (clazz != null) {
+      if (clazz != null && clazz.isInterface()) {
+        KeepReason reason = KeepReason.reflectiveUseIn(method);
+        markInterfaceAsInstantiated(clazz, graphReporter.registerClass(clazz, reason));
         worklist.addIfNotSeen(clazz);
       }
     }
 
     while (worklist.hasNext()) {
       DexProgramClass clazz = worklist.next();
-      if (!clazz.isInterface()) {
-        continue;
-      }
+      assert clazz.isInterface();
 
-      // Add this interface to the set of pinned items to ensure that we do not merge the
-      // interface into its unique subtype, if any.
-      // TODO(b/145344105): This should be superseded by the unknown interface hierarchy.
+      // Keep this interface to ensure that we do not merge the interface into its unique subtype,
+      // or merge other interfaces into it horizontally.
       keepInfo.joinClass(clazz, joiner -> joiner.disallowOptimization().disallowShrinking());
-      KeepReason reason = KeepReason.reflectiveUseIn(method);
-      markInterfaceAsInstantiated(clazz, graphReporter.registerClass(clazz, reason));
 
-      // Also pin all of its virtual methods to ensure that the devirtualizer does not perform
+      // Also keep all of its virtual methods to ensure that the devirtualizer does not perform
       // illegal rewritings of invoke-interface instructions into invoke-virtual instructions.
-      clazz.forEachProgramVirtualMethod(
-          virtualMethod -> {
-            keepInfo.joinMethod(
-                virtualMethod, joiner -> joiner.disallowOptimization().disallowShrinking());
-            markVirtualMethodAsReachable(virtualMethod.getReference(), true, method, reason);
-          });
+      if (mode.isInitialTreeShaking()) {
+        KeepReason reason = KeepReason.reflectiveUseIn(method);
+        clazz.forEachProgramVirtualMethod(
+            virtualMethod -> {
+              keepInfo.joinMethod(
+                  virtualMethod, joiner -> joiner.disallowOptimization().disallowShrinking());
+              markVirtualMethodAsReachable(virtualMethod.getReference(), true, method, reason);
+            });
+      }
 
       // Repeat for all super interfaces.
       for (DexType implementedType : clazz.getInterfaces()) {
         DexProgramClass implementedClass =
             asProgramClassOrNull(definitionFor(implementedType, clazz));
-        if (implementedClass != null) {
+        if (implementedClass != null && implementedClass.isInterface()) {
           worklist.addIfNotSeen(implementedClass);
         }
       }
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/LambdaEnumUnboxingEmptyEnumObjectTest.java b/src/test/java/com/android/tools/r8/enumunboxing/LambdaEnumUnboxingEmptyEnumObjectTest.java
new file mode 100644
index 0000000..284f8ac
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/enumunboxing/LambdaEnumUnboxingEmptyEnumObjectTest.java
@@ -0,0 +1,77 @@
+// Copyright (c) 2021, 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.enumunboxing;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoVerticalClassMerging;
+import com.android.tools.r8.TestParameters;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class LambdaEnumUnboxingEmptyEnumObjectTest extends EnumUnboxingTestBase {
+
+  private final TestParameters parameters;
+  private final boolean enumValueOptimization;
+  private final EnumKeepRules enumKeepRules;
+
+  @Parameters(name = "{0} valueOpt: {1} keep: {2}")
+  public static List<Object[]> data() {
+    return enumUnboxingTestParameters(getTestParameters().withAllRuntimesAndApiLevels().build());
+  }
+
+  public LambdaEnumUnboxingEmptyEnumObjectTest(
+      TestParameters parameters, boolean enumValueOptimization, EnumKeepRules enumKeepRules) {
+    this.parameters = parameters;
+    this.enumValueOptimization = enumValueOptimization;
+    this.enumKeepRules = enumKeepRules;
+  }
+
+  @Test
+  public void testEnumUnboxing() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass())
+        .addKeepMainRule(Main.class)
+        .addKeepRules(enumKeepRules.getKeepRules())
+        .enableNeverClassInliningAnnotations()
+        .noMinification()
+        .enableNoVerticalClassMergingAnnotations()
+        .enableInliningAnnotations()
+        .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization))
+        .addEnumUnboxingInspector(
+            inspector ->
+                inspector.assertUnboxedIf(
+                    enumKeepRules.isNone() && parameters.getBackend().isDex(), MyEnum.class))
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("null");
+  }
+
+  @NeverClassInline
+  enum MyEnum {}
+
+  @NoVerticalClassMerging
+  interface ObjectConsumer<T> {
+
+    void accept(T o);
+  }
+
+  static class Main {
+
+    public static void main(String[] args) {
+      executeObject(e -> System.out.println(String.valueOf(e)));
+    }
+
+    @NeverInline
+    static void executeObject(ObjectConsumer<MyEnum> consumer) {
+      consumer.accept(null);
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/LambdaEnumUnboxingEmptyEnumTest.java b/src/test/java/com/android/tools/r8/enumunboxing/LambdaEnumUnboxingEmptyEnumTest.java
new file mode 100644
index 0000000..288ace4
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/enumunboxing/LambdaEnumUnboxingEmptyEnumTest.java
@@ -0,0 +1,75 @@
+// Copyright (c) 2021, 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.enumunboxing;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoVerticalClassMerging;
+import com.android.tools.r8.TestParameters;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class LambdaEnumUnboxingEmptyEnumTest extends EnumUnboxingTestBase {
+
+  private final TestParameters parameters;
+  private final boolean enumValueOptimization;
+  private final EnumKeepRules enumKeepRules;
+
+  @Parameters(name = "{0} valueOpt: {1} keep: {2}")
+  public static List<Object[]> data() {
+    return enumUnboxingTestParameters(getTestParameters().withAllRuntimesAndApiLevels().build());
+  }
+
+  public LambdaEnumUnboxingEmptyEnumTest(
+      TestParameters parameters, boolean enumValueOptimization, EnumKeepRules enumKeepRules) {
+    this.parameters = parameters;
+    this.enumValueOptimization = enumValueOptimization;
+    this.enumKeepRules = enumKeepRules;
+  }
+
+  @Test
+  public void testEnumUnboxing() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(getClass())
+        .addKeepMainRule(Main.class)
+        .addKeepRules(enumKeepRules.getKeepRules())
+        .enableNeverClassInliningAnnotations()
+        .noMinification()
+        .enableNoVerticalClassMergingAnnotations()
+        .enableInliningAnnotations()
+        .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization))
+        .addEnumUnboxingInspector(
+            inspector -> inspector.assertUnboxedIf(enumKeepRules.isNone(), MyEnum.class))
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("null");
+  }
+
+  @NeverClassInline
+  enum MyEnum {}
+
+  @NoVerticalClassMerging
+  interface MyEnumConsumer {
+
+    void accept(MyEnum e);
+  }
+
+  static class Main {
+
+    public static void main(String[] args) {
+      execute(e -> System.out.println(String.valueOf(e)));
+    }
+
+    @NeverInline
+    static void execute(MyEnumConsumer consumer) {
+      consumer.accept(null);
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/internal/CompilationTestBase.java b/src/test/java/com/android/tools/r8/internal/CompilationTestBase.java
index cec9053..0a19636 100644
--- a/src/test/java/com/android/tools/r8/internal/CompilationTestBase.java
+++ b/src/test/java/com/android/tools/r8/internal/CompilationTestBase.java
@@ -75,17 +75,6 @@
     reporter = new Reporter(handler);
   }
 
-  public AndroidApp runAndCheckVerification(
-      CompilerUnderTest compiler,
-      CompilationMode mode,
-      String referenceApk,
-      List<String> pgConfs,
-      String input)
-      throws ExecutionException, IOException, CompilationFailedException {
-    return runAndCheckVerification(
-        compiler, mode, referenceApk, pgConfs, null, Collections.singletonList(input));
-  }
-
   public AndroidApp runAndCheckVerification(D8Command.Builder builder, String referenceApk)
       throws IOException, ExecutionException, CompilationFailedException {
     AndroidAppConsumers appSink = new AndroidAppConsumers(builder);
@@ -95,22 +84,6 @@
     return result;
   }
 
-  public void assertIdenticalZipFiles(File file1, File file2) throws IOException {
-    try (ZipFile zipFile1 = new ZipFile(file1); ZipFile zipFile2 = new ZipFile(file2)) {
-      final Enumeration<? extends ZipEntry> entries1 = zipFile1.entries();
-      final Enumeration<? extends ZipEntry> entries2 = zipFile2.entries();
-
-      while (entries1.hasMoreElements()) {
-        Assert.assertTrue(entries2.hasMoreElements());
-        ZipEntry entry1 = entries1.nextElement();
-        ZipEntry entry2 = entries2.nextElement();
-        Assert.assertEquals(entry1.getName(), entry2.getName());
-        Assert.assertEquals(entry1.getCrc(), entry2.getCrc());
-        Assert.assertEquals(entry1.getSize(), entry2.getSize());
-      }
-    }
-  }
-
   public AndroidApp runAndCheckVerification(
       CompilerUnderTest compiler,
       CompilationMode mode,
diff --git a/src/test/java/com/android/tools/r8/internal/D8FrameworkDeterministicTest.java b/src/test/java/com/android/tools/r8/internal/D8FrameworkDeterministicTest.java
index ab430d5..0d6061a 100644
--- a/src/test/java/com/android/tools/r8/internal/D8FrameworkDeterministicTest.java
+++ b/src/test/java/com/android/tools/r8/internal/D8FrameworkDeterministicTest.java
@@ -9,7 +9,6 @@
 import com.android.tools.r8.D8Command;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.AndroidAppConsumers;
-import java.io.IOException;
 import java.nio.file.Paths;
 import org.junit.Test;
 
@@ -17,8 +16,7 @@
   private static final int MIN_SDK = 24;
   private static final String JAR = "third_party/framework/framework_160115954.jar";
 
-  private AndroidApp doRun(D8Command.Builder builder)
-      throws IOException, CompilationFailedException {
+  private AndroidApp doRun(D8Command.Builder builder) throws CompilationFailedException {
     builder.setProgramConsumer(null);
     AndroidAppConsumers appSink = new AndroidAppConsumers(builder);
     D8.run(builder.build());
diff --git a/src/test/java/com/android/tools/r8/internal/GMSCoreLatestTest.java b/src/test/java/com/android/tools/r8/internal/GMSCoreLatestTest.java
index 3beab34..3f5ad48 100644
--- a/src/test/java/com/android/tools/r8/internal/GMSCoreLatestTest.java
+++ b/src/test/java/com/android/tools/r8/internal/GMSCoreLatestTest.java
@@ -40,7 +40,7 @@
   @Parameterized.Parameters(name = "{0}")
   public static TestParametersCollection data() {
     return getTestParameters()
-        .withDexRuntime(Version.V9_0_0)
+        .withDexRuntime(Version.DEFAULT)
         .withApiLevel(AndroidApiLevel.L)
         .build();
   }
@@ -125,9 +125,7 @@
                 containsString("Proguard configuration rule does not match anything")))
         .assertAllWarningMessagesMatch(
             anyOf(
-                containsString(
-                    "Expected stack map table for method with non-linear control flow. "
-                        + "In later version of R8, the method may be assumed not reachable."),
+                containsString("Expected stack map table for method with non-linear control flow."),
                 containsString("Ignoring option: -outjars")));
   }
 }
diff --git a/src/test/java/com/android/tools/r8/internal/GMSCoreV10Test.java b/src/test/java/com/android/tools/r8/internal/GMSCoreV10Test.java
index 30716fb..4c9b99f 100644
--- a/src/test/java/com/android/tools/r8/internal/GMSCoreV10Test.java
+++ b/src/test/java/com/android/tools/r8/internal/GMSCoreV10Test.java
@@ -43,7 +43,7 @@
   @Parameterized.Parameters(name = "{0}")
   public static TestParametersCollection data() {
     return getTestParameters()
-        .withDexRuntime(Version.V9_0_0)
+        .withDexRuntime(Version.DEFAULT)
         .withApiLevel(AndroidApiLevel.L)
         .build();
   }
diff --git a/src/test/java/com/android/tools/r8/internal/Gmail18082615TreeShakeJarVerificationTest.java b/src/test/java/com/android/tools/r8/internal/Gmail18082615TreeShakeJarVerificationTest.java
index 118bcce..4929cb2 100644
--- a/src/test/java/com/android/tools/r8/internal/Gmail18082615TreeShakeJarVerificationTest.java
+++ b/src/test/java/com/android/tools/r8/internal/Gmail18082615TreeShakeJarVerificationTest.java
@@ -24,16 +24,14 @@
 public class Gmail18082615TreeShakeJarVerificationTest extends GmailCompilationBase {
   private static final int MAX_SIZE = 20000000;
 
-  private final TestParameters parameters;
-
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    return getTestParameters().withDexRuntimes().build();
+    return getTestParameters().withNoneRuntime().build();
   }
 
   public Gmail18082615TreeShakeJarVerificationTest(TestParameters parameters) {
     super(180826, 15);
-    this.parameters = parameters;
+    parameters.assertNoneRuntime();
   }
 
   @Test
@@ -41,7 +39,7 @@
     assumeTrue(isLocalDevelopment());
 
     R8TestCompileResult compileResult =
-        testForR8(parameters.getBackend())
+        testForR8(Backend.DEX)
             .addKeepRuleFiles(
                 Paths.get(base).resolve(BASE_PG_CONF),
                 Paths.get(ToolHelper.PROGUARD_SETTINGS_FOR_INTERNAL_APPS, PG_CONF))
diff --git a/src/test/java/com/android/tools/r8/internal/Iosched2019Test.java b/src/test/java/com/android/tools/r8/internal/Iosched2019Test.java
deleted file mode 100644
index 0dbe71a..0000000
--- a/src/test/java/com/android/tools/r8/internal/Iosched2019Test.java
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) 2020, 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.internal;
-
-import static org.hamcrest.CoreMatchers.anyOf;
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assume.assumeTrue;
-
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.List;
-import java.util.stream.Collectors;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-@RunWith(Parameterized.class)
-public class Iosched2019Test extends TestBase {
-
-  private final TestParameters parameters;
-
-  @Parameterized.Parameters(name = "{0}")
-  public static TestParametersCollection data() {
-    return getTestParameters().withDexRuntimes().withAllApiLevels().build();
-  }
-
-  public Iosched2019Test(TestParameters parameters) {
-    this.parameters = parameters;
-  }
-
-  @Test
-  public void test() throws Exception {
-    assumeTrue(ToolHelper.isLocalDevelopment());
-
-    List<Path> programFiles =
-        Files.list(Paths.get(ToolHelper.THIRD_PARTY_DIR, "iosched_2019"))
-            .filter(path -> path.toString().endsWith(".jar"))
-            .collect(Collectors.toList());
-    assertEquals(155, programFiles.size());
-
-    testForR8(parameters.getBackend())
-        .addProgramFiles(programFiles)
-        .addKeepRuleFiles(
-            Paths.get(ToolHelper.THIRD_PARTY_DIR, "iosched_2019", "proguard-rules.pro"))
-        .addLibraryFiles(ToolHelper.getMostRecentAndroidJar())
-        .allowDiagnosticMessages()
-        .allowUnusedProguardConfigurationRules()
-        .setMinApi(parameters.getApiLevel())
-        .compile()
-        .assertAllInfoMessagesMatch(
-            anyOf(
-                containsString("Ignoring option: "),
-                containsString("Proguard configuration rule does not match anything: ")))
-        .assertAllWarningMessagesMatch(
-            anyOf(
-                containsString("Missing class "),
-                containsString("required for default or static interface methods desugaring"),
-                equalTo("Resource 'META-INF/MANIFEST.MF' already exists.")))
-        .assertNoErrorMessages();
-  }
-}
diff --git a/src/test/java/com/android/tools/r8/internal/Regression127524985.java b/src/test/java/com/android/tools/r8/internal/Regression127524985.java
index 4af8640..e5e6dcd 100644
--- a/src/test/java/com/android/tools/r8/internal/Regression127524985.java
+++ b/src/test/java/com/android/tools/r8/internal/Regression127524985.java
@@ -6,6 +6,7 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
 import com.android.tools.r8.utils.StringUtils;
 import java.nio.file.Path;
 import java.nio.file.Paths;
@@ -26,7 +27,11 @@
 
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimes().build();
+    return getTestParameters()
+        .withCfRuntimes()
+        .withDexRuntime(Version.DEFAULT)
+        .withAllApiLevels()
+        .build();
   }
 
   private final TestParameters parameters;
@@ -52,7 +57,7 @@
                 .addKeepAllAttributes()
                 .addKeepRules("-dontwarn"))
         .addProgramFiles(JAR)
-        .setMinApi(parameters.getRuntime())
+        .setMinApi(parameters.getApiLevel())
         .compile()
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/internal/YouTubeV1612Test.java b/src/test/java/com/android/tools/r8/internal/YouTubeV1612Test.java
index 50442c9..b7ccb02 100644
--- a/src/test/java/com/android/tools/r8/internal/YouTubeV1612Test.java
+++ b/src/test/java/com/android/tools/r8/internal/YouTubeV1612Test.java
@@ -55,7 +55,7 @@
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
     return getTestParameters()
-        .withDexRuntime(Version.V9_0_0)
+        .withDexRuntime(Version.DEFAULT)
         .withApiLevel(AndroidApiLevel.L)
         .build();
   }
diff --git a/src/test/java/com/android/tools/r8/internal/YouTubeV1620Test.java b/src/test/java/com/android/tools/r8/internal/YouTubeV1620Test.java
index 0c3abdd..2030032 100644
--- a/src/test/java/com/android/tools/r8/internal/YouTubeV1620Test.java
+++ b/src/test/java/com/android/tools/r8/internal/YouTubeV1620Test.java
@@ -55,7 +55,7 @@
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
     return getTestParameters()
-        .withDexRuntime(Version.V9_0_0)
+        .withDexRuntime(Version.DEFAULT)
         .withApiLevel(AndroidApiLevel.L)
         .build();
   }
diff --git a/src/test/java/com/android/tools/r8/internal/proto/Proto2BuilderOnlyReferencedFromDynamicMethodTest.java b/src/test/java/com/android/tools/r8/internal/proto/Proto2BuilderOnlyReferencedFromDynamicMethodTest.java
index d603cc1..d6a04df 100644
--- a/src/test/java/com/android/tools/r8/internal/proto/Proto2BuilderOnlyReferencedFromDynamicMethodTest.java
+++ b/src/test/java/com/android/tools/r8/internal/proto/Proto2BuilderOnlyReferencedFromDynamicMethodTest.java
@@ -13,6 +13,7 @@
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.google.common.collect.ImmutableList;
@@ -34,7 +35,7 @@
 
   @Parameterized.Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimesAndApiLevels().build();
+    return getTestParameters().withDexRuntime(Version.DEFAULT).withAllApiLevels().build();
   }
 
   public Proto2BuilderOnlyReferencedFromDynamicMethodTest(TestParameters parameters) {
diff --git a/src/test/java/com/android/tools/r8/internal/proto/Proto2BuilderShrinkingTest.java b/src/test/java/com/android/tools/r8/internal/proto/Proto2BuilderShrinkingTest.java
index 868c061..f8ae6c5 100644
--- a/src/test/java/com/android/tools/r8/internal/proto/Proto2BuilderShrinkingTest.java
+++ b/src/test/java/com/android/tools/r8/internal/proto/Proto2BuilderShrinkingTest.java
@@ -13,6 +13,7 @@
 
 import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.utils.StringUtils;
@@ -57,7 +58,7 @@
                 "proto2.BuilderWithProtoSetterTestClass",
                 "proto2.BuilderWithReusedSettersTestClass",
                 "proto2.HasFlaggedOffExtensionBuilderTestClass")),
-        getTestParameters().withAllRuntimesAndApiLevels().build());
+        getTestParameters().withDexRuntime(Version.DEFAULT).withAllApiLevels().build());
   }
 
   public Proto2BuilderShrinkingTest(List<String> mains, TestParameters parameters) {
diff --git a/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java b/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java
index dd056e1..5eda02a 100644
--- a/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java
+++ b/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java
@@ -16,6 +16,7 @@
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -64,7 +65,7 @@
     return buildParameters(
         BooleanUtils.values(),
         BooleanUtils.values(),
-        getTestParameters().withAllRuntimesAndApiLevels().build());
+        getTestParameters().withDexRuntime(Version.DEFAULT).withAllApiLevels().build());
   }
 
   public Proto2ShrinkingTest(
diff --git a/src/test/java/com/android/tools/r8/internal/proto/Proto3ShrinkingTest.java b/src/test/java/com/android/tools/r8/internal/proto/Proto3ShrinkingTest.java
index a3c0705..f641510 100644
--- a/src/test/java/com/android/tools/r8/internal/proto/Proto3ShrinkingTest.java
+++ b/src/test/java/com/android/tools/r8/internal/proto/Proto3ShrinkingTest.java
@@ -13,6 +13,7 @@
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -41,7 +42,7 @@
     return buildParameters(
         BooleanUtils.values(),
         BooleanUtils.values(),
-        getTestParameters().withAllRuntimesAndApiLevels().build());
+        getTestParameters().withDexRuntime(Version.DEFAULT).withAllApiLevels().build());
   }
 
   public Proto3ShrinkingTest(
diff --git a/third_party/chrome/chrome_180917_ffbaa8.tar.gz.sha1 b/third_party/chrome/chrome_180917_ffbaa8.tar.gz.sha1
index 104ad9d..3ac92ca 100644
--- a/third_party/chrome/chrome_180917_ffbaa8.tar.gz.sha1
+++ b/third_party/chrome/chrome_180917_ffbaa8.tar.gz.sha1
@@ -1 +1 @@
-e35ecc90931db82165b96f7b5f0e1c251ebe7347
\ No newline at end of file
+c32dc7f70022946c04bfe9316e35e60e8d2ee0cb
\ No newline at end of file