[ApiModel] Set api levels directly on definitions

Tracking at optimization becomes complicated when adding a NOT_SET level
since these should be canonicalized if possible. This CL moves the api
level into the definitions.

Bug: 188388130
Change-Id: Ie367c695bb9200ecc7abb94f245cc9ddec3adb86
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
index 6daff01..2b8a186 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -6,7 +6,6 @@
 import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
 import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull;
 import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getNoKotlinInfo;
-import static com.android.tools.r8.utils.AndroidApiLevelUtils.MIN_API_LEVEL;
 
 import com.android.tools.r8.dex.MixedSectionCollection;
 import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
@@ -17,7 +16,6 @@
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
 import com.android.tools.r8.ir.optimize.info.DefaultFieldOptimizationInfo;
-import com.android.tools.r8.ir.optimize.info.DefaultFieldOptimizationWithMinApiInfo;
 import com.android.tools.r8.ir.optimize.info.FieldOptimizationInfo;
 import com.android.tools.r8.ir.optimize.info.MutableFieldOptimizationInfo;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
@@ -45,7 +43,7 @@
   /** Generic signature information if the attribute is present in the input */
   private FieldTypeSignature genericSignature;
 
-  private FieldOptimizationInfo optimizationInfo;
+  private FieldOptimizationInfo optimizationInfo = DefaultFieldOptimizationInfo.getInstance();
   private KotlinFieldLevelInfo kotlinMemberInfo = getNoKotlinInfo();
 
   private static void specify(StructuralSpecification<DexEncodedField, ?> spec) {
@@ -98,20 +96,11 @@
       boolean deprecated,
       boolean d8R8Synthesized,
       AndroidApiLevel apiLevel) {
-    super(field, annotations, d8R8Synthesized);
+    super(field, annotations, d8R8Synthesized, apiLevel);
     this.accessFlags = accessFlags;
     this.staticValue = staticValue;
     this.deprecated = deprecated;
     this.genericSignature = genericSignature;
-    if (apiLevel == AndroidApiLevel.UNKNOWN) {
-      optimizationInfo = DefaultFieldOptimizationInfo.getInstance();
-    } else if (apiLevel == MIN_API_LEVEL) {
-      optimizationInfo = DefaultFieldOptimizationWithMinApiInfo.getInstance();
-    } else {
-      MutableFieldOptimizationInfo optimizationInfo = new MutableFieldOptimizationInfo();
-      this.optimizationInfo = optimizationInfo;
-      optimizationInfo.setApiReferenceLevelForDefinition(apiLevel);
-    }
     assert genericSignature != null;
     assert GenericSignatureUtils.verifyNoDuplicateGenericDefinitions(genericSignature, annotations);
   }
@@ -148,8 +137,8 @@
   }
 
   @Override
-  public AndroidApiLevel getApiReferenceLevel(AndroidApiLevel minApiLevel) {
-    return optimizationInfo.getApiReferenceLevelForDefinition(minApiLevel);
+  public AndroidApiLevel getApiLevel() {
+    return getApiLevelForDefinition();
   }
 
   public synchronized MutableFieldOptimizationInfo getMutableOptimizationInfo() {
@@ -162,10 +151,6 @@
     optimizationInfo = info;
   }
 
-  public void setMinApiOptimizationInfo(DefaultFieldOptimizationWithMinApiInfo info) {
-    optimizationInfo = info;
-  }
-
   @Override
   public KotlinFieldLevelInfo getKotlinInfo() {
     return kotlinMemberInfo;
@@ -400,6 +385,7 @@
     private FieldAccessFlags accessFlags;
     private FieldTypeSignature genericSignature;
     private DexValue staticValue;
+    private AndroidApiLevel apiLevel;
     private FieldOptimizationInfo optimizationInfo;
     private boolean deprecated;
     private boolean d8R8Synthesized;
@@ -413,6 +399,7 @@
       genericSignature = from.getGenericSignature();
       annotations = from.annotations();
       staticValue = from.staticValue;
+      apiLevel = from.getApiLevel();
       optimizationInfo =
           from.optimizationInfo.isMutableOptimizationInfo()
               ? from.optimizationInfo.asMutableFieldOptimizationInfo().mutableCopy()
@@ -468,7 +455,7 @@
               staticValue,
               deprecated,
               d8R8Synthesized,
-              AndroidApiLevel.UNKNOWN);
+              apiLevel);
       dexEncodedField.optimizationInfo = optimizationInfo;
       buildConsumer.accept(dexEncodedField);
       return dexEncodedField;
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java
index c1ce2f5..da3c5ff 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java
@@ -20,12 +20,20 @@
   // set.
   private final boolean d8R8Synthesized;
 
+  /** apiLevelForDefinition describes the api level needed for knowing all types */
+  private AndroidApiLevel apiLevelForDefinition;
+
   private final R reference;
 
