Change InvokeMethod.lookupSingleTarget() to return DexClassAndMethod

Change-Id: I26eefafdac1b01573c402a0fa9aedf72eb71f710
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java b/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
index 115bf84..ecb1b4f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
@@ -12,6 +12,10 @@
     assert holder.isProgramClass() == (this instanceof ProgramMethod);
   }
 
+  public static ProgramMethod asProgramMethodOrNull(DexClassAndMethod method) {
+    return method != null ? method.asProgramMethod() : null;
+  }
+
   public static DexClassAndMethod create(DexClass holder, DexEncodedMethod method) {
     if (holder.isProgramClass()) {
       return new ProgramMethod(holder.asProgramClass(), method);
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index ea4103f..5a1e76d 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -425,6 +425,15 @@
     return asProgramMethod(definitions);
   }
 
+  public DexClassAndMethod asDexClassAndMethod(DexDefinitionSupplier definitions) {
+    assert method.holder.isClassType();
+    DexClass clazz = definitions.definitionForHolder(method);
+    if (clazz != null) {
+      return DexClassAndMethod.create(clazz, this);
+    }
+    return null;
+  }
+
   public ProgramMethod asProgramMethod(DexDefinitionSupplier definitions) {
     assert method.holder.isClassType();
     DexProgramClass clazz = asProgramClassOrNull(definitions.definitionForHolder(method));
@@ -434,6 +443,11 @@
     return null;
   }
 
+  public static DexClassAndMethod asDexClassAndMethodOrNull(
+      DexEncodedMethod method, DexDefinitionSupplier definitions) {
+    return method != null ? method.asDexClassAndMethod(definitions) : null;
+  }
+
   public static ProgramMethod asProgramMethodOrNull(
       DexEncodedMethod method, DexDefinitionSupplier definitions) {
     return method != null ? method.asProgramMethod(definitions) : null;
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethod.java b/src/main/java/com/android/tools/r8/graph/DexMethod.java
index a0d4cbe..6f77653 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethod.java
@@ -37,6 +37,10 @@
     return name;
   }
 
+  public DexType getParameter(int index) {
+    return proto.getParameter(index);
+  }
+
   public DexTypeList getParameters() {
     return proto.parameters;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java
index 416f064..3ee0de7 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexDefinition;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
@@ -323,10 +324,11 @@
         return false;
       }
       if (appView.appInfo().hasLiveness()) {
-        DexEncodedMethod singleTarget =
+        DexClassAndMethod singleTarget =
             instruction.lookupSingleTarget(appView.withLiveness(), context);
         if (singleTarget != null) {
-          return isTypeInitializedBy(instruction, type, singleTarget, appView, mode);
+          return isTypeInitializedBy(
+              instruction, type, singleTarget.getDefinition(), appView, mode);
         }
       }
       DexMethod method = instruction.getInvokedMethod();
@@ -350,8 +352,9 @@
         // Class initialization may fail with ExceptionInInitializerError.
         return false;
       }
-      DexEncodedMethod method = instruction.lookupSingleTarget(appView, context);
-      return method != null && isTypeInitializedBy(instruction, type, method, appView, mode);
+      DexClassAndMethod method = instruction.lookupSingleTarget(appView, context);
+      return method != null
+          && isTypeInitializedBy(instruction, type, method.getDefinition(), appView, mode);
     }
 
     public static boolean forInvokeSuper(
@@ -374,10 +377,11 @@
         return false;
       }
       if (appView.appInfo().hasLiveness()) {
-        DexEncodedMethod singleTarget =
+        DexClassAndMethod singleTarget =
             instruction.lookupSingleTarget(appView.withLiveness(), context);
         if (singleTarget != null) {
-          return isTypeInitializedBy(instruction, type, singleTarget, appView, mode);
+          return isTypeInitializedBy(
+              instruction, type, singleTarget.getDefinition(), appView, mode);
         }
       }
       DexMethod method = instruction.getInvokedMethod();
@@ -418,10 +422,11 @@
         return false;
       }
       if (appView.appInfo().hasLiveness()) {
-        DexEncodedMethod singleTarget =
+        DexClassAndMethod singleTarget =
             instruction.lookupSingleTarget(appView.withLiveness(), context);
         if (singleTarget != null) {
-          return isTypeInitializedBy(instruction, type, singleTarget, appView, mode);
+          return isTypeInitializedBy(
+              instruction, type, singleTarget.getDefinition(), appView, mode);
         }
       }
       DexMethod method = instruction.getInvokedMethod();
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/DeterminismAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/DeterminismAnalysis.java
index 32c1bb1..c2a5b53 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/DeterminismAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/DeterminismAnalysis.java
@@ -4,7 +4,7 @@
 package com.android.tools.r8.ir.analysis;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -36,9 +36,10 @@
         return false;
       }
       if (instr.isInvokeMethod()) {
-        DexEncodedMethod target =
+        DexClassAndMethod target =
             instr.asInvokeMethod().lookupSingleTarget(appView, code.context());
-        if (target != null && target.getOptimizationInfo().returnValueOnlyDependsOnArguments()) {
+        if (target != null
+            && target.getDefinition().getOptimizationInfo().returnValueOnlyDependsOnArguments()) {
           continue;
         }
         return false;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/InitializedClassesOnNormalExitAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/InitializedClassesOnNormalExitAnalysis.java
index b73a496..01ea16b 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/InitializedClassesOnNormalExitAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/InitializedClassesOnNormalExitAnalysis.java
@@ -6,8 +6,8 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -132,13 +132,16 @@
         InvokeMethod invoke = instruction.asInvokeMethod();
         DexMethod method = invoke.getInvokedMethod();
         if (method.holder.isClassType()) {
-          DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, context);
+          DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, context);
           if (singleTarget != null) {
-            markInitializedOnNormalExit(singleTarget.holder());
+            markInitializedOnNormalExit(singleTarget.getHolderType());
             markInitializedOnNormalExit(
-                singleTarget.getOptimizationInfo().getInitializedClassesOnNormalExit());
+                singleTarget
+                    .getDefinition()
+                    .getOptimizationInfo()
+                    .getInitializedClassesOnNormalExit());
           } else {
-            markInitializedOnNormalExit(method.holder);
+            markInitializedOnNormalExit(method.getHolderType());
           }
         }
       }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/equivalence/BasicBlockBehavioralSubsumption.java b/src/main/java/com/android/tools/r8/ir/analysis/equivalence/BasicBlockBehavioralSubsumption.java
index ea4040c..2fb3ef7 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/equivalence/BasicBlockBehavioralSubsumption.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/equivalence/BasicBlockBehavioralSubsumption.java
@@ -8,7 +8,7 @@
 import static com.google.common.base.Predicates.or;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.ConstClass;
@@ -160,9 +160,10 @@
     }
     // For constructor calls include field initialization side effects.
     if (instruction.isInvokeConstructor(appView.dexItemFactory())) {
-      DexEncodedMethod singleTarget =
+      DexClassAndMethod singleTarget =
           instruction.asInvokeDirect().lookupSingleTarget(appView, context);
-      return singleTarget != null && !singleTarget.getOptimizationInfo().mayHaveSideEffects();
+      return singleTarget != null
+          && !singleTarget.getDefinition().getOptimizationInfo().mayHaveSideEffects();
     }
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
index 3bc0ebe..d0fd119 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
@@ -7,6 +7,7 @@
 import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
 
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -150,7 +151,7 @@
       return;
     }
 
-    DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, context);
+    DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, context);
     if (singleTarget == null) {
       // We just lost track.
       abstractInstanceFieldValues.remove(clazz);
@@ -158,7 +159,11 @@
     }
 
     InstanceFieldInitializationInfoCollection initializationInfoCollection =
