Reland "Use definition values where possible when accessing keep info."

Bug: b/265251427
Change-Id: I9cd365f4e53e0b21677d4dbf4a34bdebbe1ff37f
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java
index 82e4b48..38bf4ee 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -392,8 +392,7 @@
       return false;
     }
     // If tree shaking, only keep annotations on kept methods.
-    if (appView.appInfo().hasLiveness()
-        && !appView.appInfo().withLiveness().isPinned(method.getReference())) {
+    if (appView.appInfo().hasLiveness() && !appView.appInfo().withLiveness().isPinned(method)) {
       return false;
     }
     return true;
@@ -774,7 +773,7 @@
     // The enqueuer might build IR to trace reflective behaviour. At that point liveness is not
     // known, so be conservative with collection parameter name information.
     if (appView.appInfo().hasLiveness()
-        && !appView.appInfo().withLiveness().isPinned(encodedMethod.getReference())) {
+        && !appView.appInfo().withLiveness().isPinned(encodedMethod)) {
       return DexEncodedMethod.NO_PARAMETER_INFO;
     }
 
diff --git a/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java b/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java
index 4062f96..7d6b3a2 100644
--- a/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java
+++ b/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java
@@ -101,10 +101,10 @@
 
   public boolean isEnclosingPinned(AppView<AppInfoWithLiveness> appView) {
     if (enclosingMethod != null) {
-      return appView.appInfo().isPinned(enclosingMethod);
+      return appView.appInfo().isPinnedWithDefinitionLookup(enclosingMethod);
     }
     if (enclosingClass != null) {
-      return appView.appInfo().isPinned(enclosingClass);
+      return appView.appInfo().isPinnedWithDefinitionLookup(enclosingClass);
     }
     return false;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/InitializedClassesInInstanceMethodsAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/InitializedClassesInInstanceMethodsAnalysis.java
index 0d19daa..d849002 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/InitializedClassesInInstanceMethodsAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/InitializedClassesInInstanceMethodsAnalysis.java
@@ -35,7 +35,7 @@
       // If `subject` is kept, then it is instantiated by reflection, which means that the analysis
       // has not seen all allocation sites. In that case, we conservatively return false.
       AppInfoWithClassHierarchy appInfo = appView.appInfo();
-      if (appInfo.hasLiveness() && appInfo.withLiveness().isPinned(subject.type)) {
+      if (appInfo.hasLiveness() && appInfo.withLiveness().isPinned(subject)) {
         return false;
       }
 
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/ValueMayDependOnEnvironmentAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/ValueMayDependOnEnvironmentAnalysis.java
index 9af0407..33ab115 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/ValueMayDependOnEnvironmentAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/ValueMayDependOnEnvironmentAnalysis.java
@@ -275,7 +275,8 @@
     return root.isDefinedByInstructionSatisfying(Instruction::isConstClass)
         && !appView
             .getKeepInfo()
-            .isPinned(root.getDefinition().asConstClass().getType(), appView, options);
+            .isPinnedWithDefinitionLookup(
+                root.getDefinition().asConstClass().getType(), options, appView);
   }
 
   private boolean addLogicalBinopValueToValueGraph(
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java
index ef1b959..66ef64e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java
@@ -332,7 +332,7 @@
     }
 
     if (appView.enableWholeProgramOptimizations()
-        && appView.withLiveness().appInfo().isMinificationAllowed(holder)) {
+        && appView.withLiveness().appInfo().isMinificationAllowed(clazz)) {
       if (invokedMethod == dexItemFactory.classMethods.getName) {
         return new DexItemBasedValueString(holder, ClassNameComputationInfo.getInstance(NAME));
       }
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
index 753b6ce..12030bf 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java
@@ -113,7 +113,7 @@
       ConstClass constClass = argument.getConstInstruction().asConstClass();
 
       // Check that the service is not kept.
-      if (appView.appInfo().isPinned(constClass.getValue())) {
+      if (appView.appInfo().isPinnedWithDefinitionLookup(constClass.getValue())) {
         continue;
       }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
index c02b953..ed89e93 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
@@ -235,7 +235,7 @@
       IRCode code,
       OptimizationFeedback feedback,
       InstanceFieldInitializationInfoCollection instanceFieldInitializationInfos) {
-    assert !appView.appInfo().isPinned(method.getReference());
+    assert !appView.appInfo().isPinned(method);
 
     if (!method.isInstanceInitializer()) {
       return;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
index 1d0e301..09c8163 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
@@ -350,7 +350,7 @@
       }
       boolean mayBeRenamed =
           appView.enableWholeProgramOptimizations()
-              && appView.withLiveness().appInfo().isMinificationAllowed(holder.type);
+              && appView.withLiveness().appInfo().isMinificationAllowed(holder);
       // b/120138731: Filter out escaping uses. In such case, the result of this optimization will
       // be stored somewhere, which can lead to a regression if the corresponding class is in a deep
       // package hierarchy. For local cases, it is likely a one-time computation, but make sure the
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java b/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java
index d2ec4d6..4d3075c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java
@@ -119,8 +119,8 @@
 
     // Verify that the methods are not pinned. They shouldn't be, since we've computed an abstract
     // return value for both.
-    assert !appView.appInfo().isPinned(method.getReference());
-    assert !appView.appInfo().isPinned(parentMethod.getReference());
+    assert !appView.appInfo().isPinned(method);
+    assert !appView.appInfo().isPinned(parentMethod);
 
     if (appView
         .appInfo()
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
index 415995e..c06aea8 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
@@ -110,7 +110,7 @@
           if (oldMeta == null
               || kotlinInfo == getNoKotlinInfo()
               || (appView.appInfo().hasLiveness()
-                  && !appView.withLiveness().appInfo().isPinned(clazz.type))) {
+                  && !appView.withLiveness().appInfo().isPinned(clazz))) {
             // Remove @Metadata in DexAnnotation when there is no kotlin info and the type is not
             // missing.
             if (oldMeta != null) {
diff --git a/src/main/java/com/android/tools/r8/naming/Minifier.java b/src/main/java/com/android/tools/r8/naming/Minifier.java
index 00c0d9f..52fee79 100644
--- a/src/main/java/com/android/tools/r8/naming/Minifier.java
+++ b/src/main/java/com/android/tools/r8/naming/Minifier.java
@@ -312,7 +312,7 @@
       if (!allowMemberRenaming(holder)
           || holder.accessFlags.isAnnotation()
           || method.accessFlags.isConstructor()
-          || !appView.appInfo().isMinificationAllowed(method.getReference())) {
+          || !appView.appInfo().isMinificationAllowed(method)) {
         return method.getReference().name;
       }
       if (desugaredLibraryRenaming
@@ -327,8 +327,7 @@
 
     @Override
     public DexString getReservedName(DexEncodedField field, DexClass holder) {
-      if (holder.isLibraryClass()
-          || !appView.appInfo().isMinificationAllowed(field.getReference())) {
+      if (holder.isLibraryClass() || !appView.appInfo().isMinificationAllowed(field)) {
         return field.getReference().name;
       }
       return null;
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
index 6637177..3c128fb 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
@@ -408,7 +408,7 @@
         return mappings.get(type);
       }
       if (clazz.isProgramClass()) {
-        if (appView.appInfo().isMinificationAllowed(type)) {
+        if (appView.appInfo().isMinificationAllowed(clazz.asProgramClass())) {
           return mappings.get(type);
         }
         // TODO(b/136694827): Report a warning here if in the mapping since the user may find this
@@ -454,7 +454,7 @@
         nextName = reservedName;
       } else {
         assert !mappedNames.containsKey(reference);
-        assert appView.appInfo().isMinificationAllowed(reference);
+        assert appView.appInfo().isMinificationAllowed(method);
         nextName = super.next(method, internalState, isAvailable);
       }
       assert nextName == reference.name || !method.isInitializer();
@@ -477,7 +477,7 @@
         return reservedName;
       }
       assert !mappedNames.containsKey(reference);
-      assert appView.appInfo().isMinificationAllowed(reference);
+      assert appView.appInfo().isMinificationAllowed(field);
       return super.next(field, internalState, isAvailable);
     }
 
diff --git a/src/main/java/com/android/tools/r8/optimize/AccessModifier.java b/src/main/java/com/android/tools/r8/optimize/AccessModifier.java
index c1ee380..b2d577c 100644
--- a/src/main/java/com/android/tools/r8/optimize/AccessModifier.java
+++ b/src/main/java/com/android/tools/r8/optimize/AccessModifier.java
@@ -223,7 +223,7 @@
     boolean wasSeen = methodPoolCollection.markIfNotSeen(method.getHolder(), method.getReference());
     if (wasSeen) {
       // We can't do anything further because even renaming is not allowed due to the keep rule.
-      if (!appView.appInfo().isMinificationAllowed(method.getReference())) {
+      if (!appView.appInfo().isMinificationAllowed(method)) {
         return false;
       }
       // TODO(b/111118390): Renaming will enable more private instance methods to be publicized.
diff --git a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java
index e6df4a0..b6236d8 100644
--- a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java
+++ b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java
@@ -154,7 +154,7 @@
     // If the method is defined on the parent class, we cannot hoist the bridge.
     // TODO(b/153147967): If the declared method is abstract, we could replace it by the bridge.
     //  Add a test.
-    if (clazz.lookupMethod(method) != null) {
+    if (clazz.lookupProgramMethod(method) != null) {
       return;
     }
 
@@ -278,8 +278,8 @@
         representative.getReference());
 
     // Remove all of the bridges in the eligible subclasses.
+    assert !appView.appInfo().isPinnedWithDefinitionLookup(method);
     for (DexProgramClass subclass : eligibleSubclasses) {
-      assert !appView.appInfo().isPinned(method);
       DexEncodedMethod removed = subclass.removeMethod(method);
       assert removed != null;
     }
diff --git a/src/main/java/com/android/tools/r8/shaking/AbstractMethodRemover.java b/src/main/java/com/android/tools/r8/shaking/AbstractMethodRemover.java
index e0c7f83..edfa788 100644
--- a/src/main/java/com/android/tools/r8/shaking/AbstractMethodRemover.java
+++ b/src/main/java/com/android/tools/r8/shaking/AbstractMethodRemover.java
@@ -6,13 +6,14 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.SubtypingInfo;
 import com.android.tools.r8.logging.Log;
 import com.android.tools.r8.shaking.ScopedDexMethodSet.AddMethodIfMoreVisibleResult;
-import com.android.tools.r8.utils.IterableUtils;
-import com.android.tools.r8.utils.ListUtils;
-import java.util.List;
+import java.util.HashSet;
+import java.util.Set;
 
 /**
  * Removes abstract methods if they only shadow methods of the same signature in a superclass.
@@ -43,39 +44,38 @@
     DexClass holder = appView.definitionFor(type);
     scope = scope.newNestedScope();
     if (holder != null && holder.isProgramClass()) {
-      DexEncodedMethod[] newVirtualMethods =
-          processMethods(IterableUtils.ensureUnmodifiableList(holder.virtualMethods()));
-      if (newVirtualMethods != null) {
-        holder.setVirtualMethods(newVirtualMethods);
-      }
+      processMethods(holder.asProgramClass());
     }
     // TODO(b/154881041): Does this need the full subtype hierarchy of referenced types!?
     subtypingInfo.forAllImmediateExtendsSubtypes(type, this::processClass);
     scope = scope.getParent();
   }
 
-  private DexEncodedMethod[] processMethods(List<DexEncodedMethod> virtualMethods) {
-    if (virtualMethods == null) {
-      return null;
+  private void processMethods(DexProgramClass clazz) {
+    Set<DexEncodedMethod> toRemove = null;
+    for (ProgramMethod method : clazz.virtualProgramMethods()) {
+      if (!isNonAbstractPinnedOrWideningVisibility(method)) {
+        if (toRemove == null) {
+          toRemove = new HashSet<>();
+        }
+        toRemove.add(method.getDefinition());
+      }
     }
-    // Removal of abstract methods is rare, ListUtils.filterOrElse does no copying if nothing is
-    // filtered out.
-    List<DexEncodedMethod> filteredMethods =
-        ListUtils.filterOrElse(virtualMethods, this::isNonAbstractPinnedOrWideningVisibility);
-    return filteredMethods == virtualMethods
-        ? null
-        : filteredMethods.toArray(DexEncodedMethod.EMPTY_ARRAY);
+    if (toRemove != null) {
+      clazz.getMethodCollection().removeMethods(toRemove);
+    }
   }
 
-  private boolean isNonAbstractPinnedOrWideningVisibility(DexEncodedMethod method) {
-    if (!method.accessFlags.isAbstract()) {
+  private boolean isNonAbstractPinnedOrWideningVisibility(ProgramMethod method) {
+    if (!method.getAccessFlags().isAbstract()) {
       return true;
     }
     // Check if the method widens visibility. Adding to the scope mutates it.
-    if (scope.addMethodIfMoreVisible(method) != AddMethodIfMoreVisibleResult.NOT_ADDED) {
+    if (scope.addMethodIfMoreVisible(method.getDefinition())
+        != AddMethodIfMoreVisibleResult.NOT_ADDED) {
       return true;
     }
-    if (appView.appInfo().isPinned(method.getReference())) {
+    if (appView.appInfo().isPinned(method)) {
       return true;
     }
     // We will filter the method out since it is not pinned.
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index 387186f..cb80e54 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -918,7 +918,7 @@
       assert info.isRead() || info.isWritten();
       return true;
     }
-    assert getKeepInfo().getFieldInfo(reference, this).isShrinkingAllowed(options());
+    assert getKeepInfo().getFieldInfo(field, this).isShrinkingAllowed(options());
     return false;
   }
 
@@ -929,7 +929,7 @@
     if (info != null && info.isRead()) {
       return true;
     }
-    if (isPinned(field)) {
+    if (isPinned(encodedField)) {
       return true;
     }
     // For library classes we don't know whether a field is read.
@@ -938,8 +938,7 @@
 
   public boolean isFieldWritten(DexEncodedField encodedField) {
     assert checkIfObsolete();
-    return isFieldWrittenByFieldPutInstruction(encodedField)
-        || isPinned(encodedField.getReference());
+    return isFieldWrittenByFieldPutInstruction(encodedField) || isPinned(encodedField);
   }
 
   public boolean isFieldWrittenByFieldPutInstruction(DexEncodedField encodedField) {
@@ -957,7 +956,7 @@
   public boolean isFieldOnlyWrittenInMethod(DexEncodedField field, DexEncodedMethod method) {
     assert checkIfObsolete();
     assert isFieldWritten(field) : "Expected field `" + field.toSourceString() + "` to be written";
-    if (isPinned(field.getReference())) {
+    if (isPinned(field)) {
       return false;
     }
     return isFieldOnlyWrittenInMethodIgnoringPinning(field, method);
@@ -980,7 +979,7 @@
   public boolean isInstanceFieldWrittenOnlyInInstanceInitializers(DexEncodedField field) {
     assert checkIfObsolete();
     assert isFieldWritten(field) : "Expected field `" + field.toSourceString() + "` to be written";
-    if (isPinned(field.getReference())) {
+    if (isPinned(field)) {
       return false;
     }
     FieldAccessInfo fieldAccessInfo = getFieldAccessInfoCollection().get(field.getReference());
@@ -1027,7 +1026,7 @@
     if (neverPropagateValue.contains(field)) {
       return false;
     }
-    if (isPinned(field) && !field.getType().isAlwaysNull(appView)) {
+    if (isPinnedWithDefinitionLookup(field) && !field.getType().isAlwaysNull(appView)) {
       return false;
     }
     return true;
@@ -1039,7 +1038,9 @@
       return false;
     }
     if (!method.getReturnType().isAlwaysNull(appView)
-        && !getKeepInfo().getMethodInfo(method, this).isOptimizationAllowed(options())) {
+        && !getKeepInfo()
+            .getMethodInfoWithDefinitionLookup(method, this)
+            .isOptimizationAllowed(options())) {
       return false;
     }
     return true;
@@ -1071,18 +1072,29 @@
     return !isPinned(clazz) && !neverClassInline.contains(clazz.getType());
   }
 
-  public boolean isMinificationAllowed(DexReference reference) {
+  public boolean isMinificationAllowed(DexProgramClass clazz) {
     return options().isMinificationEnabled()
-        && keepInfo.getInfo(reference, this).isMinificationAllowed(options());
+        && keepInfo.getInfo(clazz).isMinificationAllowed(options());
+  }
+
+  public boolean isMinificationAllowed(ProgramDefinition definition) {
+    return options().isMinificationEnabled()
+        && keepInfo.getInfo(definition).isMinificationAllowed(options());
+  }
+
+  public boolean isMinificationAllowed(DexDefinition definition) {
+    return options().isMinificationEnabled()
+        && keepInfo.getInfo(definition, this).isMinificationAllowed(options());
+  }
+
+  public boolean isMinificationAllowed(DexType reference) {
+    return options().isMinificationEnabled()
+        && keepInfo.getClassInfo(reference, this).isMinificationAllowed(options());
   }
 
   public boolean isAccessModificationAllowed(ProgramDefinition definition) {
-    return isAccessModificationAllowed(definition.getReference());
-  }
-
-  public boolean isAccessModificationAllowed(DexReference reference) {
     assert options().getProguardConfiguration().isAccessModificationAllowed();
-    return keepInfo.getInfo(reference, this).isAccessModificationAllowed(options());
+    return keepInfo.getInfo(definition).isAccessModificationAllowed(options());
   }
 
   public boolean isRepackagingAllowed(DexProgramClass clazz, AppView<?> appView) {
@@ -1099,27 +1111,30 @@
     return applyMappingSeedMapper == null || !applyMappingSeedMapper.hasMapping(clazz.type);
   }
 
-  public boolean isPinned(DexReference reference) {
+  public boolean isPinnedWithDefinitionLookup(DexReference reference) {
     assert checkIfObsolete();
-    return keepInfo.isPinned(reference, this, options());
+    return keepInfo.isPinnedWithDefinitionLookup(reference, options(), this);
   }
 
   public boolean isPinned(DexDefinition definition) {
-    assert definition != null;
-    return isPinned(definition.getReference());
+    return keepInfo.isPinned(definition, options(), this);
   }
 
-  public boolean isPinned(DexClassAndMember<?, ?> member) {
-    assert member != null;
-    return isPinned(member.getReference());
+  public boolean isPinned(DexProgramClass clazz) {
+    return keepInfo.isPinned(clazz, options());
+  }
+
+  public boolean isPinned(ProgramDefinition definition) {
+    assert definition != null;
+    return keepInfo.isPinned(definition, options());
   }
 
   public boolean hasPinnedInstanceInitializer(DexType type) {
     assert type.isClassType();
     DexProgramClass clazz = asProgramClassOrNull(definitionFor(type));
     if (clazz != null) {
-      for (DexEncodedMethod method : clazz.directMethods()) {
-        if (method.isInstanceInitializer() && isPinned(method.getReference())) {
+      for (ProgramMethod method : clazz.directProgramMethods()) {
+        if (method.getDefinition().isInstanceInitializer() && isPinned(method)) {
           return true;
         }
       }
@@ -1495,11 +1510,11 @@
   }
 
   private boolean isInstantiatedOrPinned(DexProgramClass clazz) {
-    return isInstantiatedDirectly(clazz) || isPinned(clazz.type) || isInstantiatedInterface(clazz);
+    return isInstantiatedDirectly(clazz) || isPinned(clazz) || isInstantiatedInterface(clazz);
   }
 
   public boolean isPinnedNotProgramOrLibraryOverride(DexDefinition definition) {
-    if (isPinned(definition.getReference())) {
+    if (isPinned(definition)) {
       return true;
     }
     if (definition.isDexEncodedMethod()) {
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 59b7ae3..610cfa9 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -2918,8 +2918,7 @@
                                         instantiation.apply(subTypeConsumer, lambdaConsumer);
                                       },
                                       definition ->
-                                          keepInfo.isPinned(
-                                              definition.getReference(), appInfo, options));
+                                          keepInfo.isPinned(definition, options, appInfo));
                               lookupResult.forEach(
                                   target ->
                                       markVirtualDispatchTargetAsLive(
@@ -3422,7 +3421,7 @@
                       (type, subTypeConsumer, lambdaConsumer) ->
                           objectAllocationInfoCollection.forEachInstantiatedSubType(
                               type, subTypeConsumer, lambdaConsumer, appInfo),
-                      definition -> keepInfo.isPinned(definition.getReference(), appInfo, options))
+                      definition -> keepInfo.isPinned(definition, options, appInfo))
                   .forEach(
                       target ->
                           markVirtualDispatchTargetAsLive(
@@ -4328,7 +4327,7 @@
         (methodReference, companionReference) -> {
           ProgramMethod companion = appView.definitionFor(companionReference).asProgramMethod();
           KeepMethodInfo.Joiner minimumKeepInfoForCompanion =
-              keepInfo.getMethodInfo(methodReference, appInfo).joiner();
+              keepInfo.getMethodInfoWithDefinitionLookup(methodReference, appInfo).joiner();
           KeepMethodInfo.Joiner extraMinimumKeepInfoForCompanion =
               dependentMinimumKeepInfo
                   .getUnconditionalMinimumKeepInfoOrDefault(MinimumKeepInfoCollection.empty())
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java b/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
index c78e39a..f13a407 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
@@ -9,6 +9,8 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexDefinition;
 import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMember;
@@ -92,9 +94,14 @@
     return getMethodInfo(member.asDexEncodedMethod(), holder);
   }
 
+  public final KeepClassInfo getClassInfo(DexClass clazz) {
+    return clazz != null && clazz.isProgramClass()
+        ? getClassInfo(clazz.asProgramClass())
+        : keepInfoForNonProgramClass();
+  }
+
   public final KeepClassInfo getClassInfo(DexType type, DexDefinitionSupplier definitions) {
-    DexProgramClass clazz = asProgramClassOrNull(definitions.definitionFor(type));
-    return clazz == null ? keepInfoForNonProgramClass() : getClassInfo(clazz);
+    return getClassInfo(definitions.contextIndependentDefinitionFor(type));
   }
 
   public final KeepMemberInfo<?, ?> getMemberInfo(ProgramMember<?, ?> member) {
@@ -105,8 +112,21 @@
     return getMethodInfo(method.getDefinition(), method.getHolder());
   }
 
-  public final KeepMethodInfo getMethodInfo(DexMethod method, DexDefinitionSupplier definitions) {
-    DexProgramClass holder = asProgramClassOrNull(definitions.definitionFor(method.holder));
+  public final KeepMethodInfo getMethodInfo(
+      DexEncodedMethod method, DexDefinitionSupplier definitions) {
+    DexProgramClass holder =
+        asProgramClassOrNull(definitions.contextIndependentDefinitionFor(method.getHolderType()));
+    if (holder == null) {
+      return keepInfoForNonProgramMethod();
+    }
+    assert method == holder.lookupMethod(method.getReference());
+    return getMethodInfo(method, holder);
+  }
+
+  public final KeepMethodInfo getMethodInfoWithDefinitionLookup(
+      DexMethod method, DexDefinitionSupplier definitions) {
+    DexProgramClass holder =
+        asProgramClassOrNull(definitions.contextIndependentDefinitionFor(method.holder));
     if (holder == null) {
       return keepInfoForNonProgramMethod();
     }
@@ -118,7 +138,19 @@
     return getFieldInfo(field.getDefinition(), field.getHolder());
   }
 
-  public final KeepFieldInfo getFieldInfo(DexField field, DexDefinitionSupplier definitions) {
+  public final KeepFieldInfo getFieldInfo(
+      DexEncodedField field, DexDefinitionSupplier definitions) {
+    DexProgramClass holder =
+        asProgramClassOrNull(definitions.contextIndependentDefinitionFor(field.getHolderType()));
+    if (holder == null) {
+      return keepInfoForNonProgramField();
+    }
+    assert holder.lookupField(field.getReference()) == field;
+    return getFieldInfo(field, holder);
+  }
+
+  private KeepFieldInfo getFieldInfoWithDefinitionLookup(
+      DexField field, DexDefinitionSupplier definitions) {
     DexProgramClass holder = asProgramClassOrNull(definitions.definitionFor(field.holder));
     if (holder == null) {
       return keepInfoForNonProgramField();
@@ -127,15 +159,29 @@
     return definition == null ? KeepFieldInfo.bottom() : getFieldInfo(definition, holder);
   }
 
-  public final KeepInfo<?, ?> getInfo(DexReference reference, DexDefinitionSupplier definitions) {
+  private KeepInfo<?, ?> getInfoWithDefinitionLookup(
+      DexReference reference, DexDefinitionSupplier definitions) {
     if (reference.isDexType()) {
       return getClassInfo(reference.asDexType(), definitions);
     }
     if (reference.isDexMethod()) {
-      return getMethodInfo(reference.asDexMethod(), definitions);
+      return getMethodInfoWithDefinitionLookup(reference.asDexMethod(), definitions);
     }
     if (reference.isDexField()) {
-      return getFieldInfo(reference.asDexField(), definitions);
+      return getFieldInfoWithDefinitionLookup(reference.asDexField(), definitions);
+    }
+    throw new Unreachable();
+  }
+
+  public final KeepInfo<?, ?> getInfo(DexDefinition definition, DexDefinitionSupplier definitions) {
+    if (definition.isDexClass()) {
+      return getClassInfo(definition.asDexClass());
+    }
+    if (definition.isDexEncodedMethod()) {
+      return getMethodInfo(definition.asDexEncodedMethod(), definitions);
+    }
+    if (definition.isDexEncodedField()) {
+      return getFieldInfo(definition.asDexEncodedField(), definitions);
     }
     throw new Unreachable();
   }
@@ -158,37 +204,28 @@
   }
 
   public final boolean isPinned(
+      ProgramDefinition definition, GlobalKeepInfoConfiguration configuration) {
+    return getInfo(definition).isPinned(configuration);
+  }
+
+  public final boolean isPinned(
+      DexDefinition definition,
+      GlobalKeepInfoConfiguration configuration,
+      DexDefinitionSupplier definitions) {
+    return getInfo(definition, definitions).isPinned(configuration);
+  }
+
+  public final boolean isPinnedWithDefinitionLookup(
       DexReference reference,
-      DexDefinitionSupplier definitions,
-      GlobalKeepInfoConfiguration configuration) {
-    return getInfo(reference, definitions).isPinned(configuration);
-  }
-
-  public final boolean isPinned(
-      DexType type, DexDefinitionSupplier definitions, GlobalKeepInfoConfiguration configuration) {
-    return getClassInfo(type, definitions).isPinned(configuration);
-  }
-
-  public final boolean isPinned(
-      DexMethod method,
-      DexDefinitionSupplier definitions,
-      GlobalKeepInfoConfiguration configuration) {
-    return getMethodInfo(method, definitions).isPinned(configuration);
-  }
-
-  public final boolean isPinned(
-      DexField field,
-      DexDefinitionSupplier definitions,
-      GlobalKeepInfoConfiguration configuration) {
-    return getFieldInfo(field, definitions).isPinned(configuration);
+      GlobalKeepInfoConfiguration configuration,
+      DexDefinitionSupplier definitions) {
+    return getInfoWithDefinitionLookup(reference, definitions).isPinned(configuration);
   }
 
   public final boolean isMinificationAllowed(
-      DexReference reference,
-      DexDefinitionSupplier definitions,
-      GlobalKeepInfoConfiguration configuration) {
+      ProgramDefinition definition, GlobalKeepInfoConfiguration configuration) {
     return configuration.isMinificationEnabled()
-        && getInfo(reference, definitions).isMinificationAllowed(configuration);
+        && getInfo(definition).isMinificationAllowed(configuration);
   }
 
   public abstract boolean verifyPinnedTypesAreLive(Set<DexType> liveTypes, InternalOptions options);
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
index a728063..7d8610b 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -2083,12 +2083,14 @@
               (reference, minimumKeepInfo) -> {
                 if (reference.isDexType()) {
                   DexType type = reference.asDexType();
-                  assert !appInfo.hasLiveness() || appInfo.withLiveness().isPinned(type)
+                  assert !appInfo.hasLiveness()
+                          || appInfo.withLiveness().isPinnedWithDefinitionLookup(type)
                       : "Expected reference `" + type.toSourceString() + "` to be pinned";
                   requiredMembersPerType.computeIfAbsent(type, key -> Sets.newIdentityHashSet());
                 } else {
                   DexMember<?, ?> member = reference.asDexMember();
-                  assert !appInfo.hasLiveness() || appInfo.withLiveness().isPinned(member)
+                  assert !appInfo.hasLiveness()
+                          || appInfo.withLiveness().isPinnedWithDefinitionLookup(member)
                       : "Expected reference `" + member.toSourceString() + "` to be pinned";
                   requiredMembersPerType
                       .computeIfAbsent(member.holder, key -> Sets.newIdentityHashSet())
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index 32878da..4819d4d 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -359,7 +359,7 @@
 
   private void markTypeAsPinned(DexType type, AbortReason reason) {
     DexType baseType = type.toBaseType(appView.dexItemFactory());
-    if (!baseType.isClassType() || appInfo.isPinned(baseType)) {
+    if (!baseType.isClassType() || appInfo.isPinnedWithDefinitionLookup(baseType)) {
       // We check for the case where the type is pinned according to appInfo.isPinned,
       // so we only need to add it here if it is not the case.
       return;
@@ -380,14 +380,13 @@
     if (allocationInfo.isInstantiatedDirectly(sourceClass)
         || allocationInfo.isInterfaceWithUnknownSubtypeHierarchy(sourceClass)
         || allocationInfo.isImmediateInterfaceOfInstantiatedLambda(sourceClass)
-        || appInfo.isPinned(sourceClass.type)
+        || appInfo.isPinned(sourceClass)
         || pinnedTypes.contains(sourceClass.type)
         || appInfo.isNoVerticalClassMergingOfType(sourceClass.type)) {
       return false;
     }
 
     assert Streams.stream(Iterables.concat(sourceClass.fields(), sourceClass.methods()))
-        .map(DexEncodedMember::getReference)
         .noneMatch(appInfo::isPinned);
 
     if (!FeatureSplitBoundaryOptimizationUtils.isSafeForVerticalClassMerging(
@@ -395,7 +394,7 @@
       return false;
     }
     if (appView.appServices().allServiceTypes().contains(sourceClass.type)
-        && appInfo.isPinned(targetClass.type)) {
+        && appInfo.isPinned(targetClass)) {
       if (Log.ENABLED) {
         AbortReason.SERVICE_LOADER.printLogMessageForClass(sourceClass);
       }
diff --git a/src/main/java/com/android/tools/r8/utils/positions/LineNumberOptimizer.java b/src/main/java/com/android/tools/r8/utils/positions/LineNumberOptimizer.java
index c1e6850..11f01d2 100644
--- a/src/main/java/com/android/tools/r8/utils/positions/LineNumberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/utils/positions/LineNumberOptimizer.java
@@ -170,7 +170,7 @@
       }
       allSeenAreInstanceInitializers = false;
       // If the method is pinned, we cannot minify it.
-      if (!keepInfo.isMinificationAllowed(method.getReference(), appView, appView.options())) {
+      if (!keepInfo.isMinificationAllowed(method, appView.options())) {
         continue;
       }
       // With desugared library, call-backs names are reserved here.