-  public DexEncodedMember(R reference, DexAnnotationSet annotations, boolean d8R8Synthesized) {
+  public DexEncodedMember(
+      R reference,
+      DexAnnotationSet annotations,
+      boolean d8R8Synthesized,
+      AndroidApiLevel apiLevelForDefinition) {
     super(annotations);
     this.reference = reference;
     this.d8R8Synthesized = d8R8Synthesized;
+    this.apiLevelForDefinition = apiLevelForDefinition;
   }
 
   public abstract KotlinMemberLevelInfo getKotlinInfo();
@@ -85,7 +93,15 @@
 
   public abstract MemberOptimizationInfo<?> getOptimizationInfo();
 
-  public abstract AndroidApiLevel getApiReferenceLevel(AndroidApiLevel minApiLevel);
+  public abstract AndroidApiLevel getApiLevel();
+
+  public AndroidApiLevel getApiLevelForDefinition() {
+    return apiLevelForDefinition;
+  }
+
+  public void setApiLevelForDefinition(AndroidApiLevel apiLevelForDefinition) {
+    this.apiLevelForDefinition = apiLevelForDefinition;
+  }
 
   @Override
   public final boolean equals(Object other) {
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 cb44ff9..7b8e309 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -11,7 +11,6 @@
 import static com.android.tools.r8.graph.DexEncodedMethod.CompilationState.PROCESSED_NOT_INLINING_CANDIDATE;
 import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
 import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getNoKotlinInfo;
-import static com.android.tools.r8.utils.AndroidApiLevelUtils.MIN_API_LEVEL;
 import static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer;
 
 import com.android.tools.r8.cf.CfVersion;
@@ -57,7 +56,6 @@
 import com.android.tools.r8.ir.optimize.NestUtils;
 import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
 import com.android.tools.r8.ir.optimize.info.DefaultMethodOptimizationInfo;
-import com.android.tools.r8.ir.optimize.info.DefaultMethodOptimizationWithMinApiInfo;
 import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo;
 import com.android.tools.r8.ir.optimize.info.MutableMethodOptimizationInfo;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
@@ -158,9 +156,12 @@
   // TODO(b/128967328): towards finer-grained inlining constraints,
   //   we need to maintain a set of states with (potentially different) contexts.
   private CompilationState compilationState = CompilationState.NOT_PROCESSED;
-  private MethodOptimizationInfo optimizationInfo = DefaultMethodOptimizationInfo.DEFAULT_INSTANCE;
+  private MethodOptimizationInfo optimizationInfo = DefaultMethodOptimizationInfo.getInstance();
   private CallSiteOptimizationInfo callSiteOptimizationInfo = CallSiteOptimizationInfo.bottom();
   private CfVersion classFileVersion;
+  /** The apiLevelForCode describes the api level needed for knowing all references in the code */
+  private AndroidApiLevel apiLevelForCode;
+
   private KotlinMethodLevelInfo kotlinMemberInfo = getNoKotlinInfo();
   /** Generic signature information if the attribute is present in the input */
   private MethodTypeSignature genericSignature;
@@ -316,28 +317,18 @@
       AndroidApiLevel apiLevelForDefinition,
       AndroidApiLevel apiLevelForCode,
       boolean deprecated) {
-    super(method, annotations, d8R8Synthesized);
+    super(method, annotations, d8R8Synthesized, apiLevelForDefinition);
     this.accessFlags = accessFlags;
     this.deprecated = deprecated;
     this.genericSignature = genericSignature;
     this.parameterAnnotationsList = parameterAnnotationsList;
     this.code = code;
     this.classFileVersion = classFileVersion;
-    if (apiLevelForDefinition == AndroidApiLevel.UNKNOWN
-        && apiLevelForCode == AndroidApiLevel.UNKNOWN) {
-      optimizationInfo = DefaultMethodOptimizationInfo.getInstance();
-    } else if (apiLevelForDefinition == MIN_API_LEVEL && apiLevelForCode == MIN_API_LEVEL) {
-      optimizationInfo = DefaultMethodOptimizationWithMinApiInfo.getInstance();
-    } else {
-      MutableMethodOptimizationInfo optimizationInfo =
-          DefaultMethodOptimizationInfo.getInstance().toMutableOptimizationInfo();
-      optimizationInfo.setApiReferenceLevelForDefinition(apiLevelForDefinition);
-      optimizationInfo.setApiReferenceLevelForCode(apiLevelForCode);
-      this.optimizationInfo = optimizationInfo;
-    }
+    this.apiLevelForCode = apiLevelForCode;
     assert accessFlags != null;
     assert code == null || !shouldNotHaveCode();
     assert parameterAnnotationsList != null;
+    assert apiLevelForCode != null && apiLevelForDefinition != null;
   }
 
   public static DexEncodedMethod toMethodDefinitionOrNull(DexClassAndMethod method) {
@@ -1431,18 +1422,19 @@
     return optimizationInfo;
   }
 
-  public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApiLevel) {
-    return optimizationInfo.getApiReferenceLevelForDefinition(minApiLevel);
+  public AndroidApiLevel getApiLevelForCode() {
+    return apiLevelForCode;
   }
 
-  public AndroidApiLevel getApiReferenceLevelForCode(AndroidApiLevel minApiLevel) {
-    return optimizationInfo.getApiReferenceLevelForCode(minApiLevel);
+  public void setApiLevelForCode(AndroidApiLevel apiLevel) {
+    assert apiLevel != null;
+    this.apiLevelForCode = apiLevel;
   }
 
   @Override
-  public AndroidApiLevel getApiReferenceLevel(AndroidApiLevel minApiLevel) {
-    return getApiReferenceLevelForDefinition(minApiLevel)
-        .max(getApiReferenceLevelForCode(minApiLevel));
+  public AndroidApiLevel getApiLevel() {
+    return (isAbstract() ? AndroidApiLevel.B : getApiLevelForCode())
+        .max(getApiLevelForDefinition());
   }
 
   public synchronized MutableMethodOptimizationInfo getMutableOptimizationInfo() {
@@ -1457,11 +1449,6 @@
     optimizationInfo = info;
   }
 
-  public void setMinApiOptimizationInfo(DefaultMethodOptimizationWithMinApiInfo info) {
-    checkIfObsolete();
-    optimizationInfo = info;
-  }
-
   public synchronized void abandonCallSiteOptimizationInfo() {
     checkIfObsolete();
     callSiteOptimizationInfo = CallSiteOptimizationInfo.abandoned();
@@ -1525,6 +1512,8 @@
     private MethodOptimizationInfo optimizationInfo = DefaultMethodOptimizationInfo.getInstance();
     private KotlinMethodLevelInfo kotlinInfo = getNoKotlinInfo();
     private CfVersion classFileVersion = null;
+    private AndroidApiLevel apiLevelForDefinition = null;
+    private AndroidApiLevel apiLevelForCode = null;
     private boolean d8R8Synthesized = false;
 
     private Consumer<DexEncodedMethod> buildConsumer = ConsumerUtils.emptyConsumer();
@@ -1542,6 +1531,8 @@
       genericSignature = from.getGenericSignature();
       annotations = from.annotations();
       code = from.getCode();
+      apiLevelForDefinition = from.getApiLevelForDefinition();
+      apiLevelForCode = from.getApiLevelForCode();
       optimizationInfo =
           from.getOptimizationInfo().isMutableOptimizationInfo()
               ? from.getOptimizationInfo().asMutableMethodOptimizationInfo().mutableCopy()
@@ -1732,6 +1723,8 @@
       assert parameterAnnotations != null;
       assert parameterAnnotations.isEmpty()
           || parameterAnnotations.size() == method.proto.parameters.size();
+      assert apiLevelForDefinition != null;
+      assert apiLevelForCode != null;
       DexEncodedMethod result =
           new DexEncodedMethod(
               method,
@@ -1742,8 +1735,8 @@
               code,
               d8R8Synthesized,
               classFileVersion,
-              AndroidApiLevel.UNKNOWN,
-              AndroidApiLevel.UNKNOWN);
+              apiLevelForDefinition,
+              apiLevelForCode);
       result.setKotlinMemberInfo(kotlinInfo);
       result.compilationState = compilationState;
       result.optimizationInfo = optimizationInfo;
@@ -1758,5 +1751,15 @@
       this.genericSignature = methodSignature;
       return this;
     }
+
+    public Builder setApiLevelForDefinition(AndroidApiLevel apiLevelForDefinition) {
+      this.apiLevelForDefinition = apiLevelForDefinition;
+      return this;
+    }
+
+    public Builder setApiLevelForCode(AndroidApiLevel apiLevelForCode) {
+      this.apiLevelForCode = apiLevelForCode;
+      return this;
+    }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index 8a3f39a..e297bd4 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -4,7 +4,7 @@
 package com.android.tools.r8.graph;
 
 import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getNoKotlinInfo;
-import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabled;
+import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown;
 import static com.google.common.base.Predicates.alwaysTrue;
 
 import com.android.tools.r8.ProgramResource;
@@ -827,7 +827,7 @@
       AppView<?> appView,
       BiFunction<DexReference, AndroidApiLevel, AndroidApiLevel> apiLevelLookup) {
     // The api level of a class is the max level of it's members, super class and interfaces.
-    AndroidApiLevel computedApiLevel = getApiLevelIfEnabled(appView, Function.identity());
+    AndroidApiLevel computedApiLevel = minApiLevelIfEnabledOrUnknown(appView);
     for (DexType superType : allImmediateSupertypes()) {
       computedApiLevel = apiLevelLookup.apply(superType, computedApiLevel);
       if (computedApiLevel == AndroidApiLevel.UNKNOWN) {
@@ -838,9 +838,9 @@
   }
 
   public AndroidApiLevel getMembersApiReferenceLevel(AppView<?> appView) {
-    AndroidApiLevel memberLevel = getApiLevelIfEnabled(appView, Function.identity());
+    AndroidApiLevel memberLevel = minApiLevelIfEnabledOrUnknown(appView);
     for (DexEncodedMember<?, ?> member : members()) {
-      memberLevel = memberLevel.max(getApiLevelIfEnabled(appView, member::getApiReferenceLevel));
+      memberLevel = memberLevel.max(member.getApiLevel());
       if (memberLevel == AndroidApiLevel.UNKNOWN) {
         return AndroidApiLevel.UNKNOWN;
       }
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
index b4615df..9da5368 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
@@ -6,18 +6,11 @@
 
 import com.android.tools.r8.androidapi.AndroidApiReferenceLevelCache;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMember;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexMember;
+import com.android.tools.r8.graph.DexClassAndMember;
 import com.android.tools.r8.graph.LookupTarget;
 import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramField;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.optimize.info.DefaultFieldOptimizationWithMinApiInfo;
-import com.android.tools.r8.ir.optimize.info.DefaultMethodOptimizationInfo;
-import com.android.tools.r8.ir.optimize.info.DefaultMethodOptimizationWithMinApiInfo;
-import com.android.tools.r8.ir.optimize.info.MemberOptimizationInfo;
-import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo;
 import com.android.tools.r8.shaking.DefaultEnqueuerUseRegistry;
 import com.android.tools.r8.utils.AndroidApiLevel;
 
@@ -35,14 +28,12 @@
 
   @Override
   public void processNewlyLiveField(ProgramField field, ProgramDefinition context) {
-    setApiLevelForMemberDefinition(
-        field.getDefinition(), computeApiLevelForReferencedTypes(field.getReference()));
+    computeApiLevelForDefinition(field);
   }
 
   @Override
   public void processNewlyLiveMethod(ProgramMethod method, ProgramDefinition context) {
-    setApiLevelForMemberDefinition(
-        method.getDefinition(), computeApiLevelForReferencedTypes(method.getReference()));
+    computeApiLevelForDefinition(method);
   }
 
   @Override
@@ -55,71 +46,35 @@
           .tracedMethodApiLevelCallback
           .accept(method.getMethodReference(), registry.getMaxApiReferenceLevel());
     }
-    setApiLevelForMemberDefinition(
-        method.getDefinition(), computeApiLevelForReferencedTypes(method.getReference()));
-    setApiLevelForCode(method.getDefinition(), registry.getMaxApiReferenceLevel());
+    computeApiLevelForDefinition(method);
+    method.getDefinition().setApiLevelForCode(registry.getMaxApiReferenceLevel());
   }
 
   @Override
   public void notifyMarkMethodAsTargeted(ProgramMethod method) {
-    setApiLevelForMemberDefinition(method.getDefinition(), minApiLevel);
+    computeApiLevelForDefinition(method);
   }
 
   @Override
   public void notifyMarkFieldAsReachable(ProgramField field) {
-    setApiLevelForMemberDefinition(field.getDefinition(), minApiLevel);
+    computeApiLevelForDefinition(field);
   }
 
   @Override
   public void notifyMarkVirtualDispatchTargetAsLive(LookupTarget target) {
     target.accept(
-        dexClassAndMethod -> {
-          setApiLevelForMemberDefinition(dexClassAndMethod.getDefinition(), minApiLevel);
-        },
+        this::computeApiLevelForDefinition,
         lookupLambdaTarget -> {
           // The implementation method will be assigned an api level when visited.
         });
   }
 
-  private void setApiLevelForMemberDefinition(
-      DexEncodedMember<?, ?> member, AndroidApiLevel apiLevel) {
-    // To not have mutable update information for all members that all has min api level we
-    // swap the default optimization info for one with that marks the api level to be min api.
-    MemberOptimizationInfo<?> optimizationInfo = member.getOptimizationInfo();
-    if (!optimizationInfo.isMutableOptimizationInfo() && apiLevel == minApiLevel) {
-      member.accept(
-          field -> {
-            field.setMinApiOptimizationInfo(DefaultFieldOptimizationWithMinApiInfo.getInstance());
-          },
-          method -> {
-            method.setMinApiOptimizationInfo(DefaultMethodOptimizationWithMinApiInfo.getInstance());
-          });
-    } else {
-      AndroidApiLevel maxApiLevel =
-          optimizationInfo.hasApiReferenceLevelForDefinition()
-              ? apiLevel.max(optimizationInfo.getApiReferenceLevelForDefinition(minApiLevel))
-              : apiLevel;
-      member.accept(
-          field -> {
-            field.getMutableOptimizationInfo().setApiReferenceLevelForDefinition(maxApiLevel);
-          },
-          method -> {
-            method.getMutableOptimizationInfo().setApiReferenceLevelForDefinition(maxApiLevel);
-          });
-    }
-  }
-
-  private void setApiLevelForCode(DexEncodedMethod method, AndroidApiLevel apiLevel) {
-    MethodOptimizationInfo optimizationInfo = method.getOptimizationInfo();
-    assert optimizationInfo != DefaultMethodOptimizationInfo.getInstance();
-    if (!optimizationInfo.isMutableOptimizationInfo() && apiLevel == minApiLevel) {
-      assert optimizationInfo == DefaultMethodOptimizationWithMinApiInfo.getInstance();
-      return;
-    }
-    method.getMutableOptimizationInfo().setApiReferenceLevelForCode(apiLevel);
-  }
-
-  private AndroidApiLevel computeApiLevelForReferencedTypes(DexMember<?, ?> member) {
-    return member.computeApiLevelForReferencedTypes(appView, referenceLevelCache::lookupMax);
+  private void computeApiLevelForDefinition(DexClassAndMember<?, ?> member) {
+    member
+        .getDefinition()
+        .setApiLevelForDefinition(
+            member
+                .getReference()
+                .computeApiLevelForReferencedTypes(appView, referenceLevelCache::lookupMax));
   }
 }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
index a772278..43a2c8a 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
@@ -4,7 +4,7 @@
 
 package com.android.tools.r8.horizontalclassmerging;
 
-import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember;
+import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown;
 import static com.google.common.base.Predicates.not;
 
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
@@ -45,7 +45,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.function.Function;
 
 /**
  * The class merger is responsible for moving methods from the sources in {@link ClassMerger#group}
@@ -141,8 +140,8 @@
             classInitializerMerger.getCode(syntheticMethodReference),
             DexEncodedMethod.D8_R8_SYNTHESIZED,
             classInitializerMerger.getCfVersion(),
-            getApiLevelIfEnabledForNewMember(appView, ignored -> apiReferenceLevel),
-            getApiLevelIfEnabledForNewMember(appView, ignored -> apiReferenceLevel));
+            apiReferenceLevel,
+            apiReferenceLevel);
     classMethodsBuilder.addDirectMethod(definition);
 
     // In case we didn't synthesize CF code, we register the class initializer for conversion to dex
@@ -230,7 +229,7 @@
             null,
             deprecated,
             d8R8Synthesized,
-            getApiLevelIfEnabledForNewMember(appView, Function.identity()));
+            minApiLevelIfEnabledOrUnknown(appView));
 
     // For the $r8$classId synthesized fields, we try to over-approximate the set of values it may
     // have. For example, for a merge group of size 4, we may compute the set {0, 2, 3}, if the
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
index adc89fc..d6ae971 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
@@ -5,7 +5,6 @@
 package com.android.tools.r8.horizontalclassmerging;
 
 import static com.android.tools.r8.dex.Constants.TEMPORARY_INSTANCE_INITIALIZER_PREFIX;
-import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember;
 
 import com.android.tools.r8.cf.CfVersion;
 import com.android.tools.r8.dex.Constants;
@@ -372,10 +371,8 @@
             getNewCode(newMethodReference, syntheticMethodReference, needsClassId, extraNulls),
             true,
             getNewClassFileVersion(),
-            getApiLevelIfEnabledForNewMember(
-                appView, representativeMethod::getApiReferenceLevelForDefinition),
-            getApiLevelIfEnabledForNewMember(
-                appView, representativeMethod::getApiReferenceLevelForCode));
+            representativeMethod.getApiLevelForDefinition(),
+            representativeMethod.getApiLevelForCode());
     classMethodsBuilder.addDirectMethod(newInstanceInitializer);
 
     if (mode.isFinal()) {
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
index 87a3211..be6a5a2 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
@@ -4,8 +4,6 @@
 
 package com.android.tools.r8.horizontalclassmerging;
 
-import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember;
-
 import com.android.tools.r8.cf.CfVersion;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
@@ -289,10 +287,8 @@
             synthesizedCode,
             true,
             classFileVersion,
-            getApiLevelIfEnabledForNewMember(
-                appView, representativeMethod::getApiReferenceLevelForDefinition),
-            getApiLevelIfEnabledForNewMember(
-                appView, representativeMethod::getApiReferenceLevelForCode));
+            representativeMethod.getApiLevelForDefinition(),
+            representativeMethod.getApiLevelForCode());
     if (!representative.getDefinition().isLibraryMethodOverride().isUnknown()) {
       newMethod.setLibraryMethodOverride(representative.getDefinition().isLibraryMethodOverride());
     }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
index cff4480..3251db1 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
@@ -4,7 +4,7 @@
 
 package com.android.tools.r8.horizontalclassmerging.code;
 
-import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabled;
+import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown;
 import static java.lang.Integer.max;
 
 import com.android.tools.r8.cf.CfVersion;
@@ -104,12 +104,8 @@
     assert !classInitializers.isEmpty();
     return ListUtils.fold(
         classInitializers,
-        appView.options().apiModelingOptions().enableApiCallerIdentification
-            ? appView.options().minApiLevel
-            : AndroidApiLevel.UNKNOWN,
-        (accApiLevel, method) ->
-            accApiLevel.max(
-                getApiLevelIfEnabled(appView, method.getDefinition()::getApiReferenceLevel)));
+        minApiLevelIfEnabledOrUnknown(appView),
+        (accApiLevel, method) -> accApiLevel.max(method.getDefinition().getApiLevel()));
   }
 
   public static class Builder {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
index 88f451b..61e6828 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -5,7 +5,6 @@
 package com.android.tools.r8.ir.desugar;
 
 import static com.android.tools.r8.ir.desugar.lambda.ForcefullyMovedLambdaMethodConsumer.emptyForcefullyMovedLambdaMethodConsumer;
-import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember;
 import static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer;
 
 import com.android.tools.r8.dex.Constants;
@@ -40,11 +39,11 @@
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
 import com.android.tools.r8.synthesis.SyntheticProgramClassBuilder;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.function.Consumer;
-import java.util.function.Function;
 
 /**
  * Represents lambda class generated for a lambda descriptor in context of lambda instantiation
@@ -109,7 +108,7 @@
     this.lambdaField =
         !stateless ? null : factory.createField(type, type, factory.lambdaInstanceFieldName);
 
-    // Synthesize the program class one all fields are set.
+    // Synthesize the program class once all fields are set.
     synthesizeLambdaClass(builder);
   }
 
@@ -244,7 +243,8 @@
               null,
               deprecated,
               d8R8Synthesized,
-              getApiLevelIfEnabledForNewMember(appView, Function.identity())));
+              // The api level is computed when tracing.
+              AndroidApiLevel.minApiLevelIfEnabledOrUnknown(appView)));
     }
     builder.setInstanceFields(fields);
   }
@@ -270,7 +270,8 @@
                   DexValueNull.NULL,
                   deprecated,
                   d8R8Synthesized,
-                  getApiLevelIfEnabledForNewMember(appView, Function.identity()))));
+                  // The api level is computed when tracing.
+                  AndroidApiLevel.minApiLevelIfEnabledOrUnknown(appView))));
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/nest/AccessBridgeFactory.java b/src/main/java/com/android/tools/r8/ir/desugar/nest/AccessBridgeFactory.java
index 9266ad9..8814c2e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/nest/AccessBridgeFactory.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/nest/AccessBridgeFactory.java
@@ -38,6 +38,8 @@
                     .build())
             .setMethod(bridgeMethodReference)
             .setD8R8Synthesized()
+            .setApiLevelForDefinition(field.getDefinition().getApiLevel())
+            .setApiLevelForCode(field.getDefinition().getApiLevel())
             .build());
   }
 
@@ -59,6 +61,8 @@
                     .build())
             .setMethod(bridgeMethodReference)
             .setD8R8Synthesized()
+            .setApiLevelForDefinition(method.getDefinition().getApiLevelForDefinition())
+            .setApiLevelForCode(method.getDefinition().getApiLevelForCode())
             .build());
   }
 
@@ -87,6 +91,8 @@
                         builder -> builder.setDirectTarget(method.getReference(), isInterface))
                     .build())
             .setMethod(bridgeMethodReference)
+            .setApiLevelForDefinition(method.getDefinition().getApiLevelForDefinition())
+            .setApiLevelForCode(method.getDefinition().getApiLevelForDefinition())
             .setD8R8Synthesized()
             .build());
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java
index 7a95765..9614ede 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java
@@ -4,7 +4,7 @@
 
 package com.android.tools.r8.ir.optimize.enums;
 
-import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember;
+import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown;
 
 import com.android.tools.r8.cf.CfVersion;
 import com.android.tools.r8.cf.code.CfArrayStore;
@@ -48,7 +48,6 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
-import java.util.function.Function;
 import org.objectweb.asm.Opcodes;
 
 public class SharedEnumUnboxingUtilityClass extends EnumUnboxingUtilityClass {
@@ -238,7 +237,7 @@
               DexEncodedField.NO_STATIC_VALUE,
               DexEncodedField.NOT_DEPRECATED,
               DexEncodedField.D8_R8_SYNTHESIZED,
-              getApiLevelIfEnabledForNewMember(appView, Function.identity()));
+              minApiLevelIfEnabledOrUnknown(appView));
       fieldAccessInfoCollectionModifierBuilder
           .recordFieldReadInUnknownContext(valuesField.getReference())
           .recordFieldWriteInUnknownContext(valuesField.getReference());
@@ -258,8 +257,8 @@
           createClassInitializerCode(sharedUtilityClassType, valuesField),
           DexEncodedMethod.D8_R8_SYNTHESIZED,
           CfVersion.V1_6,
-          getApiLevelIfEnabledForNewMember(appView, Function.identity()),
-          getApiLevelIfEnabledForNewMember(appView, Function.identity()));
+          minApiLevelIfEnabledOrUnknown(appView),
+          minApiLevelIfEnabledOrUnknown(appView));
     }
 
     private CfCode createClassInitializerCode(
@@ -305,8 +304,8 @@
               createValuesMethodCode(sharedUtilityClassType, valuesField),
               DexEncodedMethod.D8_R8_SYNTHESIZED,
               CfVersion.V1_6,
-              getApiLevelIfEnabledForNewMember(appView, Function.identity()),
-              getApiLevelIfEnabledForNewMember(appView, Function.identity()));
+              minApiLevelIfEnabledOrUnknown(appView),
+              minApiLevelIfEnabledOrUnknown(appView));
       this.valuesMethod = valuesMethod;
       return valuesMethod;
     }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationInfo.java
index 4fd2fcd..c790a02 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationInfo.java
@@ -8,7 +8,6 @@
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.analysis.value.UnknownValue;
-import com.android.tools.r8.utils.AndroidApiLevel;
 
 public class DefaultFieldOptimizationInfo extends FieldOptimizationInfo {
 
@@ -56,11 +55,6 @@
   }
 
   @Override
-  public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi) {
-    throw new RuntimeException("Should never be called");
-  }
-
-  @Override
   public MutableFieldOptimizationInfo toMutableOptimizationInfo() {
     return new MutableFieldOptimizationInfo();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationWithMinApiInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationWithMinApiInfo.java
deleted file mode 100644
index a9c7462..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultFieldOptimizationWithMinApiInfo.java
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.ir.optimize.info;
-
-import com.android.tools.r8.utils.AndroidApiLevel;
-
-public class DefaultFieldOptimizationWithMinApiInfo extends DefaultFieldOptimizationInfo {
-
-  private static final DefaultFieldOptimizationWithMinApiInfo INSTANCE =
-      new DefaultFieldOptimizationWithMinApiInfo();
-
-  public static DefaultFieldOptimizationWithMinApiInfo getInstance() {
-    return INSTANCE;
-  }
-
-  @Override
-  public boolean hasApiReferenceLevelForDefinition() {
-    return true;
-  }
-
-  @Override
-  public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi) {
-    return minApi;
-  }
-
-  @Override
-  public MutableFieldOptimizationInfo toMutableOptimizationInfo() {
-    MutableFieldOptimizationInfo updatableFieldOptimizationInfo = super.toMutableOptimizationInfo();
-    // Use null to specify that the min api is set to minApi.
-    updatableFieldOptimizationInfo.setMinApiReferenceLevel();
-    return updatableFieldOptimizationInfo;
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
index 31ecb9b..24aeb3d 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
@@ -18,7 +18,6 @@
 import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
 import com.android.tools.r8.ir.optimize.info.initializer.DefaultInstanceInitializerInfo;
 import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
-import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.InternalOptions;
 import com.google.common.collect.ImmutableSet;
 import java.util.BitSet;
@@ -196,26 +195,6 @@
   }
 
   @Override
-  public boolean hasApiReferenceLevelForCode() {
-    return false;
-  }
-
-  @Override
-  public AndroidApiLevel getApiReferenceLevelForCode(AndroidApiLevel minApi) {
-    throw new RuntimeException("Should never be called");
-  }
-
-  @Override
-  public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi) {
-    throw new RuntimeException("Should never be called");
-  }
-
-  @Override
-  public boolean hasApiReferenceLevelForDefinition() {
-    return false;
-  }
-
-  @Override
   public MutableMethodOptimizationInfo toMutableOptimizationInfo() {
     return new MutableMethodOptimizationInfo();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationWithMinApiInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationWithMinApiInfo.java
deleted file mode 100644
index cd06dee..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationWithMinApiInfo.java
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.ir.optimize.info;
-
-import com.android.tools.r8.utils.AndroidApiLevel;
-
-public class DefaultMethodOptimizationWithMinApiInfo extends DefaultMethodOptimizationInfo {
-
-  private static final DefaultMethodOptimizationWithMinApiInfo DEFAULT_MIN_API_INSTANCE =
-      new DefaultMethodOptimizationWithMinApiInfo();
-
-  public static DefaultMethodOptimizationWithMinApiInfo getInstance() {
-    return DEFAULT_MIN_API_INSTANCE;
-  }
-
-  @Override
-  public boolean hasApiReferenceLevelForDefinition() {
-    return true;
-  }
-
-  @Override
-  public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi) {
-    return minApi;
-  }
-
-  @Override
-  public boolean hasApiReferenceLevelForCode() {
-    return true;
-  }
-
-  @Override
-  public AndroidApiLevel getApiReferenceLevelForCode(AndroidApiLevel minApi) {
-    return minApi;
-  }
-
-  @Override
-  public MutableMethodOptimizationInfo toMutableOptimizationInfo() {
-    MutableMethodOptimizationInfo updatableMethodOptimizationInfo =
-        super.toMutableOptimizationInfo();
-    // Use null to specify that the min api is set to minApi.
-    updatableMethodOptimizationInfo.setMinApiReferenceLevel();
-    return updatableMethodOptimizationInfo;
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MemberOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MemberOptimizationInfo.java
index 9cb8a2a..f5242e9 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MemberOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MemberOptimizationInfo.java
@@ -4,8 +4,6 @@
 
 package com.android.tools.r8.ir.optimize.info;
 
-import com.android.tools.r8.utils.AndroidApiLevel;
-
 public interface MemberOptimizationInfo<
     T extends MemberOptimizationInfo<T> & MutableOptimizationInfo> {
 
@@ -21,12 +19,6 @@
     return null;
   }
 
-  default boolean hasApiReferenceLevelForDefinition() {
-    return false;
-  }
-
-  AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi);
-
   T toMutableOptimizationInfo();
 
   default boolean isFieldOptimizationInfo() {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
index bb45fbc..aab9aa6 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
@@ -15,7 +15,6 @@
 import com.android.tools.r8.ir.optimize.enums.classification.EnumUnboxerMethodClassification;
 import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
 import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
-import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.InternalOptions;
 import java.util.BitSet;
 import java.util.Set;
@@ -101,10 +100,6 @@
 
   public abstract boolean returnValueHasBeenPropagated();
 
-  public abstract boolean hasApiReferenceLevelForCode();
-
-  public abstract AndroidApiLevel getApiReferenceLevelForCode(AndroidApiLevel minApi);
-
   @Override
   public boolean isMethodOptimizationInfo() {
     return true;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java
index bdab6e8..9150ea0 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java
@@ -15,8 +15,6 @@
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.analysis.value.UnknownValue;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import java.util.Optional;
 import java.util.Set;
 
 /**
@@ -38,7 +36,6 @@
   private int readBits = 0;
   private ClassTypeElement dynamicLowerBoundType = null;
   private TypeElement dynamicUpperBoundType = null;
-  private Optional<AndroidApiLevel> apiReferenceLevel = null;
 
   public MutableFieldOptimizationInfo fixupClassTypeReferences(
       AppView<? extends AppInfoWithClassHierarchy> appView, GraphLens lens) {
@@ -69,7 +66,6 @@
   public MutableFieldOptimizationInfo mutableCopy() {
     MutableFieldOptimizationInfo copy = new MutableFieldOptimizationInfo();
     copy.flags = flags;
-    copy.apiReferenceLevel = apiReferenceLevel;
     return copy;
   }
 
@@ -154,29 +150,4 @@
   public MutableFieldOptimizationInfo asMutableFieldOptimizationInfo() {
     return this;
   }
-
-  @SuppressWarnings("OptionalAssignedToNull")
-  @Override
-  public boolean hasApiReferenceLevelForDefinition() {
-    return apiReferenceLevel != null;
-  }
-
-  @Override
-  public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi) {
-    assert hasApiReferenceLevelForDefinition();
-    return apiReferenceLevel.orElse(minApi);
-  }
-
-  @Override
-  @SuppressWarnings("OptionalAssignedToNull")
-  public void setMinApiReferenceLevel() {
-    assert apiReferenceLevel == null;
-    this.apiReferenceLevel = Optional.empty();
-  }
-
-  @Override
-  public void setApiReferenceLevelForDefinition(AndroidApiLevel apiReferenceLevel) {
-    assert apiReferenceLevel != null;
-    this.apiReferenceLevel = Optional.of(apiReferenceLevel);
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
index 54184d78..3efe7f6 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
@@ -25,11 +25,9 @@
 import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
 import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfoCollection;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.InternalOptions;
 import java.util.BitSet;
-import java.util.Optional;
 import java.util.Set;
 
 public class MutableMethodOptimizationInfo extends MethodOptimizationInfo
@@ -75,9 +73,6 @@
   private SimpleInliningConstraint simpleInliningConstraint =
       NeverSimpleInliningConstraint.getInstance();
 
-  private Optional<AndroidApiLevel> codeApiReferenceLevel = null;
-  private Optional<AndroidApiLevel> definitionApiReferenceLevel = null;
-
   // To reduce the memory footprint of UpdatableMethodOptimizationInfo, all the boolean fields are
   // merged into a flag int field. The various static final FLAG fields indicate which bit is
   // used by each boolean. DEFAULT_FLAGS encodes the default value for efficient instantiation and
@@ -159,8 +154,6 @@
     nonNullParamOnNormalExits = template.nonNullParamOnNormalExits;
     classInlinerConstraint = template.classInlinerConstraint;
     enumUnboxerMethodClassification = template.enumUnboxerMethodClassification;
-    definitionApiReferenceLevel = template.definitionApiReferenceLevel;
-    codeApiReferenceLevel = template.codeApiReferenceLevel;
   }
 
   public MutableMethodOptimizationInfo fixupClassTypeReferences(
@@ -536,50 +529,6 @@
   }
 
   @Override
-  public AndroidApiLevel getApiReferenceLevelForDefinition(AndroidApiLevel minApi) {
-    assert hasApiReferenceLevelForDefinition();
-    return definitionApiReferenceLevel.orElse(minApi);
-  }
-
-  @SuppressWarnings("OptionalAssignedToNull")
-  @Override
-  public boolean hasApiReferenceLevelForDefinition() {
-    return definitionApiReferenceLevel != null;
-  }
-
-  @Override
-  @SuppressWarnings("OptionalAssignedToNull")
-  public boolean hasApiReferenceLevelForCode() {
-    return codeApiReferenceLevel != null;
-  }
-
-  @Override
-  public AndroidApiLevel getApiReferenceLevelForCode(AndroidApiLevel minApi) {
-    assert hasApiReferenceLevelForCode();
-    return codeApiReferenceLevel.orElse(minApi);
-  }
-
-  @Override
-  @SuppressWarnings("OptionalAssignedToNull")
-  public void setMinApiReferenceLevel() {
-    assert codeApiReferenceLevel == null;
-    assert definitionApiReferenceLevel == null;
-    this.codeApiReferenceLevel = Optional.empty();
-    this.definitionApiReferenceLevel = Optional.empty();
-  }
-
-  public void setApiReferenceLevelForCode(AndroidApiLevel apiLevel) {
-    assert apiLevel != null;
-    this.codeApiReferenceLevel = Optional.of(apiLevel);
-  }
-
-  @Override
-  public void setApiReferenceLevelForDefinition(AndroidApiLevel apiLevel) {
-    assert apiLevel != null;
-    this.definitionApiReferenceLevel = Optional.of(apiLevel);
-  }
-
-  @Override
   public boolean isMutableOptimizationInfo() {
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableOptimizationInfo.java
index 421f689..58f5470 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableOptimizationInfo.java
@@ -4,11 +4,6 @@
 
 package com.android.tools.r8.ir.optimize.info;
 
-import com.android.tools.r8.utils.AndroidApiLevel;
-
 public interface MutableOptimizationInfo {
 
-  void setMinApiReferenceLevel();
-
-  void setApiReferenceLevelForDefinition(AndroidApiLevel apiLevel);
 }
diff --git a/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java b/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java
index 3d76d73..bfc3ae7 100644
--- a/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java
@@ -5,7 +5,7 @@
 package com.android.tools.r8.shaking;
 
 import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
-import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember;
+import static com.android.tools.r8.utils.AndroidApiLevel.minApiLevelIfEnabledOrUnknown;
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.errors.Unreachable;
@@ -22,7 +22,6 @@
 import com.android.tools.r8.utils.Visibility;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
-import java.util.function.Function;
 
 public class ClassInitFieldSynthesizer {
 
@@ -93,7 +92,7 @@
               null,
               deprecated,
               DexEncodedField.D8_R8_SYNTHESIZED,
-              getApiLevelIfEnabledForNewMember(appView, Function.identity()));
+              minApiLevelIfEnabledOrUnknown(appView));
       clazz.appendStaticField(encodedClinitField);
     }
     lensBuilder.map(type, encodedClinitField.getReference());
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 0a49379..27d25bb 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -7,7 +7,6 @@
 import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
 import static com.android.tools.r8.ir.code.Invoke.Type.DIRECT;
 import static com.android.tools.r8.ir.code.Invoke.Type.STATIC;
-import static com.android.tools.r8.utils.AndroidApiLevelUtils.getApiLevelIfEnabledForNewMember;
 
 import com.android.tools.r8.androidapi.AndroidApiReferenceLevelCache;
 import com.android.tools.r8.errors.Unreachable;
@@ -1451,8 +1450,8 @@
               code,
               true,
               method.hasClassFileVersion() ? method.getClassFileVersion() : null,
-              getApiLevelIfEnabledForNewMember(appView, method::getApiReferenceLevelForDefinition),
-              getApiLevelIfEnabledForNewMember(appView, Function.identity()));
+              method.getApiLevelForDefinition(),
+              method.getApiLevelForDefinition());
       bridge.setLibraryMethodOverride(method.isLibraryMethodOverride());
       if (method.accessFlags.isPromotedToPublic()) {
         // The bridge is now the public method serving the role of the original method, and should
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
index 1e4082b..e127d6c 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.utils;
 
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.utils.structural.Ordered;
 import java.util.Arrays;
 import java.util.List;
@@ -75,6 +76,12 @@
     return DexVersion.getDexVersion(this);
   }
 
+  public static AndroidApiLevel minApiLevelIfEnabledOrUnknown(AppView<?> appView) {
+    return appView.options().apiModelingOptions().enableApiCallerIdentification
+        ? appView.options().minApiLevel
+        : UNKNOWN;
+  }
+
   public static List<AndroidApiLevel> getAndroidApiLevelsSorted() {
     return Arrays.asList(AndroidApiLevel.values());
   }
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java b/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
index 9272066..96c4a2b 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
@@ -4,32 +4,10 @@
 
 package com.android.tools.r8.utils;
 
-import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ProgramMethod;
-import java.util.function.Function;
 
 public class AndroidApiLevelUtils {
 
-  // Static api-level indicating that the api level is min-api.
-  public static final AndroidApiLevel MIN_API_LEVEL = null;
-
-  public static AndroidApiLevel getApiLevelIfEnabledForNewMember(
-      AppView<?> appView, Function<AndroidApiLevel, AndroidApiLevel> getter) {
-    AndroidApiLevel apiLevelIfEnabled = getApiLevelIfEnabled(appView, getter);
-    if (apiLevelIfEnabled == appView.options().minApiLevel) {
-      return MIN_API_LEVEL;
-    }
-    return apiLevelIfEnabled;
-  }
-
-  public static AndroidApiLevel getApiLevelIfEnabled(
-      AppView<?> appView, Function<AndroidApiLevel, AndroidApiLevel> getter) {
-    if (!appView.options().apiModelingOptions().enableApiCallerIdentification) {
-      return AndroidApiLevel.UNKNOWN;
-    }
-    return getter.apply(appView.options().minApiLevel);
-  }
-
   public static OptionalBool isApiSafeForInlining(
       ProgramMethod caller, ProgramMethod inlinee, InternalOptions options) {
     if (!options.apiModelingOptions().enableApiCallerIdentification) {
@@ -41,8 +19,7 @@
     return OptionalBool.of(
         caller
             .getDefinition()
-            .getApiReferenceLevel(options.minApiLevel)
-            .isGreaterThanOrEqualTo(
-                inlinee.getDefinition().getApiReferenceLevelForCode(options.minApiLevel)));
+            .getApiLevel()
+            .isGreaterThanOrEqualTo(inlinee.getDefinition().getApiLevelForCode()));
   }
 }