-        singleTarget.getOptimizationInfo().getInstanceInitializerInfo().fieldInitializationInfos();
+        singleTarget
+            .getDefinition()
+            .getOptimizationInfo()
+            .getInstanceInitializerInfo()
+            .fieldInitializationInfos();
 
     // Synchronize on the lattice element (abstractInstanceFieldValuesForClass) in case we process
     // another allocation site of `clazz` concurrently.
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/InstanceFieldValueAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/InstanceFieldValueAnalysis.java
index f508479..d42d5d1 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/InstanceFieldValueAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/InstanceFieldValueAnalysis.java
@@ -8,8 +8,8 @@
 
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
@@ -43,14 +43,14 @@
 
   private final InstanceFieldInitializationInfoFactory factory;
 
-  private final DexEncodedMethod parentConstructor;
+  private final DexClassAndMethod parentConstructor;
   private final InvokeDirect parentConstructorCall;
 
   private InstanceFieldValueAnalysis(
       AppView<AppInfoWithLiveness> appView,
       IRCode code,
       OptimizationFeedback feedback,
-      DexEncodedMethod parentConstructor,
+      DexClassAndMethod parentConstructor,
       InvokeDirect parentConstructorCall) {
     super(appView, code, feedback);
     this.factory = appView.instanceFieldInitializationInfoFactory();
@@ -90,7 +90,7 @@
       return EmptyInstanceFieldInitializationInfoCollection.getInstance();
     }
 
-    DexEncodedMethod parentConstructor =
+    DexClassAndMethod parentConstructor =
         parentConstructorCall.lookupSingleTarget(appView, code.context());
     if (parentConstructor == null) {
       return EmptyInstanceFieldInitializationInfoCollection.getInstance();
@@ -167,6 +167,7 @@
     }
     InstanceFieldInitializationInfoCollection infos =
         parentConstructor
+            .getDefinition()
             .getOptimizationInfo()
             .getInstanceInitializerInfo()
             .fieldInitializationInfos();
@@ -271,7 +272,7 @@
     if (field.isFinal()) {
       return true;
     }
-    if (appView.appInfo().isFieldOnlyWrittenInMethod(field, parentConstructor)) {
+    if (appView.appInfo().isFieldOnlyWrittenInMethod(field, parentConstructor.getDefinition())) {
       return true;
     }
     // Otherwise, conservatively return false.
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
index ebcdfff..1b4e723 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
@@ -9,8 +9,8 @@
 import static com.android.tools.r8.ir.code.Opcodes.STATIC_PUT;
 
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
@@ -339,13 +339,17 @@
       return ObjectState.empty();
     }
 
-    DexEncodedMethod singleTarget = uniqueConstructorInvoke.lookupSingleTarget(appView, context);
+    DexClassAndMethod singleTarget = uniqueConstructorInvoke.lookupSingleTarget(appView, context);
     if (singleTarget == null) {
       return ObjectState.empty();
     }
 
     InstanceFieldInitializationInfoCollection initializationInfos =
-        singleTarget.getOptimizationInfo().getInstanceInitializerInfo().fieldInitializationInfos();
+        singleTarget
+            .getDefinition()
+            .getOptimizationInfo()
+            .getInstanceInitializerInfo()
+            .fieldInitializationInfos();
     if (initializationInfos.isEmpty()) {
       return ObjectState.empty();
     }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
index 2a81647..a6d77f7 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
@@ -3,10 +3,13 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.code;
 
+import static com.android.tools.r8.graph.DexEncodedMethod.asDexClassAndMethodOrNull;
+
 import com.android.tools.r8.cf.code.CfInvoke;
 import com.android.tools.r8.code.InvokeDirectRange;
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
@@ -125,22 +128,24 @@
   }
 
   @Override
