Merge "Towards using AppView globally"
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index a47351c..af3c140 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -436,7 +436,6 @@
                   application,
                   appViewWithLiveness,
                   executorService,
-                  options,
                   timing,
                   mainDexClasses);
           appView.setGraphLense(verticalClassMerger.run());
diff --git a/src/main/java/com/android/tools/r8/cf/CfRegisterAllocator.java b/src/main/java/com/android/tools/r8/cf/CfRegisterAllocator.java
index 9effd30..5f198c0 100644
--- a/src/main/java/com/android/tools/r8/cf/CfRegisterAllocator.java
+++ b/src/main/java/com/android/tools/r8/cf/CfRegisterAllocator.java
@@ -7,6 +7,8 @@
 
 import com.android.tools.r8.cf.TypeVerificationHelper.TypeInfo;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.DebugLocalWrite;
 import com.android.tools.r8.ir.code.Dup;
@@ -56,8 +58,8 @@
  */
 public class CfRegisterAllocator implements RegisterAllocator {
 
+  private final AppView<? extends AppInfo> appView;
   private final IRCode code;
-  private final InternalOptions options;
   private final TypeVerificationHelper typeHelper;
 
   // Mapping from basic blocks to the set of values live at entry to that basic block.
@@ -112,9 +114,9 @@
   private int maxArgumentRegisterNumber = -1;
 
   public CfRegisterAllocator(
-      IRCode code, InternalOptions options, TypeVerificationHelper typeHelper) {
+      AppView<? extends AppInfo> appView, IRCode code, TypeVerificationHelper typeHelper) {
+    this.appView = appView;
     this.code = code;
-    this.options = options;
     this.typeHelper = typeHelper;
   }
 
@@ -143,7 +145,7 @@
 
   @Override
   public InternalOptions getOptions() {
-    return options;
+    return appView.options();
   }
 
   @Override
@@ -155,7 +157,7 @@
     // register allocation. We just treat the method as being in debug mode in order to keep
     // locals alive for their entire live range. In release mode the liveness is all that matters
     // and we do not actually want locals information in the output.
-    if (options.debug) {
+    if (appView.options().debug) {
       LinearScanRegisterAllocator.computeDebugInfo(blocks, liveIntervals, this, liveAtEntrySets);
     }
   }
@@ -176,7 +178,8 @@
   private ImmutableList<BasicBlock> computeLivenessInformation() {
     ImmutableList<BasicBlock> blocks = code.numberInstructions();
     liveAtEntrySets = code.computeLiveAtEntrySets();
-    LinearScanRegisterAllocator.computeLiveRanges(options, code, liveAtEntrySets, liveIntervals);
+    LinearScanRegisterAllocator.computeLiveRanges(
+        appView.options(), code, liveAtEntrySets, liveIntervals);
     return blocks;
   }
 
diff --git a/src/main/java/com/android/tools/r8/cf/LoadStoreHelper.java b/src/main/java/com/android/tools/r8/cf/LoadStoreHelper.java
index c5cb84e..9a73ab1 100644
--- a/src/main/java/com/android/tools/r8/cf/LoadStoreHelper.java
+++ b/src/main/java/com/android/tools/r8/cf/LoadStoreHelper.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.BasicBlock.ThrowingInfo;
@@ -31,17 +32,18 @@
 
 public class LoadStoreHelper {
 
+  private final AppView<? extends AppInfo> appView;
   private final IRCode code;
   private final TypeVerificationHelper typesHelper;
-  private final AppInfo appInfo;
 
   private Map<Value, ConstInstruction> clonableConstants = null;
   private ListIterator<BasicBlock> blockIterator = null;
 
-  public LoadStoreHelper(IRCode code, TypeVerificationHelper typesHelper, AppInfo appInfo) {
+  public LoadStoreHelper(
+      AppView<? extends AppInfo> appView, IRCode code, TypeVerificationHelper typesHelper) {
+    this.appView = appView;
     this.code = code;
     this.typesHelper = typesHelper;
-    this.appInfo = appInfo;
   }
 
   private static boolean hasLocalInfoOrUsersOutsideThisBlock(Value value, BasicBlock block) {
@@ -140,11 +142,11 @@
   }
 
   private StackValue createStackValue(Value value, int height) {
-    return StackValue.create(typesHelper.getTypeInfo(value), height, appInfo);
+    return StackValue.create(typesHelper.getTypeInfo(value), height, appView);
   }
 
   private StackValue createStackValue(DexType type, int height) {
-    return StackValue.create(typesHelper.createInitializedType(type), height, appInfo);
+    return StackValue.create(typesHelper.createInitializedType(type), height, appView);
   }
 
   public void loadInValues(Instruction instruction, InstructionListIterator it) {
diff --git a/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java b/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java
index 2349a3b..4bf9e04 100644
--- a/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java
+++ b/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java
@@ -6,6 +6,7 @@
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.type.Nullability;
@@ -103,9 +104,8 @@
   private final TypeInfo LONG;
   private final TypeInfo DOUBLE;
 
+  private final AppView<? extends AppInfo> appView;
   private final IRCode code;
-  private final DexItemFactory factory;
-  private final AppInfo appInfo;
 
   private Map<Value, TypeInfo> types;
   private Map<NewInstance, NewInstanceInfo> newInstanceInfos = new IdentityHashMap<>();
@@ -113,18 +113,15 @@
   // Flag to indicate that we are computing types in the fixed point.
   private boolean computingVerificationTypes = false;
 
-  public TypeVerificationHelper(IRCode code, DexItemFactory factory, AppInfo appInfo) {
+  public TypeVerificationHelper(AppView<? extends AppInfo> appView, IRCode code) {
+    this.appView = appView;
     this.code = code;
-    this.factory = factory;
-    this.appInfo = appInfo;
-    INT = new InitializedTypeInfo(factory.intType);
-    FLOAT = new InitializedTypeInfo(factory.floatType);
-    LONG = new InitializedTypeInfo(factory.longType);
-    DOUBLE = new InitializedTypeInfo(factory.doubleType);
-  }
 
-  public DexItemFactory getFactory() {
-    return factory;
+    DexItemFactory dexItemFactory = appView.dexItemFactory();
+    INT = new InitializedTypeInfo(dexItemFactory.intType);
+    FLOAT = new InitializedTypeInfo(dexItemFactory.floatType);
+    LONG = new InitializedTypeInfo(dexItemFactory.longType);
+    DOUBLE = new InitializedTypeInfo(dexItemFactory.doubleType);
   }
 
   public TypeInfo createInitializedType(DexType type) {
@@ -188,13 +185,13 @@
     Iterator<DexType> iterator = types.iterator();
     TypeLatticeElement result = getLatticeElement(iterator.next());
     while (iterator.hasNext()) {
-      result = result.join(getLatticeElement(iterator.next()), appInfo);
+      result = result.join(getLatticeElement(iterator.next()), appView.appInfo());
     }
     // All types are reference types so the join is either a class or an array.
     if (result.isClassType()) {
       return result.asClassTypeLatticeElement().getClassType();
     } else if (result.isArrayType()) {
-      return result.asArrayTypeLatticeElement().getArrayType(factory);
+      return result.asArrayTypeLatticeElement().getArrayType(appView.dexItemFactory());
     }
     throw new CompilationError("Unexpected join " + result + " of types: " +
         String.join(", ",
@@ -220,7 +217,7 @@
   }
 
   private TypeLatticeElement getLatticeElement(DexType type) {
-    return TypeLatticeElement.fromDexType(type, Nullability.maybeNull(), appInfo);
+    return TypeLatticeElement.fromDexType(type, Nullability.maybeNull(), appView.appInfo());
   }
 
   public Map<Value, TypeInfo> computeVerificationTypes() {
@@ -273,7 +270,7 @@
                   nullsUsedInPhis.add(instruction.asConstNumber());
                 }
               }
-              DexType type = instruction.computeVerificationType(this);
+              DexType type = instruction.computeVerificationType(appView, this);
               types.put(outValue, createInitializedType(type));
               addUsers(outValue, worklist);
             }
@@ -316,7 +313,7 @@
   private DexType computeVerificationType(Value value) {
     return value.isPhi()
         ? value.asPhi().computeVerificationType(this)
-        : value.definition.computeVerificationType(this);
+        : value.definition.computeVerificationType(appView, this);
   }
 
   private static void addUsers(Value value, Set<Value> worklist) {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
index ec38ea9..0674bf2 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
@@ -33,6 +33,7 @@
   public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
     Slot array = state.pop();
     assert array.type.isObject();
-    builder.addArrayLength(state.push(builder.getFactory().intType).register, array.register);
+    builder.addArrayLength(
+        state.push(builder.appView.dexItemFactory().intType).register, array.register);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
index 9f38741..e77a59e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
@@ -75,7 +75,7 @@
     assert array.type.isObject();
     ValueType memberType = ValueType.fromMemberType(type);
     if (array.preciseType != null) {
-      value = state.push(array.preciseType.toArrayElementType(builder.getFactory()));
+      value = state.push(array.preciseType.toArrayElementType(builder.appView.dexItemFactory()));
       assert state.peek().type == memberType;
     } else {
       value = state.push(memberType);
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
index 4da0b5c..6719e3f 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
@@ -74,6 +74,6 @@
 
   @Override
   public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
-    builder.addConstClass(state.push(builder.getFactory().classType).register, type);
+    builder.addConstClass(state.push(builder.appView.dexItemFactory().classType).register, type);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
index c36bd57..7f23c58 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
@@ -50,6 +50,6 @@
   @Override
   public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
     builder.addConstMethodHandle(
-        state.push(builder.getFactory().methodHandleType).register, handle);
+        state.push(builder.appView.dexItemFactory().methodHandleType).register, handle);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
index ebbaf21..1d12726 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
@@ -49,6 +49,7 @@
 
   @Override
   public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
-    builder.addConstMethodType(state.push(builder.getFactory().methodTypeType).register, type);
+    builder.addConstMethodType(
+        state.push(builder.appView.dexItemFactory().methodTypeType).register, type);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
index 0467fcd..30a3aaf 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
@@ -55,6 +55,7 @@
 
   @Override
   public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
-    builder.addConstString(state.push(builder.getFactory().stringType).register, string);
+    builder.addConstString(
+        state.push(builder.appView.dexItemFactory().stringType).register, string);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
index 8ba58b7..9c0fee6 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
@@ -70,6 +70,7 @@
 
   @Override
   public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
-    builder.addDexItemBasedConstString(state.push(builder.getFactory().stringType).register, item);
+    builder.addDexItemBasedConstString(
+        state.push(builder.appView.dexItemFactory().stringType).register, item);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
index 6a093df..cbfc0fb 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
@@ -48,6 +48,7 @@
   @Override
   public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
     int value = state.pop().register;
-    builder.addInstanceOf(state.push(builder.getFactory().booleanType).register, value, type);
+    builder.addInstanceOf(
+        state.push(builder.appView.dexItemFactory().booleanType).register, value, type);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
index a84b916..c8749fe 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
@@ -113,7 +113,8 @@
         }
       case Opcodes.INVOKEVIRTUAL:
         {
-          canonicalMethod = builder.getFactory().polymorphicMethods.canonicalize(method);
+          canonicalMethod =
+              builder.appView.dexItemFactory().polymorphicMethods.canonicalize(method);
           if (canonicalMethod == null) {
             type = Type.VIRTUAL;
             canonicalMethod = method;
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
index 0eed4a6..e2f7336 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
@@ -11,6 +11,7 @@
 import com.android.tools.r8.ir.conversion.CfState;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.utils.InternalOptions;
 import org.objectweb.asm.MethodVisitor;
 
 public class CfMultiANewArray extends CfInstruction {
@@ -53,7 +54,8 @@
 
   @Override
   public void buildIR(IRBuilder builder, CfState state, CfSourceCode code) {
-    if (!builder.isGeneratingClassFiles()) {
+    InternalOptions options = builder.appView.options();
+    if (options.isGeneratingDex()) {
       // TODO(b/109789539): Implement this case (see JarSourceCode.buildPrelude()/buildPostlude()).
       throw new Unimplemented("CfMultiANewArray to DEX backend");
     }
diff --git a/src/main/java/com/android/tools/r8/dex/ResourceAdapter.java b/src/main/java/com/android/tools/r8/dex/ResourceAdapter.java
index 630f25d..000e8e6 100644
--- a/src/main/java/com/android/tools/r8/dex/ResourceAdapter.java
+++ b/src/main/java/com/android/tools/r8/dex/ResourceAdapter.java
@@ -97,7 +97,7 @@
 
   // Returns true for files in META-INF/services/ that are never used by the application.
   public boolean shouldBeDeleted(DataEntryResource file) {
-    if (appView != null && appView.appInfo().hasLiveness()) {
+    if (appView.appInfo().hasLiveness()) {
       AppInfoWithLiveness appInfo = appView.appInfo().withLiveness();
       if (file.getName().startsWith(AppServices.SERVICE_DIRECTORY_NAME)) {
         String serviceName = file.getName().substring(AppServices.SERVICE_DIRECTORY_NAME.length());
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index 8690894..eee4acd 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -10,36 +10,34 @@
 
 public class AppView<T extends AppInfo> implements DexDefinitionSupplier {
 
+  private enum WholeProgramOptimizations {
+    ON,
+    OFF
+  }
+
   private T appInfo;
   private AppServices appServices;
   private final DexItemFactory dexItemFactory;
-  private final boolean enableWholeProgramOptimizations;
+  private final WholeProgramOptimizations wholeProgramOptimizations;
   private GraphLense graphLense;
   private final InternalOptions options;
   private VerticallyMergedClasses verticallyMergedClasses;
 
   private AppView(
-      T appInfo,
-      boolean enableWholeProgramOptimizations,
-      GraphLense graphLense,
-      InternalOptions options) {
+      T appInfo, WholeProgramOptimizations wholeProgramOptimizations, InternalOptions options) {
     this.appInfo = appInfo;
     this.dexItemFactory = appInfo != null ? appInfo.dexItemFactory : null;
-    this.enableWholeProgramOptimizations = enableWholeProgramOptimizations;
-    this.graphLense = graphLense;
+    this.wholeProgramOptimizations = wholeProgramOptimizations;
+    this.graphLense = GraphLense.getIdentityLense();
     this.options = options;
   }
 
   public static <T extends AppInfo> AppView<T> createForD8(T appInfo, InternalOptions options) {
-    boolean enableWholeProgramOptimizations = false;
-    return new AppView<>(
-        appInfo, enableWholeProgramOptimizations, GraphLense.getIdentityLense(), options);
+    return new AppView<>(appInfo, WholeProgramOptimizations.OFF, options);
   }
 
   public static <T extends AppInfo> AppView<T> createForR8(T appInfo, InternalOptions options) {
-    boolean enableWholeProgramOptimizations = true;
-    return new AppView<>(
-        appInfo, enableWholeProgramOptimizations, GraphLense.getIdentityLense(), options);
+    return new AppView<>(appInfo, WholeProgramOptimizations.ON, options);
   }
 
   public T appInfo() {
@@ -84,7 +82,7 @@
   }
 
   public boolean enableWholeProgramOptimizations() {
-    return enableWholeProgramOptimizations;
+    return wholeProgramOptimizations == WholeProgramOptimizations.ON;
   }
 
   public GraphLense graphLense() {
@@ -116,7 +114,7 @@
   private class AppViewWithLiveness extends AppView<AppInfoWithLiveness> {
 
     private AppViewWithLiveness() {
-      super(null, false, null, null);
+      super(null, null, null);
     }
 
     @Override
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java
index 6abc3fd..344f79f 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -215,23 +215,16 @@
 
   @Override
   public IRCode buildIR(
-      DexEncodedMethod encodedMethod,
-      AppInfo appInfo,
-      GraphLense graphLense,
-      InternalOptions options,
-      Origin origin) {
+      DexEncodedMethod encodedMethod, AppView<? extends AppInfo> appView, Origin origin) {
     assert getOwner() == encodedMethod;
-    return internalBuild(
-        encodedMethod, encodedMethod, appInfo, graphLense, options, null, null, origin);
+    return internalBuild(encodedMethod, encodedMethod, appView, null, null, origin);
   }
 
   @Override
   public IRCode buildInliningIR(
       DexEncodedMethod context,
       DexEncodedMethod encodedMethod,
-      AppInfo appInfo,
-      GraphLense graphLense,
-      InternalOptions options,
+      AppView<? extends AppInfo> appView,
       ValueNumberGenerator valueNumberGenerator,
       Position callerPosition,
       Origin origin) {
@@ -239,27 +232,18 @@
     assert valueNumberGenerator != null;
     assert callerPosition != null;
     return internalBuild(
-        context,
-        encodedMethod,
-        appInfo,
-        graphLense,
-        options,
-        valueNumberGenerator,
-        callerPosition,
-        origin);
+        context, encodedMethod, appView, valueNumberGenerator, callerPosition, origin);
   }
 
   private IRCode internalBuild(
       DexEncodedMethod context,
       DexEncodedMethod encodedMethod,
-      AppInfo appInfo,
-      GraphLense graphLense,
-      InternalOptions options,
+      AppView<? extends AppInfo> appView,
       ValueNumberGenerator generator,
       Position callerPosition,
       Origin origin) {
     // TODO(b/109789541): Implement CF->IR->DEX for synchronized methods.
-    if (options.isGeneratingDex() && encodedMethod.accessFlags.isSynchronized()) {
+    if (appView.options().isGeneratingDex() && encodedMethod.accessFlags.isSynchronized()) {
       throw new Unimplemented(
           "Converting CfCode to IR not supported for DEX output of synchronized methods.");
     }
@@ -267,12 +251,11 @@
         new CfSourceCode(
             this,
             encodedMethod,
-            graphLense.getOriginalMethodSignature(encodedMethod.method),
+            appView.graphLense().getOriginalMethodSignature(encodedMethod.method),
             callerPosition,
             origin,
-            options.getInternalOutputMode());
-    return new IRBuilder(encodedMethod, appInfo, source, options, origin, generator, graphLense)
-        .build(context);
+            appView.options().getInternalOutputMode());
+    return new IRBuilder(encodedMethod, appView, source, origin, generator).build(context);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/graph/Code.java b/src/main/java/com/android/tools/r8/graph/Code.java
index 4962fac..728ec2e 100644
--- a/src/main/java/com/android/tools/r8/graph/Code.java
+++ b/src/main/java/com/android/tools/r8/graph/Code.java
@@ -12,7 +12,6 @@
 import com.android.tools.r8.ir.optimize.Outliner.OutlineCode;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.utils.InternalOptions;
 
 public abstract class Code extends CachedHashValueDexItem {
 
@@ -29,18 +28,12 @@
   }
 
   public abstract IRCode buildIR(
-      DexEncodedMethod encodedMethod,
-      AppInfo appInfo,
-      GraphLense graphLense,
-      InternalOptions options,
-      Origin origin);
+      DexEncodedMethod encodedMethod, AppView<? extends AppInfo> appView, Origin origin);
 
   public IRCode buildInliningIR(
       DexEncodedMethod context,
       DexEncodedMethod encodedMethod,
-      AppInfo appInfo,
-      GraphLense graphLense,
-      InternalOptions options,
+      AppView<? extends AppInfo> appView,
       ValueNumberGenerator valueNumberGenerator,
       Position callerPosition,
       Origin origin) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index f5935d4..f303c74 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -542,12 +542,12 @@
     return null;
   }
 
-  public boolean hasMissingSuperType(AppInfo appInfo) {
-    if (superType != null && superType.isMissingOrHasMissingSuperType(appInfo)) {
+  public boolean hasMissingSuperType(DexDefinitionSupplier definitions) {
+    if (superType != null && superType.isMissingOrHasMissingSuperType(definitions)) {
       return true;
     }
     for (DexType interfaceType : interfaces.values) {
-      if (interfaceType.isMissingOrHasMissingSuperType(appInfo)) {
+      if (interfaceType.isMissingOrHasMissingSuperType(definitions)) {
         return true;
       }
     }
diff --git a/src/main/java/com/android/tools/r8/graph/DexCode.java b/src/main/java/com/android/tools/r8/graph/DexCode.java
index cea5e4d..c3b240a 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -18,7 +18,6 @@
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.StringUtils;
 import com.google.common.base.Strings;
 import it.unimi.dsi.fastutil.ints.Int2IntMap;
@@ -215,28 +214,16 @@
 
   @Override
   public IRCode buildIR(
-      DexEncodedMethod encodedMethod,
-      AppInfo appInfo,
-      GraphLense graphLense,
-      InternalOptions options,
-      Origin origin) {
+      DexEncodedMethod encodedMethod, AppView<? extends AppInfo> appView, Origin origin) {
     assert getOwner() == encodedMethod;
     DexSourceCode source =
         new DexSourceCode(
             this,
             encodedMethod,
-            graphLense.getOriginalMethodSignature(encodedMethod.method),
-            null,
-            appInfo);
+            appView.graphLense().getOriginalMethodSignature(encodedMethod.method),
+            null);
     IRBuilder builder =
-        new IRBuilder(
-            encodedMethod,
-            appInfo,
-            source,
-            options,
-            origin,
-            new ValueNumberGenerator(),
-            graphLense);
+        new IRBuilder(encodedMethod, appView, source, origin, new ValueNumberGenerator());
     return builder.build(encodedMethod);
   }
 
@@ -244,9 +231,7 @@
   public IRCode buildInliningIR(
       DexEncodedMethod context,
       DexEncodedMethod encodedMethod,
-      AppInfo appInfo,
-      GraphLense graphLense,
-      InternalOptions options,
+      AppView<? extends AppInfo> appView,
       ValueNumberGenerator valueNumberGenerator,
       Position callerPosition,
       Origin origin) {
@@ -255,12 +240,9 @@
         new DexSourceCode(
             this,
             encodedMethod,
-            graphLense.getOriginalMethodSignature(encodedMethod.method),
-            callerPosition,
-            appInfo);
-    IRBuilder builder =
-        new IRBuilder(
-            encodedMethod, appInfo, source, options, origin, valueNumberGenerator, graphLense);
+            appView.graphLense().getOriginalMethodSignature(encodedMethod.method),
+            callerPosition);
+    IRBuilder builder = new IRBuilder(encodedMethod, appView, source, origin, valueNumberGenerator);
     return builder.build(context);
   }
 
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 46719ca..9fa16f1 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -317,36 +317,20 @@
     compilationState = CompilationState.NOT_PROCESSED;
   }
 
-  public IRCode buildIR(
-      AppInfo appInfo, GraphLense graphLense, InternalOptions options, Origin origin) {
+  public IRCode buildIR(AppView<? extends AppInfo> appView, Origin origin) {
     checkIfObsolete();
-    return code == null ? null : code.buildIR(this, appInfo, graphLense, options, origin);
-  }
-
-  public IRCode buildInliningIRForTesting(
-      InternalOptions options, ValueNumberGenerator valueNumberGenerator, AppInfo appInfo) {
-    checkIfObsolete();
-    return buildInliningIR(
-        this,
-        appInfo,
-        GraphLense.getIdentityLense(),
-        options,
-        valueNumberGenerator,
-        null,
-        Origin.unknown());
+    return code == null ? null : code.buildIR(this, appView, origin);
   }
 
   public IRCode buildInliningIR(
       DexEncodedMethod context,
-      AppInfo appInfo,
-      GraphLense graphLense,
-      InternalOptions options,
+      AppView<? extends AppInfo> appView,
       ValueNumberGenerator valueNumberGenerator,
       Position callerPosition,
       Origin origin) {
     checkIfObsolete();
     return code.buildInliningIR(
-        context, this, appInfo, graphLense, options, valueNumberGenerator, callerPosition, origin);
+        context, this, appView, valueNumberGenerator, callerPosition, origin);
   }
 
   public void setCode(Code code) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index 035b472..5ef8072 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -1065,7 +1065,7 @@
   }
 
   public ReferenceTypeLatticeElement createReferenceTypeLatticeElement(
-      DexType type, Nullability nullability, AppInfo appInfo) {
+      DexType type, Nullability nullability, DexDefinitionSupplier definitions) {
     ReferenceTypeLatticeElement primary = referenceTypeLatticeElements.get(type);
     if (primary != null) {
       return nullability == primary.nullability()
@@ -1083,13 +1083,13 @@
             // It is expensive to walk through type hierarchy; collect implemented interfaces; and
             // compute the least upper bound of two interface sets. Hence, lazy computations.
             // Most likely during lattice join. See {@link ClassTypeLatticeElement#getInterfaces}.
-            primary = new ClassTypeLatticeElement(type, maybeNull(), appInfo);
+            primary = new ClassTypeLatticeElement(type, maybeNull(), definitions);
           }
         } else {
           assert type.isArrayType();
           DexType elementType = type.toArrayElementType(this);
           TypeLatticeElement elementTypeLattice =
-              TypeLatticeElement.fromDexType(elementType, maybeNull(), appInfo, true);
+              TypeLatticeElement.fromDexType(elementType, maybeNull(), definitions, true);
           primary = new ArrayTypeLatticeElement(elementTypeLattice, maybeNull());
         }
         referenceTypeLatticeElements.put(type, primary);
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index 4f90719..efd4a2b 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -105,9 +105,9 @@
     setLevel(INTERFACE_LEVEL);
   }
 
-  public boolean isMissingOrHasMissingSuperType(AppInfo appInfo) {
-    DexClass clazz = appInfo.definitionFor(this);
-    return clazz == null || clazz.hasMissingSuperType(appInfo);
+  public boolean isMissingOrHasMissingSuperType(DexDefinitionSupplier definitions) {
+    DexClass clazz = definitions.definitionFor(this);
+    return clazz == null || clazz.hasMissingSuperType(definitions);
   }
 
   public boolean isInterface() {
@@ -286,37 +286,38 @@
 
   /**
    * Collect all interfaces that this type directly or indirectly implements.
-   * @param appInfo where the definition of a certain {@link DexType} is looked up.
+   *
+   * @param definitions where the definition of a certain {@link DexType} is looked up.
    * @return a set of interfaces of {@link DexType}.
    */
-  public Set<DexType> implementedInterfaces(AppInfo appInfo) {
+  public Set<DexType> implementedInterfaces(DexDefinitionSupplier definitions) {
     if (implementedInterfaces != null) {
       return implementedInterfaces;
     }
     synchronized (this) {
       if (implementedInterfaces == null) {
         Set<DexType> interfaces = Sets.newIdentityHashSet();
-        implementedInterfaces(appInfo, interfaces);
+        implementedInterfaces(definitions, interfaces);
         implementedInterfaces = interfaces;
       }
     }
     return implementedInterfaces;
   }
 
-  private void implementedInterfaces(AppInfo appInfo, Set<DexType> interfaces) {
-    DexClass dexClass = appInfo.definitionFor(this);
+  private void implementedInterfaces(DexDefinitionSupplier definitions, Set<DexType> interfaces) {
+    DexClass dexClass = definitions.definitionFor(this);
     // Loop to traverse the super type hierarchy of the current type.
     while (dexClass != null) {
       if (dexClass.isInterface()) {
         interfaces.add(dexClass.type);
       }
       for (DexType itf : dexClass.interfaces.values) {
-        itf.implementedInterfaces(appInfo, interfaces);
+        itf.implementedInterfaces(definitions, interfaces);
       }
       if (dexClass.superType == null) {
         break;
       }
-      dexClass = appInfo.definitionFor(dexClass.superType);
+      dexClass = definitions.definitionFor(dexClass.superType);
     }
   }
 
@@ -623,11 +624,11 @@
     return type.directSubtypes.contains(this);
   }
 
-  public DexType computeLeastUpperBoundOfClasses(AppInfo appInfo, DexType other) {
+  public DexType computeLeastUpperBoundOfClasses(DexDefinitionSupplier definitions, DexType other) {
     if (this == other) {
       return this;
     }
-    DexType objectType = appInfo.dexItemFactory.objectType;
+    DexType objectType = definitions.dexItemFactory().objectType;
     // If we have no definition for either class, stop proceeding.
     if (hierarchyLevel == UNKNOWN_LEVEL || other.hierarchyLevel == UNKNOWN_LEVEL) {
       return objectType;
@@ -648,7 +649,7 @@
     DexClass dexClass;
     // Make both of other and this in the same level.
     while (t2.hierarchyLevel > t1.hierarchyLevel) {
-      dexClass = appInfo.definitionFor(t2);
+      dexClass = definitions.definitionFor(t2);
       if (dexClass == null || dexClass.superType == null) {
         return objectType;
       }
@@ -660,13 +661,13 @@
     // (It will stop at anytime when either one's definition is not found.)
     DexType lubType = t1;
     while (t2 != lubType) {
-      dexClass = appInfo.definitionFor(t2);
+      dexClass = definitions.definitionFor(t2);
       if (dexClass == null) {
         lubType = objectType;
         break;
       }
       t2 = dexClass.superType;
-      dexClass = appInfo.definitionFor(lubType);
+      dexClass = definitions.definitionFor(lubType);
       if (dexClass == null) {
         lubType = objectType;
         break;
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLense.java b/src/main/java/com/android/tools/r8/graph/GraphLense.java
index aa8523e..5dd36c6 100644
--- a/src/main/java/com/android/tools/r8/graph/GraphLense.java
+++ b/src/main/java/com/android/tools/r8/graph/GraphLense.java
@@ -388,14 +388,14 @@
   public abstract DexMethod getRenamedMethodSignature(DexMethod originalMethod);
 
   public DexEncodedMethod mapDexEncodedMethod(
-      DexEncodedMethod originalEncodedMethod, AppInfo appInfo) {
+      DexEncodedMethod originalEncodedMethod, DexDefinitionSupplier definitions) {
     DexMethod newMethod = getRenamedMethodSignature(originalEncodedMethod.method);
     // Note that:
     // * Even if `newMethod` is the same as `originalEncodedMethod.method`, we still need to look it
     //   up, since `originalEncodedMethod` may be obsolete.
     // * We can't directly use AppInfo#definitionFor(DexMethod) since definitions may not be
     //   updated either yet.
-    DexClass newHolder = appInfo.definitionFor(newMethod.holder);
+    DexClass newHolder = definitions.definitionFor(newMethod.holder);
     assert newHolder != null;
     DexEncodedMethod newEncodedMethod = newHolder.lookupMethod(newMethod);
     assert newEncodedMethod != null;
diff --git a/src/main/java/com/android/tools/r8/graph/JarCode.java b/src/main/java/com/android/tools/r8/graph/JarCode.java
index 26264a5..732f35b 100644
--- a/src/main/java/com/android/tools/r8/graph/JarCode.java
+++ b/src/main/java/com/android/tools/r8/graph/JarCode.java
@@ -124,67 +124,52 @@
 
   @Override
   public IRCode buildIR(
-      DexEncodedMethod encodedMethod,
-      AppInfo appInfo,
-      GraphLense graphLense,
-      InternalOptions options,
-      Origin origin) {
-    return internalBuildPossiblyWithLocals(
-        encodedMethod, encodedMethod, appInfo, graphLense, options, null, null);
+      DexEncodedMethod encodedMethod, AppView<? extends AppInfo> appView, Origin origin) {
+    return internalBuildPossiblyWithLocals(encodedMethod, encodedMethod, appView, null, null);
   }
 
   @Override
   public IRCode buildInliningIR(
       DexEncodedMethod context,
       DexEncodedMethod encodedMethod,
-      AppInfo appInfo,
-      GraphLense graphLense,
-      InternalOptions options,
+      AppView<? extends AppInfo> appView,
       ValueNumberGenerator generator,
       Position callerPosition,
       Origin origin) {
     assert generator != null;
     return internalBuildPossiblyWithLocals(
-        context, encodedMethod, appInfo, graphLense, options, generator, callerPosition);
+        context, encodedMethod, appView, generator, callerPosition);
   }
 
   private IRCode internalBuildPossiblyWithLocals(
       DexEncodedMethod context,
       DexEncodedMethod encodedMethod,
-      AppInfo appInfo,
-      GraphLense graphLense,
-      InternalOptions options,
+      AppView<? extends AppInfo> appView,
       ValueNumberGenerator generator,
       Position callerPosition) {
     assert getOwner() == encodedMethod;
     triggerDelayedParsingIfNeccessary();
-    if (!keepLocals(encodedMethod, options)) {
+    if (!keepLocals(encodedMethod, appView.options())) {
       // We strip locals here because we will not be able to recover from invalid info.
       node.localVariables.clear();
-      return internalBuild(
-          context, encodedMethod, appInfo, graphLense, options, generator, callerPosition);
+      return internalBuild(context, encodedMethod, appView, generator, callerPosition);
     } else {
-      return internalBuildWithLocals(
-          context, encodedMethod, appInfo, graphLense, options, generator, callerPosition);
+      return internalBuildWithLocals(context, encodedMethod, appView, generator, callerPosition);
     }
   }
 
   private IRCode internalBuildWithLocals(
       DexEncodedMethod context,
       DexEncodedMethod encodedMethod,
-      AppInfo appInfo,
-      GraphLense graphLense,
-      InternalOptions options,
+      AppView<? extends AppInfo> appView,
       ValueNumberGenerator generator,
       Position callerPosition) {
     try {
-      return internalBuild(
-          context, encodedMethod, appInfo, graphLense, options, generator, callerPosition);
+      return internalBuild(context, encodedMethod, appView, generator, callerPosition);
     } catch (InvalidDebugInfoException e) {
-      options.warningInvalidDebugInfo(encodedMethod, origin, e);
+      appView.options().warningInvalidDebugInfo(encodedMethod, origin, e);
       node.localVariables.clear();
-      return internalBuild(
-          context, encodedMethod, appInfo, graphLense, options, generator, callerPosition);
+      return internalBuild(context, encodedMethod, appView, generator, callerPosition);
     }
   }
 
@@ -201,21 +186,18 @@
   private IRCode internalBuild(
       DexEncodedMethod context,
       DexEncodedMethod encodedMethod,
-      AppInfo appInfo,
-      GraphLense graphLense,
-      InternalOptions options,
+      AppView<? extends AppInfo> appView,
       ValueNumberGenerator generator,
       Position callerPosition) {
-    assert node.localVariables.isEmpty() || keepLocals(encodedMethod, options);
+    assert node.localVariables.isEmpty() || keepLocals(encodedMethod, appView.options());
     JarSourceCode source =
         new JarSourceCode(
             method.getHolder(),
             node,
             application,
-            graphLense.getOriginalMethodSignature(encodedMethod.method),
+            appView.graphLense().getOriginalMethodSignature(encodedMethod.method),
             callerPosition);
-    IRBuilder builder =
-        new IRBuilder(encodedMethod, appInfo, source, options, origin, generator, graphLense);
+    IRBuilder builder = new IRBuilder(encodedMethod, appView, source, origin, generator);
     return builder.build(context);
   }
 
@@ -246,7 +228,7 @@
       DexType invocationContext) {
     InliningConstraintVisitor visitor =
         new InliningConstraintVisitor(
-            application, appView.appInfo(), graphLense, encodedMethod, invocationContext);
+            application, appView, graphLense, encodedMethod, invocationContext);
 
     if (appView.options().enableDesugaring
         && appView.options().interfaceMethodDesugaring == OffOrAuto.Auto
diff --git a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
index 42a427c..d1e1c5c 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
@@ -58,7 +58,6 @@
 import com.android.tools.r8.ir.code.ValueType;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.utils.InternalOptions;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
 import java.util.ArrayList;
@@ -176,36 +175,23 @@
 
   @Override
   public IRCode buildIR(
-      DexEncodedMethod encodedMethod,
-      AppInfo appInfo,
-      GraphLense graphLense,
-      InternalOptions options,
-      Origin origin) {
+      DexEncodedMethod encodedMethod, AppView<? extends AppInfo> appView, Origin origin) {
     assert getOwner() == encodedMethod;
-    return asCfCode().buildIR(encodedMethod, appInfo, graphLense, options, origin);
+    return asCfCode().buildIR(encodedMethod, appView, origin);
   }
 
   @Override
   public IRCode buildInliningIR(
       DexEncodedMethod context,
       DexEncodedMethod encodedMethod,
-      AppInfo appInfo,
-      GraphLense graphLense,
-      InternalOptions options,
+      AppView<? extends AppInfo> appView,
       ValueNumberGenerator valueNumberGenerator,
       Position callerPosition,
       Origin origin) {
     assert getOwner() == encodedMethod;
     return asCfCode()
         .buildInliningIR(
-            context,
-            encodedMethod,
-            appInfo,
-            graphLense,
-            options,
-            valueNumberGenerator,
-            callerPosition,
-            origin);
+            context, encodedMethod, appView, valueNumberGenerator, callerPosition, origin);
   }
 
   @Override
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 4e08835..120a099 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
@@ -73,8 +73,6 @@
   }
 
   public ClassInitializationAnalysis(AppView<? extends AppInfoWithLiveness> appView, IRCode code) {
-    assert appView != null;
-    assert code != null;
     this.appView = appView;
     this.code = code;
     this.dexItemFactory = appView.dexItemFactory();
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeLatticeElement.java
index a88a71d..1c16837 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeLatticeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeLatticeElement.java
@@ -6,7 +6,7 @@
 import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
 import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull;
 
-import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
 
@@ -77,8 +77,8 @@
   }
 
   @Override
-  public boolean isBasedOnMissingClass(AppInfo appInfo) {
-    return memberTypeLattice.isBasedOnMissingClass(appInfo);
+  public boolean isBasedOnMissingClass(DexDefinitionSupplier definitions) {
+    return memberTypeLattice.isBasedOnMissingClass(definitions);
   }
 
   @Override
@@ -119,7 +119,8 @@
     return (isNullable() ? 1 : -1) * memberTypeLattice.hashCode();
   }
 
-  ReferenceTypeLatticeElement join(ArrayTypeLatticeElement other, AppInfo appInfo) {
+  ReferenceTypeLatticeElement join(
+      ArrayTypeLatticeElement other, DexDefinitionSupplier definitions) {
     TypeLatticeElement aMember = getArrayMemberTypeAsMemberType();
     TypeLatticeElement bMember = other.getArrayMemberTypeAsMemberType();
     if (aMember.equals(bMember)) {
@@ -129,18 +130,22 @@
     Nullability nullability = nullability().join(other.nullability());
     if (aMember.isArrayType() && bMember.isArrayType()) {
       ReferenceTypeLatticeElement join =
-          aMember.asArrayTypeLatticeElement().join(bMember.asArrayTypeLatticeElement(), appInfo);
+          aMember
+              .asArrayTypeLatticeElement()
+              .join(bMember.asArrayTypeLatticeElement(), definitions);
       return join == null ? null : new ArrayTypeLatticeElement(join, nullability);
     }
     if (aMember.isClassType() && bMember.isClassType()) {
       ClassTypeLatticeElement join =
-          aMember.asClassTypeLatticeElement().join(bMember.asClassTypeLatticeElement(), appInfo);
+          aMember
+              .asClassTypeLatticeElement()
+              .join(bMember.asClassTypeLatticeElement(), definitions);
       return join == null ? null : new ArrayTypeLatticeElement(join, nullability);
     }
     if (aMember.isPrimitive() || bMember.isPrimitive()) {
-      return objectClassType(appInfo, nullability);
+      return objectClassType(definitions, nullability);
     }
-    return objectArrayType(appInfo, nullability);
+    return objectArrayType(definitions, nullability);
   }
 
 }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/BottomTypeLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/BottomTypeLatticeElement.java
index c44aa34..78c4e56 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/BottomTypeLatticeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/BottomTypeLatticeElement.java
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.analysis.type;
 
-import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexType;
 
 public class BottomTypeLatticeElement extends TypeLatticeElement {
@@ -24,7 +24,7 @@
   }
 
   @Override
-  public TypeLatticeElement checkCast(AppInfo appInfo, DexType castType) {
+  public TypeLatticeElement checkCast(DexDefinitionSupplier definitions, DexType castType) {
     return this;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeLatticeElement.java
index 34ef919..09dda42 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeLatticeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeLatticeElement.java
@@ -6,8 +6,8 @@
 import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
 import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull;
 
-import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexType;
 import com.google.common.collect.ImmutableSet;
 import java.util.ArrayDeque;
@@ -21,7 +21,7 @@
 public class ClassTypeLatticeElement extends ReferenceTypeLatticeElement {
 
   private Set<DexType> lazyInterfaces;
-  private AppInfo appInfoForLazyInterfacesComputation;
+  private DexDefinitionSupplier definitionsForLazyInterfacesComputation;
 
   public ClassTypeLatticeElement(
       DexType classType, Nullability nullability, Set<DexType> interfaces) {
@@ -29,18 +29,18 @@
   }
 
   public ClassTypeLatticeElement(
-      DexType classType, Nullability nullability, AppInfo appInfo) {
-    this(classType, nullability, null, appInfo);
+      DexType classType, Nullability nullability, DexDefinitionSupplier definitions) {
+    this(classType, nullability, null, definitions);
   }
 
   private ClassTypeLatticeElement(
       DexType classType,
       Nullability nullability,
       Set<DexType> interfaces,
-      AppInfo appInfo) {
+      DexDefinitionSupplier definitions) {
     super(nullability, classType);
     assert classType.isClassType();
-    appInfoForLazyInterfacesComputation = appInfo;
+    definitionsForLazyInterfacesComputation = definitions;
     lazyInterfaces = interfaces;
   }
 
@@ -55,10 +55,10 @@
     }
     synchronized (this) {
       if (lazyInterfaces == null) {
-        Set<DexType> itfs = type.implementedInterfaces(appInfoForLazyInterfacesComputation);
+        Set<DexType> itfs = type.implementedInterfaces(definitionsForLazyInterfacesComputation);
         lazyInterfaces =
-            computeLeastUpperBoundOfInterfaces(appInfoForLazyInterfacesComputation, itfs, itfs);
-        appInfoForLazyInterfacesComputation = null;
+            computeLeastUpperBoundOfInterfaces(definitionsForLazyInterfacesComputation, itfs, itfs);
+        definitionsForLazyInterfacesComputation = null;
       }
     }
     return lazyInterfaces;
@@ -70,7 +70,7 @@
       return this;
     }
     return new ClassTypeLatticeElement(
-        type, nullability, lazyInterfaces, appInfoForLazyInterfacesComputation);
+        type, nullability, lazyInterfaces, definitionsForLazyInterfacesComputation);
   }
 
   @Override
@@ -84,9 +84,10 @@
   }
 
   @Override
-  public boolean isBasedOnMissingClass(AppInfo appInfo) {
-    return getClassType().isMissingOrHasMissingSuperType(appInfo)
-        || getInterfaces().stream().anyMatch(type -> type.isMissingOrHasMissingSuperType(appInfo));
+  public boolean isBasedOnMissingClass(DexDefinitionSupplier definitions) {
+    return getClassType().isMissingOrHasMissingSuperType(definitions)
+        || getInterfaces().stream()
+            .anyMatch(type -> type.isMissingOrHasMissingSuperType(definitions));
   }
 
   @Override
@@ -116,8 +117,9 @@
     return (isNullable() ? 1 : -1) * type.hashCode();
   }
 
-  ClassTypeLatticeElement join(ClassTypeLatticeElement other, AppInfo appInfo) {
-    DexType lubType = getClassType().computeLeastUpperBoundOfClasses(appInfo, other.getClassType());
+  ClassTypeLatticeElement join(ClassTypeLatticeElement other, DexDefinitionSupplier definitions) {
+    DexType lubType =
+        getClassType().computeLeastUpperBoundOfClasses(definitions, other.getClassType());
     Set<DexType> c1lubItfs = getInterfaces();
     Set<DexType> c2lubItfs = other.getInterfaces();
     Set<DexType> lubItfs = null;
@@ -125,7 +127,7 @@
       lubItfs = c1lubItfs;
     }
     if (lubItfs == null) {
-      lubItfs = computeLeastUpperBoundOfInterfaces(appInfo, c1lubItfs, c2lubItfs);
+      lubItfs = computeLeastUpperBoundOfInterfaces(definitions, c1lubItfs, c2lubItfs);
     }
     Nullability nullability = nullability().join(other.nullability());
     return new ClassTypeLatticeElement(lubType, nullability, lubItfs);
@@ -147,12 +149,12 @@
   }
 
   static Set<DexType> computeLeastUpperBoundOfInterfaces(
-      AppInfo appInfo, Set<DexType> s1, Set<DexType> s2) {
-    Set<DexType> cached = appInfo.dexItemFactory.leastUpperBoundOfInterfacesTable.get(s1, s2);
+      DexDefinitionSupplier definitions, Set<DexType> s1, Set<DexType> s2) {
+    Set<DexType> cached = definitions.dexItemFactory().leastUpperBoundOfInterfacesTable.get(s1, s2);
     if (cached != null) {
       return cached;
     }
-    cached = appInfo.dexItemFactory.leastUpperBoundOfInterfacesTable.get(s2, s1);
+    cached = definitions.dexItemFactory().leastUpperBoundOfInterfacesTable.get(s2, s1);
     if (cached != null) {
       return cached;
     }
@@ -181,7 +183,7 @@
       // Otherwise, this type is freshly visited.
       markers.add(marker);
       // Put super interfaces into the worklist.
-      DexClass itfClass = appInfo.definitionFor(itf);
+      DexClass itfClass = definitions.definitionFor(itf);
       if (itfClass != null) {
         for (DexType superItf : itfClass.interfaces.values) {
           markers = seen.computeIfAbsent(superItf, k -> new HashSet<>());
@@ -207,7 +209,7 @@
       // If there is a strict sub interface of this interface, it is not the least element.
       boolean notTheLeast = false;
       for (DexType other : commonlyVisited) {
-        if (other.isStrictSubtypeOf(itf, appInfo)) {
+        if (other.isStrictSubtypeOf(itf, definitions)) {
           notTheLeast = true;
           break;
         }
@@ -220,8 +222,8 @@
     Set<DexType> lub = lubBuilder.build();
     // Cache the computation result only if the given two sets of interfaces are different.
     if (s1.size() != s2.size() || !s1.containsAll(s2)) {
-      synchronized (appInfo.dexItemFactory.leastUpperBoundOfInterfacesTable) {
-        appInfo.dexItemFactory.leastUpperBoundOfInterfacesTable.put(s1, s2, lub);
+      synchronized (definitions.dexItemFactory().leastUpperBoundOfInterfacesTable) {
+        definitions.dexItemFactory().leastUpperBoundOfInterfacesTable.put(s1, s2, lub);
       }
     }
     return lub;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/TopTypeLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/TopTypeLatticeElement.java
index d0d0c79..6531bff 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/TopTypeLatticeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/TopTypeLatticeElement.java
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.analysis.type;
 
-import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexType;
 
 public class TopTypeLatticeElement extends TypeLatticeElement {
@@ -24,7 +24,7 @@
   }
 
   @Override
-  public TypeLatticeElement checkCast(AppInfo appInfo, DexType castType) {
+  public TypeLatticeElement checkCast(DexDefinitionSupplier definitions, DexType castType) {
     return this;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeAnalysis.java
index 0e15644..e5ea8b7 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeAnalysis.java
@@ -8,7 +8,8 @@
 import static com.android.tools.r8.ir.analysis.type.TypeLatticeElement.fromDexType;
 
 import com.android.tools.r8.graph.AppInfo;
-import com.android.tools.r8.graph.AppInfoWithSubtyping;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.code.BasicBlock;
@@ -35,20 +36,22 @@
 
   private Mode mode = Mode.UNSET;
 
-  private final AppInfo appInfo;
+  private final AppView<? extends AppInfo> appView;
   private final DexEncodedMethod context;
 
   private final Deque<Value> worklist = new ArrayDeque<>();
 
-  public TypeAnalysis(
-      AppInfo appInfo, DexEncodedMethod encodedMethod, boolean mayHaveImpreciseTypes) {
-    this.appInfo = appInfo;
-    this.context = encodedMethod;
-    this.mayHaveImpreciseTypes = mayHaveImpreciseTypes;
+  public TypeAnalysis(AppView<? extends AppInfo> appView, DexEncodedMethod encodedMethod) {
+    this(appView, encodedMethod, false);
   }
 
-  public TypeAnalysis(AppInfo appInfo, DexEncodedMethod encodedMethod) {
-    this(appInfo, encodedMethod, false);
+  public TypeAnalysis(
+      AppView<? extends AppInfo> appView,
+      DexEncodedMethod encodedMethod,
+      boolean mayHaveImpreciseTypes) {
+    this.appView = appView;
+    this.context = encodedMethod;
+    this.mayHaveImpreciseTypes = mayHaveImpreciseTypes;
   }
 
   private void analyze() {
@@ -101,18 +104,21 @@
         TypeLatticeElement derived;
         if (argumentsSeen < 0) {
           // Receiver
-          derived = fromDexType(encodedMethod.method.holder,
-              // Now we try inlining even when the receiver could be null.
-              encodedMethod == context ? definitelyNotNull() : maybeNull(), appInfo);
+          derived =
+              fromDexType(
+                  encodedMethod.method.holder,
+                  // Now we try inlining even when the receiver could be null.
+                  encodedMethod == context ? definitelyNotNull() : maybeNull(),
+                  appView);
         } else {
           DexType argType = encodedMethod.method.proto.parameters.values[argumentsSeen];
-          derived = fromDexType(argType, maybeNull(), appInfo);
+          derived = fromDexType(argType, maybeNull(), appView);
         }
         argumentsSeen++;
         updateTypeOfValue(outValue, derived);
         // Note that we don't need to enqueue the out value of arguments here because it's constant.
       } else if (instruction.hasInvariantOutType()) {
-        TypeLatticeElement derived = instruction.evaluate(appInfo);
+        TypeLatticeElement derived = instruction.evaluate(appView);
         updateTypeOfValue(outValue, derived);
       } else {
         enqueue(outValue);
@@ -126,9 +132,7 @@
   private void analyzeValue(Value value) {
     TypeLatticeElement previous = value.getTypeLattice();
     TypeLatticeElement derived =
-        value.isPhi()
-            ? value.asPhi().computePhiType(appInfo)
-            : value.definition.evaluate(appInfo);
+        value.isPhi() ? value.asPhi().computePhiType(appView) : value.definition.evaluate(appView);
     assert mayHaveImpreciseTypes || derived.isPreciseType();
     assert !previous.isPreciseType() || derived.isPreciseType();
     updateTypeOfValue(value, derived);
@@ -146,10 +150,10 @@
       return;
     }
     if (mode == Mode.WIDENING) {
-      value.widening(appInfo, type);
+      value.widening(appView, type);
     } else {
       assert mode == Mode.NARROWING;
-      value.narrowing(appInfo, type);
+      value.narrowing(appView, type);
     }
 
     // propagate the type change to (instruction) users if any.
@@ -166,12 +170,12 @@
   }
 
   public static DexType getRefinedReceiverType(
-      AppInfoWithSubtyping appInfo, InvokeMethodWithReceiver invoke) {
+      DexDefinitionSupplier definitions, InvokeMethodWithReceiver invoke) {
     DexType receiverType = invoke.getInvokedMethod().getHolder();
     TypeLatticeElement lattice = invoke.getReceiver().getTypeLattice();
     if (lattice.isClassType()) {
       DexType refinedType = lattice.asClassTypeLatticeElement().getClassType();
-      if (refinedType.isSubtypeOf(receiverType, appInfo)) {
+      if (refinedType.isSubtypeOf(receiverType, definitions)) {
         return refinedType;
       }
     }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeLatticeElement.java
index 3ef167c..6384088 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeLatticeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeLatticeElement.java
@@ -4,7 +4,7 @@
 package com.android.tools.r8.ir.analysis.type;
 
 import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.code.Value;
@@ -56,10 +56,10 @@
    * Computes the least upper bound of the current and the other elements.
    *
    * @param other {@link TypeLatticeElement} to join.
-   * @param appInfo {@link AppInfo}.
+   * @param definitions {@link DexDefinitionSupplier}.
    * @return {@link TypeLatticeElement}, a least upper bound of {@param this} and {@param other}.
    */
-  public TypeLatticeElement join(TypeLatticeElement other, AppInfo appInfo) {
+  public TypeLatticeElement join(TypeLatticeElement other, DexDefinitionSupplier definitions) {
     if (this == other) {
       return this;
     }
@@ -91,36 +91,27 @@
     assert isReference() && other.isReference();
     assert isPreciseType() && other.isPreciseType();
     if (getClass() != other.getClass()) {
-      return objectClassType(appInfo, nullability().join(other.nullability()));
+      return objectClassType(definitions, nullability().join(other.nullability()));
     }
     // From now on, getClass() == other.getClass()
     if (isArrayType()) {
       assert other.isArrayType();
       TypeLatticeElement join =
-          asArrayTypeLatticeElement().join(other.asArrayTypeLatticeElement(), appInfo);
+          asArrayTypeLatticeElement().join(other.asArrayTypeLatticeElement(), definitions);
       return join != null ? join : (isNullable() ? this : other);
     }
     if (isClassType()) {
       assert other.isClassType();
-      return asClassTypeLatticeElement().join(other.asClassTypeLatticeElement(), appInfo);
+      return asClassTypeLatticeElement().join(other.asClassTypeLatticeElement(), definitions);
     }
     throw new Unreachable("unless a new type lattice is introduced.");
   }
 
   public static TypeLatticeElement join(
-      Iterable<TypeLatticeElement> typeLattices, AppInfo appInfo) {
+      Iterable<TypeLatticeElement> typeLattices, DexDefinitionSupplier definitions) {
     TypeLatticeElement result = BOTTOM;
     for (TypeLatticeElement other : typeLattices) {
-      result = result.join(other, appInfo);
-    }
-    return result;
-  }
-
-  public static TypeLatticeElement joinTypes(
-      Iterable<DexType> types, Nullability nullability, AppInfo appInfo) {
-    TypeLatticeElement result = BOTTOM;
-    for (DexType type : types) {
-      result = result.join(fromDexType(type, nullability, appInfo), appInfo);
+      result = result.join(other, definitions);
     }
     return result;
   }
@@ -129,14 +120,15 @@
    * Determines the strict partial order of the given {@link TypeLatticeElement}s.
    *
    * @param other expected to be *strictly* bigger than {@param this}
-   * @param appInfo {@link AppInfo} to compute the least upper bound of {@link TypeLatticeElement}
+   * @param definitions {@link DexDefinitionSupplier} to compute the least upper bound of {@link
+   *     TypeLatticeElement}
    * @return {@code true} if {@param this} is strictly less than {@param other}.
    */
-  public boolean strictlyLessThan(TypeLatticeElement other, AppInfo appInfo) {
+  public boolean strictlyLessThan(TypeLatticeElement other, DexDefinitionSupplier definitions) {
     if (equals(other)) {
       return false;
     }
-    TypeLatticeElement lub = join(other, appInfo);
+    TypeLatticeElement lub = join(other, definitions);
     return !equals(lub) && other.equals(lub);
   }
 
@@ -144,11 +136,12 @@
    * Determines the partial order of the given {@link TypeLatticeElement}s.
    *
    * @param other expected to be bigger than or equal to {@param this}
-   * @param appInfo {@link AppInfo} to compute the least upper bound of {@link TypeLatticeElement}
+   * @param definitions {@link DexDefinitionSupplier} to compute the least upper bound of {@link
+   *     TypeLatticeElement}
    * @return {@code true} if {@param this} is less than or equal to {@param other}.
    */
-  public boolean lessThanOrEqual(TypeLatticeElement other, AppInfo appInfo) {
-    return equals(other) || strictlyLessThan(other, appInfo);
+  public boolean lessThanOrEqual(TypeLatticeElement other, DexDefinitionSupplier definitions) {
+    return equals(other) || strictlyLessThan(other, definitions);
   }
 
   /**
@@ -156,7 +149,7 @@
    *
    * @return {@code} true if this type is based on a missing class.
    */
-  public boolean isBasedOnMissingClass(AppInfo appInfo) {
+  public boolean isBasedOnMissingClass(DexDefinitionSupplier definitions) {
     return false;
   }
 
@@ -290,38 +283,41 @@
     return isWide() ? 2 : 1;
   }
 
-  public static ClassTypeLatticeElement objectClassType(AppInfo appInfo, Nullability nullability) {
-    return fromDexType(appInfo.dexItemFactory.objectType, nullability, appInfo)
+  public static ClassTypeLatticeElement objectClassType(
+      DexDefinitionSupplier definitions, Nullability nullability) {
+    return fromDexType(definitions.dexItemFactory().objectType, nullability, definitions)
         .asClassTypeLatticeElement();
   }
 
-  static ArrayTypeLatticeElement objectArrayType(AppInfo appInfo, Nullability nullability) {
+  static ArrayTypeLatticeElement objectArrayType(
+      DexDefinitionSupplier definitions, Nullability nullability) {
+    DexItemFactory dexItemFactory = definitions.dexItemFactory();
     return fromDexType(
-        appInfo.dexItemFactory.createArrayType(1, appInfo.dexItemFactory.objectType),
-        nullability,
-        appInfo)
+            dexItemFactory.createArrayType(1, dexItemFactory.objectType), nullability, definitions)
         .asArrayTypeLatticeElement();
   }
 
-  public static ClassTypeLatticeElement classClassType(AppInfo appInfo, Nullability nullability) {
-    return fromDexType(appInfo.dexItemFactory.classType, nullability, appInfo)
+  public static ClassTypeLatticeElement classClassType(
+      DexDefinitionSupplier definitions, Nullability nullability) {
+    return fromDexType(definitions.dexItemFactory().classType, nullability, definitions)
         .asClassTypeLatticeElement();
   }
 
-  public static ClassTypeLatticeElement stringClassType(AppInfo appInfo, Nullability nullability) {
-    return fromDexType(appInfo.dexItemFactory.stringType, nullability, appInfo)
+  public static ClassTypeLatticeElement stringClassType(
+      DexDefinitionSupplier definitions, Nullability nullability) {
+    return fromDexType(definitions.dexItemFactory().stringType, nullability, definitions)
         .asClassTypeLatticeElement();
   }
 
   public static TypeLatticeElement fromDexType(
-      DexType type, Nullability nullability, AppInfo appInfo) {
-    return fromDexType(type, nullability, appInfo, false);
+      DexType type, Nullability nullability, DexDefinitionSupplier definitions) {
+    return fromDexType(type, nullability, definitions, false);
   }
 
   public static TypeLatticeElement fromDexType(
       DexType type,
       Nullability nullability,
-      AppInfo appInfo,
+      DexDefinitionSupplier definitions,
       boolean asArrayElementType) {
     if (type == DexItemFactory.nullValueType) {
       assert !nullability.isDefinitelyNotNull();
@@ -330,7 +326,9 @@
     if (type.isPrimitiveType()) {
       return PrimitiveTypeLatticeElement.fromDexType(type, asArrayElementType);
     }
-    return appInfo.dexItemFactory.createReferenceTypeLatticeElement(type, nullability, appInfo);
+    return definitions
+        .dexItemFactory()
+        .createReferenceTypeLatticeElement(type, nullability, definitions);
   }
 
   public boolean isValueTypeCompatible(TypeLatticeElement other) {
@@ -339,9 +337,9 @@
         || (isWide() && other.isWide());
   }
 
-  public TypeLatticeElement checkCast(AppInfo appInfo, DexType castType) {
-    TypeLatticeElement castTypeLattice = fromDexType(castType, nullability(), appInfo);
-    if (lessThanOrEqual(castTypeLattice, appInfo)) {
+  public TypeLatticeElement checkCast(DexDefinitionSupplier definitions, DexType castType) {
+    TypeLatticeElement castTypeLattice = fromDexType(castType, nullability(), definitions);
+    if (lessThanOrEqual(castTypeLattice, definitions)) {
       return this;
     }
     return castTypeLattice;
diff --git a/src/main/java/com/android/tools/r8/ir/code/Argument.java b/src/main/java/com/android/tools/r8/ir/code/Argument.java
index 997f1c5..8cbf90d 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Argument.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Argument.java
@@ -77,7 +77,8 @@
   }
 
   @Override
-  public DexType computeVerificationType(TypeVerificationHelper helper) {
+  public DexType computeVerificationType(
+      AppView<? extends AppInfo> appView, TypeVerificationHelper helper) {
     throw new Unreachable();
   }
 
@@ -87,7 +88,7 @@
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
     return outValue.getTypeLattice();
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java b/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java
index 3879639..f5e6e6c 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java
@@ -17,6 +17,7 @@
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.type.ArrayTypeLatticeElement;
@@ -147,7 +148,8 @@
   }
 
   @Override
-  public DexType computeVerificationType(TypeVerificationHelper helper) {
+  public DexType computeVerificationType(
+      AppView<? extends AppInfo> appView, TypeVerificationHelper helper) {
     // This method is not called for ArrayGet on primitive array.
     assert this.outValue.getTypeLattice().isReference();
     DexType arrayType = helper.getDexType(array());
@@ -155,7 +157,7 @@
       // JVM 8 §4.10.1.9.aaload: Array component type of null is null.
       return arrayType;
     }
-    return arrayType.toArrayElementType(helper.getFactory());
+    return arrayType.toArrayElementType(appView.dexItemFactory());
   }
 
   @Override
@@ -170,7 +172,7 @@
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
     ArrayTypeLatticeElement arrayTypeLattice = array().getTypeLattice().isArrayType()
         ? array().getTypeLattice().asArrayTypeLatticeElement()
         : null;
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java b/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java
index 7049c25..97a610f 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.cf.code.CfArrayLength;
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
@@ -100,7 +101,7 @@
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
     return TypeLatticeElement.INT;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
index 47013dd..a3a230d 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
@@ -7,6 +7,7 @@
 
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DebugLocalInfo;
 import com.android.tools.r8.graph.DebugLocalInfo.PrintLevel;
 import com.android.tools.r8.graph.DexItemFactory;
@@ -79,9 +80,8 @@
     return true;
   }
 
-  public boolean verifyTypes(AppInfo appInfo, GraphLense graphLense) {
-    assert instructions.stream()
-        .allMatch(instruction -> instruction.verifyTypes(appInfo, graphLense));
+  public boolean verifyTypes(AppView<? extends AppInfo> appView) {
+    assert instructions.stream().allMatch(instruction -> instruction.verifyTypes(appView));
     return true;
   }
 
@@ -1305,14 +1305,15 @@
   }
 
   public static BasicBlock createRethrowBlock(
-      IRCode code, Position position, DexType guard, AppInfo appInfo, InternalOptions options) {
+      IRCode code, Position position, DexType guard, AppView<? extends AppInfo> appView) {
     TypeLatticeElement guardTypeLattice =
-        TypeLatticeElement.fromDexType(guard, Nullability.definitelyNotNull(), appInfo);
+        TypeLatticeElement.fromDexType(guard, Nullability.definitelyNotNull(), appView.appInfo());
     BasicBlock block = new BasicBlock();
-    MoveException moveException = new MoveException(
-        new Value(code.valueNumberGenerator.next(), guardTypeLattice, null),
-        guard,
-        options);
+    MoveException moveException =
+        new MoveException(
+            new Value(code.valueNumberGenerator.next(), guardTypeLattice, null),
+            guard,
+            appView.options());
     moveException.setPosition(position);
     Throw throwInstruction = new Throw(moveException.outValue);
     throwInstruction.setPosition(position);
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java
index 1ab0670..d45a368 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java
@@ -7,6 +7,7 @@
 import static com.android.tools.r8.ir.code.DominatorTree.Assumption.MAY_HAVE_UNREACHABLE_BLOCKS;
 
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
@@ -333,7 +334,7 @@
 
   @Override
   public BasicBlock inlineInvoke(
-      AppInfo appInfo,
+      AppView<? extends AppInfo> appView,
       IRCode code,
       IRCode inlinee,
       ListIterator<BasicBlock> blocksIterator,
@@ -372,7 +373,7 @@
       Value receiver = invoke.inValues().get(0);
       TypeLatticeElement castTypeLattice =
           TypeLatticeElement.fromDexType(
-              downcast, receiver.getTypeLattice().nullability(), appInfo);
+              downcast, receiver.getTypeLattice().nullability(), appView);
       CheckCast castInstruction =
           new CheckCast(code.createValue(castTypeLattice), receiver, downcast);
       castInstruction.setPosition(invoke.getPosition());
@@ -422,7 +423,7 @@
     assert entryBlock.getInstructions().stream().noneMatch(Instruction::isArgument);
 
     // Actual arguments are flown to the inlinee.
-    new TypeAnalysis(appInfo, inlinee.method).narrowing(argumentUsers);
+    new TypeAnalysis(appView, inlinee.method).narrowing(argumentUsers);
 
     // The inline entry is the first block now the argument instructions are gone.
     BasicBlock inlineEntry = inlinee.entryBlock();
@@ -432,7 +433,7 @@
     if (!normalExits.isEmpty()) {
       // Ensure and locate the single return instruction of the inlinee.
       InstructionListIterator inlineeIterator =
-          ensureSingleReturnInstruction(appInfo, inlinee, normalExits);
+          ensureSingleReturnInstruction(appView, inlinee, normalExits);
 
       // Replace the invoke value with the return value if non-void.
       assert inlineeIterator.peekNext().isReturn();
@@ -441,8 +442,10 @@
         Return returnInstruction = inlineeIterator.peekNext().asReturn();
         invoke.outValue().replaceUsers(returnInstruction.returnValue());
         // The return type is flown to the original context.
-        new TypeAnalysis(appInfo, code.method).narrowing(
-            Iterables.concat(ImmutableList.of(returnInstruction.returnValue()), affectedValues));
+        new TypeAnalysis(appView, code.method)
+            .narrowing(
+                Iterables.concat(
+                    ImmutableList.of(returnInstruction.returnValue()), affectedValues));
       }
 
       // Split before return and unlink return.
@@ -517,7 +520,7 @@
   }
 
   private InstructionListIterator ensureSingleReturnInstruction(
-      AppInfo appInfo, IRCode code, List<BasicBlock> normalExits) {
+      AppView<? extends AppInfo> appView, IRCode code, List<BasicBlock> normalExits) {
     if (normalExits.size() == 1) {
       InstructionListIterator it = normalExits.get(0).listIterator();
       it.nextUntil(Instruction::isReturn);
@@ -550,7 +553,7 @@
                 null,
                 RegisterReadType.NORMAL);
         phi.addOperands(operands);
-        new TypeAnalysis(appInfo, code.method).widening(ImmutableSet.of(phi));
+        new TypeAnalysis(appView, code.method).widening(ImmutableSet.of(phi));
         value = phi;
       }
       newReturn = new Return(value);
diff --git a/src/main/java/com/android/tools/r8/ir/code/Binop.java b/src/main/java/com/android/tools/r8/ir/code/Binop.java
index 54567b5..78827cd 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Binop.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Binop.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.type.PrimitiveTypeLatticeElement;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
@@ -135,7 +136,7 @@
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
     return PrimitiveTypeLatticeElement.fromNumericType(type);
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/CheckCast.java b/src/main/java/com/android/tools/r8/ir/code/CheckCast.java
index b13e356..6c7112f 100644
--- a/src/main/java/com/android/tools/r8/ir/code/CheckCast.java
+++ b/src/main/java/com/android/tools/r8/ir/code/CheckCast.java
@@ -11,8 +11,8 @@
 import com.android.tools.r8.code.MoveObjectFrom16;
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
@@ -106,13 +106,13 @@
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
-    return object().getTypeLattice().checkCast(appInfo, type);
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
+    return object().getTypeLattice().checkCast(appView, type);
   }
 
   @Override
-  public boolean verifyTypes(AppInfo appInfo, GraphLense graphLense) {
-    assert super.verifyTypes(appInfo, graphLense);
+  public boolean verifyTypes(AppView<? extends AppInfo> appView) {
+    assert super.verifyTypes(appView);
 
     TypeLatticeElement inType = object().getTypeLattice();
 
@@ -120,12 +120,12 @@
 
     TypeLatticeElement outType = outValue().getTypeLattice();
     TypeLatticeElement castType =
-        TypeLatticeElement.fromDexType(getType(), inType.nullability(), appInfo);
+        TypeLatticeElement.fromDexType(getType(), inType.nullability(), appView);
 
-    if (inType.lessThanOrEqual(castType, appInfo)) {
+    if (inType.lessThanOrEqual(castType, appView)) {
       // Cast can be removed. Check that it is sound to replace all users of the out-value by the
       // in-value.
-      assert inType.lessThanOrEqual(outType, appInfo);
+      assert inType.lessThanOrEqual(outType, appView);
 
       // TODO(b/72693244): Consider checking equivalence. This requires that the types are always
       // as precise as possible, though, meaning that almost all changes to the IR must be followed
@@ -163,7 +163,8 @@
   }
 
   @Override
-  public DexType computeVerificationType(TypeVerificationHelper helper) {
+  public DexType computeVerificationType(
+      AppView<? extends AppInfo> appView, TypeVerificationHelper helper) {
     return type;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/Cmp.java b/src/main/java/com/android/tools/r8/ir/code/Cmp.java
index 2f346a5..8ad8d4b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Cmp.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Cmp.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.ir.analysis.constant.Bottom;
 import com.android.tools.r8.ir.analysis.constant.ConstLatticeElement;
 import com.android.tools.r8.ir.analysis.constant.LatticeElement;
@@ -225,7 +226,7 @@
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
     return TypeLatticeElement.INT;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstClass.java b/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
index b3ab484..83bbb0f 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
@@ -136,13 +136,14 @@
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
-    return TypeLatticeElement.classClassType(appInfo, Nullability.definitelyNotNull());
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
+    return TypeLatticeElement.classClassType(appView, Nullability.definitelyNotNull());
   }
 
   @Override
-  public DexType computeVerificationType(TypeVerificationHelper helper) {
-    return helper.getFactory().classType;
+  public DexType computeVerificationType(
+      AppView<? extends AppInfo> appView, TypeVerificationHelper helper) {
+    return appView.dexItemFactory().classType;
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstMethodHandle.java b/src/main/java/com/android/tools/r8/ir/code/ConstMethodHandle.java
index ebc61d0..40c879f 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstMethodHandle.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.cf.code.CfConstMethodHandle;
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethodHandle;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.type.Nullability;
@@ -106,14 +107,15 @@
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
     return TypeLatticeElement.fromDexType(
-        appInfo.dexItemFactory.methodHandleType, Nullability.definitelyNotNull(), appInfo);
+        appView.dexItemFactory().methodHandleType, Nullability.definitelyNotNull(), appView);
   }
 
   @Override
-  public DexType computeVerificationType(TypeVerificationHelper helper) {
-    return helper.getFactory().methodHandleType;
+  public DexType computeVerificationType(
+      AppView<? extends AppInfo> appView, TypeVerificationHelper helper) {
+    return appView.dexItemFactory().methodHandleType;
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstMethodType.java b/src/main/java/com/android/tools/r8/ir/code/ConstMethodType.java
index 47aa1c4..f9eee1b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstMethodType.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstMethodType.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.cf.code.CfConstMethodType;
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.type.Nullability;
@@ -98,14 +99,15 @@
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
     return TypeLatticeElement.fromDexType(
-        appInfo.dexItemFactory.methodTypeType, Nullability.definitelyNotNull(), appInfo);
+        appView.dexItemFactory().methodTypeType, Nullability.definitelyNotNull(), appView);
   }
 
   @Override
-  public DexType computeVerificationType(TypeVerificationHelper helper) {
-    return helper.getFactory().methodTypeType;
+  public DexType computeVerificationType(
+      AppView<? extends AppInfo> appView, TypeVerificationHelper helper) {
+    return appView.dexItemFactory().methodTypeType;
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java b/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
index 3976889..0847cb7 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
@@ -17,8 +17,8 @@
 import com.android.tools.r8.code.ConstWideHigh16;
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.ir.analysis.constant.Bottom;
 import com.android.tools.r8.ir.analysis.constant.ConstLatticeElement;
 import com.android.tools.r8.ir.analysis.constant.LatticeElement;
@@ -279,9 +279,10 @@
   }
 
   @Override
-  public DexType computeVerificationType(TypeVerificationHelper helper) {
+  public DexType computeVerificationType(
+      AppView<? extends AppInfo> appView, TypeVerificationHelper helper) {
     assert outType().isObject();
-    return helper.getFactory().nullValueType;
+    return appView.dexItemFactory().nullValueType;
   }
 
   @Override
@@ -293,13 +294,13 @@
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
     return outValue().getTypeLattice();
   }
 
   @Override
-  public boolean verifyTypes(AppInfo appInfo, GraphLense graphLense) {
-    assert super.verifyTypes(appInfo, graphLense);
+  public boolean verifyTypes(AppView<? extends AppInfo> appView) {
+    assert super.verifyTypes(appView);
     assert !isZero()
         || outValue().getTypeLattice().isPrimitive()
         || outValue().getTypeLattice().isNullType();
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstString.java b/src/main/java/com/android/tools/r8/ir/code/ConstString.java
index f6f1ccf..27577c0 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstString.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstString.java
@@ -131,12 +131,13 @@
   }
 
   @Override
-  public DexType computeVerificationType(TypeVerificationHelper helper) {
-    return helper.getFactory().stringType;
+  public DexType computeVerificationType(
+      AppView<? extends AppInfo> appView, TypeVerificationHelper helper) {
+    return appView.dexItemFactory().stringType;
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
-    return TypeLatticeElement.stringClassType(appInfo, Nullability.definitelyNotNull());
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
+    return TypeLatticeElement.stringClassType(appView, Nullability.definitelyNotNull());
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/code/DebugLocalWrite.java b/src/main/java/com/android/tools/r8/ir/code/DebugLocalWrite.java
index 2a5aebc..de1b6fb 100644
--- a/src/main/java/com/android/tools/r8/ir/code/DebugLocalWrite.java
+++ b/src/main/java/com/android/tools/r8/ir/code/DebugLocalWrite.java
@@ -6,6 +6,8 @@
 import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.cf.TypeVerificationHelper;
 import com.android.tools.r8.cf.code.CfStore;
+import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 
@@ -50,7 +52,8 @@
   }
 
   @Override
-  public DexType computeVerificationType(TypeVerificationHelper helper) {
+  public DexType computeVerificationType(
+      AppView<? extends AppInfo> appView, TypeVerificationHelper helper) {
     return helper.getDexType(src());
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/DexItemBasedConstString.java b/src/main/java/com/android/tools/r8/ir/code/DexItemBasedConstString.java
index 7d0d44f..d5c8c82 100644
--- a/src/main/java/com/android/tools/r8/ir/code/DexItemBasedConstString.java
+++ b/src/main/java/com/android/tools/r8/ir/code/DexItemBasedConstString.java
@@ -126,12 +126,13 @@
   }
 
   @Override
-  public DexType computeVerificationType(TypeVerificationHelper helper) {
-    return helper.getFactory().stringType;
+  public DexType computeVerificationType(
+      AppView<? extends AppInfo> appView, TypeVerificationHelper helper) {
+    return appView.dexItemFactory().stringType;
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
-    return TypeLatticeElement.stringClassType(appInfo, Nullability.definitelyNotNull());
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
+    return TypeLatticeElement.stringClassType(appView, Nullability.definitelyNotNull());
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCode.java b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
index 0d8826b..c4c130f 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRCode.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
@@ -8,7 +8,6 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DebugLocalInfo;
 import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.ir.analysis.TypeChecker;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.conversion.IRBuilder;
@@ -486,14 +485,13 @@
     return true;
   }
 
-  public boolean verifyTypes(
-      AppInfo appInfo, AppView<? extends AppInfo> appView, GraphLense graphLense) {
+  public boolean verifyTypes(AppView<? extends AppInfo> appView) {
     // We can only type check the program if we have subtyping information. Therefore, we do not
     // require that the program type checks in D8.
-    if (appView != null && appView.enableWholeProgramOptimizations()) {
+    if (appView.enableWholeProgramOptimizations()) {
       assert new TypeChecker(appView).check(this);
     }
-    assert blocks.stream().allMatch(block -> block.verifyTypes(appInfo, graphLense));
+    assert blocks.stream().allMatch(block -> block.verifyTypes(appView));
     return true;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java b/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
index 44cc6a1..3634edf 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
@@ -112,7 +112,7 @@
     // * NullPointerException (null receiver).
     // TODO(b/123857022): Should be possible to use definitionFor().
     AppInfo appInfo = appView.appInfo();
-    DexEncodedField resolvedField = appInfo.resolveFieldOn(getField().getHolder(), getField());
+    DexEncodedField resolvedField = appInfo.resolveField(getField());
     if (resolvedField == null) {
       return false;
     }
@@ -167,12 +167,13 @@
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
-    return TypeLatticeElement.fromDexType(getField().type, Nullability.maybeNull(), appInfo);
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
+    return TypeLatticeElement.fromDexType(getField().type, Nullability.maybeNull(), appView);
   }
 
   @Override
-  public DexType computeVerificationType(TypeVerificationHelper helper) {
+  public DexType computeVerificationType(
+      AppView<? extends AppInfo> appView, TypeVerificationHelper helper) {
     return getField().type;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java b/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java
index 47e229b..e2cfeb3 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.cf.code.CfInstanceOf;
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.conversion.CfBuilder;
@@ -80,7 +81,7 @@
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
     return TypeLatticeElement.INT;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/Instruction.java b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
index b05cd55..9c28e92 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
@@ -12,7 +12,6 @@
 import com.android.tools.r8.graph.DebugLocalInfo;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption;
 import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query;
 import com.android.tools.r8.ir.analysis.constant.Bottom;
@@ -1195,7 +1194,8 @@
 
   public abstract void insertLoadAndStores(InstructionListIterator it, LoadStoreHelper helper);
 
-  public DexType computeVerificationType(TypeVerificationHelper helper) {
+  public DexType computeVerificationType(
+      AppView<? extends AppInfo> appView, TypeVerificationHelper helper) {
     assert outValue == null || !outValue.getTypeLattice().isReference();
     throw new Unreachable("Instruction without object outValue cannot compute verification type");
   }
@@ -1210,13 +1210,13 @@
   }
 
   // TODO(b/72693244): maybe rename to computeOutType once TypeVerificationHelper is gone?
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
     assert outValue == null;
     throw new Unimplemented(
         "Implement type lattice evaluation for: " + getInstructionName());
   }
 
-  public boolean verifyTypes(AppInfo appInfo, GraphLense graphLense) {
+  public boolean verifyTypes(AppView<? extends AppInfo> appView) {
     // TODO(b/72693244): for instructions with invariant out type, we can verify type directly here.
     if (outValue != null) {
       TypeLatticeElement outTypeLatticeElement = outValue.getTypeLattice();
@@ -1224,12 +1224,12 @@
         DexType outBaseType =
             outTypeLatticeElement
                 .asArrayTypeLatticeElement()
-                .getArrayType(appInfo.dexItemFactory)
-                .toBaseType(appInfo.dexItemFactory);
-        assert graphLense.lookupType(outBaseType) == outBaseType;
+                .getArrayType(appView.dexItemFactory())
+                .toBaseType(appView.dexItemFactory());
+        assert appView.graphLense().lookupType(outBaseType) == outBaseType;
       } else if (outTypeLatticeElement.isClassType()) {
         DexType outType = outTypeLatticeElement.asClassTypeLatticeElement().getClassType();
-        assert graphLense.lookupType(outType) == outType;
+        assert appView.graphLense().lookupType(outType) == outType;
       }
     }
     return true;
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java b/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
index c232d3f..0a1bf67 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import java.util.ArrayList;
 import java.util.List;
@@ -100,30 +101,31 @@
    * Inline the code in {@code inlinee} into {@code code}, replacing the invoke instruction at the
    * position after the cursor.
    *
-   * The instruction at the position after cursor must be an invoke that matches the signature for
-   * the code in {@code inlinee}.
+   * <p>The instruction at the position after cursor must be an invoke that matches the signature
+   * for the code in {@code inlinee}.
    *
-   * With one exception (see below) both the calling code and the inlinee can have catch handlers.
+   * <p>With one exception (see below) both the calling code and the inlinee can have catch
+   * handlers.
    *
-   * <strong>EXCEPTION:</strong> If the invoke instruction is covered by catch handlers, and the
+   * <p><strong>EXCEPTION:</strong> If the invoke instruction is covered by catch handlers, and the
    * code for {@code inlinee} always throws (does not have a normal return) inlining is currently
    * <strong>NOT</strong> supported.
    *
-   * @param appInfo {@link AppInfo} to retrieve class definition.
+   * @param appView {@link AppView} to retrieve class definition.
    * @param code the IR code for the block this iterator originates from.
    * @param inlinee the IR code for the block this iterator originates from.
    * @param blockIterator basic block iterator used to iterate the blocks. This must be positioned
-   * just after the block for which this is the instruction iterator. After this method returns it
-   * will be positioned just after the basic block returned.
+   *     just after the block for which this is the instruction iterator. After this method returns
+   *     it will be positioned just after the basic block returned.
    * @param blocksToRemove list passed where blocks that where detached from the graph, but not
-   * removed are added. When inlining an inlinee that always throws blocks in the <code>code</code>
-   * can be detached, and not simply removed unsing the passed <code>blockIterator</code>. When
-   * iterating using <code>blockIterator</code> after then method returns the blocks in this list
-   * must be skipped when iterating with the active <code>blockIterator</code> and ultimately
-   * removed.
+   *     removed are added. When inlining an inlinee that always throws blocks in the <code>code
+   *     </code> can be detached, and not simply removed unsing the passed <code>blockIterator
+   *     </code>. When iterating using <code>blockIterator</code> after then method returns the
+   *     blocks in this list must be skipped when iterating with the active <code>blockIterator
+   *     </code> and ultimately removed.
    * @param downcast tells the inliner to issue a check cast operation.
    * @return the basic block with the instructions right after the inlining. This can be a block
-   * which can also be in the <code>blocksToRemove</code> list.
+   *     which can also be in the <code>blocksToRemove</code> list.
    */
   // TODO(sgjesse): Refactor to avoid the need for passing code.
   // TODO(sgjesse): Refactor to avoid the need for passing blocksToRemove.
@@ -131,19 +133,17 @@
   // TODO(sgjesse): Maybe find a better place for this method.
   // TODO(sgjesse): Support inlinee with throwing instructions for invokes with existing handlers.
   BasicBlock inlineInvoke(
-      AppInfo appInfo,
+      AppView<? extends AppInfo> appView,
       IRCode code,
       IRCode inlinee,
       ListIterator<BasicBlock> blockIterator,
       List<BasicBlock> blocksToRemove,
       DexType downcast);
 
-  /**
-   * See {@link #inlineInvoke(AppInfo, IRCode, IRCode, ListIterator, List, DexType)}.
-   */
-  default BasicBlock inlineInvoke(AppInfo appInfo, IRCode code, IRCode inlinee) {
+  /** See {@link #inlineInvoke(AppView, IRCode, IRCode, ListIterator, List, DexType)}. */
+  default BasicBlock inlineInvoke(AppView<? extends AppInfo> appView, IRCode code, IRCode inlinee) {
     List<BasicBlock> blocksToRemove = new ArrayList<>();
-    BasicBlock result = inlineInvoke(appInfo, code, inlinee, null, blocksToRemove, null);
+    BasicBlock result = inlineInvoke(appView, code, inlinee, null, blocksToRemove, null);
     code.removeBlocks(blocksToRemove);
     return result;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Invoke.java b/src/main/java/com/android/tools/r8/ir/code/Invoke.java
index 48e2659..03beffd 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Invoke.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Invoke.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexItem;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
@@ -262,11 +263,11 @@
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
     DexType returnType = getReturnType();
     if (returnType.isVoidType()) {
       throw new Unreachable("void methods have no type.");
     }
-    return TypeLatticeElement.fromDexType(returnType, Nullability.maybeNull(), appInfo);
+    return TypeLatticeElement.fromDexType(returnType, Nullability.maybeNull(), appView);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java b/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java
index bb42328..3d13f750 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java
@@ -7,6 +7,8 @@
 import com.android.tools.r8.cf.TypeVerificationHelper;
 import com.android.tools.r8.cf.code.CfInvokeDynamic;
 import com.android.tools.r8.code.InvokeCustomRange;
+import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexCallSite;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.CfBuilder;
@@ -121,7 +123,8 @@
   }
 
   @Override
-  public DexType computeVerificationType(TypeVerificationHelper helper) {
+  public DexType computeVerificationType(
+      AppView<? extends AppInfo> appView, TypeVerificationHelper helper) {
     return getCallSite().methodProto.returnType;
   }
 }
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 d203184..ce3fcb3 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
@@ -5,7 +5,9 @@
 
 import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.cf.TypeVerificationHelper;
+import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.AppInfoWithSubtyping;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
@@ -87,7 +89,8 @@
   }
 
   @Override
-  public DexType computeVerificationType(TypeVerificationHelper helper) {
+  public DexType computeVerificationType(
+      AppView<? extends AppInfo> appView, TypeVerificationHelper helper) {
     return getReturnType();
   }
 
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 f994058..1ca8df7 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
@@ -4,10 +4,10 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.optimize.Inliner.InlineAction;
@@ -48,8 +48,8 @@
   }
 
   @Override
-  public boolean verifyTypes(AppInfo appInfo, GraphLense graphLense) {
-    assert super.verifyTypes(appInfo, graphLense);
+  public boolean verifyTypes(AppView<? extends AppInfo> appView) {
+    assert super.verifyTypes(appView);
 
     TypeLatticeElement receiverType = getReceiver().getTypeLattice();
     assert receiverType.isPreciseType();
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java
index 0c0171f..13a8473 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.cf.code.CfMultiANewArray;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.type.Nullability;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
@@ -67,8 +68,8 @@
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
-    return TypeLatticeElement.fromDexType(type, Nullability.definitelyNotNull(), appInfo);
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
+    return TypeLatticeElement.fromDexType(type, Nullability.definitelyNotNull(), appView);
   }
 
   @Override
@@ -77,7 +78,8 @@
   }
 
   @Override
-  public DexType computeVerificationType(TypeVerificationHelper helper) {
+  public DexType computeVerificationType(
+      AppView<? extends AppInfo> appView, TypeVerificationHelper helper) {
     return type;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java b/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
index fbb7307..f89ccf6 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.code.FilledNewArrayRange;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.type.Nullability;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
@@ -97,8 +98,8 @@
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
-    return TypeLatticeElement.fromDexType(type, Nullability.definitelyNotNull(), appInfo);
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
+    return TypeLatticeElement.fromDexType(type, Nullability.definitelyNotNull(), appView);
   }
 
   @Override
@@ -107,7 +108,8 @@
   }
 
   @Override
-  public DexType computeVerificationType(TypeVerificationHelper helper) {
+  public DexType computeVerificationType(
+      AppView<? extends AppInfo> appView, TypeVerificationHelper helper) {
     throw cfUnsupported();
   }
 
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 4b9ff7d..cbc0e7c 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
@@ -80,7 +80,7 @@
   @Override
   public void buildCf(CfBuilder builder) {
     DexMethod dexMethod = getInvokedMethod();
-    DexItemFactory factory = builder.getFactory();
+    DexItemFactory factory = builder.appView.dexItemFactory();
     // When we translate InvokeVirtual on MethodHandle/VarHandle into InvokePolymorphic,
     // we translate the invoked prototype into a generic prototype that simply accepts Object[].
     // To translate InvokePolymorphic back into InvokeVirtual, use the original prototype
diff --git a/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionIterator.java b/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionIterator.java
index e8bbd69..01c66a8 100644
--- a/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionIterator.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.ir.code;
 
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import java.util.List;
 import java.util.ListIterator;
@@ -46,14 +47,14 @@
 
   @Override
   public BasicBlock inlineInvoke(
-      AppInfo appInfo,
+      AppView<? extends AppInfo> appView,
       IRCode code,
       IRCode inlinee,
       ListIterator<BasicBlock> blockIterator,
       List<BasicBlock> blocksToRemove,
       DexType downcast) {
     return currentBlockIterator.inlineInvoke(
-        appInfo, code, inlinee, blockIterator, blocksToRemove, downcast);
+        appView, code, inlinee, blockIterator, blocksToRemove, downcast);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/Load.java b/src/main/java/com/android/tools/r8/ir/code/Load.java
index 0b93773..4229b41 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Load.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Load.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.conversion.CfBuilder;
@@ -69,7 +70,8 @@
   }
 
   @Override
-  public DexType computeVerificationType(TypeVerificationHelper helper) {
+  public DexType computeVerificationType(
+      AppView<? extends AppInfo> appView, TypeVerificationHelper helper) {
     return helper.getDexType(src());
   }
 
@@ -79,7 +81,7 @@
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
     return src().getTypeLattice();
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/Move.java b/src/main/java/com/android/tools/r8/ir/code/Move.java
index 8892a52..53c0134 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Move.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Move.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.conversion.CfBuilder;
@@ -94,7 +95,7 @@
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
     return src().getTypeLattice();
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/MoveException.java b/src/main/java/com/android/tools/r8/ir/code/MoveException.java
index 96d5186..3ccd8b0 100644
--- a/src/main/java/com/android/tools/r8/ir/code/MoveException.java
+++ b/src/main/java/com/android/tools/r8/ir/code/MoveException.java
@@ -97,14 +97,14 @@
   }
 
   @Override
-  public DexType computeVerificationType(TypeVerificationHelper helper) {
+  public DexType computeVerificationType(
+      AppView<? extends AppInfo> appView, TypeVerificationHelper helper) {
     return exceptionType;
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
-    return TypeLatticeElement.fromDexType(
-        exceptionType, Nullability.definitelyNotNull(), appInfo);
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
+    return TypeLatticeElement.fromDexType(exceptionType, Nullability.definitelyNotNull(), appView);
   }
 
   public DexType getExceptionType() {
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java b/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
index a8bcea2..641b77e 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
@@ -108,7 +108,8 @@
   }
 
   @Override
-  public DexType computeVerificationType(TypeVerificationHelper helper) {
+  public DexType computeVerificationType(
+      AppView<? extends AppInfo> appView, TypeVerificationHelper helper) {
     return type;
   }
 
@@ -125,7 +126,7 @@
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
-    return TypeLatticeElement.fromDexType(type, Nullability.definitelyNotNull(), appInfo);
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
+    return TypeLatticeElement.fromDexType(type, Nullability.definitelyNotNull(), appView);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
index b5401b0..13263d9 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
@@ -100,13 +100,14 @@
   }
 
   @Override
-  public DexType computeVerificationType(TypeVerificationHelper helper) {
+  public DexType computeVerificationType(
+      AppView<? extends AppInfo> appView, TypeVerificationHelper helper) {
     return clazz;
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
-    return TypeLatticeElement.fromDexType(clazz, Nullability.definitelyNotNull(), appInfo);
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
+    return TypeLatticeElement.fromDexType(clazz, Nullability.definitelyNotNull(), appView);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/NonNull.java b/src/main/java/com/android/tools/r8/ir/code/NonNull.java
index 6b016b7..81e69f1 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NonNull.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NonNull.java
@@ -6,6 +6,7 @@
 import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.conversion.CfBuilder;
@@ -98,7 +99,7 @@
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
     return src().getTypeLattice().asNonNullable();
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/NumberConversion.java b/src/main/java/com/android/tools/r8/ir/code/NumberConversion.java
index 4e1e0ed..2b38cba 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NumberConversion.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NumberConversion.java
@@ -21,6 +21,7 @@
 import com.android.tools.r8.code.LongToInt;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.ir.analysis.type.PrimitiveTypeLatticeElement;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.conversion.CfBuilder;
@@ -142,7 +143,7 @@
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
     return PrimitiveTypeLatticeElement.fromNumericType(to);
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/Phi.java b/src/main/java/com/android/tools/r8/ir/code/Phi.java
index 812f928..5e2160f 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Phi.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Phi.java
@@ -6,8 +6,8 @@
 import com.android.tools.r8.cf.TypeVerificationHelper;
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.errors.InvalidDebugInfoException;
-import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.DebugLocalInfo;
+import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.code.BasicBlock.EdgeType;
@@ -410,10 +410,10 @@
   }
 
   // Type of phi(v1, v2, ..., vn) is the least upper bound of all those n operands.
-  public TypeLatticeElement computePhiType(AppInfo appInfo) {
+  public TypeLatticeElement computePhiType(DexDefinitionSupplier definitions) {
     TypeLatticeElement result = TypeLatticeElement.BOTTOM;
     for (Value operand : getOperands()) {
-      result = result.join(operand.getTypeLattice(), appInfo);
+      result = result.join(operand.getTypeLattice(), definitions);
     }
     return result;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/StackValue.java b/src/main/java/com/android/tools/r8/ir/code/StackValue.java
index 20f10a4..18019dc 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StackValue.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StackValue.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.cf.TypeVerificationHelper.TypeInfo;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.ir.analysis.type.Nullability;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 
@@ -20,10 +21,13 @@
     assert height >= 0;
   }
 
-  public static StackValue create(TypeInfo typeInfo, int height, AppInfo appInfo) {
+  public static StackValue create(
+      TypeInfo typeInfo, int height, AppView<? extends AppInfo> appView) {
     return new StackValue(
-        typeInfo, TypeLatticeElement.fromDexType(
-            typeInfo.getDexType(), Nullability.maybeNull(), appInfo), height);
+        typeInfo,
+        TypeLatticeElement.fromDexType(
+            typeInfo.getDexType(), Nullability.maybeNull(), appView.appInfo()),
+        height);
   }
 
   public int getHeight() {
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticGet.java b/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
index f4b0beb..6358853 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
@@ -175,13 +175,14 @@
   }
 
   @Override
-  public DexType computeVerificationType(TypeVerificationHelper helper) {
+  public DexType computeVerificationType(
+      AppView<? extends AppInfo> appView, TypeVerificationHelper helper) {
     return getField().type;
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
-    return TypeLatticeElement.fromDexType(getField().type, Nullability.maybeNull(), appInfo);
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
+    return TypeLatticeElement.fromDexType(getField().type, Nullability.maybeNull(), appView);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/Store.java b/src/main/java/com/android/tools/r8/ir/code/Store.java
index f09107f..2058ba0 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Store.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Store.java
@@ -70,7 +70,8 @@
   }
 
   @Override
-  public DexType computeVerificationType(TypeVerificationHelper helper) {
+  public DexType computeVerificationType(
+      AppView<? extends AppInfo> appView, TypeVerificationHelper helper) {
     return helper.getDexType(src());
   }
 
@@ -80,7 +81,7 @@
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
     return src().getTypeLattice();
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/Unop.java b/src/main/java/com/android/tools/r8/ir/code/Unop.java
index 5ac4668..98083c8 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Unop.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Unop.java
@@ -6,6 +6,7 @@
 import com.android.tools.r8.cf.LoadStoreHelper;
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
@@ -58,7 +59,7 @@
   }
 
   @Override
-  public TypeLatticeElement evaluate(AppInfo appInfo) {
+  public TypeLatticeElement evaluate(AppView<? extends AppInfo> appView) {
     return source().getTypeLattice();
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/code/Value.java b/src/main/java/com/android/tools/r8/ir/code/Value.java
index 3b783d9..9cbdd34 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Value.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Value.java
@@ -892,7 +892,7 @@
         && getConstInstruction().asConstNumber().isZero();
   }
 
-  public void widening(AppInfo appInfo, TypeLatticeElement newType) {
+  public void widening(AppView<? extends AppInfo> appView, TypeLatticeElement newType) {
     // TODO(b/72693244): Enable assertion.
     // During WIDENING (due to fix-point iteration), type update is monotonically upwards,
     //   i.e., towards something wider.
@@ -902,7 +902,7 @@
     typeLattice = newType;
   }
 
-  public void narrowing(AppInfo appInfo, TypeLatticeElement newType) {
+  public void narrowing(AppView<? extends AppInfo> appView, TypeLatticeElement newType) {
     // TODO(b/72693244): Enable assertion.
     // During NARROWING (e.g., after inlining), type update is monotonically downwards,
     //   i.e., towards something narrower, with more specific type info.
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java b/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java
index e9c825d..ab1e319 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java
@@ -567,7 +567,7 @@
     private void processFieldAccess(DexField field) {
       // Any field access implicitly calls the class initializer.
       if (field.clazz.isClassType()) {
-        DexEncodedField encodedField = appInfo.resolveFieldOn(field.clazz, field);
+        DexEncodedField encodedField = appInfo.resolveField(field);
         if (encodedField != null && encodedField.isStatic()) {
           addClassInitializerTarget(field.getHolder());
         }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
index 743f2a5..c9e30e2 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
@@ -19,16 +19,16 @@
 import com.android.tools.r8.cf.code.CfTryCatch;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCode.LocalVariableInfo;
 import com.android.tools.r8.graph.DebugLocalInfo;
 import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexDefinitionSupplier;
 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.graph.DexType;
-import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.code.Argument;
 import com.android.tools.r8.ir.code.BasicBlock;
@@ -52,7 +52,6 @@
 import com.android.tools.r8.ir.optimize.PeepholeOptimizer;
 import com.android.tools.r8.ir.optimize.PhiOptimizations;
 import com.android.tools.r8.ir.optimize.peepholes.BasicBlockMuncher;
-import com.android.tools.r8.utils.InternalOptions;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceMap.Entry;
@@ -76,11 +75,10 @@
   private static final int SUFFIX_SHARING_OVERHEAD = 30;
   private static final int IINC_PATTERN_SIZE = 4;
 
-  private final DexItemFactory factory;
+  public final AppView<? extends AppInfo> appView;
   private final DexEncodedMethod method;
   private final IRCode code;
 
-  private TypeVerificationHelper typeVerificationHelper;
   private Map<BasicBlock, CfLabel> labels;
   private Set<CfLabel> emittedLabels;
   private List<CfInstruction> instructions;
@@ -97,14 +95,10 @@
   private final Int2ReferenceMap<LocalVariableInfo> openLocalVariables =
       new Int2ReferenceOpenHashMap<>();
 
-  private AppInfo appInfo;
-
   private Map<NewInstance, List<InvokeDirect>> initializers;
   private List<InvokeDirect> thisInitializers;
   private Map<NewInstance, CfLabel> newInstanceLabels;
 
-  private InternalOptions options;
-
   // Internal structure maintaining the stack height.
   private static class StackHeightTracker {
     int maxHeight = 0;
@@ -131,32 +125,22 @@
     }
   }
 
-  public CfBuilder(DexEncodedMethod method, IRCode code, DexItemFactory factory) {
+  public CfBuilder(AppView<? extends AppInfo> appView, DexEncodedMethod method, IRCode code) {
+    this.appView = appView;
     this.method = method;
     this.code = code;
-    this.factory = factory;
   }
 
-  public DexItemFactory getFactory() {
-    return factory;
-  }
-
-  public CfCode build(
-      CodeRewriter rewriter,
-      GraphLense graphLense,
-      InternalOptions options,
-      AppInfo appInfo) {
-    this.options = options;
-    this.appInfo = appInfo;
+  public CfCode build(CodeRewriter rewriter) {
     computeInitializers();
-    typeVerificationHelper = new TypeVerificationHelper(code, factory, appInfo);
+    TypeVerificationHelper typeVerificationHelper = new TypeVerificationHelper(appView, code);
     typeVerificationHelper.computeVerificationTypes();
     rewriter.converter.deadCodeRemover.run(code);
     rewriteNots();
-    LoadStoreHelper loadStoreHelper = new LoadStoreHelper(code, typeVerificationHelper, appInfo);
+    LoadStoreHelper loadStoreHelper = new LoadStoreHelper(appView, code, typeVerificationHelper);
     loadStoreHelper.insertLoadsAndStores();
     // Run optimizations on phis and basic blocks in a fixpoint.
-    if (!options.testing.disallowLoadStoreOptimization) {
+    if (!appView.options().testing.disallowLoadStoreOptimization) {
       PhiOptimizations phiOptimizations = new PhiOptimizations();
       boolean reachedFixpoint = false;
       phiOptimizations.optimize(code);
@@ -166,7 +150,7 @@
       }
     }
     assert code.isConsistentSSA();
-    registerAllocator = new CfRegisterAllocator(code, options, typeVerificationHelper);
+    registerAllocator = new CfRegisterAllocator(appView, code, typeVerificationHelper);
     registerAllocator.allocateRegisters();
     loadStoreHelper.insertPhiMoves(registerAllocator);
 
@@ -181,16 +165,16 @@
     CodeRewriter.collapseTrivialGotos(method, code);
     DexBuilder.removeRedundantDebugPositions(code);
     CfCode code = buildCfCode();
-    assert verifyInvokeInterface(code, appInfo);
+    assert verifyInvokeInterface(code, appView);
     return code;
   }
 
-  private static boolean verifyInvokeInterface(CfCode code, AppInfo appInfo) {
+  private static boolean verifyInvokeInterface(CfCode code, DexDefinitionSupplier definitions) {
     for (CfInstruction instruction : code.instructions) {
       if (instruction instanceof CfInvoke) {
         CfInvoke invoke = (CfInvoke) instruction;
         if (invoke.getMethod().holder.isClassType()) {
-          DexClass holder = appInfo.definitionFor(invoke.getMethod().holder);
+          DexClass holder = definitions.definitionFor(invoke.getMethod().holder);
           assert holder == null || holder.isInterface() == invoke.isInterface();
         }
       }
@@ -199,7 +183,7 @@
   }
 
   public DexField resolveField(DexField field) {
-    DexEncodedField resolvedField = appInfo.resolveFieldOn(field.clazz, field);
+    DexEncodedField resolvedField = appView.appInfo().resolveField(field);
     return resolvedField == null ? field : resolvedField.field;
   }
 
@@ -229,7 +213,8 @@
     for (Instruction user : value.uniqueUsers()) {
       if (user instanceof InvokeDirect
           && user.inValues().get(0) == value
-          && user.asInvokeDirect().getInvokedMethod().name == factory.constructorMethodName) {
+          && user.asInvokeDirect().getInvokedMethod().name
+              == appView.dexItemFactory().constructorMethodName) {
         initializers.add(user.asInvokeDirect());
       }
     }
@@ -488,7 +473,7 @@
             // Ignore synthetic positions prior to any actual position, except when inlined
             // (that is, callerPosition != null).
             && !(currentPosition.isNone() && position.synthetic && position.callerPosition == null)
-            && (options.debug || instruction.instructionTypeCanThrow());
+            && (appView.options().debug || instruction.instructionTypeCanThrow());
     if (!didLocalsChange && !didPositionChange) {
       return;
     }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
index 661d3e9..25d1b39 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
@@ -15,6 +15,8 @@
 import com.android.tools.r8.cf.code.CfSwitch;
 import com.android.tools.r8.cf.code.CfThrow;
 import com.android.tools.r8.cf.code.CfTryCatch;
+import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCode.LocalVariableInfo;
 import com.android.tools.r8.graph.DebugLocalInfo;
@@ -265,9 +267,11 @@
   @Override
   public int traceInstruction(int instructionIndex, IRBuilder builder) {
     CfInstruction instruction = code.getInstructions().get(instructionIndex);
-    assert builder.isGeneratingClassFiles() == internalOutputMode.isGeneratingClassFiles();
+    AppView<? extends AppInfo> appView = builder.appView;
+    assert appView.options().isGeneratingClassFiles()
+        == internalOutputMode.isGeneratingClassFiles();
     if (canThrowHelper(instruction)) {
-      TryHandlerList tryHandlers = getTryHandlers(instructionIndex, builder.getFactory());
+      TryHandlerList tryHandlers = getTryHandlers(instructionIndex, appView.dexItemFactory());
       if (!tryHandlers.isEmpty()) {
         // Ensure the block starts at the start of the try-range (don't enqueue, not a target).
         builder.ensureBlockWithoutEnqueuing(tryHandlers.startOffset);
@@ -366,8 +370,7 @@
         builder.addBooleanNonThisArgument(argumentRegister++);
       } else {
         TypeLatticeElement typeLattice =
-            TypeLatticeElement.fromDexType(
-                type, Nullability.maybeNull(), builder.getAppInfo());
+            TypeLatticeElement.fromDexType(type, Nullability.maybeNull(), builder.appView);
         builder.addNonThisArgument(argumentRegister, typeLattice);
         argumentRegister += typeLattice.requiredRegisters();
       }
@@ -442,7 +445,7 @@
 
     if (canThrowHelper(instruction)) {
       Snapshot exceptionTransfer =
-          state.getSnapshot().exceptionTransfer(builder.getFactory().throwableType);
+          state.getSnapshot().exceptionTransfer(builder.appView.dexItemFactory().throwableType);
       for (int target : currentBlockInfo.exceptionalSuccessors) {
         recordStateForTarget(target, exceptionTransfer);
       }
@@ -626,7 +629,8 @@
   @Override
   public CatchHandlers<Integer> getCurrentCatchHandlers(IRBuilder builder) {
     TryHandlerList tryHandlers =
-        getTryHandlers(instructionOffset(currentInstructionIndex), builder.getFactory());
+        getTryHandlers(
+            instructionOffset(currentInstructionIndex), builder.appView.dexItemFactory());
     if (tryHandlers.isEmpty()) {
       return null;
     }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
index 0790018..373949e 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/DexSourceCode.java
@@ -27,7 +27,6 @@
 import com.android.tools.r8.code.MoveResultWide;
 import com.android.tools.r8.code.SwitchPayload;
 import com.android.tools.r8.code.Throw;
-import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.DebugLocalInfo;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.DexCode.Try;
@@ -79,11 +78,7 @@
   private final DexMethod originalMethod;
 
   public DexSourceCode(
-      DexCode code,
-      DexEncodedMethod method,
-      DexMethod originalMethod,
-      Position callerPosition,
-      AppInfo appInfo) {
+      DexCode code, DexEncodedMethod method, DexMethod originalMethod, Position callerPosition) {
     this.code = code;
     this.method = method;
     this.originalMethod = originalMethod;
@@ -172,7 +167,7 @@
       if (nextRemovedArgument != null && nextRemovedArgument.getArgumentIndex() == argumentIndex) {
         type =
             TypeLatticeElement.fromDexType(
-                nextRemovedArgument.getType(), Nullability.maybeNull(), builder.getAppInfo());
+                nextRemovedArgument.getType(), Nullability.maybeNull(), builder.appView);
         builder.addConstantOrUnusedArgument(register);
         nextRemovedArgument =
             removedArgumentIterator.hasNext() ? removedArgumentIterator.next() : null;
@@ -181,7 +176,7 @@
             TypeLatticeElement.fromDexType(
                 method.method.proto.parameters.values[usedArgumentIndex++],
                 Nullability.maybeNull(),
-                builder.getAppInfo());
+                builder.appView);
         builder.addNonThisArgument(register, type);
       }
       register += type.requiredRegisters();
@@ -203,7 +198,7 @@
   @Override
   public void buildInstruction(
       IRBuilder builder, int instructionIndex, boolean firstBlockInstruction) {
-    updateCurrentCatchHandlers(instructionIndex, builder.getFactory());
+    updateCurrentCatchHandlers(instructionIndex, builder.appView.dexItemFactory());
     updateDebugPosition(instructionIndex, builder);
     currentDexInstruction = code.instructions[instructionIndex];
     currentDexInstruction.buildIR(builder);
@@ -390,7 +385,8 @@
         }
         builder.ensureBlockWithoutEnqueuing(tryRangeStartAddress);
         // Edge to exceptional successors.
-        for (Integer handlerOffset : getUniqueTryHandlerOffsets(tryRange, builder.getFactory())) {
+        for (Integer handlerOffset :
+            getUniqueTryHandlerOffsets(tryRange, builder.appView.dexItemFactory())) {
           builder.ensureExceptionalSuccessorBlock(offset, handlerOffset);
         }
         // If the following instruction is a move-result include it in this (the invokes) block.
@@ -470,12 +466,7 @@
 
   private List<Integer> getTryHandlerOffsets(Try tryRange, DexItemFactory factory) {
     List<Integer> handlerOffsets = new ArrayList<>();
-    forEachTryRange(
-        tryRange,
-        factory,
-        (type, addr) -> {
-          handlerOffsets.add(addr);
-        });
+    forEachTryRange(tryRange, factory, (type, addr) -> handlerOffsets.add(addr));
     return handlerOffsets;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index 2e22480..0d7f6e1 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -13,12 +13,12 @@
 import com.android.tools.r8.errors.InvalidDebugInfoException;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DebugLocalInfo;
 import com.android.tools.r8.graph.DexCallSite;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexItem;
-import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexMethodHandle;
 import com.android.tools.r8.graph.DexProto;
@@ -102,7 +102,6 @@
 import com.android.tools.r8.logging.Log;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.IteratorUtils;
 import com.android.tools.r8.utils.Pair;
 import com.google.common.collect.Sets;
@@ -136,6 +135,7 @@
  * http://compilers.cs.uni-saarland.de/papers/bbhlmz13cc.pdf
  */
 public class IRBuilder {
+
   private static final TypeLatticeElement INT = TypeLatticeElement.INT;
   private static final TypeLatticeElement FLOAT = TypeLatticeElement.FLOAT;
   private static final TypeLatticeElement LONG = TypeLatticeElement.LONG;
@@ -170,16 +170,8 @@
     }
   }
 
-  public DexItemFactory getFactory() {
-    return options.itemFactory;
-  }
-
-  public AppInfo getAppInfo() {
-    return appInfo;
-  }
-
   public TypeLatticeElement getTypeLattice(DexType type, Nullability nullability) {
-    return TypeLatticeElement.fromDexType(type, nullability, appInfo);
+    return TypeLatticeElement.fromDexType(type, nullability, appView);
   }
 
   // SSA construction uses a worklist of basic blocks reachable from the entry and their
@@ -394,7 +386,7 @@
   final private ValueNumberGenerator valueNumberGenerator;
   private final DexEncodedMethod method;
   private DexEncodedMethod context;
-  private final AppInfo appInfo;
+  public final AppView<? extends AppInfo> appView;
   private final Origin origin;
   final RewrittenPrototypeDescription prototypeChanges;
   private ListIterator<RemovedArgumentInfo> removedArgumentsIterator;
@@ -406,7 +398,6 @@
   private SourceCode source;
 
   private boolean throwingInstructionInCurrentBlock = false;
-  private final InternalOptions options;
 
   // Pending local reads.
   private Value previousLocalValue = null;
@@ -431,44 +422,33 @@
 
   public IRBuilder(
       DexEncodedMethod method,
-      AppInfo appInfo,
+      AppView<? extends AppInfo> appView,
       SourceCode source,
-      InternalOptions options,
       Origin origin) {
-    this(
-        method,
-        appInfo,
-        source,
-        options,
-        origin,
-        new ValueNumberGenerator(),
-        GraphLense.getIdentityLense());
+    this(method, appView, source, origin, new ValueNumberGenerator());
   }
 
   public IRBuilder(
       DexEncodedMethod method,
-      AppInfo appInfo,
+      AppView<? extends AppInfo> appView,
       SourceCode source,
-      InternalOptions options,
       Origin origin,
-      ValueNumberGenerator valueNumberGenerator,
-      GraphLense graphLense) {
+      ValueNumberGenerator valueNumberGenerator) {
     assert source != null;
     this.method = method;
-    this.appInfo = appInfo;
+    this.appView = appView;
     this.source = source;
     this.valueNumberGenerator =
         valueNumberGenerator != null ? valueNumberGenerator : new ValueNumberGenerator();
-    this.options = options;
     this.origin = origin;
 
     if (method.isProcessed()) {
       // NOTE: This is currently assuming that we never remove additional arguments from methods
       // after they have already been processed once.
-      assert verifyMethodSignature(method, graphLense);
+      assert verifyMethodSignature(method, appView.graphLense());
       this.prototypeChanges = RewrittenPrototypeDescription.none();
     } else {
-      this.prototypeChanges = graphLense.lookupPrototypeChanges(method.method);
+      this.prototypeChanges = appView.graphLense().lookupPrototypeChanges(method.method);
 
       if (Log.ENABLED && prototypeChanges.getRemovedArgumentsInfo().hasRemovedArguments()) {
         Log.info(
@@ -490,12 +470,8 @@
     return true;
   }
 
-  public boolean isGeneratingClassFiles() {
-    return options.isGeneratingClassFiles();
-  }
-
   public boolean isDebugMode() {
-    return options.debug || method.getOptimizationInfo().isReachabilitySensitive();
+    return appView.options().debug || method.getOptimizationInfo().isReachabilitySensitive();
   }
 
   public Int2ReferenceSortedMap<BlockInfo> getCFG() {
@@ -618,7 +594,7 @@
     // Package up the IR code.
     IRCode ir =
         new IRCode(
-            options,
+            appView.options(),
             method,
             blocks,
             valueNumberGenerator,
@@ -641,10 +617,9 @@
     if (hasImpreciseValues || impreciseInstructions != null) {
       // In DEX we may need to constrain all values and instructions to precise types.
       assert source instanceof DexSourceCode;
-      new TypeConstraintResolver(this, options.reporter)
-          .resolve(impreciseInstructions, ir, appInfo, method, context);
+      new TypeConstraintResolver(appView, this).resolve(impreciseInstructions, ir, method, context);
     } else {
-      new TypeAnalysis(appInfo, context).widening(method, ir);
+      new TypeAnalysis(appView, context).widening(method, ir);
     }
 
     assert ir.isConsistentSSA();
@@ -656,7 +631,7 @@
   }
 
   public void constrainType(Value value, ValueTypeConstraint constraint) {
-    value.constrainType(constraint, method.method, origin, options.reporter);
+    value.constrainType(constraint, method.method, origin, appView.options().reporter);
   }
 
   private void addImpreciseInstruction(ImpreciseMemberTypeInstruction instruction) {
@@ -819,9 +794,10 @@
     Position position = source.getCanonicalDebugPositionAtOffset(moveExceptionItem.targetOffset);
     if (moveExceptionDest >= 0) {
       TypeLatticeElement typeLattice =
-          TypeLatticeElement.fromDexType(moveExceptionItem.guard, definitelyNotNull(), appInfo);
+          TypeLatticeElement.fromDexType(moveExceptionItem.guard, definitelyNotNull(), appView);
       Value out = writeRegister(moveExceptionDest, typeLattice, ThrowingInfo.NO_THROW, null);
-      MoveException moveException = new MoveException(out, moveExceptionItem.guard, options);
+      MoveException moveException =
+          new MoveException(out, moveExceptionItem.guard, appView.options());
       moveException.setPosition(position);
       currentBlock.add(moveException);
     }
@@ -882,7 +858,7 @@
     boolean receiverCouldBeNull = context != null && context != method;
     Nullability nullability = receiverCouldBeNull ? maybeNull() : definitelyNotNull();
     TypeLatticeElement receiver =
-        TypeLatticeElement.fromDexType(method.method.getHolder(), nullability, appInfo);
+        TypeLatticeElement.fromDexType(method.method.getHolder(), nullability, appView);
     Value value = writeRegister(register, receiver, ThrowingInfo.NO_THROW, local);
     addInstruction(new Argument(value));
     value.markAsThis();
@@ -1065,7 +1041,7 @@
   public void addCheckCast(int value, DexType type) {
     Value in = readRegister(value, ValueTypeConstraint.OBJECT);
     TypeLatticeElement castTypeLattice =
-        TypeLatticeElement.fromDexType(type, in.getTypeLattice().nullability(), appInfo);
+        TypeLatticeElement.fromDexType(type, in.getTypeLattice().nullability(), appView);
     Value out = writeRegister(value, castTypeLattice, ThrowingInfo.CAN_THROW);
     CheckCast instruction = new CheckCast(out, in, type);
     assert instruction.instructionTypeCanThrow();
@@ -1110,7 +1086,7 @@
 
   public void addConstClass(int dest, DexType type) {
     TypeLatticeElement typeLattice =
-        TypeLatticeElement.classClassType(appInfo, definitelyNotNull());
+        TypeLatticeElement.classClassType(appView, definitelyNotNull());
     Value out = writeRegister(dest, typeLattice, ThrowingInfo.CAN_THROW);
     ConstClass instruction = new ConstClass(out, type);
     assert instruction.instructionTypeCanThrow();
@@ -1118,7 +1094,7 @@
   }
 
   public void addConstMethodHandle(int dest, DexMethodHandle methodHandle) {
-    if (!options.canUseConstantMethodHandle()) {
+    if (!appView.options().canUseConstantMethodHandle()) {
       throw new ApiLevelException(
           AndroidApiLevel.P,
           "Const-method-handle",
@@ -1126,14 +1102,14 @@
     }
     TypeLatticeElement typeLattice =
         TypeLatticeElement.fromDexType(
-            appInfo.dexItemFactory.methodHandleType, definitelyNotNull(), appInfo);
+            appView.dexItemFactory().methodHandleType, definitelyNotNull(), appView);
     Value out = writeRegister(dest, typeLattice, ThrowingInfo.CAN_THROW);
     ConstMethodHandle instruction = new ConstMethodHandle(out, methodHandle);
     add(instruction);
   }
 
   public void addConstMethodType(int dest, DexProto methodType) {
-    if (!options.canUseConstantMethodType()) {
+    if (!appView.options().canUseConstantMethodType()) {
       throw new ApiLevelException(
           AndroidApiLevel.P,
           "Const-method-type",
@@ -1141,19 +1117,21 @@
     }
     TypeLatticeElement typeLattice =
         TypeLatticeElement.fromDexType(
-            appInfo.dexItemFactory.methodTypeType, definitelyNotNull(), appInfo);
+            appView.dexItemFactory().methodTypeType, definitelyNotNull(), appView);
     Value out = writeRegister(dest, typeLattice, ThrowingInfo.CAN_THROW);
     ConstMethodType instruction = new ConstMethodType(out, methodType);
     add(instruction);
   }
 
   private ThrowingInfo throwingInfoForConstStrings() {
-    return options.isGeneratingClassFiles() ? ThrowingInfo.NO_THROW : ThrowingInfo.CAN_THROW;
+    return appView.options().isGeneratingClassFiles()
+        ? ThrowingInfo.NO_THROW
+        : ThrowingInfo.CAN_THROW;
   }
 
   public void addConstString(int dest, DexString string) {
     TypeLatticeElement typeLattice =
-        TypeLatticeElement.stringClassType(appInfo, definitelyNotNull());
+        TypeLatticeElement.stringClassType(appView, definitelyNotNull());
     ThrowingInfo throwingInfo = throwingInfoForConstStrings();
     add(new ConstString(writeRegister(dest, typeLattice, throwingInfo), string, throwingInfo));
   }
@@ -1161,7 +1139,7 @@
   public void addDexItemBasedConstString(int dest, DexReference item) {
     assert method.getOptimizationInfo().useIdentifierNameString();
     TypeLatticeElement typeLattice =
-        TypeLatticeElement.stringClassType(appInfo, definitelyNotNull());
+        TypeLatticeElement.stringClassType(appView, definitelyNotNull());
     ThrowingInfo throwingInfo = throwingInfoForConstStrings();
     Value out = writeRegister(dest, typeLattice, throwingInfo);
     DexItemBasedConstString instruction = new DexItemBasedConstString(out, item, throwingInfo);
@@ -1347,11 +1325,12 @@
 
   public void addInstanceGet(int dest, int object, DexField field) {
     Value in = readRegister(object, ValueTypeConstraint.OBJECT);
-    Value out = writeRegister(
-        dest,
-        TypeLatticeElement.fromDexType(field.type, maybeNull(), appInfo),
-        ThrowingInfo.CAN_THROW);
-    out.setKnownToBeBoolean(field.type == getFactory().booleanType);
+    Value out =
+        writeRegister(
+            dest,
+            TypeLatticeElement.fromDexType(field.type, maybeNull(), appView),
+            ThrowingInfo.CAN_THROW);
+    out.setKnownToBeBoolean(field.type == appView.dexItemFactory().booleanType);
     InstanceGet instruction = new InstanceGet(out, in, field);
     assert instruction.instructionTypeCanThrow();
     addInstruction(instruction);
@@ -1376,27 +1355,27 @@
       Type type, DexItem item, DexProto callSiteProto, List<Value> arguments, boolean itf) {
     if (type == Type.POLYMORPHIC) {
       assert item instanceof DexMethod;
-      if (!options.canUseInvokePolymorphic()) {
+      if (!appView.options().canUseInvokePolymorphic()) {
         throw new ApiLevelException(
             AndroidApiLevel.O,
             "MethodHandle.invoke and MethodHandle.invokeExact",
             null /* sourceString */);
-      } else if (!options.canUseInvokePolymorphicOnVarHandle()
-          && ((DexMethod) item).getHolder() == options.itemFactory.varHandleType) {
+      } else if (!appView.options().canUseInvokePolymorphicOnVarHandle()
+          && ((DexMethod) item).getHolder() == appView.dexItemFactory().varHandleType) {
         throw new ApiLevelException(
             AndroidApiLevel.P,
             "Call to polymorphic signature of VarHandle",
             null /* sourceString */);
       }
     }
-    if (appInfo != null && type == Type.VIRTUAL) {
+    if (type == Type.VIRTUAL) {
       // If an invoke-virtual targets a private method in the current class overriding will
       // not apply (see jvm spec on method resolution 5.4.3.3 and overriding 5.4.5) and
       // therefore we use an invoke-direct instead. We need to do this as the Android Runtime
       // will not allow invoke-virtual of a private method.
       DexMethod invocationMethod = (DexMethod) item;
       if (invocationMethod.holder == method.method.holder) {
-        DexEncodedMethod directTarget = appInfo.lookupDirectTarget(invocationMethod);
+        DexEncodedMethod directTarget = appView.appInfo().lookupDirectTarget(invocationMethod);
         if (directTarget != null && invocationMethod.holder == directTarget.method.holder) {
           type = Type.DIRECT;
         }
@@ -1506,7 +1485,7 @@
     }
     checkInvokeArgumentRegisters(registerIndex, argumentRegisterCount);
     // Note: We only call this register variant from DEX inputs where isInterface does not matter.
-    assert !isGeneratingClassFiles();
+    assert appView.options().isGeneratingDex();
     addInvoke(type, method, callSiteProto, arguments, false /* isInterface */);
   }
 
@@ -1531,7 +1510,7 @@
   }
 
   public void addMultiNewArray(DexType type, int dest, int[] dimensions) {
-    assert isGeneratingClassFiles();
+    assert appView.options().isGeneratingClassFiles();
     List<Value> arguments = new ArrayList<>(dimensions.length);
     for (int dimension : dimensions) {
       arguments.add(readRegister(dimension, ValueTypeConstraint.INT));
@@ -1571,7 +1550,7 @@
     }
     checkInvokeArgumentRegisters(register, firstArgumentRegister + argumentCount);
     // Note: We only call this register variant from DEX inputs where isInterface does not matter.
-    assert !isGeneratingClassFiles();
+    assert appView.options().isGeneratingDex();
     addInvoke(type, method, callSiteProto, arguments, false /* isInterface */);
   }
 
@@ -1589,7 +1568,7 @@
     }
     checkInvokeArgumentRegisters(register, firstArgumentRegister + argumentCount);
     // Note: We only call this register variant from DEX inputs where isInterface does not matter.
-    assert !isGeneratingClassFiles();
+    assert appView.options().isGeneratingDex();
     addInvoke(Invoke.Type.NEW_ARRAY, type, null, arguments, false /* isInterface */);
   }
 
@@ -1630,7 +1609,7 @@
     Value outValue =
         writeRegister(
             dest,
-            TypeLatticeElement.fromDexType(outType, maybeNull(), appInfo),
+            TypeLatticeElement.fromDexType(outType, maybeNull(), appView),
             ThrowingInfo.CAN_THROW);
     outValue.setKnownToBeBoolean(outType.isBooleanType());
     invoke.setOutValue(outValue);
@@ -1648,7 +1627,7 @@
     Value in = readNumericRegister(value, type);
     Value out = writeNumericRegister(dest, type, ThrowingInfo.NO_THROW);
     Instruction instruction;
-    if (options.canUseNotInstruction()) {
+    if (appView.options().canUseNotInstruction()) {
       instruction = new Not(type, out, in);
     } else {
       Value minusOne = readLiteral(ValueTypeConstraint.fromNumericType(type), -1);
@@ -1662,7 +1641,7 @@
     assert type.isArrayType();
     Value in = readRegister(size, ValueTypeConstraint.INT);
     TypeLatticeElement arrayTypeLattice =
-        TypeLatticeElement.fromDexType(type, definitelyNotNull(), appInfo);
+        TypeLatticeElement.fromDexType(type, definitelyNotNull(), appView);
     Value out = writeRegister(dest, arrayTypeLattice, ThrowingInfo.CAN_THROW);
     NewArrayEmpty instruction = new NewArrayEmpty(out, in, type);
     assert instruction.instructionTypeCanThrow();
@@ -1679,7 +1658,7 @@
 
   public void addNewInstance(int dest, DexType type) {
     TypeLatticeElement instanceType =
-        TypeLatticeElement.fromDexType(type, definitelyNotNull(), appInfo);
+        TypeLatticeElement.fromDexType(type, definitelyNotNull(), appView);
     Value out = writeRegister(dest, instanceType, ThrowingInfo.CAN_THROW);
     NewInstance instruction = new NewInstance(type, out);
     assert instruction.instructionTypeCanThrow();
@@ -1687,7 +1666,7 @@
   }
 
   public void addReturn(int value) {
-    if (method.method.proto.returnType == appInfo.dexItemFactory.voidType) {
+    if (method.method.proto.returnType == appView.dexItemFactory().voidType) {
       assert prototypeChanges.hasBeenChangedToReturnVoid();
       addReturn();
     } else {
@@ -1710,11 +1689,12 @@
   }
 
   public void addStaticGet(int dest, DexField field) {
-    Value out = writeRegister(
-        dest,
-        TypeLatticeElement.fromDexType(field.type, maybeNull(), appInfo),
-        ThrowingInfo.CAN_THROW);
-    out.setKnownToBeBoolean(field.type == getFactory().booleanType);
+    Value out =
+        writeRegister(
+            dest,
+            TypeLatticeElement.fromDexType(field.type, maybeNull(), appView),
+            ThrowingInfo.CAN_THROW);
+    out.setKnownToBeBoolean(field.type == appView.dexItemFactory().booleanType);
     StaticGet instruction = new StaticGet(out, field);
     assert instruction.instructionTypeCanThrow();
     addInstruction(instruction);
@@ -1932,9 +1912,9 @@
     Value in2 = readNumericRegister(right, type);
     Value out = writeNumericRegister(dest, type, ThrowingInfo.NO_THROW);
     Instruction instruction;
-    if (options.canUseNotInstruction() &&
-        in2.isConstNumber() &&
-        in2.getConstInstruction().asConstNumber().isIntegerNegativeOne(type)) {
+    if (appView.options().canUseNotInstruction()
+        && in2.isConstNumber()
+        && in2.getConstInstruction().asConstNumber().isIntegerNegativeOne(type)) {
       instruction = new Not(type, out, in1);
     } else {
       instruction = new Xor(type, out, in1, in2);
@@ -1947,7 +1927,7 @@
     assert isNonLongIntegerType(type);
     Value in1 = readNumericRegister(value, type);
     Instruction instruction;
-    if (options.canUseNotInstruction() && constant == -1) {
+    if (appView.options().canUseNotInstruction() && constant == -1) {
       Value out = writeNumericRegister(dest, type, ThrowingInfo.NO_THROW);
       instruction = new Not(type, out, in1);
     } else {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 7900d16..85d9a2f 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -193,19 +193,22 @@
       AppView<? extends AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
       AppInfoWithLiveness appInfoWithLiveness = appViewWithLiveness.appInfo();
       assert rootSet != null;
+      this.classInliner =
+          options.enableClassInlining && options.enableInlining
+              ? new ClassInliner(appViewWithLiveness, lambdaRewriter)
+              : null;
       this.classStaticizer =
           options.enableClassStaticizer ? new ClassStaticizer(appViewWithLiveness, this) : null;
       this.nonNullTracker =
           new NonNullTracker(
-              appInfoWithLiveness, libraryMethodsReturningNonNull(appView.dexItemFactory()));
-      this.inliner = new Inliner(appViewWithLiveness, this, options, mainDexClasses);
-      this.outliner = new Outliner(appInfoWithLiveness, options, this);
+              appViewWithLiveness, libraryMethodsReturningNonNull(appView.dexItemFactory()));
+      this.inliner = new Inliner(appViewWithLiveness, mainDexClasses);
+      this.outliner = new Outliner(appViewWithLiveness, this);
       this.memberValuePropagation =
           options.enableValuePropagation ? new MemberValuePropagation(appViewWithLiveness) : null;
       this.lensCodeRewriter = new LensCodeRewriter(appViewWithLiveness);
       if (!appInfoWithLiveness.identifierNameStrings.isEmpty() && options.enableMinification) {
-        this.identifierNameStringMarker =
-            new IdentifierNameStringMarker(appInfoWithLiveness, options);
+        this.identifierNameStringMarker = new IdentifierNameStringMarker(appViewWithLiveness);
       } else {
         this.identifierNameStringMarker = null;
       }
@@ -217,6 +220,7 @@
               : null;
       this.typeChecker = new TypeChecker(appView);
     } else {
+      this.classInliner = null;
       this.classStaticizer = null;
       this.nonNullTracker = null;
       this.inliner = null;
@@ -228,20 +232,11 @@
       this.uninstantiatedTypeOptimization = null;
       this.typeChecker = null;
     }
-    this.classInliner =
-        (options.enableClassInlining && options.enableInlining && inliner != null)
-            ? new ClassInliner(
-                appView.dexItemFactory(), lambdaRewriter, options.classInliningInstructionLimit)
-            : null;
     this.deadCodeRemover = new DeadCodeRemover(appView, codeRewriter);
     this.idempotentFunctionCallCanonicalizer =
         new IdempotentFunctionCallCanonicalizer(appView.dexItemFactory());
   }
 
-  public GraphLense graphLense() {
-    return appView != null ? appView.graphLense() : GraphLense.getIdentityLense();
-  }
-
   public Set<DexCallSite> getDesugaredCallSites() {
     if (lambdaRewriter != null) {
       return lambdaRewriter.getDesugaredCallSites();
@@ -309,12 +304,11 @@
     }
   }
 
-  private Set<DexEncodedMethod> staticizeClasses(
-      OptimizationFeedback feedback, ExecutorService executorService) throws ExecutionException {
+  private void staticizeClasses(OptimizationFeedback feedback, ExecutorService executorService)
+      throws ExecutionException {
     if (classStaticizer != null) {
-      return classStaticizer.staticizeCandidates(feedback, executorService);
+      classStaticizer.staticizeCandidates(feedback, executorService);
     }
-    return ImmutableSet.of();
   }
 
   private void collectStaticizerCandidates(DexApplication application) {
@@ -519,7 +513,7 @@
     printPhase("Primary optimization pass");
 
     // Process the application identifying outlining candidates.
-    GraphLense graphLenseForIR = graphLense();
+    GraphLense graphLenseForIR = appView.graphLense();
     OptimizationFeedbackDelayed feedback = delayedOptimizationFeedback;
     {
       timing.begin("Build call graph");
@@ -535,16 +529,16 @@
           this::waveDone,
           executorService);
       timing.end();
-      assert graphLenseForIR == graphLense();
+      assert graphLenseForIR == appView.graphLense();
     }
 
     // Second inlining pass for dealing with double inline callers.
     if (inliner != null) {
       printPhase("Double caller inlining");
-      assert graphLenseForIR == graphLense();
+      assert graphLenseForIR == appView.graphLense();
       inliner.processDoubleInlineCallers(this, executorService, feedback);
       feedback.updateVisibleOptimizationInfo();
-      assert graphLenseForIR == graphLense();
+      assert graphLenseForIR == appView.graphLense();
     }
 
     // TODO(b/112831361): Implement support for staticizeClasses in CF backend.
@@ -654,7 +648,6 @@
   private void forEachSelectedOutliningMethod(
       ExecutorService executorService, BiConsumer<IRCode, DexEncodedMethod> consumer)
       throws ExecutionException {
-    assert appView != null;
     assert !options.skipIR;
     Set<DexEncodedMethod> methods = outliner.getMethodsSelectedForOutlining();
     List<Future<?>> futures = new ArrayList<>();
@@ -663,11 +656,7 @@
           executorService.submit(
               () -> {
                 IRCode code =
-                    method.buildIR(
-                        appView.appInfo(),
-                        appView.graphLense(),
-                        options,
-                        appView.appInfo().originFor(method.method.holder));
+                    method.buildIR(appView, appView.appInfo().originFor(method.method.holder));
                 assert code != null;
                 assert !method.getCode().isOutlineCode();
                 // Instead of repeating all the optimizations of rewriteCode(), only run the
@@ -685,7 +674,7 @@
 
   private void collectLambdaMergingCandidates(DexApplication application) {
     if (lambdaMerger != null) {
-      lambdaMerger.collectGroupCandidates(application, appView.appInfo().withLiveness(), options);
+      lambdaMerger.collectGroupCandidates(application, appView.withLiveness());
     }
   }
 
@@ -846,9 +835,7 @@
       feedback.markProcessed(method, ConstraintWithTarget.NEVER);
       return;
     }
-    AppInfo appInfo = appView.appInfo();
-    IRCode code =
-        method.buildIR(appInfo, graphLense(), options, appInfo.originFor(method.method.holder));
+    IRCode code = method.buildIR(appView, appView.appInfo().originFor(method.method.holder));
     if (code == null) {
       feedback.markProcessed(method, ConstraintWithTarget.NEVER);
       return;
@@ -878,7 +865,7 @@
       if (lensCodeRewriter != null) {
         lensCodeRewriter.rewrite(code, method);
       } else {
-        assert graphLense().isIdentityLense();
+        assert appView.graphLense().isIdentityLense();
       }
     }
 
@@ -899,7 +886,7 @@
     // assert fails, then the types that we have inferred are unsound, or the method does not type
     // check. In the latter case, the type checker should be extended to detect the issue such that
     // we will return with finalizeEmptyThrowingCode() above.
-    assert code.verifyTypes(appInfo, appView, graphLense());
+    assert code.verifyTypes(appView);
 
     if (classStaticizer != null) {
       classStaticizer.fixupMethodCode(method, code);
@@ -917,11 +904,12 @@
       memberValuePropagation.rewriteWithConstantValues(
           code, method.method.holder, isProcessedConcurrently);
     }
-    if (options.enableSwitchMapRemoval && appInfo.hasLiveness()) {
+    if (options.enableSwitchMapRemoval) {
+      assert appView.enableWholeProgramOptimizations();
       codeRewriter.removeSwitchMaps(code);
     }
     if (options.disableAssertions) {
-      codeRewriter.disableAssertions(appInfo, method, code, feedback);
+      codeRewriter.disableAssertions(appView, method, code, feedback);
     }
 
     previous = printMethod(code, "IR after disable assertions (SSA)", previous);
@@ -939,9 +927,9 @@
 
     previous = printMethod(code, "IR after inlining (SSA)", previous);
 
-    if (appInfo.hasLiveness()) {
+    if (appView.appInfo().hasLiveness()) {
       // Reflection optimization 1. getClass() -> const-class
-      ReflectionOptimizer.rewriteGetClass(appInfo.withLiveness(), code);
+      ReflectionOptimizer.rewriteGetClass(appView.withLiveness(), code);
     }
 
     if (!isDebugMode) {
@@ -957,14 +945,14 @@
     }
 
     if (devirtualizer != null) {
-      assert code.verifyTypes(appInfo, appView, graphLense());
+      assert code.verifyTypes(appView);
       devirtualizer.devirtualizeInvokeInterface(code, method.method.getHolder());
     }
     if (uninstantiatedTypeOptimization != null) {
       uninstantiatedTypeOptimization.rewrite(method, code);
     }
 
-    assert code.verifyTypes(appInfo, appView, graphLense());
+    assert code.verifyTypes(appView);
     codeRewriter.removeTrivialCheckCastAndInstanceOfInstructions(
         code, appView.enableWholeProgramOptimizations());
 
@@ -979,8 +967,7 @@
     codeRewriter.simplifyIf(code);
     // TODO(b/123284765) This produces a runtime-crash in Q. Activate again when fixed.
     // codeRewriter.redundantConstNumberRemoval(code);
-    new RedundantFieldLoadElimination(appInfo, code, appView.enableWholeProgramOptimizations())
-        .run();
+    new RedundantFieldLoadElimination(appView, code).run();
 
     if (options.testing.invertConditionals) {
       invertConditionalsForTesting(code);
@@ -1022,7 +1009,7 @@
 
     previous = printMethod(code, "IR after lambda desugaring (SSA)", previous);
 
-    assert code.verifyTypes(appInfo, appView, graphLense());
+    assert code.verifyTypes(appView);
 
     previous = printMethod(code, "IR before class inlining (SSA)", previous);
 
@@ -1031,7 +1018,7 @@
       // lambda, it does not get collected by merger.
       assert options.enableInlining && inliner != null;
       classInliner.processMethodCode(
-          appInfo.withLiveness(),
+          appView.withLiveness(),
           codeRewriter,
           stringOptimizer,
           method,
@@ -1169,9 +1156,9 @@
       // These hints are on the original holder. To find the original holder, we first find the
       // original method signature (this could have changed as a result of, for example, class
       // merging). Then, we find the type that now corresponds to the the original holder.
-      DexMethod originalSignature = graphLense().getOriginalMethodSignature(method.method);
+      DexMethod originalSignature = appView.graphLense().getOriginalMethodSignature(method.method);
       DexClass originalHolder =
-          appView.definitionFor(graphLense().lookupType(originalSignature.holder));
+          appView.definitionFor(appView.graphLense().lookupType(originalSignature.holder));
       if (originalHolder.hasKotlinInfo()) {
         KotlinInfo kotlinInfo = originalHolder.getKotlinInfo();
         if (kotlinInfo.hasNonNullParameterHints()) {
@@ -1232,15 +1219,15 @@
 
   private void finalizeToCf(DexEncodedMethod method, IRCode code, OptimizationFeedback feedback) {
     assert !method.getCode().isDexCode();
-    CfBuilder builder = new CfBuilder(method, code, options.itemFactory);
-    CfCode result = builder.build(codeRewriter, graphLense(), options, appView.appInfo());
+    CfBuilder builder = new CfBuilder(appView, method, code);
+    CfCode result = builder.build(codeRewriter);
     method.setCode(result);
     markProcessed(method, code, feedback);
   }
 
   private void finalizeToDex(DexEncodedMethod method, IRCode code, OptimizationFeedback feedback) {
     // Workaround massive dex2oat memory use for self-recursive methods.
-    CodeRewriter.disableDex2OatInliningForSelfRecursiveMethods(code, options, appView.appInfo());
+    CodeRewriter.disableDex2OatInliningForSelfRecursiveMethods(appView, code);
     // Perform register allocation.
     RegisterAllocator registerAllocator = performRegisterAllocation(code, method);
     method.setCode(code, registerAllocator, options);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
index 6574551..722866a 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/JarSourceCode.java
@@ -6,6 +6,8 @@
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DebugLocalInfo;
 import com.android.tools.r8.graph.DexCallSite;
 import com.android.tools.r8.graph.DexField;
@@ -2843,7 +2845,8 @@
     for (int i = 0; i < insn.dims; i++) {
       dimensions[i] = slots[i].register;
     }
-    if (builder.isGeneratingClassFiles()) {
+    AppView<? extends AppInfo> appView = builder.appView;
+    if (appView.options().isGeneratingClassFiles()) {
       int result = state.push(arrayType);
       builder.addMultiNewArray(dexArrayType, result, dimensions);
       return;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
index b88a262..e8cf039 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -58,7 +58,6 @@
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.logging.Log;
 import com.android.tools.r8.shaking.VerticalClassMerger.VerticallyMergedClasses;
-import com.android.tools.r8.utils.InternalOptions;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -71,13 +70,11 @@
 public class LensCodeRewriter {
 
   private final AppView<? extends AppInfo> appView;
-  private final InternalOptions options;
 
   private final Map<DexProto, DexProto> protoFixupCache = new ConcurrentHashMap<>();
 
   public LensCodeRewriter(AppView<? extends AppInfoWithSubtyping> appView) {
     this.appView = appView;
-    this.options = appView.options();
   }
 
   private Value makeOutValue(Instruction insn, IRCode code, Set<Value> collector) {
@@ -102,7 +99,7 @@
     boolean mayHaveUnreachableBlocks = false;
     while (blocks.hasNext()) {
       BasicBlock block = blocks.next();
-      if (block.hasCatchHandlers() && options.enableVerticalClassMerging) {
+      if (block.hasCatchHandlers() && appView.options().enableVerticalClassMerging) {
         boolean anyGuardsRenamed = block.renameGuardsInCatchHandlers(graphLense);
         if (anyGuardsRenamed) {
           mayHaveUnreachableBlocks |= unlinkDeadCatchHandlers(block);
@@ -341,7 +338,9 @@
           if (newExceptionType != moveException.getExceptionType()) {
             iterator.replaceCurrentInstruction(
                 new MoveException(
-                    makeOutValue(moveException, code, newSSAValues), newExceptionType, options));
+                    makeOutValue(moveException, code, newSSAValues),
+                    newExceptionType,
+                    appView.options()));
           }
         } else if (current.isNewArrayEmpty()) {
           NewArrayEmpty newArrayEmpty = current.asNewArrayEmpty();
@@ -366,7 +365,7 @@
       code.removeUnreachableBlocks();
     }
     if (!newSSAValues.isEmpty()) {
-      new TypeAnalysis(appInfo, method).widening(newSSAValues);
+      new TypeAnalysis(appView, method).widening(newSSAValues);
     }
     assert code.isConsistentSSA();
   }
@@ -400,17 +399,20 @@
       if (newInstance.clazz != invokedMethod.holder
           && verticallyMergedClasses.hasBeenMergedIntoSubtype(invokedMethod.holder)) {
         // Generated code will not work. Fail with a compilation error.
-        throw options.reporter.fatalError(
-            String.format(
-                "Unable to rewrite `invoke-direct %s.<init>(new %s, ...)` in method `%s` after "
-                    + "type `%s` was merged into `%s`. Please add the following rule to your "
-                    + "Proguard configuration file: `-keep,allowobfuscation class %s`.",
-                invokedMethod.holder.toSourceString(),
-                newInstance.clazz,
-                method.toSourceString(),
-                invokedMethod.holder,
-                verticallyMergedClasses.getTargetFor(invokedMethod.holder),
-                invokedMethod.holder.toSourceString()));
+        throw appView
+            .options()
+            .reporter
+            .fatalError(
+                String.format(
+                    "Unable to rewrite `invoke-direct %s.<init>(new %s, ...)` in method `%s` after "
+                        + "type `%s` was merged into `%s`. Please add the following rule to your "
+                        + "Proguard configuration file: `-keep,allowobfuscation class %s`.",
+                    invokedMethod.holder.toSourceString(),
+                    newInstance.clazz,
+                    method.toSourceString(),
+                    invokedMethod.holder,
+                    verticallyMergedClasses.getTargetFor(invokedMethod.holder),
+                    invokedMethod.holder.toSourceString()));
       }
     }
   }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/TypeConstraintResolver.java b/src/main/java/com/android/tools/r8/ir/conversion/TypeConstraintResolver.java
index 1ed85c4..363db4a 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/TypeConstraintResolver.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/TypeConstraintResolver.java
@@ -6,6 +6,7 @@
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.ir.analysis.type.ArrayTypeLatticeElement;
 import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
@@ -21,7 +22,6 @@
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.code.ValueTypeConstraint;
 import com.android.tools.r8.position.MethodPosition;
-import com.android.tools.r8.utils.Reporter;
 import com.android.tools.r8.utils.StringDiagnostic;
 import com.google.common.collect.ImmutableSet;
 import java.util.ArrayList;
@@ -52,13 +52,13 @@
  */
 public class TypeConstraintResolver {
 
+  private final AppView<? extends AppInfo> appView;
   private final IRBuilder builder;
-  private final Reporter reporter;
   private final Map<Value, Value> unificationParents = new HashMap<>();
 
-  public TypeConstraintResolver(IRBuilder builder, Reporter reporter) {
+  public TypeConstraintResolver(AppView<? extends AppInfo> appView, IRBuilder builder) {
+    this.appView = appView;
     this.builder = builder;
-    this.reporter = reporter;
   }
 
   public static ValueTypeConstraint constraintForType(TypeLatticeElement type) {
@@ -96,14 +96,13 @@
   public void resolve(
       List<ImpreciseMemberTypeInstruction> impreciseInstructions,
       IRCode code,
-      AppInfo appInfo,
       DexEncodedMethod method,
       DexEncodedMethod context) {
     // Round one will resolve at least all object vs single types.
     List<Value> remainingImpreciseValues = resolveRoundOne(code);
     // Round two will resolve any remaining single and wide types. These can depend on the types
     // of array instructions, thus we need to complete the type fixed point prior to resolving.
-    new TypeAnalysis(appInfo, context, true).widening(method, code);
+    new TypeAnalysis(appView, context, true).widening(method, code);
     // Round two resolves any remaining imprecision and finally selects a final precise type for
     // any unconstrained imprecise type.
     resolveRoundTwo(code, impreciseInstructions, remainingImpreciseValues);
@@ -150,14 +149,17 @@
     }
     ArrayList<Value> stillImprecise = constrainValues(true, remainingImpreciseValues);
     if (!stillImprecise.isEmpty()) {
-      throw reporter.fatalError(
-          new StringDiagnostic(
-              "Cannot determine precise type for value: "
-                  + stillImprecise.get(0)
-                  + ", its imprecise type is: "
-                  + stillImprecise.get(0).getTypeLattice(),
-              code.origin,
-              new MethodPosition(code.method.method)));
+      throw appView
+          .options()
+          .reporter
+          .fatalError(
+              new StringDiagnostic(
+                  "Cannot determine precise type for value: "
+                      + stillImprecise.get(0)
+                      + ", its imprecise type is: "
+                      + stillImprecise.get(0).getTypeLattice(),
+                  code.origin,
+                  new MethodPosition(code.method.method)));
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
index 3551a7c..fb5fac8 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
@@ -494,7 +494,7 @@
       return;
     }
     DexMethod originalReferencedFrom =
-        converter.graphLense().getOriginalMethodSignature(referencedFrom);
+        appView.graphLense().getOriginalMethodSignature(referencedFrom);
     StringBuilder builder = new StringBuilder();
     builder
         .append("Type `")
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
index c89019c..e91f1cc 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
@@ -32,7 +32,6 @@
 import com.android.tools.r8.ir.synthetic.ForwardMethodSourceCode;
 import com.android.tools.r8.ir.synthetic.SynthesizedCode;
 import com.android.tools.r8.origin.SynthesizedOrigin;
-import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -308,8 +307,7 @@
   // also be kept (such a situation can happen if the vertical class merger merges two interfaces).
   private boolean interfaceMethodRemovalChangesApi(DexEncodedMethod method, DexClass iface) {
     if (appView.enableWholeProgramOptimizations()) {
-      AppInfoWithLiveness appInfoWithLiveness = appView.appInfo().withLiveness();
-      if (appInfoWithLiveness.isPinned(method.method)) {
+      if (appView.appInfo().withLiveness().isPinned(method.method)) {
         return true;
       }
     }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java
index 9b096a2..01c94da 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java
@@ -71,7 +71,7 @@
       }
       InvokeStatic invoke = instruction.asInvokeStatic();
 
-      MethodGenerator generator = getMethodGeneratorOrNull(converter, invoke.getInvokedMethod());
+      MethodGenerator generator = getMethodGeneratorOrNull(invoke.getInvokedMethod());
       if (generator == null) {
         continue;
       }
@@ -151,8 +151,8 @@
     }
   }
 
-  private MethodGenerator getMethodGeneratorOrNull(IRConverter converter, DexMethod method) {
-    DexMethod original = converter.graphLense().getOriginalMethodSignature(method);
+  private MethodGenerator getMethodGeneratorOrNull(DexMethod method) {
+    DexMethod original = appView.graphLense().getOriginalMethodSignature(method);
     assert original != null;
     return rewritableMethods.getGenerator(
         original.holder.descriptor, original.name, original.proto);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java
index 29b6aa7..ff903f3 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java
@@ -202,7 +202,7 @@
 
     // If we are in R8, and we have removed all static-put instructions to some field, then record
     // that the field is no longer written.
-    if (appView != null && appView.enableWholeProgramOptimizations() && converter.isInWave()) {
+    if (appView.enableWholeProgramOptimizations() && converter.isInWave()) {
       if (appView.appInfo().hasLiveness()) {
         AppView<? extends AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
         AppInfoWithLiveness appInfoWithLiveness = appViewWithLiveness.appInfo();
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 304c86d..0015e17 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
@@ -293,8 +293,8 @@
   // For method with many self-recursive calls, insert a try-catch to disable inlining.
   // Marshmallow dex2oat aggressively inlines and eats up all the memory on devices.
   public static void disableDex2OatInliningForSelfRecursiveMethods(
-      IRCode code, InternalOptions options, AppInfo appInfo) {
-    if (!options.canHaveDex2OatInliningIssue() || code.hasCatchHandlers()) {
+      AppView<? extends AppInfo> appView, IRCode code) {
+    if (!appView.options().canHaveDex2OatInliningIssue() || code.hasCatchHandlers()) {
       // Catch handlers disables inlining, so if the method already has catch handlers
       // there is nothing to do.
       return;
@@ -317,13 +317,9 @@
       splitIterator.previous();
       BasicBlock newBlock = splitIterator.split(code, 1);
       // Generate rethrow block.
-      DexType guard = options.itemFactory.throwableType;
-      BasicBlock rethrowBlock = BasicBlock.createRethrowBlock(
-          code,
-          lastSelfRecursiveCall.getPosition(),
-          guard,
-          appInfo,
-          options);
+      DexType guard = appView.dexItemFactory().throwableType;
+      BasicBlock rethrowBlock =
+          BasicBlock.createRethrowBlock(code, lastSelfRecursiveCall.getPosition(), guard, appView);
       code.blocks.add(rethrowBlock);
       // Add catch handler to the block containing the last recursive call.
       newBlock.addCatchHandler(rethrowBlock, guard);
@@ -1606,8 +1602,7 @@
     if (options.isGeneratingClassFiles()) {
       return;
     }
-    AppInfo appInfo = appView.appInfo();
-    AppInfoWithLiveness appInfoWithLiveness = appInfo.withLiveness();
+    AppInfoWithLiveness appInfoWithLiveness = appView.appInfo().withLiveness();
     Set<Value> needToWidenValues = Sets.newIdentityHashSet();
     Set<Value> needToNarrowValues = Sets.newIdentityHashSet();
     InstructionIterator iterator = code.instructionIterator();
@@ -1647,15 +1642,16 @@
             if (target != null) {
               DexMethod invokedMethod = target.method;
               // Check if the invoked method is known to return one of its arguments.
-              DexEncodedMethod definition = appInfo.definitionFor(invokedMethod);
+              DexEncodedMethod definition = appView.definitionFor(invokedMethod);
               if (definition != null && definition.getOptimizationInfo().returnsArgument()) {
                 int argumentIndex = definition.getOptimizationInfo().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);
                   assert outValue.verifyCompatible(argument.outType());
-                  if (argument.getTypeLattice().lessThanOrEqual(
-                      outValue.getTypeLattice(), appInfo)) {
+                  if (argument
+                      .getTypeLattice()
+                      .lessThanOrEqual(outValue.getTypeLattice(), appView)) {
                     needToNarrowValues.addAll(outValue.affectedValues());
                   } else {
                     needToWidenValues.addAll(outValue.affectedValues());
@@ -1670,7 +1666,7 @@
       }
     }
     if (!needToWidenValues.isEmpty() || !needToNarrowValues.isEmpty()) {
-      TypeAnalysis analysis = new TypeAnalysis(appInfo, code.method);
+      TypeAnalysis analysis = new TypeAnalysis(appView, code.method);
       // If out value of invoke < argument (e.g., losing non-null info), widen users type.
       if (!needToWidenValues.isEmpty()) {
         analysis.widening(needToWidenValues);
@@ -1684,10 +1680,11 @@
   }
 
   /**
-   * For supporting assert javac adds the static field $assertionsDisabled to all classes which
-   * have methods with assertions. This is used to support the Java VM -ea flag.
+   * For supporting assert javac adds the static field $assertionsDisabled to all classes which have
+   * methods with assertions. This is used to support the Java VM -ea flag.
    *
-   * The class:
+   * <p>The class:
+   *
    * <pre>
    * class A {
    *   void m() {
@@ -1695,7 +1692,9 @@
    *   }
    * }
    * </pre>
+   *
    * Is compiled into:
+   *
    * <pre>
    * class A {
    *   static boolean $assertionsDisabled;
@@ -1713,7 +1712,9 @@
    *   }
    * }
    * </pre>
+   *
    * With the rewriting below (and other rewritings) the resulting code is:
+   *
    * <pre>
    * class A {
    *   void m() {
@@ -1722,7 +1723,10 @@
    * </pre>
    */
   public void disableAssertions(
-      AppInfo appInfo, DexEncodedMethod method, IRCode code, OptimizationFeedback feedback) {
+      AppView<? extends AppInfo> appView,
+      DexEncodedMethod method,
+      IRCode code,
+      OptimizationFeedback feedback) {
     if (method.isClassInitializer()) {
       if (!hasJavacClinitAssertionCode(code)) {
         return;
@@ -1732,7 +1736,7 @@
     } else {
       // If the clinit of this class did not have have code to turn on assertions don't try to
       // remove assertion code from the method.
-      DexClass clazz = appInfo.definitionFor(method.method.holder);
+      DexClass clazz = appView.definitionFor(method.method.holder);
       if (clazz == null) {
         return;
       }
@@ -2931,7 +2935,7 @@
     }
     Set<Value> affectedValues = code.removeUnreachableBlocks();
     if (!affectedValues.isEmpty()) {
-      new TypeAnalysis(appView.appInfo(), code.method).narrowing(affectedValues);
+      new TypeAnalysis(appView, code.method).narrowing(affectedValues);
     }
     assert code.isConsistentSSA();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
index 019c3ac..3f1b066 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
@@ -40,7 +40,6 @@
   private final CallSiteInformation callSiteInformation;
   private final Predicate<DexEncodedMethod> isProcessedConcurrently;
   private final InliningInfo info;
-  private final InternalOptions options;
   private final int inliningInstructionLimit;
   private int instructionAllowance;
 
@@ -51,7 +50,6 @@
       IRCode code,
       CallSiteInformation callSiteInformation,
       Predicate<DexEncodedMethod> isProcessedConcurrently,
-      InternalOptions options,
       int inliningInstructionLimit,
       int inliningInstructionAllowance) {
     this.appView = appView;
@@ -61,7 +59,6 @@
     this.callSiteInformation = callSiteInformation;
     this.isProcessedConcurrently = isProcessedConcurrently;
     info = Log.ENABLED ? new InliningInfo(method) : null;
-    this.options = options;
     this.inliningInstructionLimit = inliningInstructionLimit;
     this.instructionAllowance = inliningInstructionAllowance;
   }
@@ -185,6 +182,7 @@
       return false;
     }
 
+    InternalOptions options = appView.options();
     if (options.testing.validInliningReasons != null
         && !options.testing.validInliningReasons.contains(reason)) {
       return false;
@@ -433,7 +431,7 @@
       // Abort if inlining could lead to an explosion in the number of control flow
       // resolution blocks that setup the register state before the actual catch handler.
       if (estimatedNumberOfControlFlowResolutionBlocks
-          >= options.inliningControlFlowResolutionBlocksThreshold) {
+          >= appView.options().inliningControlFlowResolutionBlocksThreshold) {
         return true;
       }
     }
@@ -450,7 +448,7 @@
   @Override
   public void updateTypeInformationIfNeeded(
       IRCode inlinee, ListIterator<BasicBlock> blockIterator, BasicBlock block) {
-    if (inliner.options.enableNonNullTracking) {
+    if (appView.options().enableNonNullTracking) {
       BasicBlock state = IteratorUtils.peekNext(blockIterator);
       // Move the cursor back to where the first inlinee block was added.
       while (blockIterator.hasPrevious() && blockIterator.previous() != block) {
@@ -459,8 +457,8 @@
       assert IteratorUtils.peekNext(blockIterator) == block;
 
       // Kick off the tracker to add non-null IRs only to the inlinee blocks.
-      new NonNullTracker(appView.appInfo(),
-          IRConverter.libraryMethodsReturningNonNull(appView.dexItemFactory()))
+      new NonNullTracker(
+              appView, IRConverter.libraryMethodsReturningNonNull(appView.dexItemFactory()))
           .addNonNullInPart(code, blockIterator, inlinee.blocks::contains);
       assert !blockIterator.hasNext();
 
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 930ac78..d0f3599 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
@@ -221,7 +221,7 @@
       }
     }
     if (!affectedValues.isEmpty()) {
-      new TypeAnalysis(appView.appInfo(), code.method).narrowing(affectedValues);
+      new TypeAnalysis(appView, code.method).narrowing(affectedValues);
     }
     assert code.isConsistentSSA();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/EnumOrdinalMapCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/EnumOrdinalMapCollector.java
index fd387a3..aa3b405 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/EnumOrdinalMapCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/EnumOrdinalMapCollector.java
@@ -8,14 +8,12 @@
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionIterator;
 import com.android.tools.r8.ir.code.InvokeDirect;
 import com.android.tools.r8.ir.code.StaticPut;
 import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
-import com.android.tools.r8.utils.InternalOptions;
 import it.unimi.dsi.fastutil.objects.Reference2IntArrayMap;
 import it.unimi.dsi.fastutil.objects.Reference2IntMap;
 import java.util.IdentityHashMap;
@@ -31,26 +29,22 @@
  */
 public class EnumOrdinalMapCollector {
 
-  private final AppInfoWithLiveness appInfo;
-  private final GraphLense graphLense;
-  private final InternalOptions options;
+  private final AppView<? extends AppInfoWithLiveness> appView;
 
   private final Map<DexType, Reference2IntMap<DexField>> ordinalsMaps = new IdentityHashMap<>();
 
   public EnumOrdinalMapCollector(AppView<? extends AppInfoWithLiveness> appView) {
-    this.appInfo = appView.appInfo();
-    this.graphLense = appView.graphLense();
-    this.options = appView.options();
+    this.appView = appView;
   }
 
   public AppInfoWithLiveness run() {
-    for (DexProgramClass clazz : appInfo.classes()) {
+    for (DexProgramClass clazz : appView.appInfo().classes()) {
       processClasses(clazz);
     }
     if (!ordinalsMaps.isEmpty()) {
-      return appInfo.addEnumOrdinalMaps(ordinalsMaps);
+      return appView.appInfo().addEnumOrdinalMaps(ordinalsMaps);
     }
-    return appInfo;
+    return appView.appInfo();
   }
 
   private void processClasses(DexProgramClass clazz) {
@@ -59,8 +53,7 @@
       return;
     }
     DexEncodedMethod initializer = clazz.getClassInitializer();
-    IRCode code =
-        initializer.getCode().buildIR(initializer, appInfo, graphLense, options, clazz.origin);
+    IRCode code = initializer.getCode().buildIR(initializer, appView, clazz.origin);
     Reference2IntMap<DexField> ordinalsMap = new Reference2IntArrayMap<>();
     ordinalsMap.defaultReturnValue(-1);
     InstructionIterator it = code.instructionIterator();
@@ -83,7 +76,7 @@
           continue;
         }
         InvokeDirect invoke = ctorCall.asInvokeDirect();
-        if (!appInfo.dexItemFactory.isConstructor(invoke.getInvokedMethod())
+        if (!appView.dexItemFactory().isConstructor(invoke.getInvokedMethod())
             || invoke.arguments().size() < 3) {
           continue;
         }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index 299181e..9a50518 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -4,15 +4,16 @@
 package com.android.tools.r8.ir.optimize;
 
 import com.android.tools.r8.graph.AccessFlags;
-import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.AppInfoWithSubtyping;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexDefinitionSupplier;
 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.DexMethod;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.IRCode;
@@ -49,8 +50,6 @@
 public class Inliner {
 
   protected final AppView<? extends AppInfoWithLiveness> appView;
-  private final IRConverter converter;
-  final InternalOptions options;
   final MainDexClasses mainDexClasses;
 
   // State for inlining methods which are known to be called twice.
@@ -63,12 +62,8 @@
 
   public Inliner(
       AppView<? extends AppInfoWithLiveness> appView,
-      IRConverter converter,
-      InternalOptions options,
       MainDexClasses mainDexClasses) {
     this.appView = appView;
-    this.converter = converter;
-    this.options = options;
     this.mainDexClasses = mainDexClasses;
     fillInBlackList(appView.appInfo());
   }
@@ -96,7 +91,8 @@
 
   public ConstraintWithTarget computeInliningConstraint(IRCode code, DexEncodedMethod method) {
     ConstraintWithTarget result = ConstraintWithTarget.ALWAYS;
-    InliningConstraints inliningConstraints = new InliningConstraints(appView.appInfo());
+    InliningConstraints inliningConstraints =
+        new InliningConstraints(appView, GraphLense.getIdentityLense());
     InstructionIterator it = code.instructionIterator();
     while (it.hasNext()) {
       Instruction instruction = it.next();
@@ -281,7 +277,7 @@
         DexType contextHolder,
         DexType targetHolder,
         AccessFlags flags,
-        AppInfo appInfo) {
+        DexDefinitionSupplier definitions) {
       if (flags.isPublic()) {
         return ALWAYS;
       } else if (flags.isPrivate()) {
@@ -291,7 +287,7 @@
         if (targetHolder.isSamePackage(contextHolder)) {
           // Even though protected, this is visible via the same package from the context.
           return new ConstraintWithTarget(Constraint.PACKAGE, targetHolder);
-        } else if (contextHolder.isSubtypeOf(targetHolder, appInfo)) {
+        } else if (contextHolder.isSubtypeOf(targetHolder, definitions)) {
           return new ConstraintWithTarget(Constraint.SUBCLASS, targetHolder);
         }
         return NEVER;
@@ -303,27 +299,29 @@
     }
 
     public static ConstraintWithTarget classIsVisible(
-        DexType context, DexType clazz, AppInfo appInfo) {
+        DexType context, DexType clazz, DexDefinitionSupplier definitions) {
       if (clazz.isArrayType()) {
-        return classIsVisible(context, clazz.toArrayElementType(appInfo.dexItemFactory), appInfo);
+        return classIsVisible(
+            context, clazz.toArrayElementType(definitions.dexItemFactory()), definitions);
       }
 
       if (clazz.isPrimitiveType()) {
         return ALWAYS;
       }
 
-      DexClass definition = appInfo.definitionFor(clazz);
-      return definition == null ? NEVER
-          : deriveConstraint(context, clazz, definition.accessFlags, appInfo);
+      DexClass definition = definitions.definitionFor(clazz);
+      return definition == null
+          ? NEVER
+          : deriveConstraint(context, clazz, definition.accessFlags, definitions);
     }
 
     public static ConstraintWithTarget meet(
-        ConstraintWithTarget one, ConstraintWithTarget other, AppInfo appInfo) {
+        ConstraintWithTarget one, ConstraintWithTarget other, DexDefinitionSupplier definitions) {
       if (one.equals(other)) {
         return one;
       }
       if (other.constraint.ordinal() < one.constraint.ordinal()) {
-        return meet(other, one, appInfo);
+        return meet(other, one, definitions);
       }
       // From now on, one.constraint.ordinal() <= other.constraint.ordinal()
       if (one == NEVER) {
@@ -349,7 +347,7 @@
           return NEVER;
         }
         assert other.constraint == Constraint.SUBCLASS;
-        if (one.targetHolder.isSubtypeOf(other.targetHolder, appInfo)) {
+        if (one.targetHolder.isSubtypeOf(other.targetHolder, definitions)) {
           return one;
         }
         return NEVER;
@@ -379,10 +377,10 @@
       assert Constraint.SUBCLASS.isSet(constraint);
       assert one.constraint == other.constraint;
       assert one.targetHolder != other.targetHolder;
-      if (one.targetHolder.isSubtypeOf(other.targetHolder, appInfo)) {
+      if (one.targetHolder.isSubtypeOf(other.targetHolder, definitions)) {
         return one;
       }
-      if (other.targetHolder.isSubtypeOf(one.targetHolder, appInfo)) {
+      if (other.targetHolder.isSubtypeOf(one.targetHolder, definitions)) {
         return other;
       }
       // SUBCLASS of x and SUBCLASS of y while x and y are not a subtype of each other.
@@ -425,18 +423,10 @@
         DexEncodedMethod context,
         ValueNumberGenerator generator,
         AppView<? extends AppInfoWithSubtyping> appView,
-        InternalOptions options,
         Position callerPosition) {
       // Build the IR for a yet not processed method, and perform minimal IR processing.
       Origin origin = appView.appInfo().originFor(target.method.holder);
-      IRCode code = target.buildInliningIR(
-          context,
-          appView.appInfo(),
-          appView.graphLense(),
-          options,
-          generator,
-          callerPosition,
-          origin);
+      IRCode code = target.buildInliningIR(context, appView, generator, callerPosition, origin);
       if (!target.isProcessed()) {
         new LensCodeRewriter(appView).rewrite(code, target);
       }
@@ -565,7 +555,7 @@
       IRCode code,
       Predicate<DexEncodedMethod> isProcessedConcurrently,
       CallSiteInformation callSiteInformation) {
-
+    InternalOptions options = appView.options();
     DefaultInliningOracle oracle =
         createDefaultOracle(
             method,
@@ -574,7 +564,6 @@
             callSiteInformation,
             options.inliningInstructionLimit,
             options.inliningInstructionAllowance - numberOfInstructions(code));
-
     performInliningImpl(oracle, oracle, method, code);
   }
 
@@ -585,7 +574,6 @@
       CallSiteInformation callSiteInformation,
       int inliningInstructionLimit,
       int inliningInstructionAllowance) {
-
     return new DefaultInliningOracle(
         appView,
         this,
@@ -593,7 +581,6 @@
         code,
         callSiteInformation,
         isProcessedConcurrently,
-        options,
         inliningInstructionLimit,
         inliningInstructionAllowance);
   }
@@ -628,10 +615,10 @@
             }
             assert invokePosition.callerPosition == null
                 || invokePosition.getOutermostCaller().method
-                    == converter.graphLense().getOriginalMethodSignature(context.method);
+                    == appView.graphLense().getOriginalMethodSignature(context.method);
 
-            InlineeWithReason inlinee = result.buildInliningIR(
-                context, code.valueNumberGenerator, appView, options, invokePosition);
+            InlineeWithReason inlinee =
+                result.buildInliningIR(context, code.valueNumberGenerator, appView, invokePosition);
             if (inlinee != null) {
               if (strategy.willExceedBudget(inlinee, block)) {
                 continue;
@@ -652,7 +639,7 @@
               iterator.previous();
               strategy.markInlined(inlinee);
               iterator.inlineInvoke(
-                  appView.appInfo(), code, inlinee.code, blockIterator, blocksToRemove, downcast);
+                  appView, code, inlinee.code, blockIterator, blocksToRemove, downcast);
 
               classInitializationAnalysis.notifyCodeHasChanged();
               strategy.updateTypeInformationIfNeeded(inlinee.code, blockIterator, block);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
index 873eb20..afb2e0f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
@@ -6,6 +6,7 @@
 
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo.ResolutionResult;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
@@ -22,7 +23,7 @@
 // Computes the inlining constraint for a given instruction.
 public class InliningConstraints {
 
-  private AppInfoWithLiveness appInfo;
+  private AppView<? extends AppInfoWithLiveness> appView;
 
   private boolean allowStaticInterfaceMethodCalls = true;
 
@@ -38,14 +39,12 @@
   // type A to B, to create a temporary view of what the world would look like after class merging.
   private GraphLense graphLense;
 
-  public InliningConstraints(AppInfoWithLiveness appInfo) {
-    this(appInfo, GraphLense.getIdentityLense());
-  }
-
-  public InliningConstraints(AppInfoWithLiveness appInfo, GraphLense graphLense) {
+  public InliningConstraints(
+      AppView<? extends AppInfoWithLiveness> appView, GraphLense graphLense) {
     assert graphLense.isContextFreeForMethods();
-    this.appInfo = appInfo;
-    this.graphLense = graphLense;
+    assert appView.graphLense() != graphLense || graphLense.isIdentityLense();
+    this.appView = appView;
+    this.graphLense = graphLense; // Note: Intentionally *not* appView.graphLense().
   }
 
   public void disallowStaticInterfaceMethodCalls() {
@@ -77,11 +76,11 @@
   }
 
   public ConstraintWithTarget forCheckCast(DexType type, DexType invocationContext) {
-    return ConstraintWithTarget.classIsVisible(invocationContext, type, appInfo);
+    return ConstraintWithTarget.classIsVisible(invocationContext, type, appView);
   }
 
   public ConstraintWithTarget forConstClass(DexType type, DexType invocationContext) {
-    return ConstraintWithTarget.classIsVisible(invocationContext, type, appInfo);
+    return ConstraintWithTarget.classIsVisible(invocationContext, type, appView);
   }
 
   public ConstraintWithTarget forConstInstruction() {
@@ -111,17 +110,17 @@
   public ConstraintWithTarget forInstanceGet(DexField field, DexType invocationContext) {
     DexField lookup = graphLense.lookupField(field);
     return forFieldInstruction(
-        lookup, appInfo.lookupInstanceTarget(lookup.clazz, lookup), invocationContext);
+        lookup, appView.appInfo().lookupInstanceTarget(lookup.clazz, lookup), invocationContext);
   }
 
   public ConstraintWithTarget forInstanceOf(DexType type, DexType invocationContext) {
-    return ConstraintWithTarget.classIsVisible(invocationContext, type, appInfo);
+    return ConstraintWithTarget.classIsVisible(invocationContext, type, appView);
   }
 
   public ConstraintWithTarget forInstancePut(DexField field, DexType invocationContext) {
     DexField lookup = graphLense.lookupField(field);
     return forFieldInstruction(
-        lookup, appInfo.lookupInstanceTarget(lookup.clazz, lookup), invocationContext);
+        lookup, appView.appInfo().lookupInstanceTarget(lookup.clazz, lookup), invocationContext);
   }
 
   public ConstraintWithTarget forInvoke(DexMethod method, Type type, DexType invocationContext) {
@@ -151,20 +150,22 @@
 
   public ConstraintWithTarget forInvokeDirect(DexMethod method, DexType invocationContext) {
     DexMethod lookup = graphLense.lookupMethod(method);
-    return forSingleTargetInvoke(lookup, appInfo.lookupDirectTarget(lookup), invocationContext);
+    return forSingleTargetInvoke(
+        lookup, appView.appInfo().lookupDirectTarget(lookup), invocationContext);
   }
 
   public ConstraintWithTarget forInvokeInterface(DexMethod method, DexType invocationContext) {
     DexMethod lookup = graphLense.lookupMethod(method);
-    return forVirtualInvoke(lookup, appInfo.lookupInterfaceTargets(lookup), invocationContext);
+    return forVirtualInvoke(
+        lookup, appView.appInfo().lookupInterfaceTargets(lookup), invocationContext);
   }
 
   public ConstraintWithTarget forInvokeMultiNewArray(DexType type, DexType invocationContext) {
-    return ConstraintWithTarget.classIsVisible(invocationContext, type, appInfo);
+    return ConstraintWithTarget.classIsVisible(invocationContext, type, appView);
   }
 
   public ConstraintWithTarget forInvokeNewArray(DexType type, DexType invocationContext) {
-    return ConstraintWithTarget.classIsVisible(invocationContext, type, appInfo);
+    return ConstraintWithTarget.classIsVisible(invocationContext, type, appView);
   }
 
   public ConstraintWithTarget forInvokePolymorphic(DexMethod method, DexType invocationContext) {
@@ -173,7 +174,8 @@
 
   public ConstraintWithTarget forInvokeStatic(DexMethod method, DexType invocationContext) {
     DexMethod lookup = graphLense.lookupMethod(method);
-    return forSingleTargetInvoke(lookup, appInfo.lookupStaticTarget(lookup), invocationContext);
+    return forSingleTargetInvoke(
+        lookup, appView.appInfo().lookupStaticTarget(lookup), invocationContext);
   }
 
   public ConstraintWithTarget forInvokeSuper(DexMethod method, DexType invocationContext) {
@@ -183,7 +185,8 @@
 
   public ConstraintWithTarget forInvokeVirtual(DexMethod method, DexType invocationContext) {
     DexMethod lookup = graphLense.lookupMethod(method);
-    return forVirtualInvoke(lookup, appInfo.lookupVirtualTargets(lookup), invocationContext);
+    return forVirtualInvoke(
+        lookup, appView.appInfo().lookupVirtualTargets(lookup), invocationContext);
   }
 
   public ConstraintWithTarget forJumpInstruction() {
@@ -208,7 +211,7 @@
   }
 
   public ConstraintWithTarget forNewArrayEmpty(DexType type, DexType invocationContext) {
-    return ConstraintWithTarget.classIsVisible(invocationContext, type, appInfo);
+    return ConstraintWithTarget.classIsVisible(invocationContext, type, appView);
   }
 
   public ConstraintWithTarget forNewArrayFilledData() {
@@ -216,7 +219,7 @@
   }
 
   public ConstraintWithTarget forNewInstance(DexType type, DexType invocationContext) {
-    return ConstraintWithTarget.classIsVisible(invocationContext, type, appInfo);
+    return ConstraintWithTarget.classIsVisible(invocationContext, type, appView);
   }
 
   public ConstraintWithTarget forNonNull() {
@@ -234,13 +237,13 @@
   public ConstraintWithTarget forStaticGet(DexField field, DexType invocationContext) {
     DexField lookup = graphLense.lookupField(field);
     return forFieldInstruction(
-        lookup, appInfo.lookupStaticTarget(lookup.clazz, lookup), invocationContext);
+        lookup, appView.appInfo().lookupStaticTarget(lookup.clazz, lookup), invocationContext);
   }
 
   public ConstraintWithTarget forStaticPut(DexField field, DexType invocationContext) {
     DexField lookup = graphLense.lookupField(field);
     return forFieldInstruction(
-        lookup, appInfo.lookupStaticTarget(lookup.clazz, lookup), invocationContext);
+        lookup, appView.appInfo().lookupStaticTarget(lookup.clazz, lookup), invocationContext);
   }
 
   public ConstraintWithTarget forStore() {
@@ -267,16 +270,16 @@
       DexField field, DexEncodedField target, DexType invocationContext) {
     // Resolve the field if possible and decide whether the instruction can inlined.
     DexType fieldHolder = graphLense.lookupType(field.clazz);
-    DexClass fieldClass = appInfo.definitionFor(fieldHolder);
+    DexClass fieldClass = appView.definitionFor(fieldHolder);
     if (target != null && fieldClass != null) {
       ConstraintWithTarget fieldConstraintWithTarget =
           ConstraintWithTarget.deriveConstraint(
-              invocationContext, fieldHolder, target.accessFlags, appInfo);
+              invocationContext, fieldHolder, target.accessFlags, appView);
       ConstraintWithTarget classConstraintWithTarget =
           ConstraintWithTarget.deriveConstraint(
-              invocationContext, fieldHolder, fieldClass.accessFlags, appInfo);
+              invocationContext, fieldHolder, fieldClass.accessFlags, appView);
       return ConstraintWithTarget.meet(
-          fieldConstraintWithTarget, classConstraintWithTarget, appInfo);
+          fieldConstraintWithTarget, classConstraintWithTarget, appView);
     }
     return ConstraintWithTarget.NEVER;
   }
@@ -288,7 +291,7 @@
     }
     if (target != null) {
       DexType methodHolder = graphLense.lookupType(target.method.holder);
-      DexClass methodClass = appInfo.definitionFor(methodHolder);
+      DexClass methodClass = appView.definitionFor(methodHolder);
       if (methodClass != null) {
         if (!allowStaticInterfaceMethodCalls && methodClass.isInterface() && target.hasCode()) {
           // See b/120121170.
@@ -297,13 +300,13 @@
 
         ConstraintWithTarget methodConstraintWithTarget =
             ConstraintWithTarget.deriveConstraint(
-                invocationContext, methodHolder, target.accessFlags, appInfo);
+                invocationContext, methodHolder, target.accessFlags, appView);
         // We also have to take the constraint of the enclosing class into account.
         ConstraintWithTarget classConstraintWithTarget =
             ConstraintWithTarget.deriveConstraint(
-                invocationContext, methodHolder, methodClass.accessFlags, appInfo);
+                invocationContext, methodHolder, methodClass.accessFlags, appView);
         return ConstraintWithTarget.meet(
-            methodConstraintWithTarget, classConstraintWithTarget, appInfo);
+            methodConstraintWithTarget, classConstraintWithTarget, appView);
       }
     }
     return ConstraintWithTarget.NEVER;
@@ -320,7 +323,7 @@
 
     // Perform resolution and derive inlining constraints based on the accessibility of the
     // resolution result.
-    ResolutionResult resolutionResult = appInfo.resolveMethod(method.holder, method);
+    ResolutionResult resolutionResult = appView.appInfo().resolveMethod(method.holder, method);
     DexEncodedMethod resolutionTarget = resolutionResult.asResultOfResolve();
     if (resolutionTarget == null) {
       // This will fail at runtime.
@@ -328,11 +331,11 @@
     }
 
     DexType methodHolder = graphLense.lookupType(resolutionTarget.method.holder);
-    DexClass methodClass = appInfo.definitionFor(methodHolder);
+    DexClass methodClass = appView.definitionFor(methodHolder);
     assert methodClass != null;
     ConstraintWithTarget methodConstraintWithTarget =
         ConstraintWithTarget.deriveConstraint(
-            invocationContext, methodHolder, resolutionTarget.accessFlags, appInfo);
+            invocationContext, methodHolder, resolutionTarget.accessFlags, appView);
     // We also have to take the constraint of the enclosing class of the resolution result
     // into account. We do not allow inlining this method if it is calling something that
     // is inaccessible. Inlining in that case could move the code to another package making a
@@ -340,9 +343,9 @@
     // we have to make sure that inlining cannot make it inaccessible.
     ConstraintWithTarget classConstraintWithTarget =
         ConstraintWithTarget.deriveConstraint(
-            invocationContext, methodHolder, methodClass.accessFlags, appInfo);
+            invocationContext, methodHolder, methodClass.accessFlags, appView);
     ConstraintWithTarget result =
-        ConstraintWithTarget.meet(methodConstraintWithTarget, classConstraintWithTarget, appInfo);
+        ConstraintWithTarget.meet(methodConstraintWithTarget, classConstraintWithTarget, appView);
     if (result == ConstraintWithTarget.NEVER) {
       return result;
     }
@@ -351,11 +354,11 @@
     // of the method itself.
     for (DexEncodedMethod target : targets) {
       methodHolder = graphLense.lookupType(target.method.holder);
-      assert appInfo.definitionFor(methodHolder) != null;
+      assert appView.definitionFor(methodHolder) != null;
       methodConstraintWithTarget =
           ConstraintWithTarget.deriveConstraint(
-              invocationContext, methodHolder, target.accessFlags, appInfo);
-      result = ConstraintWithTarget.meet(result, methodConstraintWithTarget, appInfo);
+              invocationContext, methodHolder, target.accessFlags, appView);
+      result = ConstraintWithTarget.meet(result, methodConstraintWithTarget, appView);
       if (result == ConstraintWithTarget.NEVER) {
         return result;
       }
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 002461f..0d5a895 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
@@ -220,7 +220,7 @@
         && current.outValue().canBeNull()) {
       Value knownToBeNonNullValue = current.outValue();
       TypeLatticeElement typeLattice = knownToBeNonNullValue.getTypeLattice();
-      knownToBeNonNullValue.narrowing(appView.appInfo(), typeLattice.asNonNullable());
+      knownToBeNonNullValue.narrowing(appView, typeLattice.asNonNullable());
       affectedValues.addAll(knownToBeNonNullValue.affectedValues());
     }
     if (target.getOptimizationInfo().returnsConstant()) {
@@ -310,7 +310,7 @@
               && outValue.getTypeLattice().isReference()
               && outValue.canBeNull()) {
             TypeLatticeElement typeLattice = outValue.getTypeLattice();
-            outValue.narrowing(appView.appInfo(), typeLattice.asNonNullable());
+            outValue.narrowing(appView, typeLattice.asNonNullable());
             affectedValues.addAll(outValue.affectedValues());
           }
         }
@@ -367,7 +367,7 @@
       }
     }
     if (!affectedValues.isEmpty()) {
-      new TypeAnalysis(appView.appInfo(), code.method).narrowing(affectedValues);
+      new TypeAnalysis(appView, code.method).narrowing(affectedValues);
     }
     assert code.isConsistentSSA();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java b/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java
index 9a0a550..2a1092e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java
@@ -6,6 +6,7 @@
 import static com.android.tools.r8.ir.code.DominatorTree.Assumption.MAY_HAVE_UNREACHABLE_BLOCKS;
 
 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.DexMethod;
 import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
@@ -40,13 +41,13 @@
 
 public class NonNullTracker {
 
-  private final AppInfoWithLiveness appInfo;
+  private final AppView<? extends AppInfoWithLiveness> appView;
   private final Set<DexMethod> libraryMethodsReturningNonNull;
 
   public NonNullTracker(
-      AppInfoWithLiveness appInfo,
+      AppView<? extends AppInfoWithLiveness> appView,
       Set<DexMethod> libraryMethodsReturningNonNull) {
-    this.appInfo = appInfo;
+    this.appView = appView;
     this.libraryMethodsReturningNonNull = libraryMethodsReturningNonNull;
   }
 
@@ -121,7 +122,9 @@
         }
         if (current.isInvokeMethod() && !current.isInvokePolymorphic()) {
           DexEncodedMethod singleTarget =
-              current.asInvokeMethod().lookupSingleTarget(appInfo, code.method.method.getHolder());
+              current
+                  .asInvokeMethod()
+                  .lookupSingleTarget(appView.appInfo(), code.method.method.getHolder());
           if (singleTarget != null
               && singleTarget.getOptimizationInfo().getNonNullParamOnNormalExits() != null) {
             BitSet facts = singleTarget.getOptimizationInfo().getNonNullParamOnNormalExits();
@@ -218,7 +221,7 @@
       }
     }
     if (!affectedValues.isEmpty()) {
-      new TypeAnalysis(appInfo, code.method).narrowing(affectedValues);
+      new TypeAnalysis(appView, code.method).narrowing(affectedValues);
     }
   }
 
@@ -500,7 +503,7 @@
     // Since z is defined as "z = (T) x", and x is nullable, it is no longer sound to have that z
     // is not nullable. This is fixed by rerunning the type analysis for the affected values.
     if (!affectedValues.isEmpty()) {
-      new TypeAnalysis(appInfo, code.method).widening(affectedValues);
+      new TypeAnalysis(appView, code.method).widening(affectedValues);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
index 5ba7eb1..a7ec086 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
@@ -10,13 +10,13 @@
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ClassAccessFlags;
 import com.android.tools.r8.graph.Code;
 import com.android.tools.r8.graph.DebugLocalInfo;
 import com.android.tools.r8.graph.DexAnnotationSet;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexProto;
@@ -103,7 +103,6 @@
  */
 public class Outliner {
 
-  private final InternalOptions options;
   /** Result of first step (see {@link Outliner#identifyCandidateMethods()}. */
   private final List<List<DexEncodedMethod>> candidateMethodLists = new ArrayList<>();
   /** Result of second step (see {@link Outliner#selectMethodsForOutlining()}. */
@@ -115,9 +114,7 @@
 
   static final int MAX_IN_SIZE = 5;  // Avoid using ranged calls for outlined code.
 
-  final private AppInfoWithLiveness appInfo;
-  final private DexItemFactory dexItemFactory;
-  final private IRConverter converter;
+  private final AppView<? extends AppInfoWithLiveness> appView;
   private final InliningConstraints inliningConstraints;
 
   private abstract static class OutlineInstruction {
@@ -360,7 +357,7 @@
     @Override
     public int createInstruction(IRBuilder builder, Outline outline, int argumentMapIndex) {
       TypeLatticeElement latticeElement =
-          TypeLatticeElement.fromDexType(clazz, definitelyNotNull(), builder.getAppInfo());
+          TypeLatticeElement.fromDexType(clazz, definitelyNotNull(), builder.appView);
       Value outValue =
           builder.writeRegister(outline.argumentCount(), latticeElement, ThrowingInfo.CAN_THROW);
       Instruction newInstruction = new NewInstance(clazz, outValue);
@@ -496,8 +493,7 @@
       Value outValue = null;
       if (hasOutValue) {
         TypeLatticeElement latticeElement =
-            TypeLatticeElement.fromDexType(
-                method.proto.returnType, maybeNull(), builder.getAppInfo());
+            TypeLatticeElement.fromDexType(method.proto.returnType, maybeNull(), builder.appView);
         outValue =
             builder.writeRegister(outline.argumentCount(), latticeElement, ThrowingInfo.CAN_THROW);
       }
@@ -571,14 +567,14 @@
     DexProto buildProto() {
       if (proto == null) {
         DexType[] argumentTypesArray = argumentTypes.toArray(new DexType[argumentTypes.size()]);
-        proto = dexItemFactory.createProto(returnType, argumentTypesArray);
+        proto = appView.dexItemFactory().createProto(returnType, argumentTypesArray);
       }
       return proto;
     }
 
     // Build the DexMethod for this outline.
     DexMethod buildMethod(DexType clazz, DexString name) {
-      return dexItemFactory.createMethod(clazz, buildProto(), name);
+      return appView.dexItemFactory().createMethod(clazz, buildProto(), name);
     }
 
     @Override
@@ -695,7 +691,7 @@
         builder.append(instruction.getDetailsString());
         builder.append("\n");
       }
-      if (returnType == dexItemFactory.voidType) {
+      if (returnType == appView.dexItemFactory().voidType) {
         builder.append("Return-Void");
       } else {
         StringUtils.appendRightPadded(builder, "Return", 20);
@@ -798,7 +794,7 @@
         // Add this instruction.
         includeInstruction(instruction);
         // Check if this instruction ends the outline.
-        if (actualInstructions >= options.outline.maxSize) {
+        if (actualInstructions >= appView.options().outline.maxSize) {
           candidate(start, index + 1);
         } else {
           index++;
@@ -848,7 +844,7 @@
         return false;
       }
       InvokeMethod invoke = instruction.asInvokeMethod();
-      boolean constructor = dexItemFactory.isConstructor(invoke.getInvokedMethod());
+      boolean constructor = appView.dexItemFactory().isConstructor(invoke.getInvokedMethod());
 
       // See whether we could move this invoke somewhere else. We reuse the logic from inlining
       // here, as the constraints are the same.
@@ -932,7 +928,7 @@
           }
           if (returnValueUsersLeft == 0) {
             returnValue = null;
-            returnType = dexItemFactory.voidType;
+            returnType = appView.dexItemFactory().voidType;
           }
         }
       }
@@ -961,7 +957,7 @@
               DexType receiverType = argumentTypeFromInvoke(invoke, i);
               // Ensure that the outline argument type is specific enough.
               if (receiverType.isClassType()) {
-                if (receiverType.isSubtypeOf(argumentTypes.get(argumentIndex), appInfo)) {
+                if (receiverType.isSubtypeOf(argumentTypes.get(argumentIndex), appView)) {
                   argumentTypes.set(argumentIndex, receiverType);
                 }
               }
@@ -978,7 +974,8 @@
               argumentTypes
                   .add(instruction.asInvokeMethod().getInvokedMethod().proto.parameters.values[i]);
             } else {
-              argumentTypes.add(instruction.asBinop().getNumericType().dexTypeFor(dexItemFactory));
+              argumentTypes.add(
+                  instruction.asBinop().getNumericType().dexTypeFor(appView.dexItemFactory()));
             }
             argumentsMap.add(argumentTypes.size() - 1);
           }
@@ -993,7 +990,7 @@
         } else {
           updateReturnValueState(
               instruction.outValue(),
-              instruction.asBinop().getNumericType().dexTypeFor(dexItemFactory));
+              instruction.asBinop().getNumericType().dexTypeFor(appView.dexItemFactory()));
         }
       }
     }
@@ -1003,7 +1000,7 @@
       // If the return value is not used don't track it.
       if (returnValueUsersLeft == 0) {
         returnValue = null;
-        returnType = dexItemFactory.voidType;
+        returnType = appView.dexItemFactory().voidType;
       } else {
         returnValue = newReturnValue;
         returnType = newReturnType;
@@ -1039,7 +1036,7 @@
           nonConstInstructions++;
         }
       }
-      if (nonConstInstructions < options.outline.minSize) {
+      if (nonConstInstructions < appView.options().outline.minSize) {
         reset(start + 1);
         return;
       }
@@ -1061,7 +1058,7 @@
       argumentTypes = new ArrayList<>(MAX_IN_SIZE);
       argumentsMap = new ArrayList<>(MAX_IN_SIZE);
       argumentRegisters = 0;
-      returnType = dexItemFactory.voidType;
+      returnType = appView.dexItemFactory().voidType;
       returnValue = null;
       returnValueUsersLeft = 0;
       pendingNewInstanceIndex = -1;
@@ -1202,12 +1199,9 @@
     }
   }
 
-  public Outliner(AppInfoWithLiveness appInfo, InternalOptions options, IRConverter converter) {
-    this.appInfo = appInfo;
-    this.dexItemFactory = appInfo.dexItemFactory;
-    this.converter = converter;
-    this.inliningConstraints = new InliningConstraints(appInfo);
-    this.options = options;
+  public Outliner(AppView<? extends AppInfoWithLiveness> appView, IRConverter converter) {
+    this.appView = appView;
+    this.inliningConstraints = new InliningConstraints(appView, GraphLense.getIdentityLense());
   }
 
   public BiConsumer<IRCode, DexEncodedMethod> identifyCandidateMethods() {
@@ -1236,12 +1230,10 @@
     assert methodsSelectedForOutlining.size() == 0;
     assert outlineSites.size() == 0;
     for (List<DexEncodedMethod> outlineMethods : candidateMethodLists) {
-      if (outlineMethods.size() >= options.outline.threshold) {
+      if (outlineMethods.size() >= appView.options().outline.threshold) {
         for (DexEncodedMethod outlineMethod : outlineMethods) {
           methodsSelectedForOutlining.add(
-              converter
-                  .graphLense()
-                  .mapDexEncodedMethod(outlineMethod, appInfo));
+              appView.graphLense().mapDexEncodedMethod(outlineMethod, appView));
         }
       }
     }
@@ -1265,7 +1257,8 @@
       MethodAccessFlags methodAccess =
           MethodAccessFlags.fromSharedAccessFlags(
               Constants.ACC_PUBLIC | Constants.ACC_STATIC, false);
-      DexString methodName = dexItemFactory.createString(OutlineOptions.METHOD_PREFIX + count);
+      DexString methodName =
+          appView.dexItemFactory().createString(OutlineOptions.METHOD_PREFIX + count);
       DexMethod method = outline.buildMethod(type, methodName);
       List<DexEncodedMethod> sites = outlineSites.get(outline);
       assert !sites.isEmpty();
@@ -1276,7 +1269,7 @@
               DexAnnotationSet.empty(),
               ParameterAnnotationsList.empty(),
               new OutlineCode(outline));
-      if (options.isGeneratingClassFiles()) {
+      if (appView.options().isGeneratingClassFiles()) {
         direct[count].upgradeClassFileVersion(sites.get(0).getClassFileVersion());
       }
       generatedOutlines.put(outline, method);
@@ -1285,9 +1278,9 @@
     // No need to sort the direct methods as they are generated in sorted order.
 
     // Build the outliner class.
-    DexType superType = dexItemFactory.createType("Ljava/lang/Object;");
+    DexType superType = appView.dexItemFactory().createType("Ljava/lang/Object;");
     DexTypeList interfaces = DexTypeList.empty();
-    DexString sourceFile = dexItemFactory.createString("outline");
+    DexString sourceFile = appView.dexItemFactory().createString("outline");
     ClassAccessFlags accessFlags = ClassAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC);
     DexProgramClass clazz =
         new DexProgramClass(
@@ -1306,7 +1299,7 @@
             DexEncodedField.EMPTY_ARRAY, // Instance fields.
             direct,
             DexEncodedMethod.EMPTY_ARRAY, // Virtual methods.
-            options.itemFactory.getSkipNameValidationForTesting());
+            appView.dexItemFactory().getSkipNameValidationForTesting());
     return clazz;
   }
 
@@ -1315,7 +1308,7 @@
     assert candidateMethodLists.isEmpty();
     List<Outline> result = new ArrayList<>();
     for (Entry<Outline, List<DexEncodedMethod>> entry : outlineSites.entrySet()) {
-      if (entry.getValue().size() >= options.outline.threshold) {
+      if (entry.getValue().size() >= appView.options().outline.threshold) {
         result.add(entry.getKey());
       }
     }
@@ -1404,7 +1397,7 @@
       // Fill in the Argument instructions in the argument block.
       for (int i = 0; i < outline.argumentTypes.size(); i++) {
         TypeLatticeElement typeLattice =
-            TypeLatticeElement.fromDexType(outline.argumentTypes.get(i), maybeNull(), appInfo);
+            TypeLatticeElement.fromDexType(outline.argumentTypes.get(i), maybeNull(), appView);
         builder.addNonThisArgument(i, typeLattice);
       }
       builder.flushArgumentInstructions();
@@ -1425,7 +1418,7 @@
     public void buildInstruction(
         IRBuilder builder, int instructionIndex, boolean firstBlockInstruction) {
       if (instructionIndex == outline.templateInstructions.size()) {
-        if (outline.returnType == dexItemFactory.voidType) {
+        if (outline.returnType == appView.dexItemFactory().voidType) {
           builder.addReturn();
         } else {
           builder.addReturn(outline.argumentCount());
@@ -1520,14 +1513,10 @@
 
     @Override
     public IRCode buildIR(
-        DexEncodedMethod encodedMethod,
-        AppInfo appInfo,
-        GraphLense graphLense,
-        InternalOptions options,
-        Origin origin) {
+        DexEncodedMethod encodedMethod, AppView<? extends AppInfo> appView, Origin origin) {
       assert getOwner() == encodedMethod;
       OutlineSourceCode source = new OutlineSourceCode(outline, encodedMethod.method);
-      return new IRBuilder(encodedMethod, appInfo, source, options, origin).build(encodedMethod);
+      return new IRBuilder(encodedMethod, appView, source, origin).build(encodedMethod);
     }
 
     @Override
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 9b0ab04..e298873 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
@@ -5,6 +5,7 @@
 package com.android.tools.r8.ir.optimize;
 
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexField;
@@ -29,10 +30,9 @@
 // TODO(ager): Evaluate speed/size for computing active field sets in a fixed-point computation.
 public class RedundantFieldLoadElimination {
 
-  private final AppInfo appInfo;
+  private final AppView<? extends AppInfo> appView;
   private final DexEncodedMethod method;
   private final IRCode code;
-  private final boolean enableWholeProgramOptimizations;
   private final DominatorTree dominatorTree;
 
   // Maps keeping track of fields that have an already loaded value at basic block entry.
@@ -46,12 +46,10 @@
   private HashMap<FieldAndObject, Instruction> activeInstanceFields;
   private HashMap<DexField, Instruction> activeStaticFields;
 
-  public RedundantFieldLoadElimination(
-      AppInfo appInfo, IRCode code, boolean enableWholeProgramOptimizations) {
-    this.appInfo = appInfo;
+  public RedundantFieldLoadElimination(AppView<? extends AppInfo> appView, IRCode code) {
+    this.appView = appView;
     this.method = code.method;
     this.code = code;
-    this.enableWholeProgramOptimizations = enableWholeProgramOptimizations;
     dominatorTree = new DominatorTree(code);
   }
 
@@ -80,10 +78,11 @@
   }
 
   private boolean couldBeVolatile(DexField field) {
-    if (!enableWholeProgramOptimizations && field.getHolder() != method.method.getHolder()) {
+    if (!appView.enableWholeProgramOptimizations()
+        && field.getHolder() != method.method.getHolder()) {
       return true;
     }
-    DexEncodedField definition = appInfo.definitionFor(field);
+    DexEncodedField definition = appView.definitionFor(field);
     return definition == null || definition.accessFlags.isVolatile();
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
index 9d41edc..bd0fdea 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
@@ -9,6 +9,7 @@
 import static com.android.tools.r8.utils.DescriptorUtils.getSimpleClassNameFromDescriptor;
 
 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.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
@@ -75,8 +76,9 @@
   }
 
   // Rewrite getClass() call to const-class if the type of the given instance is effectively final.
-  public static void rewriteGetClass(AppInfoWithLiveness appInfo, IRCode code) {
+  public static void rewriteGetClass(AppView<? extends AppInfoWithLiveness> appView, IRCode code) {
     InstructionIterator it = code.instructionIterator();
+    DexItemFactory dexItemFactory = appView.dexItemFactory();
     while (it.hasNext()) {
       Instruction current = it.next();
       // Conservatively bail out if the containing block has catch handlers.
@@ -90,7 +92,7 @@
       InvokeVirtual invoke = current.asInvokeVirtual();
       DexMethod invokedMethod = invoke.getInvokedMethod();
       // Class<?> Object#getClass() is final and cannot be overridden.
-      if (invokedMethod != appInfo.dexItemFactory.objectMethods.getClass) {
+      if (invokedMethod != dexItemFactory.objectMethods.getClass) {
         continue;
       }
       Value in = invoke.getReceiver();
@@ -103,31 +105,32 @@
           || inType.isNullable()) {
         continue;
       }
-      DexType type = inType.isClassType()
-          ? inType.asClassTypeLatticeElement().getClassType()
-          : inType.asArrayTypeLatticeElement().getArrayType(appInfo.dexItemFactory);
-      DexType baseType = type.toBaseType(appInfo.dexItemFactory);
+      DexType type =
+          inType.isClassType()
+              ? inType.asClassTypeLatticeElement().getClassType()
+              : inType.asArrayTypeLatticeElement().getArrayType(dexItemFactory);
+      DexType baseType = type.toBaseType(dexItemFactory);
       // Make sure base type is a class type.
       if (!baseType.isClassType()) {
         continue;
       }
       // Only consider program class, e.g., platform can introduce sub types in different versions.
-      DexClass clazz = appInfo.definitionFor(baseType);
+      DexClass clazz = appView.definitionFor(baseType);
       if (clazz == null || !clazz.isProgramClass()) {
         continue;
       }
       // Only consider effectively final class. Exception: new Base().getClass().
       if (!baseType.hasSubtypes()
-          || !appInfo.isInstantiatedIndirectly(baseType)
+          || !appView.appInfo().isInstantiatedIndirectly(baseType)
           || (!in.isPhi() && in.definition.isCreatingInstanceOrArray())) {
         // Make sure the target (base) type is visible.
         ConstraintWithTarget constraints =
-            ConstraintWithTarget.classIsVisible(code.method.method.getHolder(), baseType, appInfo);
+            ConstraintWithTarget.classIsVisible(code.method.method.getHolder(), baseType, appView);
         if (constraints == ConstraintWithTarget.NEVER) {
           continue;
         }
         TypeLatticeElement typeLattice =
-            TypeLatticeElement.classClassType(appInfo, definitelyNotNull());
+            TypeLatticeElement.classClassType(appView, definitelyNotNull());
         Value value = code.createValue(typeLattice, invoke.getLocalInfo());
         ConstClass constClass = new ConstClass(value, type);
         it.replaceCurrentInstruction(constClass);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/SwitchMapCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/SwitchMapCollector.java
index 47284cc..a20539c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/SwitchMapCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/SwitchMapCollector.java
@@ -10,13 +10,11 @@
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionIterator;
 import com.android.tools.r8.ir.code.InvokeVirtual;
 import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
-import com.android.tools.r8.utils.InternalOptions;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceArrayMap;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
 import java.util.Arrays;
@@ -62,30 +60,26 @@
  */
 public class SwitchMapCollector {
 
-  private final AppInfoWithLiveness appInfo;
-  private final GraphLense graphLense;
-  private final InternalOptions options;
+  private final AppView<? extends AppInfoWithLiveness> appView;
   private final DexString switchMapPrefix;
   private final DexType intArrayType;
 
   private final Map<DexField, Int2ReferenceMap<DexField>> switchMaps = new IdentityHashMap<>();
 
   public SwitchMapCollector(AppView<? extends AppInfoWithLiveness> appView) {
-    this.appInfo = appView.appInfo();
-    this.graphLense = appView.graphLense();
-    this.options = appView.options();
-    switchMapPrefix = appInfo.dexItemFactory.createString("$SwitchMap$");
-    intArrayType = appInfo.dexItemFactory.createType("[I");
+    this.appView = appView;
+    switchMapPrefix = appView.dexItemFactory().createString("$SwitchMap$");
+    intArrayType = appView.dexItemFactory().createType("[I");
   }
 
   public AppInfoWithLiveness run() {
-    for (DexProgramClass clazz : appInfo.classes()) {
+    for (DexProgramClass clazz : appView.appInfo().classes()) {
       processClasses(clazz);
     }
     if (!switchMaps.isEmpty()) {
-      return appInfo.addSwitchMaps(switchMaps);
+      return appView.appInfo().addSwitchMaps(switchMaps);
     }
-    return appInfo;
+    return appView.appInfo();
   }
 
   private void processClasses(DexProgramClass clazz) {
@@ -96,8 +90,7 @@
     List<DexEncodedField> switchMapFields = Arrays.stream(clazz.staticFields())
         .filter(this::maybeIsSwitchMap).collect(Collectors.toList());
     if (!switchMapFields.isEmpty()) {
-      IRCode initializer =
-          clazz.getClassInitializer().buildIR(appInfo, graphLense, options, clazz.origin);
+      IRCode initializer = clazz.getClassInitializer().buildIR(appView, clazz.origin);
       switchMapFields.forEach(field -> extractSwitchMap(field, initializer));
     }
   }
@@ -121,9 +114,10 @@
             return;
           }
           InvokeVirtual invoke = value.asInvokeVirtual();
-          DexClass holder = appInfo.definitionFor(invoke.getInvokedMethod().holder);
-          if (holder == null ||
-              (!holder.accessFlags.isEnum() && holder.type != appInfo.dexItemFactory.enumType)) {
+          DexClass holder = appView.definitionFor(invoke.getInvokedMethod().holder);
+          if (holder == null
+              || (!holder.accessFlags.isEnum()
+                  && holder.type != appView.dexItemFactory().enumType)) {
             return;
           }
           Instruction enumGet = invoke.arguments().get(0).definition;
@@ -131,7 +125,7 @@
             return;
           }
           DexField enumField = enumGet.asStaticGet().getField();
-          if (!appInfo.definitionFor(enumField.getHolder()).accessFlags.isEnum()) {
+          if (!appView.definitionFor(enumField.getHolder()).accessFlags.isEnum()) {
             return;
           }
           if (switchMap.put(integerIndex, enumField) != null) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
index 1f4c1c3..da18d38 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.ir.optimize.classinliner;
 
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory;
@@ -25,16 +26,15 @@
 import java.util.stream.Collectors;
 
 public final class ClassInliner {
-  private final DexItemFactory factory;
+
+  private final AppView<? extends AppInfoWithLiveness> appView;
   private final LambdaRewriter lambdaRewriter;
-  private final int totalMethodInstructionLimit;
   private final ConcurrentHashMap<DexClass, Boolean> knownClasses = new ConcurrentHashMap<>();
 
-  public ClassInliner(DexItemFactory factory,
-      LambdaRewriter lambdaRewriter, int totalMethodInstructionLimit) {
-    this.factory = factory;
+  public ClassInliner(
+      AppView<? extends AppInfoWithLiveness> appView, LambdaRewriter lambdaRewriter) {
+    this.appView = appView;
     this.lambdaRewriter = lambdaRewriter;
-    this.totalMethodInstructionLimit = totalMethodInstructionLimit;
   }
 
   // Process method code and inline eligible class instantiations, in short:
@@ -115,7 +115,7 @@
   //   }
   //
   public final void processMethodCode(
-      AppInfoWithLiveness appInfo,
+      AppView<? extends AppInfoWithLiveness> appView,
       CodeRewriter codeRewriter,
       StringOptimizer stringOptimizer,
       DexEncodedMethod method,
@@ -144,11 +144,10 @@
         Instruction root = rootsIterator.next();
         InlineCandidateProcessor processor =
             new InlineCandidateProcessor(
-                factory,
-                appInfo,
+                appView,
                 lambdaRewriter,
                 inliner,
-                clazz -> isClassEligible(appInfo, clazz),
+                clazz -> isClassEligible(appView, clazz),
                 isProcessedConcurrently,
                 method,
                 root);
@@ -169,7 +168,8 @@
         }
 
         // Is inlining allowed.
-        if (processor.getEstimatedCombinedSizeForInlining() >= totalMethodInstructionLimit) {
+        if (processor.getEstimatedCombinedSizeForInlining()
+            >= appView.options().classInliningInstructionLimit) {
           continue;
         }
 
@@ -201,10 +201,10 @@
     }
   }
 
-  private boolean isClassEligible(AppInfoWithLiveness appInfo, DexClass clazz) {
+  private boolean isClassEligible(AppView<? extends AppInfoWithLiveness> appView, DexClass clazz) {
     Boolean eligible = knownClasses.get(clazz);
     if (eligible == null) {
-      Boolean computed = computeClassEligible(appInfo, clazz);
+      Boolean computed = computeClassEligible(appView, clazz);
       Boolean existing = knownClasses.putIfAbsent(clazz, computed);
       assert existing == null || existing == computed;
       eligible = existing == null ? computed : existing;
@@ -216,24 +216,26 @@
   //   - is not an abstract class or interface
   //   - does not declare finalizer
   //   - does not trigger any static initializers except for its own
-  private boolean computeClassEligible(AppInfoWithLiveness appInfo, DexClass clazz) {
+  private boolean computeClassEligible(
+      AppView<? extends AppInfoWithLiveness> appView, DexClass clazz) {
     if (clazz == null
         || clazz.isLibraryClass()
         || clazz.accessFlags.isAbstract()
         || clazz.accessFlags.isInterface()
-        || appInfo.neverClassInline.contains(clazz.type)) {
+        || appView.appInfo().neverClassInline.contains(clazz.type)) {
       return false;
     }
 
     // Class must not define finalizer.
+    DexItemFactory dexItemFactory = appView.dexItemFactory();
     for (DexEncodedMethod method : clazz.virtualMethods()) {
-      if (method.method.name == factory.finalizeMethodName &&
-          method.method.proto == factory.objectMethods.finalize.proto) {
+      if (method.method.name == dexItemFactory.finalizeMethodName
+          && method.method.proto == dexItemFactory.objectMethods.finalize.proto) {
         return false;
       }
     }
 
     // Check for static initializers in this class or any of interfaces it implements.
-    return !clazz.initializationOfParentTypesMayHaveSideEffects(appInfo);
+    return !clazz.initializationOfParentTypesMayHaveSideEffects(appView.appInfo());
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/FieldValueHelper.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/FieldValueHelper.java
index 425ce11..bbbb3e8 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/FieldValueHelper.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/FieldValueHelper.java
@@ -7,6 +7,7 @@
 import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull;
 
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.code.BasicBlock;
@@ -29,17 +30,18 @@
   private final DexField field;
   private final IRCode code;
   private final Instruction root;
-  private final AppInfo appInfo;
+  private final AppView<? extends AppInfo> appView;
 
   private Value defaultValue = null;
   private final Map<BasicBlock, Value> ins = new IdentityHashMap<>();
   private final Map<BasicBlock, Value> outs = new IdentityHashMap<>();
 
-  FieldValueHelper(DexField field, IRCode code, Instruction root, AppInfo appInfo) {
+  FieldValueHelper(
+      DexField field, IRCode code, Instruction root, AppView<? extends AppInfo> appView) {
     this.field = field;
     this.code = code;
     this.root = root;
-    this.appInfo = appInfo;
+    this.appView = appView;
   }
 
   void replaceValue(Value oldValue, Value newValue) {
@@ -94,7 +96,7 @@
           new Phi(
               code.valueNumberGenerator.next(),
               block,
-              TypeLatticeElement.fromDexType(field.type, maybeNull(), appInfo),
+              TypeLatticeElement.fromDexType(field.type, maybeNull(), appView),
               null,
               RegisterReadType.NORMAL);
       ins.put(block, phi);
@@ -142,8 +144,8 @@
     assert root == valueProducingInsn;
     if (defaultValue == null) {
       // If we met newInstance it means that default value is supposed to be used.
-      defaultValue = code.createValue(
-          TypeLatticeElement.fromDexType(field.type, maybeNull(), appInfo));
+      defaultValue =
+          code.createValue(TypeLatticeElement.fromDexType(field.type, maybeNull(), appView));
       ConstNumber defaultValueInsn = new ConstNumber(defaultValue, 0);
       defaultValueInsn.setPosition(root.getPosition());
       LinkedList<Instruction> instructions = block.getInstructions();
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 ec61b42..f36a132 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
@@ -6,6 +6,7 @@
 
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo.ResolutionResult;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexEncodedMethod.ClassInlinerEligibility;
@@ -13,7 +14,6 @@
 import com.android.tools.r8.graph.DexEncodedMethod.TrivialInitializer.TrivialClassInitializer;
 import com.android.tools.r8.graph.DexEncodedMethod.TrivialInitializer.TrivialInstanceInitializer;
 import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.OptimizationInfo;
@@ -58,8 +58,7 @@
   private static final ImmutableSet<If.Type> ALLOWED_ZERO_TEST_TYPES =
       ImmutableSet.of(If.Type.EQ, If.Type.NE);
 
-  private final DexItemFactory factory;
-  private final AppInfoWithLiveness appInfo;
+  private final AppView<? extends AppInfoWithLiveness> appView;
   private final LambdaRewriter lambdaRewriter;
   private final Inliner inliner;
   private final Predicate<DexClass> isClassEligible;
@@ -82,21 +81,19 @@
   private int estimatedCombinedSizeForInlining = 0;
 
   InlineCandidateProcessor(
-      DexItemFactory factory,
-      AppInfoWithLiveness appInfo,
+      AppView<? extends AppInfoWithLiveness> appView,
       LambdaRewriter lambdaRewriter,
       Inliner inliner,
       Predicate<DexClass> isClassEligible,
       Predicate<DexEncodedMethod> isProcessedConcurrently,
       DexEncodedMethod method,
       Instruction root) {
-    this.factory = factory;
+    this.appView = appView;
     this.lambdaRewriter = lambdaRewriter;
     this.inliner = inliner;
     this.isClassEligible = isClassEligible;
     this.method = method;
     this.root = root;
-    this.appInfo = appInfo;
     this.isProcessedConcurrently = isProcessedConcurrently;
   }
 
@@ -123,7 +120,7 @@
       isDesugaredLambda = eligibleClassDefinition != null;
     }
     if (eligibleClassDefinition == null) {
-      eligibleClassDefinition = appInfo.definitionFor(eligibleClass);
+      eligibleClassDefinition = appView.definitionFor(eligibleClass);
     }
     return eligibleClassDefinition != null;
   }
@@ -229,9 +226,11 @@
     assert info == null || info instanceof TrivialClassInitializer;
     DexField instanceField = root.asStaticGet().getField();
     // Singleton instance field must NOT be pinned.
-    return info != null &&
-        ((TrivialClassInitializer) info).field == instanceField &&
-        !appInfo.isPinned(eligibleClassDefinition.lookupStaticField(instanceField).field);
+    return info != null
+        && ((TrivialClassInitializer) info).field == instanceField
+        && !appView
+            .appInfo()
+            .isPinned(eligibleClassDefinition.lookupStaticField(instanceField).field);
   }
 
   /**
@@ -273,7 +272,7 @@
           // Eligible constructor call (for new instance roots only).
           if (user.isInvokeDirect()) {
             InvokeDirect invoke = user.asInvokeDirect();
-            if (factory.isConstructor(invoke.getInvokedMethod())) {
+            if (appView.dexItemFactory().isConstructor(invoke.getInvokedMethod())) {
               boolean isCorrespondingConstructorCall =
                   root.isNewInstance()
                       && !invoke.inValues().isEmpty()
@@ -414,10 +413,10 @@
     boolean needToRemoveUnreachableBlocks = false;
     for (Instruction user : eligibleInstance.uniqueUsers()) {
       // Remove the call to superclass constructor.
-      if (root.isNewInstance() &&
-          user.isInvokeDirect() &&
-          factory.isConstructor(user.asInvokeDirect().getInvokedMethod()) &&
-          user.asInvokeDirect().getInvokedMethod().holder == eligibleClassDefinition.superType) {
+      if (root.isNewInstance()
+          && user.isInvokeDirect()
+          && appView.dexItemFactory().isConstructor(user.asInvokeDirect().getInvokedMethod())
+          && user.asInvokeDirect().getInvokedMethod().holder == eligibleClassDefinition.superType) {
         removeInstruction(user);
         continue;
       }
@@ -491,14 +490,14 @@
     if (value != null) {
       FieldValueHelper helper =
           fieldHelpers.computeIfAbsent(
-              fieldRead.getField(), field -> new FieldValueHelper(field, code, root, appInfo));
+              fieldRead.getField(), field -> new FieldValueHelper(field, code, root, appView));
       Value newValue = helper.getValueForFieldRead(fieldRead.getBlock(), fieldRead);
       value.replaceUsers(newValue);
       for (FieldValueHelper fieldValueHelper : fieldHelpers.values()) {
         fieldValueHelper.replaceValue(value, newValue);
       }
       assert value.numberOfAllUsers() == 0;
-      new TypeAnalysis(appInfo, code.method).widening(code.method, code);
+      new TypeAnalysis(appView, code.method).widening(code.method, code);
     }
     removeInstruction(fieldRead);
   }
@@ -525,7 +524,7 @@
 
   private InliningInfo isEligibleConstructorCall(
       InvokeDirect invoke, DexEncodedMethod singleTarget, Supplier<InliningOracle> defaultOracle) {
-    assert factory.isConstructor(invoke.getInvokedMethod());
+    assert appView.dexItemFactory().isConstructor(invoke.getInvokedMethod());
     assert isEligibleSingleTarget(singleTarget);
 
     // Must be a constructor called on the receiver.
@@ -559,7 +558,7 @@
     // NOTE: since we already classified the class as eligible, it does not have
     //       any class initializers in superclass chain or in superinterfaces, see
     //       details in ClassInliner::computeClassEligible(...).
-    if (eligibleClassDefinition.superType != factory.objectType) {
+    if (eligibleClassDefinition.superType != appView.dexItemFactory().objectType) {
       TrivialInitializer info = singleTarget.getOptimizationInfo().getTrivialInitializerInfo();
       if (!(info instanceof TrivialInstanceInitializer)) {
         return null;
@@ -650,7 +649,7 @@
 
     // We should not inline a method if the invocation has type interface or virtual and the
     // signature of the invocation resolves to a private or static method.
-    ResolutionResult resolutionResult = appInfo.resolveMethod(callee.holder, callee);
+    ResolutionResult resolutionResult = appView.appInfo().resolveMethod(callee.holder, callee);
     if (resolutionResult.hasSingleTarget()
         && !resolutionResult.asSingleTarget().isVirtualMethod()) {
       return null;
@@ -686,7 +685,8 @@
   }
 
   private boolean isExtraMethodCall(InvokeMethod invoke) {
-    if (invoke.isInvokeDirect() && factory.isConstructor(invoke.getInvokedMethod())) {
+    if (invoke.isInvokeDirect()
+        && appView.dexItemFactory().isConstructor(invoke.getInvokedMethod())) {
       return false;
     }
     if (invoke.isInvokeMethodWithReceiver()
@@ -845,10 +845,10 @@
   }
 
   private boolean isTrivialInitializer(DexMethod method) {
-    if (method == appInfo.dexItemFactory.objectMethods.constructor) {
+    if (method == appView.dexItemFactory().objectMethods.constructor) {
       return true;
     }
-    DexEncodedMethod encodedMethod = appInfo.definitionFor(method);
+    DexEncodedMethod encodedMethod = appView.definitionFor(method);
     return encodedMethod != null
         && encodedMethod.getOptimizationInfo().getTrivialInitializerInfo() != null;
   }
@@ -858,10 +858,10 @@
     if (isDesugaredLambda && inlineeHolder == eligibleClass) {
       return true;
     }
-    if (appInfo.isPinned(inlineeHolder)) {
+    if (appView.appInfo().isPinned(inlineeHolder)) {
       return false;
     }
-    DexClass inlineeClass = appInfo.definitionFor(inlineeHolder);
+    DexClass inlineeClass = appView.definitionFor(inlineeHolder);
     assert inlineeClass != null;
 
     KotlinInfo kotlinInfo = inlineeClass.getKotlinInfo();
@@ -879,7 +879,7 @@
   private DexEncodedMethod findSingleTarget(InvokeMethod invoke) {
     if (isExtraMethodCall(invoke)) {
       DexType invocationContext = method.method.holder;
-      return invoke.lookupSingleTarget(appInfo, invocationContext);
+      return invoke.lookupSingleTarget(appView.appInfo(), invocationContext);
     }
     // We don't use computeSingleTarget(...) on invoke since it sometimes fails to
     // find the single target, while this code may be more successful since we exactly
@@ -908,7 +908,7 @@
       // return false.
       return true;
     }
-    if (!singleTarget.isInliningCandidate(method, Reason.SIMPLE, appInfo)) {
+    if (!singleTarget.isInliningCandidate(method, Reason.SIMPLE, appView.appInfo())) {
       // If `singleTarget` is not an inlining candidate, we won't be able to inline it here.
       //
       // Note that there may be some false negatives here since the method may
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
index 3538e8c..66ae73a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
@@ -34,7 +34,6 @@
 import com.android.tools.r8.ir.optimize.lambda.kotlin.KotlinLambdaGroupIdFactory;
 import com.android.tools.r8.kotlin.Kotlin;
 import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
-import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.StringDiagnostic;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.android.tools.r8.utils.ThrowingConsumer;
@@ -147,29 +146,35 @@
   // We do this before methods are being processed to guarantee stable order of
   // lambdas inside each group.
   public final void collectGroupCandidates(
-      DexApplication app, AppInfoWithLiveness infoWithLiveness, InternalOptions options) {
-    assert infoWithLiveness != null;
+      DexApplication app, AppView<? extends AppInfoWithLiveness> appView) {
     // Collect lambda groups.
     app.classes().stream()
-        .filter(cls -> !infoWithLiveness.isPinned(cls.type))
-        .filter(cls -> cls.hasKotlinInfo() &&
-            cls.getKotlinInfo().isSyntheticClass() &&
-            cls.getKotlinInfo().asSyntheticClass().isLambda())
+        .filter(cls -> !appView.appInfo().isPinned(cls.type))
+        .filter(
+            cls ->
+                cls.hasKotlinInfo()
+                    && cls.getKotlinInfo().isSyntheticClass()
+                    && cls.getKotlinInfo().asSyntheticClass().isLambda())
         .sorted((a, b) -> a.type.slowCompareTo(b.type)) // Ensure stable ordering.
-        .forEachOrdered(lambda -> {
-          try {
-            LambdaGroupId id = KotlinLambdaGroupIdFactory.create(kotlin, lambda, options);
-            LambdaGroup group = groups.computeIfAbsent(id, LambdaGroupId::createGroup);
-            group.add(lambda);
-            lambdas.put(lambda.type, group);
-          } catch (LambdaStructureError error) {
-            if (error.reportable) {
-              reporter.info(
-                  new StringDiagnostic("Unrecognized Kotlin lambda [" +
-                      lambda.type.toSourceString() + "]: " + error.getMessage()));
-            }
-          }
-        });
+        .forEachOrdered(
+            lambda -> {
+              try {
+                LambdaGroupId id =
+                    KotlinLambdaGroupIdFactory.create(kotlin, lambda, appView.options());
+                LambdaGroup group = groups.computeIfAbsent(id, LambdaGroupId::createGroup);
+                group.add(lambda);
+                lambdas.put(lambda.type, group);
+              } catch (LambdaStructureError error) {
+                if (error.reportable) {
+                  reporter.info(
+                      new StringDiagnostic(
+                          "Unrecognized Kotlin lambda ["
+                              + lambda.type.toSourceString()
+                              + "]: "
+                              + error.getMessage()));
+                }
+              }
+            });
 
     // Remove trivial groups.
     removeTrivialLambdaGroups();
@@ -233,9 +238,8 @@
       // Then, there is a dilemma: other sub optimizations trigger subtype lookup that will throw
       // NPE if it cannot find the holder for this synthesized lambda group.
       // One hack here is to mark those methods `processed` so that the lense rewriter is skipped.
-      synthesizedClass.forEachMethod(encodedMethod -> {
-        encodedMethod.markProcessed(ConstraintWithTarget.NEVER);
-      });
+      synthesizedClass.forEachMethod(
+          encodedMethod -> encodedMethod.markProcessed(ConstraintWithTarget.NEVER));
     }
     converter.optimizeSynthesizedClasses(lambdaGroupsClasses.values(), executorService);
 
@@ -324,7 +328,7 @@
     }
     Set<DexEncodedMethod> methods =
         methodsToReprocess.stream()
-            .map(method -> converter.graphLense().mapDexEncodedMethod(method, appView.appInfo()))
+            .map(method -> appView.graphLense().mapDexEncodedMethod(method, appView))
             .collect(Collectors.toSet());
     List<Future<?>> futures = new ArrayList<>();
     for (DexEncodedMethod method : methods) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java
index d69190f..9473341 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java
@@ -534,10 +534,10 @@
   //  2. Rewrite instance methods of classes being staticized into static ones
   //  3. Rewrite methods referencing staticized members, also remove instance creation
   //
-  public final Set<DexEncodedMethod> staticizeCandidates(
+  public final void staticizeCandidates(
       OptimizationFeedback feedback, ExecutorService executorService) throws ExecutionException {
     phase = Phase.None; // We are done with processing/examining methods.
-    return new StaticizingProcessor(this, executorService).run(feedback);
+    new StaticizingProcessor(appView, this, executorService).run(feedback);
   }
 
   public final void fixupMethodCode(DexEncodedMethod method, IRCode code) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerGraphLense.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerGraphLense.java
index 96bb394..5380baf 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerGraphLense.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerGraphLense.java
@@ -4,10 +4,10 @@
 
 package com.android.tools.r8.ir.optimize.staticizer;
 
+import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.graph.GraphLense.NestedGraphLense;
 import com.android.tools.r8.ir.code.Invoke.Type;
 import com.google.common.collect.BiMap;
@@ -16,17 +16,17 @@
 class ClassStaticizerGraphLense extends NestedGraphLense {
 
   ClassStaticizerGraphLense(
-      GraphLense previous,
-      DexItemFactory factory,
+      AppView<? extends AppInfo> appView,
       BiMap<DexField, DexField> fieldMapping,
       BiMap<DexMethod, DexMethod> methodMapping) {
-    super(ImmutableMap.of(),
+    super(
+        ImmutableMap.of(),
         methodMapping,
         fieldMapping,
         fieldMapping.inverse(),
         methodMapping.inverse(),
-        previous,
-        factory);
+        appView.graphLense(),
+        appView.dexItemFactory());
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
index 7106005..6331d5f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
@@ -6,6 +6,7 @@
 
 import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull;
 
+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.DexEncodedField;
@@ -30,6 +31,7 @@
 import com.android.tools.r8.ir.conversion.OptimizationFeedback;
 import com.android.tools.r8.ir.optimize.Outliner;
 import com.android.tools.r8.ir.optimize.staticizer.ClassStaticizer.CandidateInfo;
+import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.google.common.collect.BiMap;
 import com.google.common.collect.HashBiMap;
@@ -52,6 +54,7 @@
 
 final class StaticizingProcessor {
 
+  private final AppView<? extends AppInfoWithLiveness> appView;
   private final ClassStaticizer classStaticizer;
   private final ExecutorService executorService;
 
@@ -61,13 +64,16 @@
   private final Map<DexField, CandidateInfo> singletonFields = new IdentityHashMap<>();
   private final Map<DexType, DexType> candidateToHostMapping = new IdentityHashMap<>();
 
-  StaticizingProcessor(ClassStaticizer classStaticizer, ExecutorService executorService) {
+  StaticizingProcessor(
+      AppView<? extends AppInfoWithLiveness> appView,
+      ClassStaticizer classStaticizer,
+      ExecutorService executorService) {
+    this.appView = appView;
     this.classStaticizer = classStaticizer;
     this.executorService = executorService;
   }
 
-  /** @return the set of methods that have been reprocessed as a result of staticizing. */
-  final Set<DexEncodedMethod> run(OptimizationFeedback feedback) throws ExecutionException {
+  final void run(OptimizationFeedback feedback) throws ExecutionException {
     // Filter out candidates based on the information we collected while examining methods.
     finalEligibilityCheck();
 
@@ -90,8 +96,6 @@
     methods.addAll(referencingExtraMethods);
     methods.addAll(hostClassInits.keySet());
     processMethodsConcurrently(methods, this::rewriteReferences, feedback);
-
-    return methods;
   }
 
   private void finalEligibilityCheck() {
@@ -484,8 +488,7 @@
         }
       }
       candidateClass.setVirtualMethods(DexEncodedMethod.EMPTY_ARRAY);
-      candidateClass.setDirectMethods(
-          newDirectMethods.toArray(new DexEncodedMethod[newDirectMethods.size()]));
+      candidateClass.setDirectMethods(newDirectMethods.toArray(DexEncodedMethod.EMPTY_ARRAY));
 
       // Consider moving static members from candidate into host.
       DexType hostType = candidate.hostType();
@@ -501,12 +504,7 @@
     }
 
     if (!methodMapping.isEmpty() || !fieldMapping.isEmpty()) {
-      classStaticizer.converter.appView.setGraphLense(
-          new ClassStaticizerGraphLense(
-              classStaticizer.converter.graphLense(),
-              classStaticizer.factory,
-              fieldMapping,
-              methodMapping));
+      appView.setGraphLense(new ClassStaticizerGraphLense(appView, fieldMapping, methodMapping));
     }
     return staticizedMethods;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java
index faff2ac..21935b4 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/AbstractSynthesizedCode.java
@@ -6,9 +6,9 @@
 
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.Code;
 import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Position;
@@ -17,7 +17,6 @@
 import com.android.tools.r8.ir.conversion.SourceCode;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.utils.InternalOptions;
 import java.util.function.Consumer;
 
 public abstract class AbstractSynthesizedCode extends Code {
@@ -37,21 +36,15 @@
 
   @Override
   public final IRCode buildIR(
-      DexEncodedMethod encodedMethod,
-      AppInfo appInfo,
-      GraphLense graphLense,
-      InternalOptions options,
-      Origin origin) {
+      DexEncodedMethod encodedMethod, AppView<? extends AppInfo> appView, Origin origin) {
     assert getOwner() == encodedMethod;
     IRBuilder builder =
         new IRBuilder(
             encodedMethod,
-            appInfo,
+            appView,
             getSourceCodeProvider().get(null),
-            options,
             origin,
-            new ValueNumberGenerator(),
-            graphLense);
+            new ValueNumberGenerator());
     return builder.build(encodedMethod);
   }
 
@@ -59,9 +52,7 @@
   public IRCode buildInliningIR(
       DexEncodedMethod context,
       DexEncodedMethod encodedMethod,
-      AppInfo appInfo,
-      GraphLense graphLense,
-      InternalOptions options,
+      AppView<? extends AppInfo> appView,
       ValueNumberGenerator valueNumberGenerator,
       Position callerPosition,
       Origin origin) {
@@ -69,12 +60,10 @@
     IRBuilder builder =
         new IRBuilder(
             encodedMethod,
-            appInfo,
+            appView,
             getSourceCodeProvider().get(callerPosition),
-            options,
             origin,
-            valueNumberGenerator,
-            graphLense);
+            valueNumberGenerator);
     return builder.build(context);
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticSourceCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticSourceCode.java
index 031ae7e..a75b3bc 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/SyntheticSourceCode.java
@@ -189,7 +189,7 @@
           builder.writeRegister(
               receiverRegister,
               TypeLatticeElement.fromDexType(
-                  receiver, Nullability.definitelyNotNull(), builder.getAppInfo()),
+                  receiver, Nullability.definitelyNotNull(), builder.appView),
               NO_THROW);
       builder.add(new Argument(receiverValue));
       receiverValue.markAsThis();
@@ -200,8 +200,7 @@
     for (int i = 0; i < parameters.length; i++) {
       // TODO(zerny): Why does this not call builder.addNonThisArgument?
       TypeLatticeElement typeLattice =
-          TypeLatticeElement.fromDexType(
-              parameters[i], Nullability.maybeNull(), builder.getAppInfo());
+          TypeLatticeElement.fromDexType(parameters[i], Nullability.maybeNull(), builder.appView);
       Value paramValue = builder.writeRegister(paramRegisters[i], typeLattice, NO_THROW);
       paramValues[i] = paramValue;
       builder.add(new Argument(paramValue));
diff --git a/src/main/java/com/android/tools/r8/jar/InliningConstraintVisitor.java b/src/main/java/com/android/tools/r8/jar/InliningConstraintVisitor.java
index 4bfb5ce..d3cda4a 100644
--- a/src/main/java/com/android/tools/r8/jar/InliningConstraintVisitor.java
+++ b/src/main/java/com/android/tools/r8/jar/InliningConstraintVisitor.java
@@ -8,6 +8,7 @@
 
 import com.android.tools.r8.dex.Constants;
 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.DexEncodedMethod;
 import com.android.tools.r8.graph.DexField;
@@ -36,7 +37,7 @@
 public class InliningConstraintVisitor extends MethodVisitor {
 
   private final JarApplicationReader application;
-  private final AppInfoWithLiveness appInfo;
+  private final AppView<? extends AppInfoWithLiveness> appView;
   private final GraphLense graphLense;
   private final InliningConstraints inliningConstraints;
   private final DexEncodedMethod method;
@@ -46,16 +47,16 @@
 
   public InliningConstraintVisitor(
       JarApplicationReader application,
-      AppInfoWithLiveness appInfo,
+      AppView<? extends AppInfoWithLiveness> appView,
       GraphLense graphLense,
       DexEncodedMethod method,
       DexType invocationContext) {
     super(ASM6);
     assert graphLense.isContextFreeForMethods();
     this.application = application;
-    this.appInfo = appInfo;
+    this.appView = appView;
     this.graphLense = graphLense;
-    this.inliningConstraints = new InliningConstraints(appInfo, graphLense);
+    this.inliningConstraints = new InliningConstraints(appView, graphLense);
     this.method = method;
     this.invocationContext = invocationContext;
 
@@ -73,7 +74,7 @@
   }
 
   private void updateConstraint(ConstraintWithTarget other) {
-    constraint = ConstraintWithTarget.meet(constraint, other, appInfo);
+    constraint = ConstraintWithTarget.meet(constraint, other, appView);
   }
 
   // Used to signal that the result is ready, such that we do not need to visit all instructions of
@@ -180,7 +181,7 @@
         type = Invoke.Type.VIRTUAL;
         // Instructions that target a private method in the same class translates to invoke-direct.
         if (target.holder == method.method.holder) {
-          DexClass clazz = appInfo.definitionFor(target.holder);
+            DexClass clazz = appView.definitionFor(target.holder);
           if (clazz != null && clazz.lookupDirectMethod(target) != null) {
             type = Invoke.Type.DIRECT;
           }
diff --git a/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java b/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java
index 577da26..e5f9218 100644
--- a/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java
@@ -134,20 +134,19 @@
       return;
     }
     // Now, `field` is reference. Find its definition and check if it's renamed.
-    DexType holderType = field.getHolder();
-    DexClass holder = appInfo.definitionFor(holderType);
+    DexClass holder = appInfo.definitionFor(field.clazz);
     // We don't care pruned types or library classes.
     if (holder == null || holder.isLibraryClass()) {
       return;
     }
-    definition = appInfo.resolveFieldOn(holderType, field);
+    definition = appInfo.resolveField(field);
     if (definition == null) {
       // The program is already broken in the sense that it has an unresolvable field reference.
       // Leave it as-is.
       return;
     }
     assert definition.field != field;
-    assert definition.field.getHolder() != holderType;
+    assert definition.field.clazz != field.clazz;
     // If the definition is renamed,
     if (renaming.containsKey(definition.field)) {
       // Assign the same, renamed name as the definition to the reference.
diff --git a/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java b/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java
index 0638816..9479ab3 100644
--- a/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java
+++ b/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java
@@ -7,12 +7,11 @@
 import static com.android.tools.r8.naming.IdentifierNameStringUtils.inferMemberOrTypeFromNameString;
 import static com.android.tools.r8.naming.IdentifierNameStringUtils.isReflectionMethod;
 
-import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
 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.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexReference;
@@ -36,7 +35,6 @@
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.position.TextPosition;
 import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
-import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.StringDiagnostic;
 import com.google.common.collect.Streams;
 import it.unimi.dsi.fastutil.objects.Object2BooleanMap;
@@ -47,21 +45,18 @@
 import java.util.stream.Collectors;
 
 public class IdentifierNameStringMarker {
-  private final AppInfo appInfo;
-  private final DexItemFactory dexItemFactory;
-  private final Object2BooleanMap<DexReference> identifierNameStrings;
-  private final InternalOptions options;
 
-  public IdentifierNameStringMarker(AppInfoWithLiveness appInfo, InternalOptions options) {
-    this.appInfo = appInfo;
-    this.dexItemFactory = appInfo.dexItemFactory;
+  private final AppView<? extends AppInfoWithLiveness> appView;
+  private final Object2BooleanMap<DexReference> identifierNameStrings;
+
+  public IdentifierNameStringMarker(AppView<? extends AppInfoWithLiveness> appView) {
+    this.appView = appView;
     // Note that this info is only available at AppInfoWithLiveness.
-    this.identifierNameStrings = appInfo.identifierNameStrings;
-    this.options = options;
+    this.identifierNameStrings = appView.appInfo().identifierNameStrings;
   }
 
   public void decoupleIdentifierNameStringsInFields() {
-    for (DexProgramClass clazz : appInfo.classes()) {
+    for (DexProgramClass clazz : appView.appInfo().classes()) {
       for (DexEncodedField field : clazz.staticFields()) {
         decoupleIdentifierNameStringInStaticField(field);
       }
@@ -78,7 +73,7 @@
       return;
     }
     DexString original = ((DexValueString) staticValue).getValue();
-    DexReference itemBasedString = inferMemberOrTypeFromNameString(appInfo, original);
+    DexReference itemBasedString = inferMemberOrTypeFromNameString(appView, original);
     if (itemBasedString != null) {
       encodedField.setStaticValue(new DexItemBasedValueString(itemBasedString));
     }
@@ -88,8 +83,7 @@
     if (!code.hasConstString) {
       return;
     }
-    final ThrowingInfo throwingInfo =
-        options.isGeneratingClassFiles() ? ThrowingInfo.NO_THROW : ThrowingInfo.NO_THROW;
+    ThrowingInfo throwingInfo = ThrowingInfo.defaultForConstString(appView.options());
     DexType originHolder = code.method.method.getHolder();
     ListIterator<BasicBlock> blocks = code.listIterator();
     while (blocks.hasNext()) {
@@ -118,15 +112,13 @@
               ? instruction.asStaticPut().inValue()
               : instruction.asInstancePut().value();
           if (!in.isConstString()) {
-            warnUndeterminedIdentifierIfNecessary(
-                appInfo, options, field, originHolder, instruction, null);
+            warnUndeterminedIdentifierIfNecessary(field, originHolder, instruction, null);
             continue;
           }
           DexString original = in.getConstInstruction().asConstString().getValue();
-          DexReference itemBasedString = inferMemberOrTypeFromNameString(appInfo, original);
+          DexReference itemBasedString = inferMemberOrTypeFromNameString(appView, original);
           if (itemBasedString == null) {
-            warnUndeterminedIdentifierIfNecessary(
-                appInfo, options, field, originHolder, instruction, original);
+            warnUndeterminedIdentifierIfNecessary(field, originHolder, instruction, original);
             continue;
           }
           // Move the cursor back to $fieldPut
@@ -176,18 +168,17 @@
           }
           List<Value> ins = invoke.arguments();
           Value[] changes = new Value [ins.size()];
-          if (isReflectionMethod(dexItemFactory, invokedMethod)) {
-            DexReference itemBasedString = identifyIdentifier(appInfo, invoke);
+          if (isReflectionMethod(appView.dexItemFactory(), invokedMethod)) {
+            DexReference itemBasedString = identifyIdentifier(appView, invoke);
             if (itemBasedString == null) {
-              warnUndeterminedIdentifierIfNecessary(
-                  appInfo, options, invokedMethod, originHolder, instruction, null);
+              warnUndeterminedIdentifierIfNecessary(invokedMethod, originHolder, instruction, null);
               continue;
             }
             DexType returnType = invoke.getReturnType();
             boolean isClassForName =
-                returnType.descriptor == dexItemFactory.classDescriptor;
+                returnType.descriptor == appView.dexItemFactory().classDescriptor;
             boolean isReferenceFieldUpdater =
-                returnType.descriptor == dexItemFactory.referenceFieldUpdaterDescriptor;
+                returnType.descriptor == appView.dexItemFactory().referenceFieldUpdaterDescriptor;
             int positionOfIdentifier = isClassForName ? 0 : (isReferenceFieldUpdater ? 2 : 1);
             Value in = invoke.arguments().get(positionOfIdentifier);
             // Move the cursor back to $invoke
@@ -227,14 +218,14 @@
               Value in = ins.get(i);
               if (!in.isConstString()) {
                 warnUndeterminedIdentifierIfNecessary(
-                    appInfo, options, invokedMethod, originHolder, instruction, null);
+                    invokedMethod, originHolder, instruction, null);
                 continue;
               }
               DexString original = in.getConstInstruction().asConstString().getValue();
-              DexReference itemBasedString = inferMemberOrTypeFromNameString(appInfo, original);
+              DexReference itemBasedString = inferMemberOrTypeFromNameString(appView, original);
               if (itemBasedString == null) {
                 warnUndeterminedIdentifierIfNecessary(
-                    appInfo, options, invokedMethod, originHolder, instruction, original);
+                    invokedMethod, originHolder, instruction, original);
                 continue;
               }
               // Move the cursor back to $invoke
@@ -291,8 +282,6 @@
   }
 
   private void warnUndeterminedIdentifierIfNecessary(
-      AppInfo appInfo,
-      InternalOptions options,
       DexReference member,
       DexType originHolder,
       Instruction instruction,
@@ -303,16 +292,16 @@
     if (!matchedByExplicitRule) {
       return;
     }
-    DexClass originClass = appInfo.definitionFor(originHolder);
+    DexClass originClass = appView.definitionFor(originHolder);
     // If the origin is a library class, it is out of developers' control.
     if (originClass != null && originClass.isLibraryClass()) {
       return;
     }
     // Undetermined identifiers matter only if minification is enabled.
-    if (!options.getProguardConfiguration().isObfuscating()) {
+    if (!appView.options().getProguardConfiguration().isObfuscating()) {
       return;
     }
-    Origin origin = appInfo.originFor(originHolder);
+    Origin origin = appView.appInfo().originFor(originHolder);
     String kind = member instanceof DexField ? "field" : "method";
     String originalMessage = original == null ? "what identifier string flows to "
         : "what '" + original.toString() + "' refers to, which flows to ";
@@ -326,6 +315,6 @@
             ? new StringDiagnostic(message, origin,
             new TextPosition(0L, instruction.getPosition().line, 1))
             : new StringDiagnostic(message, origin);
-    options.reporter.warning(diagnostic);
+    appView.options().reporter.warning(diagnostic);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/naming/IdentifierNameStringUtils.java b/src/main/java/com/android/tools/r8/naming/IdentifierNameStringUtils.java
index 706620f..ba27d47 100644
--- a/src/main/java/com/android/tools/r8/naming/IdentifierNameStringUtils.java
+++ b/src/main/java/com/android/tools/r8/naming/IdentifierNameStringUtils.java
@@ -5,8 +5,8 @@
 
 import static com.android.tools.r8.utils.DescriptorUtils.javaTypeToDescriptorIfValidJavaType;
 
-import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexDefinitionSupplier;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory;
@@ -140,19 +140,20 @@
    * Returns a {@link DexReference} if one of the arguments to the invoke instruction is a constant
    * string that corresponds to either a class or member name (i.e., an identifier).
    *
-   * @param appInfo {@link AppInfo} that gives access to {@link DexItemFactory}.
+   * @param definitions {@link DexDefinitionSupplier} that gives access to {@link DexItemFactory}.
    * @param invoke {@link InvokeMethod} that is expected to have an identifier in its arguments.
    * @return {@link DexReference} corresponding to the first constant string argument that matches a
    *     class or member name, or {@code null} if no such constant was found.
    */
-  public static DexReference identifyIdentifier(AppInfo appInfo, InvokeMethod invoke) {
+  public static DexReference identifyIdentifier(
+      DexDefinitionSupplier definitions, InvokeMethod invoke) {
     List<Value> ins = invoke.arguments();
     // The only static call: Class#forName, which receives (String) as ins.
     if (ins.size() == 1) {
       Value in = ins.get(0);
       if (in.isConstString()) {
         ConstString constString = in.getConstInstruction().asConstString();
-        return inferMemberOrTypeFromNameString(appInfo, constString.getValue());
+        return inferMemberOrTypeFromNameString(definitions, constString.getValue());
       }
       if (in.isDexItemBasedConstString()) {
         DexItemBasedConstString constString = in.getConstInstruction().asDexItemBasedConstString();
@@ -162,7 +163,8 @@
     }
     // All the other cases receive either (Class, String) or (Class, String, Class[]) as ins.
     boolean isReferenceFieldUpdater =
-        invoke.getReturnType().descriptor == appInfo.dexItemFactory.referenceFieldUpdaterDescriptor;
+        invoke.getReturnType().descriptor
+            == definitions.dexItemFactory().referenceFieldUpdaterDescriptor;
     int positionOfIdentifier = isReferenceFieldUpdater ? 2 : 1;
     Value in = ins.get(positionOfIdentifier);
     if (in.isConstString()) {
@@ -176,7 +178,7 @@
         // declared in the library. Hence there is no need to handle this case.
         return null;
       }
-      DexClass holder = appInfo.definitionFor(holderType);
+      DexClass holder = definitions.definitionFor(holderType);
       if (holder == null) {
         return null;
       }
@@ -195,7 +197,7 @@
       }
       assert numOfParams == 3;
       DexTypeList arguments =
-          retrieveDexTypeListFromClassList(invoke, ins.get(2), appInfo.dexItemFactory);
+          retrieveDexTypeListFromClassList(invoke, ins.get(2), definitions.dexItemFactory());
       if (arguments == null) {
         return null;
       }
@@ -208,21 +210,23 @@
     return null;
   }
 
-  static DexReference inferMemberOrTypeFromNameString(AppInfo appInfo, DexString dexString) {
+  static DexReference inferMemberOrTypeFromNameString(
+      DexDefinitionSupplier definitions, DexString dexString) {
     // "fully.qualified.ClassName.fieldOrMethodName"
     // "fully.qualified.ClassName#fieldOrMethodName"
-    DexReference itemBasedString = inferMemberFromNameString(appInfo, dexString);
+    DexReference itemBasedString = inferMemberFromNameString(definitions, dexString);
     if (itemBasedString == null) {
       // "fully.qualified.ClassName"
       String maybeDescriptor = javaTypeToDescriptorIfValidJavaType(dexString.toString());
       if (maybeDescriptor != null) {
-        return appInfo.dexItemFactory.createType(maybeDescriptor);
+        return definitions.dexItemFactory().createType(maybeDescriptor);
       }
     }
     return itemBasedString;
   }
 
-  private static DexReference inferMemberFromNameString(AppInfo appInfo, DexString dexString) {
+  private static DexReference inferMemberFromNameString(
+      DexDefinitionSupplier definitions, DexString dexString) {
     String identifier = dexString.toString();
     String typeIdentifier = null;
     String memberIdentifier = null;
@@ -250,8 +254,8 @@
     if (maybeDescriptor == null) {
       return null;
     }
-    DexType type = appInfo.dexItemFactory.createType(maybeDescriptor);
-    DexClass holder = appInfo.definitionFor(type);
+    DexType type = definitions.dexItemFactory().createType(maybeDescriptor);
+    DexClass holder = definitions.definitionFor(type);
     if (holder == null) {
       return null;
     }
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 8224503..b6aa517 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -311,8 +311,7 @@
         if (!visited.add(staticFieldWritten)) {
           continue;
         }
-        DexEncodedField encodedStaticFieldWritten =
-            appInfo.resolveFieldOn(staticFieldWritten.clazz, staticFieldWritten);
+        DexEncodedField encodedStaticFieldWritten = appInfo.resolveField(staticFieldWritten);
         if (encodedStaticFieldWritten != null
             && encodedStaticFieldWritten.isProgramField(appInfo)) {
           result.add(encodedStaticFieldWritten.field);
@@ -614,7 +613,7 @@
         Log.verbose(getClass(), "Register Sput `%s`.", field);
       }
 
-      DexEncodedField encodedField = appInfo.resolveFieldOn(field.clazz, field);
+      DexEncodedField encodedField = appInfo.resolveField(field);
       if (encodedField != null && encodedField.isProgramField(appInfo)) {
         boolean isWrittenOutsideEnclosingStaticInitializer =
             currentMethod.method.holder != encodedField.field.clazz
@@ -1151,7 +1150,7 @@
   }
 
   private void markStaticFieldAsLive(DexField field, KeepReason reason) {
-    markStaticFieldAsLive(field, reason, appInfo.resolveFieldOn(field.clazz, field));
+    markStaticFieldAsLive(field, reason, appInfo.resolveField(field));
   }
 
   private void markStaticFieldAsLive(
@@ -1281,7 +1280,7 @@
     if (Log.ENABLED) {
       Log.verbose(getClass(), "Marking instance field `%s` as reachable.", field);
     }
-    DexEncodedField encodedField = appInfo.resolveFieldOn(field.clazz, field);
+    DexEncodedField encodedField = appInfo.resolveField(field);
     if (encodedField == null) {
       reportMissingField(field);
       return;
@@ -1760,7 +1759,7 @@
   private void handleReflectiveBehavior(DexEncodedMethod method) {
     DexType originHolder = method.method.holder;
     Origin origin = appInfo.originFor(originHolder);
-    IRCode code = method.buildIR(appInfo, appView.graphLense(), options, origin);
+    IRCode code = method.buildIR(appView, origin);
     Iterator<Instruction> iterator = code.instructionIterator();
     while (iterator.hasNext()) {
       Instruction instruction = iterator.next();
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 613ec66..8f8b8c0 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -44,7 +44,6 @@
 import com.android.tools.r8.logging.Log;
 import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
 import com.android.tools.r8.utils.FieldSignatureEquivalence;
-import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.MethodSignatureEquivalence;
 import com.android.tools.r8.utils.Timing;
 import com.google.common.base.Equivalence;
@@ -203,7 +202,6 @@
   private final ExecutorService executorService;
   private final GraphLense graphLense;
   private final MethodPoolCollection methodPoolCollection;
-  private final InternalOptions options;
   private final Timing timing;
   private Collection<DexMethod> invokes;
 
@@ -231,7 +229,6 @@
       DexApplication application,
       AppView<? extends AppInfoWithLiveness> appView,
       ExecutorService executorService,
-      InternalOptions options,
       Timing timing,
       MainDexClasses mainDexClasses) {
     this.application = application;
@@ -240,7 +237,6 @@
     this.executorService = executorService;
     this.graphLense = appView.graphLense();
     this.methodPoolCollection = new MethodPoolCollection(application);
-    this.options = options;
     this.renamedMembersLense = new VerticalClassMergerGraphLense.Builder();
     this.timing = timing;
     this.mainDexClasses = mainDexClasses;
@@ -1632,7 +1628,7 @@
   }
 
   private boolean disallowInlining(DexEncodedMethod method, DexType invocationContext) {
-    if (options.enableInlining) {
+    if (appView.options().enableInlining) {
       if (method.getCode().isJarCode()) {
         JarCode jarCode = method.getCode().asJarCode();
         ConstraintWithTarget constraint =
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index 55071c1..3ccdc81 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -958,7 +958,7 @@
     System.out.println(SmaliWriter.smali(app, options));
   }
 
-  protected DexEncodedMethod getMethod(
+  protected MethodSubject getMethodSubject(
       CodeInspector inspector,
       String className,
       String returnType,
@@ -968,7 +968,21 @@
     assertTrue(clazz.isPresent());
     MethodSubject method = clazz.method(returnType, methodName, parameters);
     assertTrue(method.isPresent());
-    return method.getMethod();
+    return method;
+  }
+
+  protected MethodSubject getMethodSubject(
+      AndroidApp application,
+      String className,
+      String returnType,
+      String methodName,
+      List<String> parameters) {
+    try {
+      CodeInspector inspector = new CodeInspector(application);
+      return getMethodSubject(inspector, className, returnType, methodName, parameters);
+    } catch (Exception e) {
+      return null;
+    }
   }
 
   protected DexEncodedMethod getMethod(
@@ -977,12 +991,16 @@
       String returnType,
       String methodName,
       List<String> parameters) {
-    try {
-      CodeInspector inspector = new CodeInspector(application);
-      return getMethod(inspector, className, returnType, methodName, parameters);
-    } catch (Exception e) {
-      return null;
-    }
+    return getMethodSubject(application, className, returnType, methodName, parameters).getMethod();
+  }
+
+  protected DexEncodedMethod getMethod(
+      CodeInspector inspector,
+      String className,
+      String returnType,
+      String methodName,
+      List<String> parameters) {
+    return getMethodSubject(inspector, className, returnType, methodName, parameters).getMethod();
   }
 
   protected static void checkInstructions(
diff --git a/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java b/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
index 7e0bfec..0363c3e 100644
--- a/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
+++ b/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
@@ -33,7 +33,7 @@
 public class TargetLookupTest extends SmaliTestBase {
 
   @Test
-  public void lookupDirect() throws Exception {
+  public void lookupDirect() {
     SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
 
     builder.addDefaultConstructor();
diff --git a/src/test/java/com/android/tools/r8/ir/BasicBlockIteratorTest.java b/src/test/java/com/android/tools/r8/ir/BasicBlockIteratorTest.java
index 656afc2..0a9696e 100644
--- a/src/test/java/com/android/tools/r8/ir/BasicBlockIteratorTest.java
+++ b/src/test/java/com/android/tools/r8/ir/BasicBlockIteratorTest.java
@@ -6,18 +6,18 @@
 
 import com.android.tools.r8.dex.ApplicationReader;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexApplication;
-import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.InstructionListIterator;
-import com.android.tools.r8.ir.code.ValueNumberGenerator;
 import com.android.tools.r8.smali.SmaliBuilder;
 import com.android.tools.r8.smali.SmaliBuilder.MethodSignature;
 import com.android.tools.r8.smali.SmaliTestBase;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.Timing;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import com.google.common.collect.ImmutableList;
 import java.util.List;
 import java.util.ListIterator;
@@ -52,17 +52,14 @@
     );
 
     AndroidApp application = buildApplication(builder);
+    InternalOptions options = new InternalOptions();
     DexApplication dexApplication =
-        new ApplicationReader(
-                application, new InternalOptions(), new Timing("BasicBlockIteratorTest"))
-            .read();
-    AppInfo appInfo = new AppInfo(dexApplication);
+        new ApplicationReader(application, options, new Timing("BasicBlockIteratorTest")).read();
+    AppView<? extends AppInfo> appView = AppView.createForD8(new AppInfo(dexApplication), options);
 
     // Build the code, and split the code into three blocks.
-    ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
-    DexEncodedMethod method = getMethod(application, signature);
-    IRCode code =
-        method.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator, appInfo);
+    MethodSubject methodSubject = getMethodSubject(application, signature);
+    IRCode code = methodSubject.buildIR();
     ListIterator<BasicBlock> blocks = code.listIterator();
     InstructionListIterator iter = blocks.next().listIterator();
     iter.nextUntil(i -> !i.isArgument());
diff --git a/src/test/java/com/android/tools/r8/ir/InlineTest.java b/src/test/java/com/android/tools/r8/ir/InlineTest.java
index 68b466a..d7b2762 100644
--- a/src/test/java/com/android/tools/r8/ir/InlineTest.java
+++ b/src/test/java/com/android/tools/r8/ir/InlineTest.java
@@ -6,27 +6,62 @@
 
 import static org.junit.Assert.assertEquals;
 
-import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppInfoWithSubtyping;
+import com.android.tools.r8.graph.AppServices;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexApplication;
-import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionListIterator;
-import com.android.tools.r8.ir.code.ValueNumberGenerator;
+import com.android.tools.r8.shaking.Enqueuer;
+import com.android.tools.r8.shaking.ProguardClassFilter;
+import com.android.tools.r8.shaking.ProguardKeepRule;
+import com.android.tools.r8.shaking.RootSetBuilder;
+import com.android.tools.r8.shaking.RootSetBuilder.RootSet;
 import com.android.tools.r8.smali.SmaliBuilder;
 import com.android.tools.r8.smali.SmaliBuilder.MethodSignature;
 import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.ThreadUtils;
+import com.android.tools.r8.utils.Timing;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import com.google.common.collect.ImmutableList;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.ListIterator;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
 import org.junit.Test;
 
 public class InlineTest extends IrInjectionTestBase {
 
-  TestApplication codeForMethodReplaceTest(int a, int b) throws Exception {
+  public TestApplication buildTestApplication(
+      DexApplication application,
+      InternalOptions options,
+      MethodSubject method,
+      List<IRCode> additionalCode)
+      throws ExecutionException {
+    AppView<AppInfoWithSubtyping> appView =
+        AppView.createForR8(new AppInfoWithSubtyping(application), options);
+    appView.setAppServices(AppServices.builder(appView).build());
+    ExecutorService executorService = ThreadUtils.getExecutorService(options);
+    RootSet rootSet =
+        new RootSetBuilder(
+                appView,
+                application,
+                ImmutableList.of(ProguardKeepRule.defaultKeepAllRule(unused -> {})),
+                options)
+            .run(executorService);
+    Timing timing = new Timing(getClass().getSimpleName());
+    Enqueuer enqueuer = new Enqueuer(appView, options, null);
+    appView.setAppInfo(
+        enqueuer.traceApplication(rootSet, ProguardClassFilter.empty(), executorService, timing));
+
+    return new TestApplication(appView, rootSet, method, additionalCode);
+  }
+
+  private TestApplication codeForMethodReplaceTest(int a, int b) throws ExecutionException {
     SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
 
     MethodSignature signature = builder.addStaticMethod(
@@ -73,25 +108,22 @@
     );
 
     InternalOptions options = new InternalOptions();
-    DexApplication application = buildApplication(builder, options);
-    AppInfo appInfo = new AppInfo(application);
+    DexApplication application = buildApplication(builder, options).toDirect();
 
     // Return the processed method for inspection.
-    ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
-    DexEncodedMethod method = getMethod(application, signature);
-    IRCode code = method.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
+    MethodSubject methodSubject = getMethodSubject(application, signature);
 
-    DexEncodedMethod methodA = getMethod(application, signatureA);
-    IRCode codeA = methodA.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
+    MethodSubject methodASubject = getMethodSubject(application, signatureA);
+    IRCode codeA = methodASubject.buildIR(options.itemFactory);
 
-    DexEncodedMethod methodB = getMethod(application, signatureB);
-    IRCode codeB = methodB.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
+    MethodSubject methodBSubject = getMethodSubject(application, signatureB);
+    IRCode codeB = methodBSubject.buildIR(options.itemFactory);
 
-    return new TestApplication(application, method, code,
-        ImmutableList.of(codeA, codeB), valueNumberGenerator, options);
+    return buildTestApplication(
+        application, options, methodSubject, ImmutableList.of(codeA, codeB));
   }
 
-  public void runInlineTest(int a, int b, int expectedA, int expectedB) throws Exception {
+  private void runInlineTest(int a, int b, int expectedA, int expectedB) throws Exception {
     // Run code without inlining.
     TestApplication test = codeForMethodReplaceTest(a, b);
     String result = test.run();
@@ -102,18 +134,18 @@
     // Run code inlining a.
     test = codeForMethodReplaceTest(a, b);
     iterator = test.code.entryBlock().listIterator();
-    iterator.nextUntil(instruction -> instruction.isInvoke());
+    iterator.nextUntil(Instruction::isInvoke);
     iterator.previous();
-    iterator.inlineInvoke(test.appInfo, test.code, test.additionalCode.get(0));
+    iterator.inlineInvoke(test.appView, test.code, test.additionalCode.get(0));
     result = test.run();
     assertEquals(Integer.toString(expectedA), result);
 
     // Run code inlining b (where a is actually called).
     test = codeForMethodReplaceTest(a, b);
     iterator = test.code.entryBlock().listIterator();
-    iterator.nextUntil(instruction -> instruction.isInvoke());
+    iterator.nextUntil(Instruction::isInvoke);
     iterator.previous();
-    iterator.inlineInvoke(test.appInfo, test.code, test.additionalCode.get(1));
+    iterator.inlineInvoke(test.appView, test.code, test.additionalCode.get(1));
     result = test.run();
     assertEquals(Integer.toString(expectedB), result);
   }
@@ -124,7 +156,8 @@
     runInlineTest(1, 2, 3, 1);
   }
 
-  TestApplication codeForMethodReplaceReturnVoidTest(int a, int b) throws Exception {
+  private TestApplication codeForMethodReplaceReturnVoidTest(int a, int b)
+      throws ExecutionException {
     SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
 
     MethodSignature signature = builder.addStaticMethod(
@@ -157,19 +190,15 @@
     );
 
     InternalOptions options = new InternalOptions();
-    DexApplication application = buildApplication(builder, options);
-    AppInfo appInfo = new AppInfo(application);
+    DexApplication application = buildApplication(builder, options).toDirect();
 
     // Return the processed method for inspection.
-    ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
-    DexEncodedMethod method = getMethod(application, signature);
-    IRCode code = method.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
+    MethodSubject methodSubject = getMethodSubject(application, signature);
 
-    DexEncodedMethod methodA = getMethod(application, signatureA);
-    IRCode codeA = methodA.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
+    MethodSubject methodASubject = getMethodSubject(application, signatureA);
+    IRCode codeA = methodASubject.buildIR(options.itemFactory);
 
-    return new TestApplication(application, method, code,
-        ImmutableList.of(codeA), valueNumberGenerator, options);
+    return buildTestApplication(application, options, methodSubject, ImmutableList.of(codeA));
   }
 
   @Test
@@ -184,14 +213,14 @@
     // Run code inlining a.
     test = codeForMethodReplaceReturnVoidTest(1, 2);
     iterator = test.code.entryBlock().listIterator();
-    iterator.nextUntil(instruction -> instruction.isInvoke());
+    iterator.nextUntil(Instruction::isInvoke);
     iterator.previous();
-    iterator.inlineInvoke(test.appInfo, test.code, test.additionalCode.get(0));
+    iterator.inlineInvoke(test.appView, test.code, test.additionalCode.get(0));
     result = test.run();
     assertEquals(Integer.toString(1), result);
   }
 
-  TestApplication codeForMultipleMethodReplaceTest(int a, int b) throws Exception {
+  private TestApplication codeForMultipleMethodReplaceTest(int a, int b) throws ExecutionException {
     SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
 
     MethodSignature signature = builder.addStaticMethod(
@@ -238,33 +267,29 @@
     );
 
     InternalOptions options = new InternalOptions();
-    DexApplication application = buildApplication(builder, options);
-    AppInfo appInfo = new AppInfo(application);
+    DexApplication application = buildApplication(builder, options).toDirect();
 
     // Return the processed method for inspection.
-    ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
-    DexEncodedMethod method = getMethod(application, signature);
-    IRCode code = method.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
+    MethodSubject methodSubject = getMethodSubject(application, signature);
 
     // Build three copies of a and b for inlining three times.
     List<IRCode> additionalCode = new ArrayList<>();
     for (int i = 0; i < 3; i++) {
-      DexEncodedMethod methodA = getMethod(application, signatureA);
-      IRCode codeA = methodA.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
+      MethodSubject methodASubject = getMethodSubject(application, signatureA);
+      IRCode codeA = methodASubject.buildIR(options.itemFactory);
       additionalCode.add(codeA);
     }
 
     for (int i = 0; i < 3; i++) {
-      DexEncodedMethod methodB = getMethod(application, signatureB);
-      IRCode codeB = methodB.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
+      MethodSubject methodBSubject = getMethodSubject(application, signatureB);
+      IRCode codeB = methodBSubject.buildIR(options.itemFactory);
       additionalCode.add(codeB);
     }
 
-    return new TestApplication(application, method, code,
-        additionalCode, valueNumberGenerator, options);
+    return buildTestApplication(application, options, methodSubject, additionalCode);
   }
 
-  public void runInlineMultipleTest(int a, int b, int expectedA, int expectedB) throws Exception {
+  private void runInlineMultipleTest(int a, int b, int expectedA, int expectedB) throws Exception {
     // Run code without inlining.
     TestApplication test = codeForMultipleMethodReplaceTest(a, b);
     String result = test.run();
@@ -280,11 +305,11 @@
     while (blocksIterator.hasNext()) {
       BasicBlock block = blocksIterator.next();
       iterator = block.listIterator();
-      Instruction invoke = iterator.nextUntil(instruction -> instruction.isInvoke());
+      Instruction invoke = iterator.nextUntil(Instruction::isInvoke);
       if (invoke != null) {
         iterator.previous();
         iterator.inlineInvoke(
-            test.appInfo, test.code, inlinee.next(), blocksIterator, blocksToRemove, null);
+            test.appView, test.code, inlinee.next(), blocksIterator, blocksToRemove, null);
         assert blocksToRemove.isEmpty();
       }
     }
@@ -298,11 +323,11 @@
     while (blocksIterator.hasNext()) {
       BasicBlock block = blocksIterator.next();
       iterator = block.listIterator();
-      Instruction invoke = iterator.nextUntil(instruction -> instruction.isInvoke());
+      Instruction invoke = iterator.nextUntil(Instruction::isInvoke);
       if (invoke != null) {
         iterator.previous();
         iterator.inlineInvoke(
-            test.appInfo, test.code, inlinee.next(), blocksIterator, blocksToRemove, null);
+            test.appView, test.code, inlinee.next(), blocksIterator, blocksToRemove, null);
         assert blocksToRemove.isEmpty();
       }
     }
@@ -316,8 +341,8 @@
     runInlineMultipleTest(1, 2, 7, 8);
   }
 
-  TestApplication codeForMethodReplaceTestWithCatchHandler(int a, int b, boolean twoGuards)
-      throws Exception {
+  private TestApplication codeForMethodReplaceTestWithCatchHandler(int a, int b, boolean twoGuards)
+      throws ExecutionException {
     SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
 
     String secondGuard = twoGuards ?
@@ -375,25 +400,22 @@
     );
 
     InternalOptions options = new InternalOptions();
-    DexApplication application = buildApplication(builder, options);
-    AppInfo appInfo = new AppInfo(application);
+    DexApplication application = buildApplication(builder, options).toDirect();
 
     // Return the processed method for inspection.
-    ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
-    DexEncodedMethod method = getMethod(application, signature);
-    IRCode code = method.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
+    MethodSubject methodSubject = getMethodSubject(application, signature);
 
-    DexEncodedMethod methodA = getMethod(application, signatureA);
-    IRCode codeA = methodA.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
+    MethodSubject methodASubject = getMethodSubject(application, signatureA);
+    IRCode codeA = methodASubject.buildIR(options.itemFactory);
 
-    DexEncodedMethod methodB = getMethod(application, signatureB);
-    IRCode codeB = methodB.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
+    MethodSubject methodBSubject = getMethodSubject(application, signatureB);
+    IRCode codeB = methodBSubject.buildIR(options.itemFactory);
 
-    return new TestApplication(application, method, code,
-        ImmutableList.of(codeA, codeB), valueNumberGenerator, options);
+    return buildTestApplication(
+        application, options, methodSubject, ImmutableList.of(codeA, codeB));
   }
 
-  public void runInlineCallerHasCatchHandlersTest(
+  private void runInlineCallerHasCatchHandlersTest(
       int a, int b, boolean twoGuards, int expectedA, int expectedB) throws Exception {
     // Run code without inlining.
     TestApplication test = codeForMethodReplaceTestWithCatchHandler(a, b, twoGuards);
@@ -405,18 +427,18 @@
     // Run code inlining a.
     test = codeForMethodReplaceTestWithCatchHandler(a, b, twoGuards);
     iterator = test.code.blocks.get(1).listIterator();
-    iterator.nextUntil(instruction -> instruction.isInvoke());
+    iterator.nextUntil(Instruction::isInvoke);
     iterator.previous();
-    iterator.inlineInvoke(test.appInfo, test.code, test.additionalCode.get(0));
+    iterator.inlineInvoke(test.appView, test.code, test.additionalCode.get(0));
     result = test.run();
     assertEquals(Integer.toString(expectedA), result);
 
     // Run code inlining b (where a is actually called).
     test = codeForMethodReplaceTestWithCatchHandler(a, b, twoGuards);
     iterator = test.code.blocks.get(1).listIterator();
-    iterator.nextUntil(instruction -> instruction.isInvoke());
+    iterator.nextUntil(Instruction::isInvoke);
     iterator.previous();
-    iterator.inlineInvoke(test.appInfo, test.code, test.additionalCode.get(1));
+    iterator.inlineInvoke(test.appView, test.code, test.additionalCode.get(1));
     result = test.run();
     assertEquals(Integer.toString(expectedB), result);
   }
@@ -429,7 +451,8 @@
     runInlineCallerHasCatchHandlersTest(1, 2, true, 3, 1);
   }
 
-  TestApplication codeForInlineCanThrow(int a, int b, boolean twoGuards) throws Exception {
+  private TestApplication codeForInlineCanThrow(int a, int b, boolean twoGuards)
+      throws ExecutionException {
     SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
 
     String secondGuard = twoGuards ?
@@ -490,26 +513,23 @@
     );
 
     InternalOptions options = new InternalOptions();
-    DexApplication application = buildApplication(builder, options);
-    AppInfo appInfo = new AppInfo(application);
+    DexApplication application = buildApplication(builder, options).toDirect();
 
     // Return the processed method for inspection.
-    ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
-    DexEncodedMethod method = getMethod(application, signature);
-    IRCode code = method.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
+    MethodSubject methodSubject = getMethodSubject(application, signature);
 
-    DexEncodedMethod methodA = getMethod(application, signatureA);
-    IRCode codeA = methodA.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
+    MethodSubject methodASubject = getMethodSubject(application, signatureA);
+    IRCode codeA = methodASubject.buildIR(options.itemFactory);
 
-    DexEncodedMethod methodB = getMethod(application, signatureB);
-    IRCode codeB = methodB.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
+    MethodSubject methodBSubject = getMethodSubject(application, signatureB);
+    IRCode codeB = methodBSubject.buildIR(options.itemFactory);
 
-    return new TestApplication(application, method, code,
-        ImmutableList.of(codeA, codeB), valueNumberGenerator, options);
+    return buildTestApplication(
+        application, options, methodSubject, ImmutableList.of(codeA, codeB));
   }
 
-  public void runInlineCanThrow(
-      int a, int b, boolean twoGuards, int expectedA, int expectedB) throws Exception {
+  private void runInlineCanThrow(int a, int b, boolean twoGuards, int expectedA, int expectedB)
+      throws Exception {
     // Run code without inlining.
     TestApplication test = codeForInlineCanThrow(a, b, twoGuards);
     String result = test.run();
@@ -520,18 +540,18 @@
     // Run code inlining a.
     test = codeForInlineCanThrow(a, b, twoGuards);
     iterator = test.code.entryBlock().listIterator();
-    iterator.nextUntil(instruction -> instruction.isInvoke());
+    iterator.nextUntil(Instruction::isInvoke);
     iterator.previous();
-    iterator.inlineInvoke(test.appInfo, test.code, test.additionalCode.get(0));
+    iterator.inlineInvoke(test.appView, test.code, test.additionalCode.get(0));
     result = test.run();
     assertEquals(Integer.toString(expectedA), result);
 
     // Run code inlining b (where a is actually called).
     test = codeForInlineCanThrow(a, b, twoGuards);
     iterator = test.code.entryBlock().listIterator();
-    iterator.nextUntil(instruction -> instruction.isInvoke());
+    iterator.nextUntil(Instruction::isInvoke);
     iterator.previous();
-    iterator.inlineInvoke(test.appInfo, test.code, test.additionalCode.get(1));
+    iterator.inlineInvoke(test.appView, test.code, test.additionalCode.get(1));
     result = test.run();
     assertEquals(Integer.toString(expectedB), result);
   }
@@ -544,7 +564,7 @@
     runInlineCanThrow(2, 0, true, -2, -1);
   }
 
-  private TestApplication codeForInlineAlwaysThrows(boolean twoGuards) throws Exception {
+  private TestApplication codeForInlineAlwaysThrows(boolean twoGuards) throws ExecutionException {
     SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
 
     String secondGuard = twoGuards ?
@@ -604,22 +624,19 @@
     );
 
     InternalOptions options = new InternalOptions();
-    DexApplication application = buildApplication(builder, options);
-    AppInfo appInfo = new AppInfo(application);
+    DexApplication application = buildApplication(builder, options).toDirect();
 
     // Return the processed method for inspection.
-    ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
-    DexEncodedMethod method = getMethod(application, signature);
-    IRCode code = method.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
+    MethodSubject methodSubject = getMethodSubject(application, signature);
 
-    DexEncodedMethod methodA = getMethod(application, signatureA);
-    IRCode codeA = methodA.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
+    MethodSubject methodASubject = getMethodSubject(application, signatureA);
+    IRCode codeA = methodASubject.buildIR(options.itemFactory);
 
-    DexEncodedMethod methodB = getMethod(application, signatureB);
-    IRCode codeB = methodB.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
+    MethodSubject methodBSubject = getMethodSubject(application, signatureB);
+    IRCode codeB = methodBSubject.buildIR(options.itemFactory);
 
-    return new TestApplication(application, method, code,
-        ImmutableList.of(codeA, codeB), valueNumberGenerator, options);
+    return buildTestApplication(
+        application, options, methodSubject, ImmutableList.of(codeA, codeB));
   }
 
   private void runInlineAlwaysThrows(boolean twoGuards, int expectedA, int expectedB)
@@ -636,7 +653,7 @@
     iterator = test.code.entryBlock().listIterator();
     iterator.nextUntil(Instruction::isInvoke);
     iterator.previous();
-    iterator.inlineInvoke(test.appInfo, test.code, test.additionalCode.get(0));
+    iterator.inlineInvoke(test.appView, test.code, test.additionalCode.get(0));
 
     result = test.run();
     assertEquals(Integer.toString(expectedA), result);
@@ -646,7 +663,7 @@
     iterator = test.code.entryBlock().listIterator();
     iterator.nextUntil(Instruction::isInvoke);
     iterator.previous();
-    iterator.inlineInvoke(test.appInfo, test.code, test.additionalCode.get(1));
+    iterator.inlineInvoke(test.appView, test.code, test.additionalCode.get(1));
     result = test.run();
     assertEquals(Integer.toString(expectedB), result);
   }
@@ -657,7 +674,8 @@
     runInlineAlwaysThrows(true, -2, -1);
   }
 
-  private TestApplication codeForInlineAlwaysThrowsMultiple(boolean twoGuards) throws Exception {
+  private TestApplication codeForInlineAlwaysThrowsMultiple(boolean twoGuards)
+      throws ExecutionException {
     SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
 
     String secondGuard = twoGuards ?
@@ -719,30 +737,26 @@
     );
 
     InternalOptions options = new InternalOptions();
-    DexApplication application = buildApplication(builder, options);
-    AppInfo appInfo = new AppInfo(application);
+    DexApplication application = buildApplication(builder, options).toDirect();
 
     // Return the processed method for inspection.
-    ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
-    DexEncodedMethod method = getMethod(application, signature);
-    IRCode code = method.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
+    MethodSubject methodSubject = getMethodSubject(application, signature);
 
     // Build three copies of a and b for inlining three times.
     List<IRCode> additionalCode = new ArrayList<>();
     for (int i = 0; i < 3; i++) {
-      DexEncodedMethod methodA = getMethod(application, signatureA);
-      IRCode codeA = methodA.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
+      MethodSubject methodASubject = getMethodSubject(application, signatureA);
+      IRCode codeA = methodASubject.buildIR(options.itemFactory);
       additionalCode.add(codeA);
     }
 
     for (int i = 0; i < 3; i++) {
-      DexEncodedMethod methodB = getMethod(application, signatureB);
-      IRCode codeB = methodB.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
+      MethodSubject methodBSubject = getMethodSubject(application, signatureB);
+      IRCode codeB = methodBSubject.buildIR(options.itemFactory);
       additionalCode.add(codeB);
     }
 
-    return new TestApplication(
-        application, method, code, additionalCode, valueNumberGenerator, options);
+    return buildTestApplication(application, options, methodSubject, additionalCode);
   }
 
   private void runInlineAlwaysThrowsMultiple(boolean twoGuards, int expectedA, int expectedB)
@@ -770,7 +784,7 @@
         if (invoke != null) {
           iterator.previous();
           iterator.inlineInvoke(
-              test.appInfo, test.code, inlinee.next(), blocksIterator, blocksToRemove, null);
+              test.appView, test.code, inlinee.next(), blocksIterator, blocksToRemove, null);
         }
       }
       test.code.removeBlocks(blocksToRemove);
@@ -794,7 +808,7 @@
         if (invoke != null) {
           iterator.previous();
           iterator.inlineInvoke(
-              test.appInfo, test.code, inlinee.next(), blocksIterator, blocksToRemove, null);
+              test.appView, test.code, inlinee.next(), blocksIterator, blocksToRemove, null);
         }
       }
       test.code.removeBlocks(blocksToRemove);
@@ -809,8 +823,8 @@
     runInlineAlwaysThrowsMultiple(true, -2, -1);
   }
 
-  private TestApplication codeForInlineAlwaysThrowsMultipleWithControlFlow(
-      int a, boolean twoGuards) throws Exception {
+  private TestApplication codeForInlineAlwaysThrowsMultipleWithControlFlow(int a, boolean twoGuards)
+      throws ExecutionException {
     SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
 
     String secondGuard = twoGuards ?
@@ -879,30 +893,26 @@
     );
 
     InternalOptions options = new InternalOptions();
-    DexApplication application = buildApplication(builder, options);
-    AppInfo appInfo = new AppInfo(application);
+    DexApplication application = buildApplication(builder, options).toDirect();
 
     // Return the processed method for inspection.
-    ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
-    DexEncodedMethod method = getMethod(application, signature);
-    IRCode code = method.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
+    MethodSubject methodSubject = getMethodSubject(application, signature);
 
     // Build three copies of a and b for inlining three times.
     List<IRCode> additionalCode = new ArrayList<>();
     for (int i = 0; i < 3; i++) {
-      DexEncodedMethod methodA = getMethod(application, signatureA);
-      IRCode codeA = methodA.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
+      MethodSubject methodASubject = getMethodSubject(application, signatureA);
+      IRCode codeA = methodASubject.buildIR(options.itemFactory);
       additionalCode.add(codeA);
     }
 
     for (int i = 0; i < 3; i++) {
-      DexEncodedMethod methodB = getMethod(application, signatureB);
-      IRCode codeB = methodB.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
+      MethodSubject methodBSubject = getMethodSubject(application, signatureB);
+      IRCode codeB = methodBSubject.buildIR(options.itemFactory);
       additionalCode.add(codeB);
     }
 
-    return new TestApplication(
-        application, method, code, additionalCode, valueNumberGenerator, options);
+    return buildTestApplication(application, options, methodSubject, additionalCode);
   }
 
   private void runInlineAlwaysThrowsMultipleWithControlFlow(
@@ -930,7 +940,7 @@
         if (invoke != null) {
           iterator.previous();
           iterator.inlineInvoke(
-              test.appInfo, test.code, inlinee.next(), blocksIterator, blocksToRemove, null);
+              test.appView, test.code, inlinee.next(), blocksIterator, blocksToRemove, null);
         }
       }
       test.code.removeBlocks(blocksToRemove);
@@ -954,7 +964,7 @@
         if (invoke != null) {
           iterator.previous();
           iterator.inlineInvoke(
-              test.appInfo, test.code, inlinee.next(), blocksIterator, blocksToRemove, null);
+              test.appView, test.code, inlinee.next(), blocksIterator, blocksToRemove, null);
         }
       }
       test.code.removeBlocks(blocksToRemove);
@@ -975,7 +985,7 @@
 
   private TestApplication codeForInlineWithHandlersCanThrow(
       int a, int b, int c, boolean twoGuards, boolean callerHasCatchAll, boolean inlineeHasCatchAll)
-      throws Exception {
+      throws ExecutionException {
     SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
 
     String secondGuard = "";
@@ -1129,22 +1139,19 @@
     );
 
     InternalOptions options = new InternalOptions();
-    DexApplication application = buildApplication(builder, options);
-    AppInfo appInfo = new AppInfo(application);
+    DexApplication application = buildApplication(builder, options).toDirect();
 
     // Return the processed method for inspection.
-    ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
-    DexEncodedMethod method = getMethod(application, signature);
-    IRCode code = method.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
+    MethodSubject methodSubject = getMethodSubject(application, signature);
 
-    DexEncodedMethod methodA = getMethod(application, signatureA);
-    IRCode codeA = methodA.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
+    MethodSubject methodASubject = getMethodSubject(application, signatureA);
+    IRCode codeA = methodASubject.buildIR(options.itemFactory);
 
-    DexEncodedMethod methodB = getMethod(application, signatureB);
-    IRCode codeB = methodB.buildInliningIRForTesting(options, valueNumberGenerator, appInfo);
+    MethodSubject methodBSubject = getMethodSubject(application, signatureB);
+    IRCode codeB = methodBSubject.buildIR(options.itemFactory);
 
-    return new TestApplication(application, method, code,
-        ImmutableList.of(codeA, codeB), valueNumberGenerator, options);
+    return buildTestApplication(
+        application, options, methodSubject, ImmutableList.of(codeA, codeB));
   }
 
   private void runInlineWithHandlersCanThrow(int a, int b, int c,
@@ -1164,7 +1171,7 @@
     iterator = test.code.blocks.get(1).listIterator();
     iterator.nextUntil(Instruction::isInvoke);
     iterator.previous();
-    iterator.inlineInvoke(test.appInfo, test.code, test.additionalCode.get(0));
+    iterator.inlineInvoke(test.appView, test.code, test.additionalCode.get(0));
     result = test.run();
     assertEquals(Integer.toString(expectedA), result);
 
@@ -1174,7 +1181,7 @@
     iterator = test.code.blocks.get(1).listIterator();
     iterator.nextUntil(Instruction::isInvoke);
     iterator.previous();
-    iterator.inlineInvoke(test.appInfo, test.code, test.additionalCode.get(1));
+    iterator.inlineInvoke(test.appView, test.code, test.additionalCode.get(1));
     result = test.run();
     assertEquals(Integer.toString(expectedB), result);
   }
diff --git a/src/test/java/com/android/tools/r8/ir/InstructionIteratorTest.java b/src/test/java/com/android/tools/r8/ir/InstructionIteratorTest.java
index 6c7c2d3..5ab4a24 100644
--- a/src/test/java/com/android/tools/r8/ir/InstructionIteratorTest.java
+++ b/src/test/java/com/android/tools/r8/ir/InstructionIteratorTest.java
@@ -4,18 +4,15 @@
 
 package com.android.tools.r8.ir;
 
-import com.android.tools.r8.graph.AppInfo;
-import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionListIterator;
-import com.android.tools.r8.ir.code.ValueNumberGenerator;
 import com.android.tools.r8.smali.SmaliBuilder;
 import com.android.tools.r8.smali.SmaliBuilder.MethodSignature;
 import com.android.tools.r8.smali.SmaliTestBase;
 import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import com.google.common.collect.ImmutableList;
 import java.util.List;
 import java.util.ListIterator;
@@ -33,7 +30,7 @@
    * <p>First block: Argument instructions Second block: Add instruction Third block: Return
    * instruction
    */
-  IRCode simpleCode() {
+  private IRCode simpleCode() {
     SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
 
     String returnType = "int";
@@ -48,13 +45,10 @@
     );
 
     AndroidApp application = buildApplication(builder);
-    AppInfo appInfo = getAppInfo(application);
 
     // Build the code, and split the code into three blocks.
-    ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
-    DexEncodedMethod method = getMethod(application, signature);
-    IRCode code =
-        method.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator, appInfo);
+    MethodSubject methodSubject = getMethodSubject(application, signature);
+    IRCode code = methodSubject.buildIR();
     ListIterator<BasicBlock> blocks = code.listIterator();
     InstructionListIterator iter = blocks.next().listIterator();
     iter.nextUntil(i -> !i.isArgument());
diff --git a/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java b/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java
index 0251cf3..083f478 100644
--- a/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java
+++ b/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java
@@ -16,6 +16,8 @@
 import com.android.tools.r8.ir.code.ValueNumberGenerator;
 import com.android.tools.r8.ir.conversion.IRConverter;
 import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.shaking.MainDexClasses;
+import com.android.tools.r8.shaking.RootSetBuilder.RootSet;
 import com.android.tools.r8.smali.SmaliBuilder;
 import com.android.tools.r8.smali.SmaliBuilder.MethodSignature;
 import com.android.tools.r8.smali.SmaliTestBase;
@@ -24,6 +26,7 @@
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.Timing;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import java.io.IOException;
 import java.util.List;
 import java.util.ListIterator;
@@ -51,56 +54,54 @@
     }
   }
 
-  protected DexEncodedMethod getMethod(DexApplication application, MethodSignature signature) {
-    return getMethod(application,
-        signature.clazz, signature.returnType, signature.name, signature.parameterTypes);
+  protected MethodSubject getMethodSubject(DexApplication application, MethodSignature signature) {
+    return getMethodSubject(
+        application,
+        signature.clazz,
+        signature.returnType,
+        signature.name,
+        signature.parameterTypes);
   }
 
-  protected DexEncodedMethod getMethod(
+  protected MethodSubject getMethodSubject(
       DexApplication application,
       String className,
       String returnType,
       String methodName,
       List<String> parameters) {
     CodeInspector inspector = new CodeInspector(application);
-    return getMethod(inspector, className, returnType, methodName, parameters);
+    return getMethodSubject(inspector, className, returnType, methodName, parameters);
   }
 
   public class TestApplication {
 
     public final DexApplication application;
-    public final AppInfo appInfo;
+    public final AppView<? extends AppInfo> appView;
+    public final RootSet rootSet;
+
     public final DexEncodedMethod method;
     public final IRCode code;
     public final List<IRCode> additionalCode;
-    public final ValueNumberGenerator valueNumberGenerator;
-    public final InternalOptions options;
     public final AndroidAppConsumers consumers;
 
-    public TestApplication(
-        DexApplication application,
-        DexEncodedMethod method,
-        IRCode code,
-        ValueNumberGenerator valueNumberGenerator,
-        InternalOptions options) {
-      this(application, method, code, null, valueNumberGenerator, options);
+    public final ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
+
+    public TestApplication(AppView<? extends AppInfo> appView, MethodSubject method) {
+      this(appView, null, method, null);
     }
 
     public TestApplication(
-        DexApplication application,
-        DexEncodedMethod method,
-        IRCode code,
-        List<IRCode> additionalCode,
-        ValueNumberGenerator valueNumberGenerator,
-        InternalOptions options) {
-      this.application = application;
-      this.appInfo = new AppInfo(application);
-      this.method = method;
-      this.code = code;
+        AppView<? extends AppInfo> appView,
+        RootSet rootSet,
+        MethodSubject method,
+        List<IRCode> additionalCode) {
+      this.application = appView.appInfo().app;
+      this.appView = appView;
+      this.rootSet = rootSet;
+      this.method = method.getMethod();
+      this.code = method.buildIR(appView.dexItemFactory());
       this.additionalCode = additionalCode;
-      this.valueNumberGenerator = valueNumberGenerator;
-      this.options = options;
-      consumers = new AndroidAppConsumers(options);
+      this.consumers = new AndroidAppConsumers(appView.options());
     }
 
     public int countArgumentInstructions() {
@@ -131,10 +132,10 @@
     }
 
     public String run() throws IOException {
-      AppInfo appInfo = new AppInfo(application);
-      IRConverter converter = new IRConverter(AppView.createForD8(appInfo, options));
+      Timing timing = new Timing(getClass().getSimpleName());
+      IRConverter converter = new IRConverter(appView, timing, null, MainDexClasses.NONE, rootSet);
       converter.replaceCodeForTesting(method, code);
-      AndroidApp app = writeDex(application, options);
+      AndroidApp app = writeDex(application, appView.options());
       return runOnArtRaw(app, DEFAULT_MAIN_CLASS_NAME).stdout;
     }
   }
diff --git a/src/test/java/com/android/tools/r8/ir/LinearFlowIteratorTest.java b/src/test/java/com/android/tools/r8/ir/LinearFlowIteratorTest.java
index 0a11f41..d33da76 100644
--- a/src/test/java/com/android/tools/r8/ir/LinearFlowIteratorTest.java
+++ b/src/test/java/com/android/tools/r8/ir/LinearFlowIteratorTest.java
@@ -5,18 +5,15 @@
 package com.android.tools.r8.ir;
 
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.graph.AppInfo;
-import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionListIterator;
 import com.android.tools.r8.ir.code.LinearFlowInstructionIterator;
-import com.android.tools.r8.ir.code.ValueNumberGenerator;
 import com.android.tools.r8.jasmin.JasminBuilder;
 import com.android.tools.r8.jasmin.JasminBuilder.ClassBuilder;
 import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import com.google.common.collect.ImmutableList;
 import java.util.ListIterator;
 import org.junit.Test;
@@ -53,12 +50,10 @@
     appBuilder.addClassProgramData(jasminBuilder.buildClasses());
 
     // Build the code, and split the code into three blocks.
-    ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
     AndroidApp app = compileWithD8(appBuilder.build());
-    AppInfo appInfo = getAppInfo(app);
-    DexEncodedMethod method = getMethod(app, "foo", "void", "bar", ImmutableList.of("int"));
-    IRCode code =
-        method.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator, appInfo);
+    MethodSubject methodSubject =
+        getMethodSubject(app, "foo", "void", "bar", ImmutableList.of("int"));
+    IRCode code = methodSubject.buildIR();
     ListIterator<BasicBlock> blocks = code.listIterator();
     blocks.next();
     InstructionListIterator iter = blocks.next().listIterator();
@@ -91,12 +86,9 @@
     appBuilder.addClassProgramData(jasminBuilder.buildClasses());
 
     // Build the code, and split the code into three blocks.
-    ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
     AndroidApp app = compileWithD8(appBuilder.build());
-    AppInfo appInfo = getAppInfo(app);
-    DexEncodedMethod method = getMethod(app, "foo", "void", "bar", ImmutableList.of("int"));
-    IRCode code =
-        method.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator, appInfo);
+    MethodSubject method = getMethodSubject(app, "foo", "void", "bar", ImmutableList.of("int"));
+    IRCode code = method.buildIR();
     ListIterator<BasicBlock> blocks = code.listIterator();
     InstructionListIterator iter = blocks.next().listIterator();
     iter.nextUntil(i -> !i.isArgument());
diff --git a/src/test/java/com/android/tools/r8/ir/SplitBlockTest.java b/src/test/java/com/android/tools/r8/ir/SplitBlockTest.java
index 2a6e8c8..006fc5b 100644
--- a/src/test/java/com/android/tools/r8/ir/SplitBlockTest.java
+++ b/src/test/java/com/android/tools/r8/ir/SplitBlockTest.java
@@ -9,8 +9,8 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexApplication;
-import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.code.Add;
 import com.android.tools.r8.ir.code.BasicBlock;
@@ -21,10 +21,10 @@
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.code.Position;
 import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.code.ValueNumberGenerator;
 import com.android.tools.r8.smali.SmaliBuilder;
 import com.android.tools.r8.smali.SmaliBuilder.MethodSignature;
 import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import com.google.common.collect.ImmutableList;
 import java.util.ArrayList;
 import java.util.List;
@@ -32,7 +32,7 @@
 
 public class SplitBlockTest extends IrInjectionTestBase {
 
-  TestApplication codeWithoutCatchHandlers() throws Exception {
+  private TestApplication codeWithoutCatchHandlers() {
     SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
 
     String returnType = "int";
@@ -61,15 +61,11 @@
 
     InternalOptions options = new InternalOptions();
     DexApplication application = buildApplication(builder, options);
-    AppInfo appInfo = new AppInfo(application);
+    AppView<? extends AppInfo> appView = AppView.createForD8(new AppInfo(application), options);
 
     // Return the processed method for inspection.
-    ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
-    DexEncodedMethod method = getMethod(application, signature);
-    IRCode code =
-        method.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator, appInfo);
-
-    return new TestApplication(application, method, code, valueNumberGenerator, options);
+    MethodSubject methodSubject = getMethodSubject(application, signature);
+    return new TestApplication(appView, methodSubject);
   }
 
   @Test
@@ -141,7 +137,7 @@
     }
   }
 
-  TestApplication codeWithCatchHandlers(boolean shouldThrow, boolean twoGuards) throws Exception {
+  private TestApplication codeWithCatchHandlers(boolean shouldThrow, boolean twoGuards) {
     SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
 
     String secondGuard = twoGuards ?
@@ -181,17 +177,14 @@
 
     InternalOptions options = new InternalOptions();
     DexApplication application = buildApplication(builder, options);
-    AppInfo appInfo = new AppInfo(application);
+    AppView<? extends AppInfo> appView = AppView.createForD8(new AppInfo(application), options);
 
     // Return the processed method for inspection.
-    ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
-    DexEncodedMethod method = getMethod(application, signature);
-    IRCode code =
-        method.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator, appInfo);
-    return new TestApplication(application, method, code, valueNumberGenerator, options);
+    MethodSubject methodSubject = getMethodSubject(application, signature);
+    return new TestApplication(appView, methodSubject);
   }
 
-  public void hasCatchandlerIfThrowing(BasicBlock block) {
+  private void hasCatchandlerIfThrowing(BasicBlock block) {
     boolean throwing = false;
     for (Instruction instruction : block.getInstructions()) {
       throwing |= instruction.instructionTypeCanThrow();
@@ -199,7 +192,7 @@
     assertEquals(throwing, block.hasCatchHandlers());
   }
 
-  public void runCatchHandlerTest(boolean codeThrows, boolean twoGuards) throws Exception {
+  private void runCatchHandlerTest(boolean codeThrows, boolean twoGuards) throws Exception {
     final int secondBlockInstructions = 4;
     final int initialBlockCount = twoGuards ? 7 : 6;
     // Try split between all instructions in second block.
@@ -237,7 +230,7 @@
     runCatchHandlerTest(true, true);
   }
 
-  public void runCatchHandlerSplitThreeTest(boolean codeThrows, boolean twoGuards)
+  private void runCatchHandlerSplitThreeTest(boolean codeThrows, boolean twoGuards)
       throws Exception {
     final int secondBlockInstructions = 4;
     final int initialBlockCount = twoGuards ? 7 : 6;
@@ -277,7 +270,7 @@
     runCatchHandlerSplitThreeTest(true, true);
   }
 
-  TestApplication codeWithIf(boolean hitTrueBranch) throws Exception {
+  private TestApplication codeWithIf(boolean hitTrueBranch) {
     SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
 
     String returnType = "int";
@@ -308,18 +301,14 @@
 
     InternalOptions options = new InternalOptions();
     DexApplication application = buildApplication(builder, options);
-    AppInfo appInfo = new AppInfo(application);
+    AppView<? extends AppInfo> appView = AppView.createForD8(new AppInfo(application), options);
 
     // Return the processed method for inspection.
-    ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
-    DexEncodedMethod method = getMethod(application, signature);
-    IRCode code =
-        method.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator, appInfo);
-
-    return new TestApplication(application, method, code, valueNumberGenerator, options);
+    MethodSubject methodSubject = getMethodSubject(application, signature);
+    return new TestApplication(appView, methodSubject);
   }
 
-  public void runWithIfTest(boolean hitTrueBranch) throws Exception {
+  private void runWithIfTest(boolean hitTrueBranch) throws Exception {
     final int initialBlockCount = 3;
     final int argumentInstructions = 2;
     final int firstBlockInstructions = 3;
@@ -358,7 +347,7 @@
     runWithIfTest(true);
   }
 
-  public void splitBeforeReturn(boolean hitTrueBranch) throws Exception {
+  private void splitBeforeReturn(boolean hitTrueBranch) throws Exception {
     TestApplication test = codeWithIf(hitTrueBranch);
     IRCode code = test.code;
     // Locate the exit blocks and split before the return.
@@ -397,7 +386,7 @@
     splitBeforeReturn(true);
   }
 
-  TestApplication codeWithSwitch(boolean hitCase) throws Exception {
+  private TestApplication codeWithSwitch(boolean hitCase) {
     SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
 
     String returnType = "int";
@@ -436,18 +425,14 @@
 
     InternalOptions options = new InternalOptions();
     DexApplication application = buildApplication(builder, options);
-    AppInfo appInfo = new AppInfo(application);
+    AppView<? extends AppInfo> appView = AppView.createForD8(new AppInfo(application), options);
 
     // Return the processed method for inspection.
-    ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
-    DexEncodedMethod method = getMethod(application, signature);
-    IRCode code =
-        method.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator, appInfo);
-
-    return new TestApplication(application, method, code, valueNumberGenerator, options);
+    MethodSubject methodSubject = getMethodSubject(application, signature);
+    return new TestApplication(appView, methodSubject);
   }
 
-  public void runWithSwitchTest(boolean hitCase) throws Exception {
+  private void runWithSwitchTest(boolean hitCase) throws Exception {
     final int initialBlockCount = 5;
     final int argumentInstructions = 1;
     final int firstBlockInstructions = 2;
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/AnalysisTestBase.java b/src/test/java/com/android/tools/r8/ir/analysis/AnalysisTestBase.java
index e3ab0e7..b53d969 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/AnalysisTestBase.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/AnalysisTestBase.java
@@ -9,10 +9,8 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.dex.ApplicationReader;
 import com.android.tools.r8.graph.AppInfo;
-import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
-import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.Timing;
@@ -55,11 +53,7 @@
   public void buildAndCheckIR(String methodName, Consumer<IRCode> irInspector) throws Exception {
     CodeInspector inspector = new CodeInspector(app);
     MethodSubject methodSubject = inspector.clazz(className).uniqueMethodWithName(methodName);
-    IRCode code =
-        methodSubject
-            .getMethod()
-            .buildIR(appInfo, GraphLense.getIdentityLense(), options, Origin.unknown());
-    irInspector.accept(code);
+    irInspector.accept(methodSubject.buildIR());
   }
 
   @SuppressWarnings("unchecked")
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java
index eadec82..c5ac021 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java
@@ -11,9 +11,9 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.ir.code.Argument;
 import com.android.tools.r8.ir.code.ArrayGet;
 import com.android.tools.r8.ir.code.IRCode;
@@ -32,10 +32,10 @@
 import com.android.tools.r8.ir.optimize.nonnull.NonNullAfterFieldAccess;
 import com.android.tools.r8.ir.optimize.nonnull.NonNullAfterInvoke;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
-import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import java.util.Map;
@@ -49,16 +49,16 @@
       boolean npeCaught,
       BiConsumer<AppInfoWithLiveness, IRCode> inspector)
       throws Exception {
-    AppInfoWithLiveness appInfo = build(mainClass);
-    CodeInspector codeInspector = new CodeInspector(appInfo.app);
+    AppView<? extends AppInfoWithLiveness> appView = build(mainClass);
+    CodeInspector codeInspector = new CodeInspector(appView.appInfo().app);
+    MethodSubject fooSubject = codeInspector.clazz(mainClass.getName()).method(signature);
     DexEncodedMethod foo = codeInspector.clazz(mainClass.getName()).method(signature).getMethod();
-    IRCode irCode =
-        foo.buildIR(appInfo, GraphLense.getIdentityLense(), TEST_OPTIONS, Origin.unknown());
-    NonNullTracker nonNullTracker = new NonNullTracker(appInfo, ImmutableSet.of());
+    IRCode irCode = fooSubject.buildIR();
+    NonNullTracker nonNullTracker = new NonNullTracker(appView, ImmutableSet.of());
     nonNullTracker.addNonNull(irCode);
-    TypeAnalysis analysis = new TypeAnalysis(appInfo, foo);
+    TypeAnalysis analysis = new TypeAnalysis(appView, foo);
     analysis.widening(foo, irCode);
-    inspector.accept(appInfo, irCode);
+    inspector.accept(appView.appInfo(), irCode);
     verifyLastInvoke(irCode, npeCaught);
   }
 
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeAnalysisTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeAnalysisTest.java
index d85b8dd..5ab424a 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeAnalysisTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeAnalysisTest.java
@@ -13,10 +13,10 @@
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.dex.ApplicationReader;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.ir.code.ArrayLength;
 import com.android.tools.r8.ir.code.CheckCast;
 import com.android.tools.r8.ir.code.ConstString;
@@ -38,6 +38,7 @@
 import com.android.tools.r8.utils.Smali;
 import com.android.tools.r8.utils.Timing;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import java.nio.charset.StandardCharsets;
@@ -51,7 +52,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.function.BiConsumer;
-import java.util.function.Consumer;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -67,16 +67,17 @@
 
   private final String dirName;
   private final String smaliFileName;
-  private final Consumer<AppInfo> inspection;
+  private final BiConsumer<AppView<? extends AppInfo>, CodeInspector> inspection;
 
-  public TypeAnalysisTest(String test, Consumer<AppInfo> inspection) {
+  public TypeAnalysisTest(
+      String test, BiConsumer<AppView<? extends AppInfo>, CodeInspector> inspection) {
     dirName = test.substring(0, test.lastIndexOf('/'));
     smaliFileName = test.substring(test.lastIndexOf('/') + 1) + ".smali";
     this.inspection = inspection;
   }
 
   @Parameters(name = "{0}")
-  public static Collection<Object[]> data() throws Exception {
+  public static Collection<Object[]> data() {
     List<String> tests = Arrays.asList(
         "arithmetic/Arithmetic",
         "fibonacci/Fibonacci",
@@ -88,7 +89,8 @@
         "type-confusion-regression5/TestObject"
     );
 
-    Map<String, Consumer<AppInfo>> inspections = new HashMap<>();
+    Map<String, BiConsumer<AppView<? extends AppInfo>, CodeInspector>> inspections =
+        new HashMap<>();
     inspections.put("arithmetic/Arithmetic", TypeAnalysisTest::arithmetic);
     inspections.put("fibonacci/Fibonacci", TypeAnalysisTest::fibonacci);
     inspections.put("fill-array-data/FillArrayData", TypeAnalysisTest::fillArrayData);
@@ -100,7 +102,7 @@
 
     List<Object[]> testCases = new ArrayList<>();
     for (String test : tests) {
-      Consumer<AppInfo> inspection = inspections.get(test);
+      BiConsumer<AppView<? extends AppInfo>, CodeInspector> inspection = inspections.get(test);
       testCases.add(new Object[]{test, inspection});
     }
     return testCases;
@@ -117,7 +119,9 @@
     DexApplication dexApplication =
         new ApplicationReader(app, TEST_OPTIONS, new Timing("TypeAnalysisTest.appReader"))
             .read().toDirect();
-    inspection.accept(new AppInfo(dexApplication));
+    inspection.accept(
+        AppView.createForR8(new AppInfo(dexApplication), TEST_OPTIONS),
+        new CodeInspector(dexApplication));
   }
 
   private static void forEachOutValue(
@@ -132,16 +136,15 @@
   }
 
   // Simple one path with a lot of arithmetic operations.
-  private static void arithmetic(AppInfo appInfo) {
-    CodeInspector inspector = new CodeInspector(appInfo.app);
-    DexEncodedMethod subtract =
-        inspector.clazz("Test")
+  private static void arithmetic(AppView<? extends AppInfo> appView, CodeInspector inspector) {
+    MethodSubject subtractSubject =
+        inspector
+            .clazz("Test")
             .method(
-                new MethodSignature("subtractConstants8bitRegisters", "int", ImmutableList.of()))
-            .getMethod();
-    IRCode irCode =
-        subtract.buildIR(appInfo, GraphLense.getIdentityLense(), TEST_OPTIONS, Origin.unknown());
-    TypeAnalysis analysis = new TypeAnalysis(appInfo, subtract);
+                new MethodSignature("subtractConstants8bitRegisters", "int", ImmutableList.of()));
+    DexEncodedMethod subtract = subtractSubject.getMethod();
+    IRCode irCode = subtractSubject.buildIR();
+    TypeAnalysis analysis = new TypeAnalysis(appView, subtract);
     analysis.widening(subtract, irCode);
     forEachOutValue(irCode, (v, l) -> {
       // v9 <- 9 (INT_OR_FLOAT), which is never used later, hence imprecise.
@@ -150,31 +153,25 @@
   }
 
   // A couple branches, along with some recursive calls.
-  private static void fibonacci(AppInfo appInfo) {
-    CodeInspector inspector = new CodeInspector(appInfo.app);
-    DexEncodedMethod fib =
-        inspector.clazz("Test")
-            .method(new MethodSignature("fibonacci", "int", ImmutableList.of("int")))
-            .getMethod();
-    IRCode irCode =
-        fib.buildIR(appInfo, GraphLense.getIdentityLense(), TEST_OPTIONS, Origin.unknown());
-    TypeAnalysis analysis = new TypeAnalysis(appInfo, fib);
+  private static void fibonacci(AppView<? extends AppInfo> appView, CodeInspector inspector) {
+    MethodSubject fibSubject =
+        inspector
+            .clazz("Test")
+            .method(new MethodSignature("fibonacci", "int", ImmutableList.of("int")));
+    DexEncodedMethod fib = fibSubject.getMethod();
+    IRCode irCode = fibSubject.buildIR();
+    TypeAnalysis analysis = new TypeAnalysis(appView, fib);
     analysis.widening(fib, irCode);
-    forEachOutValue(irCode, (v, l) -> {
-      assertEither(l, INT, NULL);
-    });
+    forEachOutValue(irCode, (v, l) -> assertEither(l, INT, NULL));
   }
 
   // fill-array-data
-  private static void fillArrayData(AppInfo appInfo) {
-    CodeInspector inspector = new CodeInspector(appInfo.app);
-    DexEncodedMethod test1 =
-        inspector.clazz("Test")
-            .method(new MethodSignature("test1", "int[]", ImmutableList.of()))
-            .getMethod();
-    IRCode irCode =
-        test1.buildIR(appInfo, GraphLense.getIdentityLense(), TEST_OPTIONS, Origin.unknown());
-    TypeAnalysis analysis = new TypeAnalysis(appInfo, test1);
+  private static void fillArrayData(AppView<? extends AppInfo> appView, CodeInspector inspector) {
+    MethodSubject test1Subject =
+        inspector.clazz("Test").method(new MethodSignature("test1", "int[]", ImmutableList.of()));
+    DexEncodedMethod test1 = test1Subject.getMethod();
+    IRCode irCode = test1Subject.buildIR();
+    TypeAnalysis analysis = new TypeAnalysis(appView, test1);
     analysis.widening(test1, irCode);
     Value array = null;
     InstructionIterator iterator = irCode.instructionIterator();
@@ -199,15 +196,12 @@
   }
 
   // filled-new-array
-  private static void filledNewArray(AppInfo appInfo) {
-    CodeInspector inspector = new CodeInspector(appInfo.app);
-    DexEncodedMethod test4 =
-        inspector.clazz("Test")
-            .method(new MethodSignature("test4", "int[]", ImmutableList.of()))
-            .getMethod();
-    IRCode irCode =
-        test4.buildIR(appInfo, GraphLense.getIdentityLense(), TEST_OPTIONS, Origin.unknown());
-    TypeAnalysis analysis = new TypeAnalysis(appInfo, test4);
+  private static void filledNewArray(AppView<? extends AppInfo> appView, CodeInspector inspector) {
+    MethodSubject test4Subject =
+        inspector.clazz("Test").method(new MethodSignature("test4", "int[]", ImmutableList.of()));
+    DexEncodedMethod test4 = test4Subject.getMethod();
+    IRCode irCode = test4Subject.buildIR();
+    TypeAnalysis analysis = new TypeAnalysis(appView, test4);
     analysis.widening(test4, irCode);
     Value array = null;
     InstructionIterator iterator = irCode.instructionIterator();
@@ -232,15 +226,12 @@
   }
 
   // Make sure the analysis does not hang.
-  private static void infiniteLoop(AppInfo appInfo) {
-    CodeInspector inspector = new CodeInspector(appInfo.app);
-    DexEncodedMethod loop2 =
-        inspector.clazz("Test")
-            .method(new MethodSignature("loop2", "void", ImmutableList.of()))
-            .getMethod();
-    IRCode irCode =
-        loop2.buildIR(appInfo, GraphLense.getIdentityLense(), TEST_OPTIONS, Origin.unknown());
-    TypeAnalysis analysis = new TypeAnalysis(appInfo, loop2);
+  private static void infiniteLoop(AppView<? extends AppInfo> appView, CodeInspector inspector) {
+    MethodSubject loop2Subject =
+        inspector.clazz("Test").method(new MethodSignature("loop2", "void", ImmutableList.of()));
+    DexEncodedMethod loop2 = loop2Subject.getMethod();
+    IRCode irCode = loop2Subject.buildIR();
+    TypeAnalysis analysis = new TypeAnalysis(appView, loop2);
     analysis.widening(loop2, irCode);
     forEachOutValue(irCode, (v, l) -> {
       if (l.isClassType()) {
@@ -253,15 +244,14 @@
   }
 
   // move-exception
-  private static void tryCatch(AppInfo appInfo) {
-    CodeInspector inspector = new CodeInspector(appInfo.app);
-    DexEncodedMethod test2 =
-        inspector.clazz("Test")
-            .method(new MethodSignature("test2_throw", "int", ImmutableList.of()))
-            .getMethod();
-    IRCode irCode =
-        test2.buildIR(appInfo, GraphLense.getIdentityLense(), TEST_OPTIONS, Origin.unknown());
-    TypeAnalysis analysis = new TypeAnalysis(appInfo, test2);
+  private static void tryCatch(AppView<? extends AppInfo> appView, CodeInspector inspector) {
+    MethodSubject test2Subject =
+        inspector
+            .clazz("Test")
+            .method(new MethodSignature("test2_throw", "int", ImmutableList.of()));
+    DexEncodedMethod test2 = test2Subject.getMethod();
+    IRCode irCode = test2Subject.buildIR();
+    TypeAnalysis analysis = new TypeAnalysis(appView, test2);
     analysis.widening(test2, irCode);
     forEachOutValue(irCode, (v, l) -> {
       if (l.isClassType()) {
@@ -273,23 +263,22 @@
   }
 
   // One very complicated example.
-  private static void typeConfusion(AppInfo appInfo) {
-    CodeInspector inspector = new CodeInspector(appInfo.app);
-    DexEncodedMethod method =
-        inspector.clazz("TestObject")
+  private static void typeConfusion(AppView<? extends AppInfo> appView, CodeInspector inspector) {
+    MethodSubject methodSubject =
+        inspector
+            .clazz("TestObject")
             .method(
-                new MethodSignature("a", "void",
-                    ImmutableList.of("Test", "Test", "Test", "Test")))
-            .getMethod();
-    DexType test = appInfo.dexItemFactory.createType("LTest;");
-    Map<Class<? extends Instruction>, TypeLatticeElement> expectedLattices = ImmutableMap.of(
-        ArrayLength.class, INT,
-        ConstString.class, TypeLatticeElement.stringClassType(appInfo, definitelyNotNull()),
-        CheckCast.class, TypeLatticeElement.fromDexType(test, maybeNull(), appInfo),
-        NewInstance.class, TypeLatticeElement.fromDexType(test, definitelyNotNull(), appInfo));
-    IRCode irCode =
-        method.buildIR(appInfo, GraphLense.getIdentityLense(), TEST_OPTIONS, Origin.unknown());
-    TypeAnalysis analysis = new TypeAnalysis(appInfo, method);
+                new MethodSignature("a", "void", ImmutableList.of("Test", "Test", "Test", "Test")));
+    DexEncodedMethod method = methodSubject.getMethod();
+    DexType test = appView.dexItemFactory().createType("LTest;");
+    Map<Class<? extends Instruction>, TypeLatticeElement> expectedLattices =
+        ImmutableMap.of(
+            ArrayLength.class, INT,
+            ConstString.class, TypeLatticeElement.stringClassType(appView, definitelyNotNull()),
+            CheckCast.class, TypeLatticeElement.fromDexType(test, maybeNull(), appView),
+            NewInstance.class, TypeLatticeElement.fromDexType(test, definitelyNotNull(), appView));
+    IRCode irCode = methodSubject.buildIR();
+    TypeAnalysis analysis = new TypeAnalysis(appView, method);
     analysis.widening(method, irCode);
     forEachOutValue(irCode, (v, l) -> {
       verifyTypeEnvironment(expectedLattices, v, l);
@@ -306,21 +295,20 @@
   }
 
   // One more complicated example.
-  private static void typeConfusion5(AppInfo appInfo) {
-    CodeInspector inspector = new CodeInspector(appInfo.app);
-    DexEncodedMethod method =
-        inspector.clazz("TestObject")
-            .method(
-                new MethodSignature("onClick", "void", ImmutableList.of("Test")))
-            .getMethod();
-    DexType test = appInfo.dexItemFactory.createType("LTest;");
-    Map<Class<? extends Instruction>, TypeLatticeElement> expectedLattices = ImmutableMap.of(
-      ConstString.class, TypeLatticeElement.stringClassType(appInfo, definitelyNotNull()),
-      InstanceOf.class, INT,
-      StaticGet.class, TypeLatticeElement.fromDexType(test, maybeNull(), appInfo));
-    IRCode irCode =
-        method.buildIR(appInfo, GraphLense.getIdentityLense(), TEST_OPTIONS, Origin.unknown());
-    TypeAnalysis analysis = new TypeAnalysis(appInfo, method);
+  private static void typeConfusion5(AppView<? extends AppInfo> appView, CodeInspector inspector) {
+    MethodSubject methodSubject =
+        inspector
+            .clazz("TestObject")
+            .method(new MethodSignature("onClick", "void", ImmutableList.of("Test")));
+    DexEncodedMethod method = methodSubject.getMethod();
+    DexType test = appView.dexItemFactory().createType("LTest;");
+    Map<Class<? extends Instruction>, TypeLatticeElement> expectedLattices =
+        ImmutableMap.of(
+            ConstString.class, TypeLatticeElement.stringClassType(appView, definitelyNotNull()),
+            InstanceOf.class, INT,
+            StaticGet.class, TypeLatticeElement.fromDexType(test, maybeNull(), appView));
+    IRCode irCode = methodSubject.buildIR();
+    TypeAnalysis analysis = new TypeAnalysis(appView, method);
     analysis.widening(method, irCode);
     forEachOutValue(irCode, (v, l) -> verifyTypeEnvironment(expectedLattices, v, l));
   }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java
index 09cb601..2f5740c 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java
@@ -7,8 +7,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.GraphLense;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.InstancePut;
 import com.android.tools.r8.ir.code.Instruction;
@@ -20,9 +19,9 @@
 import com.android.tools.r8.ir.optimize.nonnull.NonNullAfterInvoke;
 import com.android.tools.r8.ir.optimize.nonnull.NonNullAfterNullCheck;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
-import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import com.google.common.collect.ImmutableSet;
 import java.util.function.Consumer;
 import org.junit.Test;
@@ -35,14 +34,13 @@
       int expectedNumberOfNonNull,
       Consumer<IRCode> testAugmentedIRCode)
       throws Exception {
-    AppInfoWithLiveness appInfo = build(testClass);
-    CodeInspector codeInspector = new CodeInspector(appInfo.app);
-    DexEncodedMethod foo = codeInspector.clazz(testClass.getName()).method(signature).getMethod();
-    IRCode irCode =
-        foo.buildIR(appInfo, GraphLense.getIdentityLense(), TEST_OPTIONS, Origin.unknown());
+    AppView<? extends AppInfoWithLiveness> appView = build(testClass);
+    CodeInspector codeInspector = new CodeInspector(appView.appInfo().app);
+    MethodSubject fooSubject = codeInspector.clazz(testClass.getName()).method(signature);
+    IRCode irCode = fooSubject.buildIR();
     checkCountOfNonNull(irCode, 0);
 
-    NonNullTracker nonNullTracker = new NonNullTracker(appInfo, ImmutableSet.of());
+    NonNullTracker nonNullTracker = new NonNullTracker(appView, ImmutableSet.of());
 
     nonNullTracker.addNonNull(irCode);
     assertTrue(irCode.isConsistentSSA());
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTestBase.java b/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTestBase.java
index ecdf9fd..e98eeb1 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTestBase.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTestBase.java
@@ -24,31 +24,26 @@
 import java.util.concurrent.ExecutorService;
 
 public abstract class NonNullTrackerTestBase extends TestBase {
-  protected static final InternalOptions TEST_OPTIONS = new InternalOptions();
 
-  protected AppInfoWithLiveness build(Class<?> mainClass) throws Exception {
+  protected AppView<? extends AppInfoWithLiveness> build(Class<?> mainClass) throws Exception {
     Timing timing = new Timing(getClass().getSimpleName());
     AndroidApp app = buildAndroidApp(ToolHelper.getClassAsBytes(mainClass));
-    DexApplication dexApplication =
-        new ApplicationReader(app, TEST_OPTIONS, timing).read().toDirect();
+    InternalOptions options = new InternalOptions();
+    DexApplication dexApplication = new ApplicationReader(app, options, timing).read().toDirect();
     AppView<? extends AppInfoWithSubtyping> appView =
-        AppView.createForR8(new AppInfoWithSubtyping(dexApplication), TEST_OPTIONS);
+        AppView.createForR8(new AppInfoWithSubtyping(dexApplication), options);
     appView.setAppServices(AppServices.builder(appView).build());
-    ExecutorService executorService = ThreadUtils.getExecutorService(TEST_OPTIONS);
+    ExecutorService executorService = ThreadUtils.getExecutorService(options);
     RootSet rootSet =
         new RootSetBuilder(
-            appView,
-            dexApplication,
-            ImmutableList.of(ProguardKeepRule.defaultKeepAllRule(unused -> {})),
-            TEST_OPTIONS)
-        .run(executorService);
-    Enqueuer enqueuer =
-        new Enqueuer(appView, TEST_OPTIONS, null);
-    return enqueuer.traceApplication(
-        rootSet,
-        ProguardClassFilter.empty(),
-        executorService,
-        timing);
+                appView,
+                dexApplication,
+                ImmutableList.of(ProguardKeepRule.defaultKeepAllRule(unused -> {})),
+                options)
+            .run(executorService);
+    Enqueuer enqueuer = new Enqueuer(appView, options, null);
+    return AppView.createForR8(
+        enqueuer.traceApplication(rootSet, ProguardClassFilter.empty(), executorService, timing),
+        options);
   }
-
 }
diff --git a/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java b/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
index 80a3285..9dd9def 100644
--- a/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
@@ -7,6 +7,7 @@
 
 import com.android.tools.r8.errors.Unimplemented;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.analysis.type.Nullability;
@@ -106,7 +107,7 @@
 
     @Override
     public BasicBlock inlineInvoke(
-        AppInfo appInfo,
+        AppView<? extends AppInfo> appView,
         IRCode code,
         IRCode inlinee,
         ListIterator<BasicBlock> blockIterator,
diff --git a/src/test/java/com/android/tools/r8/ir/regalloc/Regress68656641.java b/src/test/java/com/android/tools/r8/ir/regalloc/Regress68656641.java
index 1a463f2..a0e937d 100644
--- a/src/test/java/com/android/tools/r8/ir/regalloc/Regress68656641.java
+++ b/src/test/java/com/android/tools/r8/ir/regalloc/Regress68656641.java
@@ -5,16 +5,15 @@
 
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.DexApplication;
-import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.code.ValueNumberGenerator;
 import com.android.tools.r8.smali.SmaliBuilder;
 import com.android.tools.r8.smali.SmaliBuilder.MethodSignature;
 import com.android.tools.r8.smali.SmaliTestBase;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import com.google.common.collect.ImmutableList;
 import java.util.PriorityQueue;
 import org.junit.Test;
@@ -48,11 +47,9 @@
         1,
         "    return-void");
     AndroidApp application = buildApplication(builder);
-    AppInfo appInfo = getAppInfo(application);
     // Build the code, and split the code into three blocks.
-    ValueNumberGenerator valueNumberGenerator = new ValueNumberGenerator();
-    DexEncodedMethod method = getMethod(application, signature);
-    return method.buildInliningIRForTesting(new InternalOptions(), valueNumberGenerator, appInfo);
+    MethodSubject methodSubject = getMethodSubject(application, signature);
+    return methodSubject.buildIR();
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java b/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java
index cfc49fe..b7a60bc 100644
--- a/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java
+++ b/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java
@@ -275,10 +275,10 @@
     return ToolHelper.runArtNoVerificationErrors(out.toString(), main);
   }
 
-  protected DexEncodedMethod getMethod(AndroidApp application, String clazz,
-      MethodSignature signature) {
-    return getMethod(application,
-        clazz, signature.type, signature.name, Arrays.asList(signature.parameters));
+  protected DexEncodedMethod getMethod(
+      AndroidApp application, String clazz, MethodSignature signature) {
+    return getMethod(
+        application, clazz, signature.type, signature.name, Arrays.asList(signature.parameters));
   }
 
   protected MethodSubject getMethodSubject(
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index bdf815e..483b02e 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -29,6 +29,7 @@
 import com.android.tools.r8.errors.DexFileOverflowDiagnostic;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ClassAccessFlags;
 import com.android.tools.r8.graph.Code;
 import com.android.tools.r8.graph.DebugLocalInfo;
@@ -751,8 +752,7 @@
                 DexAnnotationSet.empty(),
                 ParameterAnnotationsList.empty(),
                 code);
-        IRCode ir =
-            code.buildIR(method, null, GraphLense.getIdentityLense(), options, Origin.unknown());
+        IRCode ir = code.buildIR(method, AppView.createForR8(null, options), Origin.unknown());
         RegisterAllocator allocator = new LinearScanRegisterAllocator(appInfo, ir, options);
         method.setCode(ir, allocator, options);
         directMethods[i] = method;
diff --git a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
index 2673690..93e4a4f 100644
--- a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
+++ b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.naming;
 
+import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.graph.AppInfoWithSubtyping;
 import com.android.tools.r8.graph.AppServices;
@@ -65,6 +66,7 @@
     ProguardConfiguration configuration =
         ToolHelper.loadProguardConfiguration(dexItemFactory, configPaths);
     InternalOptions options = new InternalOptions(configuration, new Reporter());
+    options.programConsumer = DexIndexedConsumer.emptyConsumer();
 
     ExecutorService executor = ThreadUtils.getExecutorService(1);
 
diff --git a/src/test/java/com/android/tools/r8/smali/CatchSuccessorFallthroughTest.java b/src/test/java/com/android/tools/r8/smali/CatchSuccessorFallthroughTest.java
index 482cb9a..06ccf5a 100644
--- a/src/test/java/com/android/tools/r8/smali/CatchSuccessorFallthroughTest.java
+++ b/src/test/java/com/android/tools/r8/smali/CatchSuccessorFallthroughTest.java
@@ -6,11 +6,12 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.dex.ApplicationReader;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Phi;
@@ -70,21 +71,19 @@
         "  return-void");
 
     AndroidApp originalApplication = buildApplication(builder);
+
+    InternalOptions options = new InternalOptions();
+    options.programConsumer = DexIndexedConsumer.emptyConsumer();
+
     DexApplication application =
         new ApplicationReader(
-                originalApplication,
-                new InternalOptions(),
-                new Timing("CatchSuccessorFallthroughTest"))
+                originalApplication, options, new Timing("CatchSuccessorFallthroughTest"))
             .read();
 
     DexEncodedMethod method = getMethod(originalApplication, methodSig);
     // Get the IR pre-optimization.
     IRCode code =
-        method.buildIR(
-            new AppInfo(application),
-            GraphLense.getIdentityLense(),
-            new InternalOptions(),
-            Origin.unknown());
+        method.buildIR(AppView.createForD8(new AppInfo(application), options), Origin.unknown());
 
     // Find the exit block and assert that the value is a phi merging the exceptional edge
     // with the normal edge.
diff --git a/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java b/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
index dfab990..c528eb0 100644
--- a/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
+++ b/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
@@ -26,6 +26,7 @@
 import com.android.tools.r8.utils.Timing;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import java.io.IOException;
 import java.nio.file.Path;
 import java.util.Collection;
@@ -130,23 +131,39 @@
     }
   }
 
-  protected DexEncodedMethod getMethod(Path appPath, MethodSignature signature) {
+  protected MethodSubject getMethodSubject(Path appPath, MethodSignature signature) {
     try {
       CodeInspector inspector = new CodeInspector(appPath);
-      return getMethod(inspector, signature);
+      return getMethodSubject(inspector, signature);
     } catch (IOException | ExecutionException e) {
       throw new RuntimeException(e);
     }
   }
 
-  protected DexEncodedMethod getMethod(CodeInspector inspector, MethodSignature signature) {
-    return getMethod(
+  protected MethodSubject getMethodSubject(CodeInspector inspector, MethodSignature signature) {
+    return getMethodSubject(
         inspector, signature.clazz, signature.returnType, signature.name, signature.parameterTypes);
   }
 
+  protected MethodSubject getMethodSubject(AndroidApp application, MethodSignature signature) {
+    return getMethodSubject(
+        application,
+        signature.clazz,
+        signature.returnType,
+        signature.name,
+        signature.parameterTypes);
+  }
+
+  protected DexEncodedMethod getMethod(Path appPath, MethodSignature signature) {
+    return getMethodSubject(appPath, signature).getMethod();
+  }
+
+  protected DexEncodedMethod getMethod(CodeInspector inspector, MethodSignature signature) {
+    return getMethodSubject(inspector, signature).getMethod();
+  }
+
   protected DexEncodedMethod getMethod(AndroidApp application, MethodSignature signature) {
-    return getMethod(application,
-        signature.clazz, signature.returnType, signature.name, signature.parameterTypes);
+    return getMethodSubject(application, signature).getMethod();
   }
 
   /**
@@ -220,8 +237,9 @@
     assertEquals(1, getNumberOfProgramClasses(processdApplication));
 
     // Return the processed method for inspection.
-    return getMethod(
-        processdApplication, DEFAULT_CLASS_NAME, returnType, DEFAULT_METHOD_NAME, parameters);
+    return getMethodSubject(
+            processdApplication, DEFAULT_CLASS_NAME, returnType, DEFAULT_METHOD_NAME, parameters)
+        .getMethod();
   }
 
   public String runArt(AndroidApp application) {
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
index 87ae2ec..97de52dd 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
@@ -6,6 +6,7 @@
 
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
 import com.android.tools.r8.naming.MemberNaming.Signature;
@@ -13,7 +14,7 @@
 public class AbsentMethodSubject extends MethodSubject {
 
   @Override
-  public IRCode buildIR() {
+  public IRCode buildIR(DexItemFactory dexItemFactory) {
     throw new Unreachable("Cannot build IR for an absent method");
   }
 
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
index 4d7c0fc..15b2977 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
@@ -4,12 +4,14 @@
 
 package com.android.tools.r8.utils.codeinspector;
 
+import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfPosition;
 import com.android.tools.r8.code.Instruction;
 import com.android.tools.r8.errors.Unimplemented;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.Code;
 import com.android.tools.r8.graph.DexAnnotation;
@@ -18,8 +20,8 @@
 import com.android.tools.r8.graph.DexDebugInfo;
 import com.android.tools.r8.graph.DexDebugPositionState;
 import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.graph.JarCode;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.naming.MemberNaming;
@@ -27,6 +29,7 @@
 import com.android.tools.r8.naming.signature.GenericSignatureParser;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.Reporter;
 import it.unimi.dsi.fastutil.objects.Reference2IntMap;
 import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
 import java.util.Arrays;
@@ -47,15 +50,16 @@
   }
 
   @Override
-  public IRCode buildIR() {
+  public IRCode buildIR(DexItemFactory dexItemFactory) {
+    InternalOptions options = new InternalOptions(dexItemFactory, new Reporter());
+    options.programConsumer = DexIndexedConsumer.emptyConsumer();
+
     DexEncodedMethod method = getMethod();
     return method
         .getCode()
         .buildIR(
             method,
-            new AppInfo(codeInspector.application),
-            GraphLense.getIdentityLense(),
-            new InternalOptions(),
+            AppView.createForD8(new AppInfo(codeInspector.application), options),
             Origin.unknown());
   }
 
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
index 8fb4001..7979530 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.utils.codeinspector;
 
 import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
 import com.google.common.collect.Streams;
@@ -14,7 +15,11 @@
 
 public abstract class MethodSubject extends MemberSubject {
 
-  public abstract IRCode buildIR();
+  public final IRCode buildIR() {
+    return buildIR(new DexItemFactory());
+  }
+
+  public abstract IRCode buildIR(DexItemFactory dexItemFactory);
 
   public abstract boolean isAbstract();