-  public DexEncodedMethod lookupSingleTarget(
+  public DexClassAndMethod lookupSingleTarget(
       AppView<?> appView,
       ProgramMethod context,
       TypeElement receiverUpperBoundType,
       ClassTypeElement receiverLowerBoundType) {
     DexMethod invokedMethod = getInvokedMethod();
+    DexEncodedMethod result;
     if (appView.appInfo().hasLiveness()) {
       AppInfoWithLiveness appInfo = appView.appInfo().withLiveness();
-      DexEncodedMethod result = appInfo.lookupDirectTarget(invokedMethod, context);
+      result = appInfo.lookupDirectTarget(invokedMethod, context);
       assert verifyD8LookupResult(
           result, appView.appInfo().lookupDirectTargetOnItself(invokedMethod, context));
-      return result;
+    } else {
+      // In D8, we can treat invoke-direct instructions as having a single target if the invoke is
+      // targeting a method in the enclosing class.
+      result = appView.appInfo().lookupDirectTargetOnItself(invokedMethod, context);
     }
-    // In D8, we can treat invoke-direct instructions as having a single target if the invoke is
-    // targeting a method in the enclosing class.
-    return appView.appInfo().lookupDirectTargetOnItself(invokedMethod, context);
+    return asDexClassAndMethodOrNull(result, appView);
   }
 
   @Override
@@ -189,12 +194,16 @@
 
     // Trivial instance initializers do not read any fields.
     if (appView.dexItemFactory().isConstructor(invokedMethod)) {
-      DexEncodedMethod singleTarget = lookupSingleTarget(appView, context);
+      DexClassAndMethod singleTarget = lookupSingleTarget(appView, context);
 
       // If we have a single target in the program, then use the computed initializer info.
       // If we have a single target in the library, then fallthrough to the library modeling below.
-      if (singleTarget != null && singleTarget.isProgramMethod(appView)) {
-        return singleTarget.getOptimizationInfo().getInstanceInitializerInfo().readSet();
+      if (singleTarget != null && singleTarget.isProgramMethod()) {
+        return singleTarget
+            .getDefinition()
+            .getOptimizationInfo()
+            .getInstanceInitializerInfo()
+            .readSet();
       }
     }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java b/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java
index 83acc1d..6412e17 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java
@@ -3,11 +3,13 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.code;
 
+import static com.android.tools.r8.graph.DexEncodedMethod.asDexClassAndMethodOrNull;
 import static com.android.tools.r8.ir.analysis.type.TypeAnalysis.toRefinedReceiverType;
 
 import com.android.tools.r8.cf.code.CfInvoke;
 import com.android.tools.r8.code.InvokeInterfaceRange;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
@@ -95,25 +97,27 @@
   }
 
   @Override
-  public DexEncodedMethod lookupSingleTarget(
+  public DexClassAndMethod lookupSingleTarget(
       AppView<?> appView,
       ProgramMethod context,
       TypeElement receiverUpperBoundType,
       ClassTypeElement receiverLowerBoundType) {
-    if (appView.appInfo().hasLiveness()) {
-      AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
-      return appViewWithLiveness
-          .appInfo()
-          .lookupSingleVirtualTarget(
-              getInvokedMethod(),
-              context,
-              true,
-              appView,
-              toRefinedReceiverType(
-                  receiverUpperBoundType, getInvokedMethod(), appViewWithLiveness),
-              receiverLowerBoundType);
+    if (!appView.appInfo().hasLiveness()) {
+      return null;
     }
-    return null;
+    AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
+    DexEncodedMethod result =
+        appViewWithLiveness
+            .appInfo()
+            .lookupSingleVirtualTarget(
+                getInvokedMethod(),
+                context,
+                true,
+                appView,
+                toRefinedReceiverType(
+                    receiverUpperBoundType, getInvokedMethod(), appViewWithLiveness),
+                receiverLowerBoundType);
+    return asDexClassAndMethodOrNull(result, appView);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
index c8dd6ec..a78a16b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.cf.TypeVerificationHelper;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -75,11 +76,10 @@
   // In subclasses, e.g., invoke-virtual or invoke-super, use a narrower receiver type by using
   // receiver type and calling context---the holder of the method where the current invocation is.
   // TODO(b/140204899): Refactor lookup methods to be defined in a single place.
-  public abstract DexEncodedMethod lookupSingleTarget(AppView<?> appView, ProgramMethod context);
+  public abstract DexClassAndMethod lookupSingleTarget(AppView<?> appView, ProgramMethod context);
 
   public final ProgramMethod lookupSingleProgramTarget(AppView<?> appView, ProgramMethod context) {
-    DexEncodedMethod singleTarget = lookupSingleTarget(appView, context);
-    return singleTarget != null ? singleTarget.asProgramMethod(appView) : null;
+    return DexClassAndMethod.asProgramMethodOrNull(lookupSingleTarget(appView, context));
   }
 
   // TODO(b/140204899): Refactor lookup methods to be defined in a single place.
@@ -209,9 +209,9 @@
   public AbstractValue getAbstractValue(
       AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
     assert hasOutValue();
-    DexEncodedMethod method = lookupSingleTarget(appView, context);
+    DexClassAndMethod method = lookupSingleTarget(appView, context);
     if (method != null) {
-      return method.getOptimizationInfo().getAbstractReturnValue();
+      return method.getDefinition().getOptimizationInfo().getAbstractReturnValue();
     }
     return UnknownValue.getInstance();
   }
@@ -227,9 +227,10 @@
 
   @Override
   public boolean throwsNpeIfValueIsNull(Value value, AppView<?> appView, ProgramMethod context) {
-    DexEncodedMethod singleTarget = lookupSingleTarget(appView, context);
+    DexClassAndMethod singleTarget = lookupSingleTarget(appView, context);
     if (singleTarget != null) {
-      BitSet nonNullParamOrThrow = singleTarget.getOptimizationInfo().getNonNullParamOrThrow();
+      BitSet nonNullParamOrThrow =
+          singleTarget.getDefinition().getOptimizationInfo().getNonNullParamOrThrow();
       if (nonNullParamOrThrow != null) {
         int argumentIndex = inValues.indexOf(value);
         return argumentIndex >= 0 && nonNullParamOrThrow.get(argumentIndex);
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java
index b006d6a..09db288 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMethodWithReceiver.java
@@ -3,10 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.code;
 
-import static com.android.tools.r8.graph.DexEncodedMethod.asProgramMethodOrNull;
-
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -73,7 +72,7 @@
   }
 
   @Override
-  public final DexEncodedMethod lookupSingleTarget(AppView<?> appView, ProgramMethod context) {
+  public final DexClassAndMethod lookupSingleTarget(AppView<?> appView, ProgramMethod context) {
     TypeElement receiverUpperBoundType = null;
     ClassTypeElement receiverLowerBoundType = null;
     if (appView.enableWholeProgramOptimizations()) {
@@ -84,7 +83,7 @@
     return lookupSingleTarget(appView, context, receiverUpperBoundType, receiverLowerBoundType);
   }
 
-  public abstract DexEncodedMethod lookupSingleTarget(
+  public abstract DexClassAndMethod lookupSingleTarget(
       AppView<?> appView,
       ProgramMethod context,
       TypeElement receiverUpperBoundType,
@@ -95,9 +94,8 @@
       ProgramMethod context,
       TypeElement receiverUpperBoundType,
       ClassTypeElement receiverLowerBoundType) {
-    return asProgramMethodOrNull(
-        lookupSingleTarget(appView, context, receiverUpperBoundType, receiverLowerBoundType),
-        appView);
+    return DexClassAndMethod.asProgramMethodOrNull(
+        lookupSingleTarget(appView, context, receiverUpperBoundType, receiverLowerBoundType));
   }
 
   @Override
@@ -237,18 +235,19 @@
     }
 
     // Find the target and check if the invoke may have side effects.
-    DexEncodedMethod target = lookupSingleTarget(appViewWithLiveness, context);
-    if (target == null) {
+    DexClassAndMethod singleTarget = lookupSingleTarget(appViewWithLiveness, context);
+    if (singleTarget == null) {
       return true;
     }
 
     // Verify that the target method does not have side-effects.
-    if (appViewWithLiveness.appInfo().noSideEffects.containsKey(target.method)) {
+    if (appViewWithLiveness.appInfo().noSideEffects.containsKey(singleTarget.getReference())) {
       return false;
     }
 
-    MethodOptimizationInfo optimizationInfo = target.getOptimizationInfo();
-    if (target.isInstanceInitializer()) {
+    DexEncodedMethod singleTargetDefinition = singleTarget.getDefinition();
+    MethodOptimizationInfo optimizationInfo = singleTargetDefinition.getOptimizationInfo();
+    if (singleTargetDefinition.isInstanceInitializer()) {
       InstanceInitializerInfo initializerInfo = optimizationInfo.getInstanceInitializerInfo();
       if (!initializerInfo.mayHaveOtherSideEffectsThanInstanceFieldAssignments()) {
         return !isInvokeDirect();
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java b/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java
index dbcafdc..425262b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java
@@ -7,7 +7,7 @@
 import com.android.tools.r8.code.InvokePolymorphicRange;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProto;
@@ -125,7 +125,7 @@
   }
 
   @Override
-  public DexEncodedMethod lookupSingleTarget(AppView<?> appView, ProgramMethod context) {
+  public DexClassAndMethod lookupSingleTarget(AppView<?> appView, ProgramMethod context) {
     // TODO(herhut): Implement lookup target for invokePolymorphic.
     return null;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
index 696d674..4e8746d 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
@@ -3,10 +3,13 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.code;
 
+import static com.android.tools.r8.graph.DexEncodedMethod.asDexClassAndMethodOrNull;
+
 import com.android.tools.r8.cf.code.CfInvoke;
 import com.android.tools.r8.code.InvokeStaticRange;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
@@ -107,24 +110,27 @@
   }
 
   @Override
-  public DexEncodedMethod lookupSingleTarget(AppView<?> appView, ProgramMethod context) {
+  public DexClassAndMethod lookupSingleTarget(AppView<?> appView, ProgramMethod context) {
     DexMethod invokedMethod = getInvokedMethod();
+    DexEncodedMethod result;
     if (appView.appInfo().hasLiveness()) {
       AppInfoWithLiveness appInfo = appView.appInfo().withLiveness();
-      DexEncodedMethod result = appInfo.lookupStaticTarget(invokedMethod, context);
+      result = appInfo.lookupStaticTarget(invokedMethod, context);
       assert verifyD8LookupResult(
           result, appView.appInfo().lookupStaticTargetOnItself(invokedMethod, context));
-      return result;
+    } else {
+      // Allow optimizing static library invokes in D8.
+      DexClass clazz = appView.definitionForHolder(getInvokedMethod());
+      if (clazz != null
+          && (clazz.isLibraryClass() || appView.libraryMethodOptimizer().isModeled(clazz.type))) {
+        result = clazz.lookupMethod(getInvokedMethod());
+      } else {
+        // In D8, we can treat invoke-static instructions as having a single target if the invoke is
+        // targeting a method in the enclosing class.
+        result = appView.appInfo().lookupStaticTargetOnItself(invokedMethod, context);
+      }
     }
-    // Allow optimizing static library invokes in D8.
-    DexClass clazz = appView.definitionForHolder(getInvokedMethod());
-    if (clazz != null
-        && (clazz.isLibraryClass() || appView.libraryMethodOptimizer().isModeled(clazz.type))) {
-      return clazz.lookupMethod(getInvokedMethod());
-    }
-    // In D8, we can treat invoke-static instructions as having a single target if the invoke is
-    // targeting a method in the enclosing class.
-    return appView.appInfo().lookupStaticTargetOnItself(invokedMethod, context);
+    return asDexClassAndMethodOrNull(result, appView);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java b/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java
index 34fa59c..8ce0b70 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java
@@ -3,9 +3,12 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.code;
 
+import static com.android.tools.r8.graph.DexEncodedMethod.asDexClassAndMethodOrNull;
+
 import com.android.tools.r8.cf.code.CfInvoke;
 import com.android.tools.r8.code.InvokeSuperRange;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
@@ -102,7 +105,7 @@
   }
 
   @Override
-  public DexEncodedMethod lookupSingleTarget(
+  public DexClassAndMethod lookupSingleTarget(
       AppView<?> appView,
       ProgramMethod context,
       TypeElement receiverUpperBoundType,
@@ -111,7 +114,8 @@
       AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
       AppInfoWithLiveness appInfo = appViewWithLiveness.appInfo();
       if (appInfo.isSubtype(context.getHolderType(), getInvokedMethod().holder)) {
-        return appInfo.lookupSuperTarget(getInvokedMethod(), context);
+        DexEncodedMethod result = appInfo.lookupSuperTarget(getInvokedMethod(), context);
+        return asDexClassAndMethodOrNull(result, appView);
       }
     }
     return null;
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java b/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
index e7fb163..d4f737e 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
@@ -3,12 +3,14 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.code;
 
+import static com.android.tools.r8.graph.DexEncodedMethod.asDexClassAndMethodOrNull;
 import static com.android.tools.r8.ir.analysis.type.TypeAnalysis.toRefinedReceiverType;
 
 import com.android.tools.r8.cf.code.CfInvoke;
 import com.android.tools.r8.code.InvokeVirtualRange;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
@@ -96,7 +98,7 @@
   }
 
   @Override
-  public DexEncodedMethod lookupSingleTarget(
+  public DexClassAndMethod lookupSingleTarget(
       AppView<?> appView,
       ProgramMethod context,
       TypeElement receiverUpperBoundType,
@@ -105,38 +107,43 @@
         appView, context, receiverUpperBoundType, receiverLowerBoundType, getInvokedMethod());
   }
 
-  public static DexEncodedMethod lookupSingleTarget(
+  public static DexClassAndMethod lookupSingleTarget(
       AppView<?> appView,
       ProgramMethod context,
       TypeElement receiverUpperBoundType,
       ClassTypeElement receiverLowerBoundType,
       DexMethod method) {
+    DexEncodedMethod result = null;
     if (appView.appInfo().hasLiveness()) {
       AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
-      return appViewWithLiveness
-          .appInfo()
-          .lookupSingleVirtualTarget(
-              method,
-              context,
-              false,
-              appView,
-              toRefinedReceiverType(receiverUpperBoundType, method, appViewWithLiveness),
-              receiverLowerBoundType);
-    }
-    // In D8, allow lookupSingleTarget() to be used for finding final library methods. This is used
-    // for library modeling.
-    DexType holder = method.holder;
-    if (holder.isClassType()) {
-      DexClass clazz = appView.definitionFor(holder);
-      if (clazz != null
-          && (clazz.isLibraryClass() || appView.libraryMethodOptimizer().isModeled(clazz.type))) {
-        DexEncodedMethod singleTargetCandidate = clazz.lookupMethod(method);
-        if (singleTargetCandidate != null && (clazz.isFinal() || singleTargetCandidate.isFinal())) {
-          return singleTargetCandidate;
+      result =
+          appViewWithLiveness
+              .appInfo()
+              .lookupSingleVirtualTarget(
+                  method,
+                  context,
+                  false,
+                  appView,
+                  toRefinedReceiverType(receiverUpperBoundType, method, appViewWithLiveness),
+                  receiverLowerBoundType);
+    } else {
+      // In D8, allow lookupSingleTarget() to be used for finding final library methods. This is
+      // used
+      // for library modeling.
+      DexType holder = method.holder;
+      if (holder.isClassType()) {
+        DexClass clazz = appView.definitionFor(holder);
+        if (clazz != null
+            && (clazz.isLibraryClass() || appView.libraryMethodOptimizer().isModeled(clazz.type))) {
+          DexEncodedMethod singleTargetCandidate = clazz.lookupMethod(method);
+          if (singleTargetCandidate != null
+              && (clazz.isFinal() || singleTargetCandidate.isFinal())) {
+            result = singleTargetCandidate;
+          }
         }
       }
     }
-    return null;
+    return asDexClassAndMethodOrNull(result, appView);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/AssumeInserter.java b/src/main/java/com/android/tools/r8/ir/optimize/AssumeInserter.java
index 0008896..d6eae9a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/AssumeInserter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/AssumeInserter.java
@@ -8,8 +8,8 @@
 
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
 import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
@@ -225,13 +225,13 @@
 
   private boolean computeAssumedValuesFromSingleTarget(
       IRCode code, InvokeMethod invoke, AssumedValues.Builder assumedValuesBuilder) {
-    DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, code.context());
+    DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, code.context());
     if (singleTarget == null) {
       return false;
     }
 
     boolean needsAssumeInstruction = false;
-    MethodOptimizationInfo optimizationInfo = singleTarget.getOptimizationInfo();
+    MethodOptimizationInfo optimizationInfo = singleTarget.getDefinition().getOptimizationInfo();
 
     // Case (2), invocations that are guaranteed to return a non-null value.
     Value outValue = invoke.outValue();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index 4c61a1c..61b13cb 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -16,6 +16,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DebugLocalInfo;
 import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory;
@@ -1253,9 +1254,14 @@
         }
 
         // Check if the invoked method is known to return one of its arguments.
-        DexEncodedMethod target = invoke.lookupSingleTarget(appView, code.context());
-        if (target != null && target.getOptimizationInfo().returnsArgument()) {
-          int argumentIndex = target.getOptimizationInfo().getReturnedArgument();
+        DexClassAndMethod target = invoke.lookupSingleTarget(appView, code.context());
+        if (target == null) {
+          continue;
+        }
+
+        MethodOptimizationInfo optimizationInfo = target.getDefinition().getOptimizationInfo();
+        if (optimizationInfo.returnsArgument()) {
+          int argumentIndex = optimizationInfo.getReturnedArgument();
           // Replace the out value of the invoke with the argument and ignore the out value.
           if (argumentIndex >= 0 && checkArgumentType(invoke, argumentIndex)) {
             Value argument = invoke.arguments().get(argumentIndex);
@@ -2878,13 +2884,14 @@
         }
 
         InvokeMethod invoke = instruction.asInvokeMethod();
-        DexEncodedMethod singleTarget =
+        DexClassAndMethod singleTarget =
             invoke.lookupSingleTarget(appView.withLiveness(), code.context());
         if (singleTarget == null) {
           continue;
         }
 
-        MethodOptimizationInfo optimizationInfo = singleTarget.getOptimizationInfo();
+        MethodOptimizationInfo optimizationInfo =
+            singleTarget.getDefinition().getOptimizationInfo();
 
         // If the invoke instruction is a null check, we can remove it.
         boolean isNullCheck = false;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java b/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
index 4c7570c..d648bc1 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
@@ -123,19 +123,18 @@
           // Check if the instruction can be rewritten to invoke-super. This allows inlining of the
           // enclosing method into contexts outside the current class.
           if (appView.options().testing.enableInvokeSuperToInvokeVirtualRewriting) {
-            DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, context);
+            DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, context);
             if (singleTarget != null) {
-              DexClass holder = appView.definitionForHolder(singleTarget, context);
-              assert holder != null;
               DexMethod invokedMethod = invoke.getInvokedMethod();
-              DexEncodedMethod newSingleTarget =
+              DexClassAndMethod newSingleTarget =
                   InvokeVirtual.lookupSingleTarget(
                       appView,
                       context,
                       invoke.getReceiver().getDynamicUpperBoundType(appView),
                       invoke.getReceiver().getDynamicLowerBoundType(appView),
                       invokedMethod);
-              if (newSingleTarget == singleTarget) {
+              if (newSingleTarget != null
+                  && newSingleTarget.getReference() == singleTarget.getReference()) {
                 it.replaceCurrentInstruction(
                     new InvokeVirtual(invokedMethod, invoke.outValue(), invoke.arguments()));
                 continue;
@@ -173,12 +172,11 @@
           continue;
         }
         InvokeInterface invoke = current.asInvokeInterface();
-        DexEncodedMethod target = invoke.lookupSingleTarget(appView, context);
+        DexClassAndMethod target = invoke.lookupSingleTarget(appView, context);
         if (target == null) {
           continue;
         }
-        DexType holderType = target.holder();
-        DexClass holderClass = appView.definitionFor(holderType);
+        DexClass holderClass = target.getHolder();
         // Make sure we are not landing on another interface, e.g., interface's default method.
         if (holderClass == null || holderClass.isInterface()) {
           continue;
@@ -190,7 +188,7 @@
         }
 
         InvokeVirtual devirtualizedInvoke =
-            new InvokeVirtual(target.method, invoke.outValue(), invoke.inValues());
+            new InvokeVirtual(target.getReference(), invoke.outValue(), invoke.inValues());
         it.replaceCurrentInstruction(devirtualizedInvoke);
         devirtualizedCall.put(invoke, devirtualizedInvoke);
 
@@ -204,11 +202,12 @@
         // CodeRewriter#removeTrivialCheckCastAndInstanceOfInstructions}.
         // a <- check-cast A i  // Otherwise ART verification error.
         // (out <-) invoke-virtual a, ... A#foo
-        if (holderType != invoke.getInvokedMethod().holder) {
+        if (holderClass.getType() != invoke.getInvokedMethod().holder) {
           Value receiver = invoke.getReceiver();
           TypeElement receiverTypeLattice = receiver.getType();
           TypeElement castTypeLattice =
-              TypeElement.fromDexType(holderType, receiverTypeLattice.nullability(), appView);
+              TypeElement.fromDexType(
+                  holderClass.getType(), receiverTypeLattice.nullability(), appView);
           // Avoid adding trivial cast and up-cast.
           // We should not use strictlyLessThan(castType, receiverType), which detects downcast,
           // due to side-casts, e.g., A (unused) < I, B < I, and cast from A to B.
@@ -224,8 +223,8 @@
             // a2 <- check-cast A i  // We should be able to reuse a1 here!
             // invoke-virtual a2, ... A#m2 (from I#m2)
             if (castedReceiverCache.containsKey(receiver)
-                && castedReceiverCache.get(receiver).containsKey(holderType)) {
-              Value cachedReceiver = castedReceiverCache.get(receiver).get(holderType);
+                && castedReceiverCache.get(receiver).containsKey(holderClass.getType())) {
+              Value cachedReceiver = castedReceiverCache.get(receiver).get(holderClass.getType());
               if (dominatorTree.dominatedBy(block, cachedReceiver.definition.getBlock())) {
                 newReceiver = cachedReceiver;
               }
@@ -237,9 +236,9 @@
               // Cache the new receiver with a narrower type to avoid redundant checkcast.
               if (!receiver.hasLocalInfo()) {
                 castedReceiverCache.putIfAbsent(receiver, new IdentityHashMap<>());
-                castedReceiverCache.get(receiver).put(holderType, newReceiver);
+                castedReceiverCache.get(receiver).put(holderClass.getType(), newReceiver);
               }
-              CheckCast checkCast = new CheckCast(newReceiver, receiver, holderType);
+              CheckCast checkCast = new CheckCast(newReceiver, receiver, holderClass.getType());
               checkCast.setPosition(invoke.getPosition());
               newCheckCastInstructions.add(checkCast);
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/IdempotentFunctionCallCanonicalizer.java b/src/main/java/com/android/tools/r8/ir/optimize/IdempotentFunctionCallCanonicalizer.java
index 10d17e7..72abb27 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/IdempotentFunctionCallCanonicalizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/IdempotentFunctionCallCanonicalizer.java
@@ -4,7 +4,7 @@
 package com.android.tools.r8.ir.optimize;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -17,6 +17,7 @@
 import com.android.tools.r8.ir.code.InvokeMethod;
 import com.android.tools.r8.ir.code.Position;
 import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo;
 import com.android.tools.r8.logging.Log;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.StringUtils;
@@ -154,10 +155,14 @@
           //  return the resolution result such that the call site can perform the accessibility
           //  check, or (iii) always perform the accessibility check such that it can be skipped
           //  at the call site.
-          DexEncodedMethod target = invoke.lookupSingleTarget(appViewWithLiveness, context);
-          if (target == null
-              || target.getOptimizationInfo().mayHaveSideEffects()
-              || !target.getOptimizationInfo().returnValueOnlyDependsOnArguments()) {
+          DexClassAndMethod target = invoke.lookupSingleTarget(appViewWithLiveness, context);
+          if (target == null) {
+            continue;
+          }
+
+          MethodOptimizationInfo optimizationInfo = target.getDefinition().getOptimizationInfo();
+          if (optimizationInfo.mayHaveSideEffects()
+              || !optimizationInfo.returnValueOnlyDependsOnArguments()) {
             continue;
           }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
index 96fd58c..621f3b9 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
@@ -8,6 +8,7 @@
 import static com.google.common.base.Predicates.alwaysTrue;
 
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexDefinition;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
@@ -103,12 +104,16 @@
         || appView.appInfo().noSideEffects.containsKey(field.field);
   }
 
-  private boolean mayPropagateValueFor(DexEncodedMethod method) {
-    if (method.isProgramMethod(appView)) {
-      return appView.appInfo().mayPropagateValueFor(method.method);
+  private boolean mayPropagateValueFor(DexClassAndMethod method) {
+    if (method.isProgramMethod()) {
+      return appView.appInfo().mayPropagateValueFor(method.getReference());
     }
-    return appView.appInfo().assumedValues.containsKey(method.method)
-        || appView.appInfo().noSideEffects.containsKey(method.method);
+    return appView.appInfo().assumedValues.containsKey(method.getReference())
+        || appView.appInfo().noSideEffects.containsKey(method.getReference());
+  }
+
+  private ProguardMemberRuleLookup lookupMemberRule(DexClassAndMethod method) {
+    return method != null ? lookupMemberRule(method.getDefinition()) : null;
   }
 
   private ProguardMemberRuleLookup lookupMemberRule(DexDefinition definition) {
@@ -245,7 +250,7 @@
       return;
     }
 
-    DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, context);
+    DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, context);
     ProguardMemberRuleLookup lookup = lookupMemberRule(singleTarget);
     if (lookup == null) {
       // -assumenosideeffects rules are applied to upward visible and overriding methods, but only
@@ -264,7 +269,7 @@
       if (singleTarget != null
           && lookup.type == RuleType.ASSUME_NO_SIDE_EFFECTS
           && !lookup.rule.hasReturnValue()) {
-        ProguardMemberRule rule = appView.appInfo().assumedValues.get(singleTarget.toReference());
+        ProguardMemberRule rule = appView.appInfo().assumedValues.get(singleTarget.getReference());
         if (rule != null) {
           lookup = new ProguardMemberRuleLookup(RuleType.ASSUME_VALUES, rule);
         }
@@ -280,7 +285,8 @@
       return;
     }
 
-    AbstractValue abstractReturnValue = singleTarget.getOptimizationInfo().getAbstractReturnValue();
+    AbstractValue abstractReturnValue =
+        singleTarget.getDefinition().getOptimizationInfo().getAbstractReturnValue();
 
     if (abstractReturnValue.isSingleValue()) {
       SingleValue singleReturnValue = abstractReturnValue.asSingleValue();
@@ -299,7 +305,7 @@
           replaceInstructionByNullCheckIfPossible(invoke, iterator, context);
         } else if (invoke.isInvokeStatic()) {
           replaceInstructionByInitClassIfPossible(
-              invoke, singleTarget.holder(), code, iterator, context);
+              invoke, singleTarget.getHolderType(), code, iterator, context);
         }
 
         // Insert the definition of the replacement.
@@ -309,7 +315,7 @@
         } else {
           iterator.add(replacement);
         }
-        singleTarget.getMutableOptimizationInfo().markAsPropagated();
+        singleTarget.getDefinition().getMutableOptimizationInfo().markAsPropagated();
       }
     }
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
index b6bd724..54976af 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
@@ -8,8 +8,8 @@
 
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -352,14 +352,14 @@
       return;
     }
 
-    DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, method);
-    if (singleTarget == null || !singleTarget.isInstanceInitializer()) {
+    DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, method);
+    if (singleTarget == null || !singleTarget.getDefinition().isInstanceInitializer()) {
       killAllNonFinalActiveFields();
       return;
     }
 
     InstanceInitializerInfo instanceInitializerInfo =
-        singleTarget.getOptimizationInfo().getInstanceInitializerInfo();
+        singleTarget.getDefinition().getOptimizationInfo().getInstanceInitializerInfo();
     if (instanceInitializerInfo.mayHaveOtherSideEffectsThanInstanceFieldAssignments()) {
       killAllNonFinalActiveFields();
     }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
index c8cc00e..d0fc9c5 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AccessControl;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexField;
@@ -296,21 +297,21 @@
           }
 
           // TODO(b/156853206): Avoid duplicating resolution.
-          DexEncodedMethod singleTargetMethod = invokeMethod.lookupSingleTarget(appView, method);
-          if (singleTargetMethod == null) {
+          DexClassAndMethod singleTarget = invokeMethod.lookupSingleTarget(appView, method);
+          if (singleTarget == null) {
             return user; // Not eligible.
           }
 
-          if (isEligibleLibraryMethodCall(invokeMethod, singleTargetMethod)) {
+          if (isEligibleLibraryMethodCall(invokeMethod, singleTarget)) {
             continue;
           }
 
-          ProgramMethod singleTarget = singleTargetMethod.asProgramMethod(appView);
-          if (!isEligibleSingleTarget(singleTarget)) {
+          ProgramMethod singleProgramTarget = singleTarget.asProgramMethod();
+          if (!isEligibleSingleTarget(singleProgramTarget)) {
             return user; // Not eligible.
           }
 
-          if (AccessControl.isClassAccessible(singleTarget.getHolder(), method, appView)
+          if (AccessControl.isClassAccessible(singleProgramTarget.getHolder(), method, appView)
               .isPossiblyFalse()) {
             return user; // Not eligible.
           }
@@ -324,7 +325,7 @@
                       && !invoke.inValues().isEmpty()
                       && root.outValue() == invoke.getReceiver();
               if (isCorrespondingConstructorCall) {
-                InliningInfo inliningInfo = isEligibleConstructorCall(invoke, singleTarget);
+                InliningInfo inliningInfo = isEligibleConstructorCall(invoke, singleProgramTarget);
                 if (inliningInfo != null) {
                   methodCallsOnInstance.put(invoke, inliningInfo);
                   continue;
@@ -340,7 +341,7 @@
             InvokeMethodWithReceiver invoke = user.asInvokeMethodWithReceiver();
             InliningInfo inliningInfo =
                 isEligibleDirectVirtualMethodCall(
-                    invoke, resolutionResult, singleTarget, indirectUsers, defaultOracle);
+                    invoke, resolutionResult, singleProgramTarget, indirectUsers, defaultOracle);
             if (inliningInfo != null) {
               methodCallsOnInstance.put(invoke, inliningInfo);
               continue;
@@ -351,7 +352,7 @@
           if (isExtraMethodCall(invokeMethod)) {
             assert !invokeMethod.isInvokeSuper();
             assert !invokeMethod.isInvokePolymorphic();
-            if (isExtraMethodCallEligible(invokeMethod, singleTarget, defaultOracle)) {
+            if (isExtraMethodCallEligible(invokeMethod, singleProgramTarget, defaultOracle)) {
               continue;
             }
           }
@@ -646,11 +647,11 @@
           continue;
         }
 
-        DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, method);
+        DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, method);
         if (singleTarget != null) {
           Predicate<InvokeMethod> noSideEffectsPredicate =
               dexItemFactory.libraryMethodsWithoutSideEffects.getOrDefault(
-                  singleTarget.method, alwaysFalse());
+                  singleTarget.getReference(), alwaysFalse());
           if (noSideEffectsPredicate.test(invoke)) {
             if (!invoke.hasOutValue() || !invoke.outValue().hasAnyUsers()) {
               removeInstruction(invoke);
@@ -1169,13 +1170,13 @@
     return true;
   }
 
-  private boolean isEligibleLibraryMethodCall(InvokeMethod invoke, DexEncodedMethod singleTarget) {
+  private boolean isEligibleLibraryMethodCall(InvokeMethod invoke, DexClassAndMethod singleTarget) {
     Predicate<InvokeMethod> noSideEffectsPredicate =
-        dexItemFactory.libraryMethodsWithoutSideEffects.get(singleTarget.method);
+        dexItemFactory.libraryMethodsWithoutSideEffects.get(singleTarget.getReference());
     if (noSideEffectsPredicate != null && noSideEffectsPredicate.test(invoke)) {
       return !invoke.hasOutValue() || !invoke.outValue().hasAnyUsers();
     }
-    if (singleTarget.method == dexItemFactory.objectsMethods.requireNonNull) {
+    if (singleTarget.getReference() == dexItemFactory.objectsMethods.requireNonNull) {
       return !invoke.hasOutValue() || !invoke.outValue().hasAnyUsers();
     }
     return false;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
index c766569..334e4fa 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
@@ -10,6 +10,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexCallSite;
 import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMember;
 import com.android.tools.r8.graph.DexEncodedMethod;
@@ -211,7 +212,7 @@
     DexMethod invokedMethod = invokeStatic.getInvokedMethod();
     DexProgramClass enumClass = getEnumUnboxingCandidateOrNull(invokedMethod.holder);
     if (enumClass != null) {
-      DexEncodedMethod method = invokeStatic.lookupSingleTarget(appView, context);
+      DexClassAndMethod method = invokeStatic.lookupSingleTarget(appView, context);
       if (method != null) {
         eligibleEnums.add(enumClass.type);
       } else {
@@ -726,19 +727,13 @@
         }
         return Reason.INVALID_INVOKE_ON_ARRAY;
       }
-      DexEncodedMethod encodedSingleTarget =
-          invokeMethod.lookupSingleTarget(appView, code.context());
-      if (encodedSingleTarget == null) {
+      DexClassAndMethod singleTarget = invokeMethod.lookupSingleTarget(appView, code.context());
+      if (singleTarget == null) {
         return Reason.INVALID_INVOKE;
       }
-      DexMethod singleTarget = encodedSingleTarget.method;
-      DexClass dexClass = appView.definitionFor(singleTarget.holder, code.context());
-      if (dexClass == null) {
-        assert false;
-        return Reason.INVALID_INVOKE;
-      }
+      DexClass dexClass = singleTarget.getHolder();
       if (dexClass.isProgramClass()) {
-        if (dexClass.isEnum() && encodedSingleTarget.isInstanceInitializer()) {
+        if (dexClass.isEnum() && singleTarget.getDefinition().isInstanceInitializer()) {
           if (code.method().holder() == dexClass.type && code.method().isClassInitializer()) {
             // The enum instance initializer is allowed to be called only from the enum clinit.
             return Reason.ELIGIBLE;
@@ -748,10 +743,10 @@
         }
         // Check that the enum-value only flows into parameters whose type exactly matches the
         // enum's type.
-        int offset = BooleanUtils.intValue(!encodedSingleTarget.isStatic());
-        for (int i = 0; i < singleTarget.proto.parameters.size(); i++) {
+        int offset = BooleanUtils.intValue(!singleTarget.getDefinition().isStatic());
+        for (int i = 0; i < singleTarget.getReference().getParameters().size(); i++) {
           if (invokeMethod.getArgument(offset + i) == enumValue) {
-            if (singleTarget.proto.parameters.values[i].toBaseType(factory) != enumClass.type) {
+            if (singleTarget.getReference().getParameter(i).toBaseType(factory) != enumClass.type) {
               return Reason.GENERIC_INVOKE;
             }
           }
@@ -768,43 +763,44 @@
         return Reason.INVALID_INVOKE;
       }
       assert dexClass.isLibraryClass();
+      DexMethod singleTargetReference = singleTarget.getReference();
       if (dexClass.type != factory.enumType) {
         // System.identityHashCode(Object) is supported for proto enums.
         // Object#getClass without outValue and Objects.requireNonNull are supported since R8
         // rewrites explicit null checks to such instructions.
-        if (singleTarget == factory.javaLangSystemMethods.identityHashCode) {
+        if (singleTargetReference == factory.javaLangSystemMethods.identityHashCode) {
           return Reason.ELIGIBLE;
         }
-        if (singleTarget == factory.stringMembers.valueOf) {
+        if (singleTargetReference == factory.stringMembers.valueOf) {
           addRequiredNameData(enumClass.type);
           return Reason.ELIGIBLE;
         }
-        if (singleTarget == factory.objectMembers.getClass
+        if (singleTargetReference == factory.objectMembers.getClass
             && (!invokeMethod.hasOutValue() || !invokeMethod.outValue().hasAnyUsers())) {
           // This is a hidden null check.
           return Reason.ELIGIBLE;
         }
-        if (singleTarget == factory.objectsMethods.requireNonNull
-            || singleTarget == factory.objectsMethods.requireNonNullWithMessage) {
+        if (singleTargetReference == factory.objectsMethods.requireNonNull
+            || singleTargetReference == factory.objectsMethods.requireNonNullWithMessage) {
           return Reason.ELIGIBLE;
         }
         return Reason.UNSUPPORTED_LIBRARY_CALL;
       }
       // TODO(b/147860220): EnumSet and EnumMap may be interesting to model.
-      if (singleTarget == factory.enumMembers.compareTo) {
+      if (singleTargetReference == factory.enumMembers.compareTo) {
         return Reason.ELIGIBLE;
-      } else if (singleTarget == factory.enumMembers.equals) {
+      } else if (singleTargetReference == factory.enumMembers.equals) {
         return Reason.ELIGIBLE;
-      } else if (singleTarget == factory.enumMembers.nameMethod
-          || singleTarget == factory.enumMembers.toString) {
+      } else if (singleTargetReference == factory.enumMembers.nameMethod
+          || singleTargetReference == factory.enumMembers.toString) {
         assert invokeMethod.asInvokeMethodWithReceiver().getReceiver() == enumValue;
         addRequiredNameData(enumClass.type);
         return Reason.ELIGIBLE;
-      } else if (singleTarget == factory.enumMembers.ordinalMethod) {
+      } else if (singleTargetReference == factory.enumMembers.ordinalMethod) {
         return Reason.ELIGIBLE;
-      } else if (singleTarget == factory.enumMembers.hashCode) {
+      } else if (singleTargetReference == factory.enumMembers.hashCode) {
         return Reason.ELIGIBLE;
-      } else if (singleTarget == factory.enumMembers.constructor) {
+      } else if (singleTargetReference == factory.enumMembers.constructor) {
         // Enum constructor call is allowed only if called from an enum initializer.
         if (code.method().isInstanceInitializer() && code.method().holder() == enumClass.type) {
           return Reason.ELIGIBLE;
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 9125b1c..cb6a6fa 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
@@ -45,6 +45,7 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexField;
@@ -260,11 +261,11 @@
         case INVOKE_STATIC:
           {
             InvokeStatic invoke = insn.asInvokeStatic();
-            DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, context);
+            DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, context);
             if (singleTarget == null) {
               return; // Not allowed.
             }
-            if (singleTarget.method == dexItemFactory.objectsMethods.requireNonNull) {
+            if (singleTarget.getReference() == dexItemFactory.objectsMethods.requireNonNull) {
               if (!invoke.hasOutValue() || !invoke.outValue().hasAnyUsers()) {
                 continue;
               }
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 dcb128a..69bdef8 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
@@ -5,7 +5,7 @@
 package com.android.tools.r8.ir.optimize.library;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
@@ -39,13 +39,13 @@
       IRCode code,
       InstructionListIterator instructionIterator,
       InvokeMethod invoke,
-      DexEncodedMethod singleTarget,
+      DexClassAndMethod singleTarget,
       Set<Value> affectedValues) {
-    if (singleTarget.method == dexItemFactory.booleanMembers.booleanValue) {
+    if (singleTarget.getReference() == dexItemFactory.booleanMembers.booleanValue) {
       optimizeBooleanValue(code, instructionIterator, invoke);
-    } else if (singleTarget.method == dexItemFactory.booleanMembers.parseBoolean) {
+    } else if (singleTarget.getReference() == dexItemFactory.booleanMembers.parseBoolean) {
       optimizeParseBoolean(code, instructionIterator, invoke);
-    } else if (singleTarget.method == dexItemFactory.booleanMembers.valueOf) {
+    } else if (singleTarget.getReference() == dexItemFactory.booleanMembers.valueOf) {
       optimizeValueOf(code, instructionIterator, invoke, affectedValues);
     }
   }
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 658fcb5..4323220 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
@@ -7,7 +7,7 @@
 import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
@@ -36,9 +36,9 @@
       IRCode code,
       InstructionListIterator instructionIterator,
       InvokeMethod invoke,
-      DexEncodedMethod singleTarget,
+      DexClassAndMethod singleTarget,
       Set<Value> affectedValues) {
-    if (singleTarget.method == appView.dexItemFactory().enumMembers.valueOf
+    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 bcea380..d6c8ada 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
@@ -5,8 +5,8 @@
 package com.android.tools.r8.ir.optimize.library;
 
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory.LibraryMembers;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -118,7 +118,7 @@
       Instruction instruction = instructionIterator.next();
       if (instruction.isInvokeMethod()) {
         InvokeMethod invoke = instruction.asInvokeMethod();
-        DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, code.context());
+        DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, code.context());
         if (singleTarget != null) {
           optimizeInvoke(code, instructionIterator, invoke, singleTarget, affectedValues);
         }
@@ -133,11 +133,11 @@
       IRCode code,
       InstructionListIterator instructionIterator,
       InvokeMethod invoke,
-      DexEncodedMethod singleTarget,
+      DexClassAndMethod singleTarget,
       Set<Value> affectedValues) {
     LibraryMethodModelCollection optimizer =
         libraryMethodModelCollections.getOrDefault(
-            singleTarget.holder(), NopLibraryMethodModelCollection.getInstance());
+            singleTarget.getHolderType(), NopLibraryMethodModelCollection.getInstance());
     optimizer.optimize(code, instructionIterator, invoke, singleTarget, 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 5608b94..843e9ab 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
@@ -4,7 +4,7 @@
 
 package com.android.tools.r8.ir.optimize.library;
 
-import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.InstructionListIterator;
@@ -29,6 +29,6 @@
       IRCode code,
       InstructionListIterator instructionIterator,
       InvokeMethod invoke,
-      DexEncodedMethod singleTarget,
+      DexClassAndMethod singleTarget,
       Set<Value> affectedValues);
 }
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 35220c7..f8847d3 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
@@ -5,7 +5,7 @@
 package com.android.tools.r8.ir.optimize.library;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
@@ -104,11 +104,11 @@
       IRCode code,
       InstructionListIterator instructionIterator,
       InvokeMethod invoke,
-      DexEncodedMethod singleTarget,
+      DexClassAndMethod singleTarget,
       Set<Value> affectedValues) {
     int maxRemovedAndroidLogLevel =
         appView.options().getProguardConfiguration().getMaxRemovedAndroidLogLevel();
-    if (singleTarget.method == isLoggableMethod) {
+    if (singleTarget.getReference() == isLoggableMethod) {
       Value logLevelValue = invoke.arguments().get(1).getAliasedValue();
       if (!logLevelValue.isPhi() && !logLevelValue.hasLocalInfo()) {
         Instruction definition = logLevelValue.definition;
@@ -118,27 +118,27 @@
               code, instructionIterator, invoke, maxRemovedAndroidLogLevel >= logLevel ? 0 : 1);
         }
       }
-    } else if (singleTarget.method == vMethod) {
+    } else if (singleTarget.getReference() == vMethod) {
       if (maxRemovedAndroidLogLevel >= VERBOSE) {
         replaceInvokeWithConstNumber(code, instructionIterator, invoke, 0);
       }
-    } else if (singleTarget.method == dMethod) {
+    } else if (singleTarget.getReference() == dMethod) {
       if (maxRemovedAndroidLogLevel >= DEBUG) {
         replaceInvokeWithConstNumber(code, instructionIterator, invoke, 0);
       }
-    } else if (singleTarget.method == iMethod) {
+    } else if (singleTarget.getReference() == iMethod) {
       if (maxRemovedAndroidLogLevel >= INFO) {
         replaceInvokeWithConstNumber(code, instructionIterator, invoke, 0);
       }
-    } else if (singleTarget.method == wMethod) {
+    } else if (singleTarget.getReference() == wMethod) {
       if (maxRemovedAndroidLogLevel >= WARN) {
         replaceInvokeWithConstNumber(code, instructionIterator, invoke, 0);
       }
-    } else if (singleTarget.method == eMethod) {
+    } else if (singleTarget.getReference() == eMethod) {
       if (maxRemovedAndroidLogLevel >= ERROR) {
         replaceInvokeWithConstNumber(code, instructionIterator, invoke, 0);
       }
-    } else if (singleTarget.method == wtfMethod) {
+    } else if (singleTarget.getReference() == wtfMethod) {
       if (maxRemovedAndroidLogLevel >= ASSERT) {
         replaceInvokeWithConstNumber(code, instructionIterator, invoke, 0);
       }
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 9a0980f..f852393 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
@@ -5,7 +5,7 @@
 package com.android.tools.r8.ir.optimize.library;
 
 import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.InstructionListIterator;
@@ -34,6 +34,6 @@
       IRCode code,
       InstructionListIterator instructionIterator,
       InvokeMethod invoke,
-      DexEncodedMethod singleTarget,
+      DexClassAndMethod singleTarget,
       Set<Value> affectedValues) {}
 }
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 1674baf..f16af45 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
@@ -5,7 +5,7 @@
 package com.android.tools.r8.ir.optimize.library;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
+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.IRCode;
@@ -32,9 +32,9 @@
       IRCode code,
       InstructionListIterator instructionIterator,
       InvokeMethod invoke,
-      DexEncodedMethod singleTarget,
+      DexClassAndMethod singleTarget,
       Set<Value> affectedValues) {
-    if (singleTarget.method == dexItemFactory.objectMembers.getClass) {
+    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 c78a123..8fcc1ac 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
@@ -5,7 +5,7 @@
 package com.android.tools.r8.ir.optimize.library;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
+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.IRCode;
@@ -32,9 +32,9 @@
       IRCode code,
       InstructionListIterator instructionIterator,
       InvokeMethod invoke,
-      DexEncodedMethod singleTarget,
+      DexClassAndMethod singleTarget,
       Set<Value> affectedValues) {
-    if (dexItemFactory.objectsMethods.isRequireNonNullMethod(singleTarget.method)) {
+    if (dexItemFactory.objectsMethods.isRequireNonNullMethod(singleTarget.getReference())) {
       optimizeRequireNonNull(instructionIterator, invoke, affectedValues);
     }
   }
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 64dce88..18ad3e6 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
@@ -5,7 +5,7 @@
 package com.android.tools.r8.ir.optimize.library;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexType;
@@ -38,9 +38,9 @@
       IRCode code,
       InstructionListIterator instructionIterator,
       InvokeMethod invoke,
-      DexEncodedMethod singleTarget,
+      DexClassAndMethod singleTarget,
       Set<Value> affectedValues) {
-    if (singleTarget.method == dexItemFactory.stringMembers.equals) {
+    if (singleTarget.getReference() == dexItemFactory.stringMembers.equals) {
       optimizeEquals(code, instructionIterator, invoke);
     }
   }
@@ -74,9 +74,10 @@
       return false;
     }
 
-    DexEncodedMethod singleTarget =
+    DexClassAndMethod singleTarget =
         classNameDefinition.asInvokeVirtual().lookupSingleTarget(appView, context);
-    if (singleTarget == null || singleTarget.method != dexItemFactory.classMethods.getName) {
+    if (singleTarget == null
+        || singleTarget.getReference() != dexItemFactory.classMethods.getName) {
       return false;
     }
 
diff --git a/src/main/java/com/android/tools/r8/shaking/LibraryMethodOverrideAnalysis.java b/src/main/java/com/android/tools/r8/shaking/LibraryMethodOverrideAnalysis.java
index c6a1725..2de5c70 100644
--- a/src/main/java/com/android/tools/r8/shaking/LibraryMethodOverrideAnalysis.java
+++ b/src/main/java/com/android/tools/r8/shaking/LibraryMethodOverrideAnalysis.java
@@ -6,6 +6,7 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
@@ -222,13 +223,13 @@
         }
       }
 
-      DexEncodedMethod singleTarget = invoke.lookupSingleTarget(appView, context);
+      DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, context);
       if (singleTarget == null) {
         return false;
       }
 
       InstanceInitializerInfo initializerInfo =
-          singleTarget.getOptimizationInfo().getInstanceInitializerInfo();
+          singleTarget.getDefinition().getOptimizationInfo().getInstanceInitializerInfo();
       return initializerInfo.receiverNeverEscapesOutsideConstructorChain();
     }
   }