Merge "Sort members by renamed name in Proguard map"
diff --git a/src/main/java/com/android/tools/r8/GenerateMainDexList.java b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
index 26097c1..fe946da 100644
--- a/src/main/java/com/android/tools/r8/GenerateMainDexList.java
+++ b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.graph.AppInfoWithSubtyping;
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.shaking.Enqueuer;
 import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
 import com.android.tools.r8.shaking.MainDexListBuilder;
@@ -41,7 +42,7 @@
     AppInfoWithSubtyping appInfo = new AppInfoWithSubtyping(application);
     RootSet mainDexRootSet =
         new RootSetBuilder(appInfo, application, options.mainDexKeepRules, options).run(executor);
-    Enqueuer enqueuer = new Enqueuer(appInfo, options, true);
+    Enqueuer enqueuer = new Enqueuer(appInfo, GraphLense.getIdentityLense(), options, true);
     AppInfoWithLiveness mainDexAppInfo = enqueuer.traceMainDex(mainDexRootSet, executor, timing);
     // LiveTypes is the result.
     Set<DexType> mainDexClasses =
diff --git a/src/main/java/com/android/tools/r8/PrintSeeds.java b/src/main/java/com/android/tools/r8/PrintSeeds.java
index 782c91d..4410d8a 100644
--- a/src/main/java/com/android/tools/r8/PrintSeeds.java
+++ b/src/main/java/com/android/tools/r8/PrintSeeds.java
@@ -6,6 +6,7 @@
 import com.android.tools.r8.dex.ApplicationReader;
 import com.android.tools.r8.graph.AppInfoWithSubtyping;
 import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.shaking.Enqueuer;
 import com.android.tools.r8.shaking.RootSetBuilder;
 import com.android.tools.r8.shaking.RootSetBuilder.RootSet;
@@ -84,7 +85,7 @@
           new RootSetBuilder(
                   appInfo, application, options.proguardConfiguration.getRules(), options)
               .run(executor);
-      Enqueuer enqueuer = new Enqueuer(appInfo, options, false);
+      Enqueuer enqueuer = new Enqueuer(appInfo, GraphLense.getIdentityLense(), options, false);
       appInfo = enqueuer.traceApplication(rootSet, executor, timing);
       RootSetBuilder.writeSeeds(
           appInfo.withLiveness(),
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index c03d928..16858af 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -292,6 +292,7 @@
         Enqueuer enqueuer =
             new Enqueuer(
                 appView.getAppInfo(),
+                appView.getGraphLense(),
                 options,
                 options.forceProguardCompatibility,
                 compatibility,
@@ -380,10 +381,9 @@
                   .rewrittenWithLense(application.asDirect(), appView.getGraphLense()));
         }
         // Collect switch maps and ordinals maps.
+        appViewWithLiveness.setAppInfo(new SwitchMapCollector(appViewWithLiveness, options).run());
         appViewWithLiveness.setAppInfo(
-            new SwitchMapCollector(appViewWithLiveness.getAppInfo(), options).run());
-        appViewWithLiveness.setAppInfo(
-            new EnumOrdinalMapCollector(appViewWithLiveness.getAppInfo(), options).run());
+            new EnumOrdinalMapCollector(appViewWithLiveness, options).run());
 
         // TODO(b/79143143): re-enable once fixed.
         // graphLense = new BridgeMethodAnalysis(graphLense, appInfo.withLiveness()).run();
@@ -419,7 +419,8 @@
 
       if (!options.mainDexKeepRules.isEmpty()) {
         appView.setAppInfo(new AppInfoWithSubtyping(application));
-        Enqueuer enqueuer = new Enqueuer(appView.getAppInfo(), options, true);
+        Enqueuer enqueuer =
+            new Enqueuer(appView.getAppInfo(), appView.getGraphLense(), options, true);
         // Lets find classes which may have code executed before secondary dex files installation.
         RootSet mainDexRootSet =
             new RootSetBuilder(appView.getAppInfo(), application, options.mainDexKeepRules, options)
@@ -443,7 +444,11 @@
         timing.begin("Post optimization code stripping");
         try {
           Enqueuer enqueuer =
-              new Enqueuer(appView.getAppInfo(), options, options.forceProguardCompatibility);
+              new Enqueuer(
+                  appView.getAppInfo(),
+                  appView.getGraphLense(),
+                  options,
+                  options.forceProguardCompatibility);
           appView.setAppInfo(enqueuer.traceApplication(rootSet, executorService, timing));
 
           AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
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 776cc42..e41120d 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -201,14 +201,19 @@
 
   @Override
   public IRCode buildIR(
-      DexEncodedMethod encodedMethod, AppInfo appInfo, InternalOptions options, Origin origin) {
-    return internalBuild(encodedMethod, appInfo, options, null, null, origin);
+      DexEncodedMethod encodedMethod,
+      AppInfo appInfo,
+      GraphLense graphLense,
+      InternalOptions options,
+      Origin origin) {
+    return internalBuild(encodedMethod, appInfo, graphLense, options, null, null, origin);
   }
 
   @Override
   public IRCode buildInliningIR(
       DexEncodedMethod encodedMethod,
       AppInfo appInfo,
+      GraphLense graphLense,
       InternalOptions options,
       ValueNumberGenerator valueNumberGenerator,
       Position callerPosition,
@@ -216,12 +221,13 @@
     assert valueNumberGenerator != null;
     assert callerPosition != null;
     return internalBuild(
-        encodedMethod, appInfo, options, valueNumberGenerator, callerPosition, origin);
+        encodedMethod, appInfo, graphLense, options, valueNumberGenerator, callerPosition, origin);
   }
 
   private IRCode internalBuild(
       DexEncodedMethod encodedMethod,
       AppInfo appInfo,
+      GraphLense graphLense,
       InternalOptions options,
       ValueNumberGenerator generator,
       Position callerPosition,
@@ -235,14 +241,11 @@
         new CfSourceCode(
             this,
             encodedMethod,
+            graphLense.getOriginalMethodSignature(encodedMethod.method),
             callerPosition,
             origin,
             options.lineNumberOptimization == LineNumberOptimization.ON);
-    IRBuilder builder =
-        (generator == null)
-            ? new IRBuilder(encodedMethod, appInfo, source, options)
-            : new IRBuilder(encodedMethod, appInfo, source, options, generator);
-    return builder.build();
+    return new IRBuilder(encodedMethod, appInfo, source, options, generator).build();
   }
 
   @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 60a5ef5..0484a63 100644
--- a/src/main/java/com/android/tools/r8/graph/Code.java
+++ b/src/main/java/com/android/tools/r8/graph/Code.java
@@ -17,11 +17,16 @@
 public abstract class Code extends CachedHashValueDexItem {
 
   public abstract IRCode buildIR(
-      DexEncodedMethod encodedMethod, AppInfo appInfo, InternalOptions options, Origin origin);
+      DexEncodedMethod encodedMethod,
+      AppInfo appInfo,
+      GraphLense graphLense,
+      InternalOptions options,
+      Origin origin);
 
   public IRCode buildInliningIR(
       DexEncodedMethod encodedMethod,
       AppInfo appInfo,
+      GraphLense graphLense,
       InternalOptions options,
       ValueNumberGenerator valueNumberGenerator,
       Position callerPosition,
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 b1b5f8a..4a0a483 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -164,10 +164,18 @@
 
   @Override
   public IRCode buildIR(
-      DexEncodedMethod encodedMethod, AppInfo appInfo, InternalOptions options, Origin origin) {
+      DexEncodedMethod encodedMethod,
+      AppInfo appInfo,
+      GraphLense graphLense,
+      InternalOptions options,
+      Origin origin) {
     DexSourceCode source =
         new DexSourceCode(
-            this, encodedMethod, null, options.lineNumberOptimization == LineNumberOptimization.ON);
+            this,
+            encodedMethod,
+            graphLense.getOriginalMethodSignature(encodedMethod.method),
+            null,
+            options.lineNumberOptimization == LineNumberOptimization.ON);
     IRBuilder builder = new IRBuilder(encodedMethod, appInfo, source, options);
     return builder.build();
   }
@@ -176,6 +184,7 @@
   public IRCode buildInliningIR(
       DexEncodedMethod encodedMethod,
       AppInfo appInfo,
+      GraphLense graphLense,
       InternalOptions options,
       ValueNumberGenerator valueNumberGenerator,
       Position callerPosition,
@@ -184,6 +193,7 @@
         new DexSourceCode(
             this,
             encodedMethod,
+            graphLense.getOriginalMethodSignature(encodedMethod.method),
             callerPosition,
             options.lineNumberOptimization == LineNumberOptimization.ON);
     IRBuilder builder =
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 a6032e4..cf1a105 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -252,23 +252,26 @@
     compilationState = CompilationState.NOT_PROCESSED;
   }
 
-  public IRCode buildIR(AppInfo appInfo, InternalOptions options, Origin origin) {
-    return code == null ? null : code.buildIR(this, appInfo, options, origin);
+  public IRCode buildIR(
+      AppInfo appInfo, GraphLense graphLense, InternalOptions options, Origin origin) {
+    return code == null ? null : code.buildIR(this, appInfo, graphLense, options, origin);
   }
 
   public IRCode buildInliningIRForTesting(
       InternalOptions options, ValueNumberGenerator valueNumberGenerator) {
-    return buildInliningIR(null, options, valueNumberGenerator, null, Origin.unknown());
+    return buildInliningIR(
+        null, GraphLense.getIdentityLense(), options, valueNumberGenerator, null, Origin.unknown());
   }
 
   public IRCode buildInliningIR(
       AppInfo appInfo,
+      GraphLense graphLense,
       InternalOptions options,
       ValueNumberGenerator valueNumberGenerator,
       Position callerPosition,
       Origin origin) {
     return code.buildInliningIR(
-        this, appInfo, options, valueNumberGenerator, callerPosition, origin);
+        this, appInfo, graphLense, options, valueNumberGenerator, callerPosition, origin);
   }
 
   public void setCode(Code code) {
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 a48841f..28143ad 100644
--- a/src/main/java/com/android/tools/r8/graph/JarCode.java
+++ b/src/main/java/com/android/tools/r8/graph/JarCode.java
@@ -108,17 +108,22 @@
 
   @Override
   public IRCode buildIR(
-      DexEncodedMethod encodedMethod, AppInfo appInfo, InternalOptions options, Origin origin) {
+      DexEncodedMethod encodedMethod,
+      AppInfo appInfo,
+      GraphLense graphLense,
+      InternalOptions options,
+      Origin origin) {
     triggerDelayedParsingIfNeccessary();
     return options.debug
-        ? internalBuildWithLocals(encodedMethod, appInfo, options, null, null)
-        : internalBuild(encodedMethod, appInfo, options, null, null);
+        ? internalBuildWithLocals(encodedMethod, appInfo, graphLense, options, null, null)
+        : internalBuild(encodedMethod, appInfo, graphLense, options, null, null);
   }
 
   @Override
   public IRCode buildInliningIR(
       DexEncodedMethod encodedMethod,
       AppInfo appInfo,
+      GraphLense graphLense,
       InternalOptions options,
       ValueNumberGenerator generator,
       Position callerPosition,
@@ -126,41 +131,45 @@
     assert generator != null;
     triggerDelayedParsingIfNeccessary();
     return options.debug
-        ? internalBuildWithLocals(encodedMethod, appInfo, options, generator, callerPosition)
-        : internalBuild(encodedMethod, appInfo, options, generator, callerPosition);
+        ? internalBuildWithLocals(
+            encodedMethod, appInfo, graphLense, options, generator, callerPosition)
+        : internalBuild(encodedMethod, appInfo, graphLense, options, generator, callerPosition);
   }
 
   private IRCode internalBuildWithLocals(
       DexEncodedMethod encodedMethod,
       AppInfo appInfo,
+      GraphLense graphLense,
       InternalOptions options,
       ValueNumberGenerator generator,
       Position callerPosition) {
     try {
-      return internalBuild(encodedMethod, appInfo, options, generator, callerPosition);
+      return internalBuild(encodedMethod, appInfo, graphLense, options, generator, callerPosition);
     } catch (InvalidDebugInfoException e) {
       options.warningInvalidDebugInfo(encodedMethod, origin, e);
       node.localVariables.clear();
-      return internalBuild(encodedMethod, appInfo, options, generator, callerPosition);
+      return internalBuild(encodedMethod, appInfo, graphLense, options, generator, callerPosition);
     }
   }
 
   private IRCode internalBuild(
       DexEncodedMethod encodedMethod,
       AppInfo appInfo,
+      GraphLense graphLense,
       InternalOptions options,
       ValueNumberGenerator generator,
       Position callerPosition) {
     if (!options.debug) {
       node.localVariables.clear();
     }
-    JarSourceCode source = new JarSourceCode(
-        method.getHolder(), node, application, encodedMethod.method, callerPosition);
-    IRBuilder builder =
-        (generator == null)
-            ? new IRBuilder(encodedMethod, appInfo, source, options)
-            : new IRBuilder(encodedMethod, appInfo, source, options, generator);
-    return builder.build();
+    JarSourceCode source =
+        new JarSourceCode(
+            method.getHolder(),
+            node,
+            application,
+            graphLense.getOriginalMethodSignature(encodedMethod.method),
+            callerPosition);
+    return new IRBuilder(encodedMethod, appInfo, source, options, generator).build();
   }
 
   @Override
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 afc2969..b6eb879 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
@@ -175,20 +175,32 @@
 
   @Override
   public IRCode buildIR(
-      DexEncodedMethod encodedMethod, AppInfo appInfo, InternalOptions options, Origin origin) {
-    return asCfCode().buildIR(encodedMethod, appInfo, options, origin);
+      DexEncodedMethod encodedMethod,
+      AppInfo appInfo,
+      GraphLense graphLense,
+      InternalOptions options,
+      Origin origin) {
+    return asCfCode().buildIR(encodedMethod, appInfo, graphLense, options, origin);
   }
 
   @Override
   public IRCode buildInliningIR(
       DexEncodedMethod encodedMethod,
       AppInfo appInfo,
+      GraphLense graphLense,
       InternalOptions options,
       ValueNumberGenerator valueNumberGenerator,
       Position callerPosition,
       Origin origin) {
-    return asCfCode().buildInliningIR(
-        encodedMethod, appInfo, options, valueNumberGenerator, callerPosition, origin);
+    return asCfCode()
+        .buildInliningIR(
+            encodedMethod,
+            appInfo,
+            graphLense,
+            options,
+            valueNumberGenerator,
+            callerPosition,
+            origin);
   }
 
   @Override
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 f5b0a31..35ce779 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
@@ -76,6 +76,7 @@
   private final Int2ReferenceMap<DebugLocalInfo> emittedLocals = new Int2ReferenceOpenHashMap<>();
   private Int2ReferenceMap<DebugLocalInfo> pendingLocals = null;
   private boolean pendingLocalChanges = false;
+  private BasicBlock pendingFrame = null;
 
   private final List<LocalVariableInfo> localVariablesTable = new ArrayList<>();
   private final Int2ReferenceMap<LocalVariableInfo> openLocalVariables =
@@ -259,7 +260,6 @@
     BasicBlock block = blockIterator.next();
     CfLabel tryCatchStart = null;
     CatchHandlers<BasicBlock> tryCatchHandlers = CatchHandlers.EMPTY_BASIC_BLOCK;
-    BasicBlock pendingFrame = null;
     boolean previousFallthrough = false;
     do {
       assert stack.isEmpty();
@@ -286,17 +286,6 @@
         pendingFrame = block;
         emitLabel(getLabel(block));
       }
-      if (pendingFrame != null) {
-        boolean advancesPC = hasMaterializingInstructions(block, nextBlock);
-        // If block has no materializing instructions, then we postpone emitting the frame
-        // until the next block. In this case, nextBlock must be non-null
-        // (or we would fall off the edge of the method).
-        assert advancesPC || nextBlock != null;
-        if (advancesPC) {
-          addFrame(pendingFrame, Collections.emptyList());
-          pendingFrame = null;
-        }
-      }
       JumpInstruction exit = block.exit();
       boolean fallthrough =
           (exit.isGoto() && exit.asGoto().getTarget() == nextBlock)
@@ -308,7 +297,7 @@
         pendingLocals = new Int2ReferenceOpenHashMap<>(locals);
         pendingLocalChanges = true;
       }
-      buildCfInstructions(block, fallthrough, stack);
+      buildCfInstructions(block, nextBlock, fallthrough, stack);
       block = nextBlock;
       previousFallthrough = fallthrough;
     } while (block != null);
@@ -346,7 +335,19 @@
     return false;
   }
 
-  private void buildCfInstructions(BasicBlock block, boolean fallthrough, Stack stack) {
+  private void buildCfInstructions(
+      BasicBlock block, BasicBlock nextBlock, boolean fallthrough, Stack stack) {
+    if (pendingFrame != null) {
+      boolean advancesPC = hasMaterializingInstructions(block, nextBlock);
+      // If block has no materializing instructions, then we postpone emitting the frame
+      // until the next block. In this case, nextBlock must be non-null
+      // (or we would fall off the edge of the method).
+      assert advancesPC || nextBlock != null;
+      if (advancesPC) {
+        addFrame(pendingFrame, Collections.emptyList());
+        pendingFrame = null;
+      }
+    }
     InstructionIterator it = block.iterator();
     while (it.hasNext()) {
       Instruction instruction = it.next();
@@ -394,30 +395,7 @@
     }
     CfLabel label = ensureLabel();
     if (didLocalsChange) {
-      Int2ReferenceSortedMap<DebugLocalInfo> ending =
-          DebugLocalInfo.endingLocals(emittedLocals, pendingLocals);
-      Int2ReferenceSortedMap<DebugLocalInfo> starting =
-          DebugLocalInfo.startingLocals(emittedLocals, pendingLocals);
-      assert !ending.isEmpty() || !starting.isEmpty();
-      for (Entry<DebugLocalInfo> entry : ending.int2ReferenceEntrySet()) {
-        int localIndex = entry.getIntKey();
-        LocalVariableInfo info = openLocalVariables.remove(localIndex);
-        info.setEnd(label);
-        localVariablesTable.add(info);
-        DebugLocalInfo removed = emittedLocals.remove(localIndex);
-        assert removed == entry.getValue();
-      }
-      if (!starting.isEmpty()) {
-        for (Entry<DebugLocalInfo> entry : starting.int2ReferenceEntrySet()) {
-          int localIndex = entry.getIntKey();
-          assert !emittedLocals.containsKey(localIndex);
-          assert !openLocalVariables.containsKey(localIndex);
-          openLocalVariables.put(
-              localIndex, new LocalVariableInfo(localIndex, entry.getValue(), label));
-          emittedLocals.put(localIndex, entry.getValue());
-        }
-      }
-      pendingLocalChanges = false;
+      updateLocals(label);
     }
     if (didPositionChange) {
       add(new CfPosition(label, position));
@@ -425,6 +403,33 @@
     }
   }
 
+  private void updateLocals(CfLabel label) {
+    Int2ReferenceSortedMap<DebugLocalInfo> ending =
+        DebugLocalInfo.endingLocals(emittedLocals, pendingLocals);
+    Int2ReferenceSortedMap<DebugLocalInfo> starting =
+        DebugLocalInfo.startingLocals(emittedLocals, pendingLocals);
+    assert !ending.isEmpty() || !starting.isEmpty();
+    for (Entry<DebugLocalInfo> entry : ending.int2ReferenceEntrySet()) {
+      int localIndex = entry.getIntKey();
+      LocalVariableInfo info = openLocalVariables.remove(localIndex);
+      info.setEnd(label);
+      localVariablesTable.add(info);
+      DebugLocalInfo removed = emittedLocals.remove(localIndex);
+      assert removed == entry.getValue();
+    }
+    if (!starting.isEmpty()) {
+      for (Entry<DebugLocalInfo> entry : starting.int2ReferenceEntrySet()) {
+        int localIndex = entry.getIntKey();
+        assert !emittedLocals.containsKey(localIndex);
+        assert !openLocalVariables.containsKey(localIndex);
+        openLocalVariables.put(
+            localIndex, new LocalVariableInfo(localIndex, entry.getValue(), label));
+        emittedLocals.put(localIndex, entry.getValue());
+      }
+    }
+    pendingLocalChanges = false;
+  }
+
   private boolean localsChanged() {
     if (!pendingLocalChanges) {
       return false;
@@ -461,11 +466,25 @@
 
     Collection<Value> locals = registerAllocator.getLocalsAtBlockEntry(block);
     Int2ReferenceSortedMap<FrameType> mapping = new Int2ReferenceAVLTreeMap<>();
-
     for (Value local : locals) {
       mapping.put(getLocalRegister(local), getFrameType(block, local));
     }
-    instructions.add(new CfFrame(mapping, stackTypes));
+    CfFrame frame = new CfFrame(mapping, stackTypes);
+
+    // Make sure to end locals on this transition before the synthetic CfFrame instruction.
+    // Otherwise we might extend the live range of a local across a CfFrame instruction that
+    // the local is not live across. For example if we have a return followed by a move exception
+    // where the locals end. Inserting a CfFrame instruction between the return and the move
+    // exception without ending the locals will lead to having the local alive on the CfFrame
+    // instruction which is not correct and will cause us to not be able to build IR from the
+    // CfCode.
+    boolean didLocalsChange = localsChanged();
+    if (didLocalsChange) {
+      CfLabel label = ensureLabel();
+      updateLocals(label);
+    }
+
+    instructions.add(frame);
   }
 
   private FrameType getFrameType(BasicBlock liveBlock, Value local) {
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 bc2222f..7892afb 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
@@ -20,6 +20,7 @@
 import com.android.tools.r8.graph.DebugLocalInfo;
 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.DexType;
 import com.android.tools.r8.ir.code.CanonicalPositions;
 import com.android.tools.r8.ir.code.CatchHandlers;
@@ -199,6 +200,7 @@
   public CfSourceCode(
       CfCode code,
       DexEncodedMethod method,
+      DexMethod originalMethod,
       Position callerPosition,
       Origin origin,
       boolean preserveCaller) {
@@ -217,7 +219,7 @@
     }
     this.state = new CfState(origin);
     canonicalPositions =
-        new CanonicalPositions(callerPosition, preserveCaller, cfPositionCount, this.method.method);
+        new CanonicalPositions(callerPosition, preserveCaller, cfPositionCount, originalMethod);
   }
 
   @Override
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 10bf6a5..94516a2 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
@@ -75,26 +75,30 @@
 
   private List<DexDebugEntry> debugEntries = null;
   // In case of inlining the position of the invoke in the caller.
-  private final DexMethod method;
+  private final DexMethod originalMethod;
 
   public DexSourceCode(
-      DexCode code, DexEncodedMethod method, Position callerPosition, boolean preserveCaller) {
+      DexCode code,
+      DexEncodedMethod method,
+      DexMethod originalMethod,
+      Position callerPosition,
+      boolean preserveCaller) {
     this.code = code;
     this.proto = method.method.proto;
     this.accessFlags = method.accessFlags;
-    this.method = method.method;
+    this.originalMethod = originalMethod;
 
     argumentTypes = computeArgumentTypes();
     DexDebugInfo info = code.getDebugInfo();
     if (info != null) {
-      debugEntries = info.computeEntries(method.method);
+      debugEntries = info.computeEntries(originalMethod);
     }
     canonicalPositions =
         new CanonicalPositions(
             callerPosition,
             preserveCaller,
             debugEntries == null ? 0 : debugEntries.size(),
-            this.method);
+            originalMethod);
   }
 
   @Override
@@ -253,7 +257,7 @@
   private Position getCanonicalPositionAppendCaller(DexDebugEntry entry) {
     // If this instruction has already been inlined then this.method must be the outermost caller.
     assert entry.callerPosition == null
-        || entry.callerPosition.getOutermostCaller().method == method;
+        || entry.callerPosition.getOutermostCaller().method == originalMethod;
 
     return canonicalPositions.getCanonical(
         new Position(
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 62450d4..98b4502 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
@@ -329,19 +329,23 @@
   // Flag indicating if the instructions define values with imprecise types.
   private boolean hasImpreciseInstructionOutValueTypes = false;
 
-  public IRBuilder(DexEncodedMethod method, AppInfo appInfo,
-      SourceCode source, InternalOptions options) {
+  public IRBuilder(
+      DexEncodedMethod method, AppInfo appInfo, SourceCode source, InternalOptions options) {
     this(method, appInfo, source, options, new ValueNumberGenerator());
   }
 
   public IRBuilder(
-      DexEncodedMethod method, AppInfo appInfo, SourceCode source,
-      InternalOptions options, ValueNumberGenerator valueNumberGenerator) {
+      DexEncodedMethod method,
+      AppInfo appInfo,
+      SourceCode source,
+      InternalOptions options,
+      ValueNumberGenerator valueNumberGenerator) {
     assert source != null;
     this.method = method;
     this.appInfo = appInfo;
     this.source = source;
-    this.valueNumberGenerator = valueNumberGenerator;
+    this.valueNumberGenerator =
+        valueNumberGenerator != null ? valueNumberGenerator : new ValueNumberGenerator();
     this.options = options;
   }
 
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 00c3754..f523b46 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
@@ -495,7 +495,8 @@
           executorService.submit(
               () -> {
                 IRCode code =
-                    method.buildIR(appInfo, options, appInfo.originFor(method.method.holder));
+                    method.buildIR(
+                        appInfo, graphLense, options, appInfo.originFor(method.method.holder));
                 assert code != null;
                 assert !method.getCode().isOutlineCode();
                 // Instead of repeating all the optimizations of rewriteCode(), only run the
@@ -637,7 +638,8 @@
       feedback.markProcessed(method, ConstraintWithTarget.NEVER);
       return;
     }
-    IRCode code = method.buildIR(appInfo, options, appInfo.originFor(method.method.holder));
+    IRCode code =
+        method.buildIR(appInfo, graphLense, options, appInfo.originFor(method.method.holder));
     if (code == null) {
       feedback.markProcessed(method, ConstraintWithTarget.NEVER);
       return;
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 1170dab..85a0f99 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
@@ -187,20 +187,20 @@
   // Cooked position to indicate positions in synthesized code (ie, for synchronization).
   private Position syntheticPosition = null;
 
-  private final DexMethod method;
+  private final DexMethod originalMethod;
   private final Position callerPosition;
 
   public JarSourceCode(
       DexType clazz,
       MethodNode node,
       JarApplicationReader application,
-      DexMethod method,
+      DexMethod originalMethod,
       Position callerPosition) {
     assert node != null;
     assert node.desc != null;
     this.node = node;
     this.application = application;
-    this.method = method;
+    this.originalMethod = originalMethod;
     this.clazz = clazz;
     this.callerPosition = callerPosition;
     parameterTypes = Arrays.asList(application.getArgumentTypes(node.desc));
@@ -2862,12 +2862,12 @@
 
   private Position getCanonicalPosition(int line) {
     return canonicalPositions.computeIfAbsent(
-        line, l -> new Position(l, null, method, callerPosition));
+        line, l -> new Position(l, null, originalMethod, callerPosition));
   }
 
   private Position getPreamblePosition() {
     if (preamblePosition == null) {
-      preamblePosition = Position.synthetic(0, method, null);
+      preamblePosition = Position.synthetic(0, originalMethod, null);
     }
     return preamblePosition;
   }
@@ -2891,8 +2891,8 @@
       }
       syntheticPosition =
           (min == Integer.MAX_VALUE)
-              ? Position.noneWithMethod(method, callerPosition)
-              : Position.synthetic(min < max ? min - 1 : min, method, callerPosition);
+              ? Position.noneWithMethod(originalMethod, callerPosition)
+              : Position.synthetic(min < max ? min - 1 : min, originalMethod, callerPosition);
     }
     return syntheticPosition;
   }
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 1b68f7d..e23b534 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
@@ -3,10 +3,12 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.optimize;
 
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.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;
@@ -30,12 +32,14 @@
 public class EnumOrdinalMapCollector {
 
   private final AppInfoWithLiveness appInfo;
+  private final GraphLense graphLense;
   private final InternalOptions options;
 
   private final Map<DexType, Reference2IntMap<DexField>> ordinalsMaps = new IdentityHashMap<>();
 
-  public EnumOrdinalMapCollector(AppInfoWithLiveness appInfo, InternalOptions options) {
-    this.appInfo = appInfo;
+  public EnumOrdinalMapCollector(AppView<AppInfoWithLiveness> appView, InternalOptions options) {
+    this.appInfo = appView.getAppInfo();
+    this.graphLense = appView.getGraphLense();
     this.options = options;
   }
 
@@ -55,7 +59,8 @@
       return;
     }
     DexEncodedMethod initializer = clazz.getClassInitializer();
-    IRCode code = initializer.getCode().buildIR(initializer, appInfo, options, clazz.origin);
+    IRCode code =
+        initializer.getCode().buildIR(initializer, appInfo, graphLense, options, clazz.origin);
     Reference2IntMap<DexField> ordinalsMap = new Reference2IntArrayMap<>();
     ordinalsMap.defaultReturnValue(-1);
     InstructionIterator it = code.instructionIterator();
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 7ea7379..12baa2c 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
@@ -409,7 +409,8 @@
         Position callerPosition) {
       // Build the IR for a yet not processed method, and perform minimal IR processing.
       Origin origin = appInfo.originFor(target.method.holder);
-      IRCode code = target.buildInliningIR(appInfo, options, generator, callerPosition, origin);
+      IRCode code =
+          target.buildInliningIR(appInfo, graphLense, options, generator, callerPosition, origin);
       if (!target.isProcessed()) {
         new LensCodeRewriter(graphLense, appInfo).rewrite(code, target);
       }
@@ -586,7 +587,8 @@
               invokePosition = Position.noneWithMethod(method.method, null);
             }
             assert invokePosition.callerPosition == null
-                || invokePosition.getOutermostCaller().method == method.method;
+                || invokePosition.getOutermostCaller().method
+                    == graphLense.getOriginalMethodSignature(method.method);
 
             IRCode inlinee =
                 result.buildInliningIR(
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 505d192..5f8fd6b 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
@@ -20,6 +20,7 @@
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DexTypeList;
+import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ParameterAnnotationsList;
 import com.android.tools.r8.graph.UseRegistry;
@@ -1164,10 +1165,13 @@
 
     @Override
     public IRCode buildIR(
-        DexEncodedMethod encodedMethod, AppInfo appInfo, InternalOptions options, Origin origin) {
+        DexEncodedMethod encodedMethod,
+        AppInfo appInfo,
+        GraphLense graphLense,
+        InternalOptions options,
+        Origin origin) {
       OutlineSourceCode source = new OutlineSourceCode(outline);
-      IRBuilder builder = new IRBuilder(encodedMethod, appInfo, source, options);
-      return builder.build();
+      return new IRBuilder(encodedMethod, appInfo, source, options).build();
     }
 
     @Override
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 a586355..c2fbc9e 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
@@ -3,12 +3,14 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.optimize;
 
+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.DexField;
 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;
@@ -61,14 +63,16 @@
 public class SwitchMapCollector {
 
   private final AppInfoWithLiveness appInfo;
+  private final GraphLense graphLense;
   private final InternalOptions options;
   private final DexString switchMapPrefix;
   private final DexType intArrayType;
 
   private final Map<DexField, Int2ReferenceMap<DexField>> switchMaps = new IdentityHashMap<>();
 
-  public SwitchMapCollector(AppInfoWithLiveness appInfo, InternalOptions options) {
-    this.appInfo = appInfo;
+  public SwitchMapCollector(AppView<AppInfoWithLiveness> appView, InternalOptions options) {
+    this.appInfo = appView.getAppInfo();
+    this.graphLense = appView.getGraphLense();
     this.options = options;
     switchMapPrefix = appInfo.dexItemFactory.createString("$SwitchMap$");
     intArrayType = appInfo.dexItemFactory.createType("[I");
@@ -92,7 +96,8 @@
     List<DexEncodedField> switchMapFields = Arrays.stream(clazz.staticFields())
         .filter(this::maybeIsSwitchMap).collect(Collectors.toList());
     if (!switchMapFields.isEmpty()) {
-      IRCode initializer = clazz.getClassInitializer().buildIR(appInfo, options, clazz.origin);
+      IRCode initializer =
+          clazz.getClassInitializer().buildIR(appInfo, graphLense, options, clazz.origin);
       switchMapFields.forEach(field -> extractSwitchMap(field, initializer));
     }
   }
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java
index 7835da2..aa6be96 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.graph.AppInfo;
 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;
@@ -47,16 +48,27 @@
 
   @Override
   public final IRCode buildIR(
-      DexEncodedMethod encodedMethod, AppInfo appInfo, InternalOptions options, Origin origin) {
+      DexEncodedMethod encodedMethod,
+      AppInfo appInfo,
+      GraphLense graphLense,
+      InternalOptions options,
+      Origin origin) {
     return new IRBuilder(encodedMethod, appInfo, sourceCodeProvider.get(), options).build();
   }
 
   @Override
   public IRCode buildInliningIR(
-      DexEncodedMethod encodedMethod, AppInfo appInfo, InternalOptions options,
-      ValueNumberGenerator valueNumberGenerator, Position callerPosition, Origin origin) {
-    return new IRBuilder(encodedMethod, appInfo,
-        sourceCodeProvider.get(), options, valueNumberGenerator).build();
+      DexEncodedMethod encodedMethod,
+      AppInfo appInfo,
+      GraphLense graphLense,
+      InternalOptions options,
+      ValueNumberGenerator valueNumberGenerator,
+      Position callerPosition,
+      Origin origin) {
+    IRBuilder builder =
+        new IRBuilder(
+            encodedMethod, appInfo, sourceCodeProvider.get(), options, valueNumberGenerator);
+    return builder.build();
   }
 
   @Override
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 6a12b60..bcd489e 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -94,6 +94,7 @@
   private boolean tracingMainDex = false;
 
   private final AppInfoWithSubtyping appInfo;
+  private final GraphLense graphLense;
   private final InternalOptions options;
   private RootSet rootSet;
 
@@ -218,15 +219,23 @@
    */
   private final ProguardConfiguration.Builder compatibility;
 
-  public Enqueuer(AppInfoWithSubtyping appInfo, InternalOptions options,
+  public Enqueuer(
+      AppInfoWithSubtyping appInfo,
+      GraphLense graphLense,
+      InternalOptions options,
       boolean forceProguardCompatibility) {
-    this(appInfo, options, forceProguardCompatibility, null, null);
+    this(appInfo, graphLense, options, forceProguardCompatibility, null, null);
   }
 
-  public Enqueuer(AppInfoWithSubtyping appInfo, InternalOptions options,
+  public Enqueuer(
+      AppInfoWithSubtyping appInfo,
+      GraphLense graphLense,
+      InternalOptions options,
       boolean forceProguardCompatibility,
-      ProguardConfiguration.Builder compatibility, ProtoLiteExtension protoLiteExtension) {
+      ProguardConfiguration.Builder compatibility,
+      ProtoLiteExtension protoLiteExtension) {
     this.appInfo = appInfo;
+    this.graphLense = graphLense;
     this.compatibility = compatibility;
     this.options = options;
     this.protoLiteExtension = protoLiteExtension;
@@ -1478,7 +1487,7 @@
   private void handleProguardReflectiveBehavior(DexEncodedMethod method) {
     DexType originHolder = method.method.holder;
     Origin origin = appInfo.originFor(originHolder);
-    IRCode code = method.buildIR(appInfo, options, origin);
+    IRCode code = method.buildIR(appInfo, graphLense, options, origin);
     code.instructionIterator().forEachRemaining(instr ->
         handleProguardReflectiveBehavior(instr, originHolder));
   }
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 59bd91b..a329513 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
@@ -14,6 +14,7 @@
 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.Argument;
 import com.android.tools.r8.ir.code.ArrayGet;
 import com.android.tools.r8.ir.code.IRCode;
@@ -58,7 +59,8 @@
     AppInfo appInfo = new AppInfo(dexApplication);
     CodeInspector codeInspector = new CodeInspector(appInfo.app);
     DexEncodedMethod foo = codeInspector.clazz(mainClass.getName()).method(signature).getMethod();
-    IRCode irCode = foo.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
+    IRCode irCode =
+        foo.buildIR(appInfo, GraphLense.getIdentityLense(), TEST_OPTIONS, Origin.unknown());
     NonNullTracker nonNullTracker = new NonNullTracker();
     nonNullTracker.addNonNull(irCode);
     TypeAnalysis analysis = new TypeAnalysis(appInfo, foo, irCode);
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 d3efebe..9c1214c 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
@@ -14,6 +14,7 @@
 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;
@@ -122,7 +123,8 @@
             .method(
                 new MethodSignature("subtractConstants8bitRegisters", "int", ImmutableList.of()))
             .getMethod();
-    IRCode irCode = subtract.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
+    IRCode irCode =
+        subtract.buildIR(appInfo, GraphLense.getIdentityLense(), TEST_OPTIONS, Origin.unknown());
     TypeAnalysis analysis = new TypeAnalysis(appInfo, subtract, irCode);
     analysis.forEach((v, l) -> {
       assertEither(l, PRIMITIVE, NULL, TOP);
@@ -136,7 +138,8 @@
         inspector.clazz("Test")
             .method(new MethodSignature("fibonacci", "int", ImmutableList.of("int")))
             .getMethod();
-    IRCode irCode = fib.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
+    IRCode irCode =
+        fib.buildIR(appInfo, GraphLense.getIdentityLense(), TEST_OPTIONS, Origin.unknown());
     TypeAnalysis analysis = new TypeAnalysis(appInfo, fib, irCode);
     analysis.forEach((v, l) -> {
       assertEither(l, PRIMITIVE, NULL);
@@ -150,7 +153,8 @@
         inspector.clazz("Test")
             .method(new MethodSignature("test1", "int[]", ImmutableList.of()))
             .getMethod();
-    IRCode irCode = test1.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
+    IRCode irCode =
+        test1.buildIR(appInfo, GraphLense.getIdentityLense(), TEST_OPTIONS, Origin.unknown());
     TypeAnalysis analysis = new TypeAnalysis(appInfo, test1, irCode);
     Value array = null;
     InstructionIterator iterator = irCode.instructionIterator();
@@ -181,7 +185,8 @@
         inspector.clazz("Test")
             .method(new MethodSignature("test4", "int[]", ImmutableList.of()))
             .getMethod();
-    IRCode irCode = test4.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
+    IRCode irCode =
+        test4.buildIR(appInfo, GraphLense.getIdentityLense(), TEST_OPTIONS, Origin.unknown());
     TypeAnalysis analysis = new TypeAnalysis(appInfo, test4, irCode);
     Value array = null;
     InstructionIterator iterator = irCode.instructionIterator();
@@ -212,7 +217,8 @@
         inspector.clazz("Test")
             .method(new MethodSignature("loop2", "void", ImmutableList.of()))
             .getMethod();
-    IRCode irCode = loop2.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
+    IRCode irCode =
+        loop2.buildIR(appInfo, GraphLense.getIdentityLense(), TEST_OPTIONS, Origin.unknown());
     TypeAnalysis analysis = new TypeAnalysis(appInfo, loop2, irCode);
     analysis.forEach((v, l) -> {
       if (l.isClassTypeLatticeElement()) {
@@ -231,7 +237,8 @@
         inspector.clazz("Test")
             .method(new MethodSignature("test2_throw", "int", ImmutableList.of()))
             .getMethod();
-    IRCode irCode = test2.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
+    IRCode irCode =
+        test2.buildIR(appInfo, GraphLense.getIdentityLense(), TEST_OPTIONS, Origin.unknown());
     TypeAnalysis analysis = new TypeAnalysis(appInfo, test2, irCode);
     analysis.forEach((v, l) -> {
       if (l.isClassTypeLatticeElement()) {
@@ -257,7 +264,8 @@
         ConstString.class, new ClassTypeLatticeElement(appInfo.dexItemFactory.stringType, false),
         CheckCast.class, new ClassTypeLatticeElement(test, true),
         NewInstance.class, new ClassTypeLatticeElement(test, false));
-    IRCode irCode = method.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
+    IRCode irCode =
+        method.buildIR(appInfo, GraphLense.getIdentityLense(), TEST_OPTIONS, Origin.unknown());
     TypeAnalysis analysis = new TypeAnalysis(appInfo, method, irCode);
     analysis.forEach((v, l) -> verifyTypeEnvironment(expectedLattices, v, l));
   }
@@ -275,7 +283,8 @@
       ConstString.class, new ClassTypeLatticeElement(appInfo.dexItemFactory.stringType, false),
       InstanceOf.class, PRIMITIVE,
       StaticGet.class, new ClassTypeLatticeElement(test, true));
-    IRCode irCode = method.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
+    IRCode irCode =
+        method.buildIR(appInfo, GraphLense.getIdentityLense(), TEST_OPTIONS, Origin.unknown());
     TypeAnalysis analysis = new TypeAnalysis(appInfo, method, irCode);
     analysis.forEach((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 9993b68..b1647cc 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
@@ -13,6 +13,7 @@
 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.graph.GraphLense;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.InstancePut;
 import com.android.tools.r8.ir.code.Instruction;
@@ -48,7 +49,8 @@
     AppInfo appInfo = new AppInfo(dexApplication);
     CodeInspector codeInspector = new CodeInspector(appInfo.app);
     DexEncodedMethod foo = codeInspector.clazz(testClass.getName()).method(signature).getMethod();
-    IRCode irCode = foo.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
+    IRCode irCode =
+        foo.buildIR(appInfo, GraphLense.getIdentityLense(), TEST_OPTIONS, Origin.unknown());
     checkCountOfNonNull(irCode, 0);
 
     NonNullTracker nonNullTracker = new NonNullTracker();
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 fc41672..0df78bc 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -38,6 +38,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DexTypeList;
 import com.android.tools.r8.graph.DirectMappedDexApplication;
+import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ParameterAnnotationsList;
 import com.android.tools.r8.ir.code.CatchHandlers;
@@ -650,7 +651,8 @@
                 DexAnnotationSet.empty(),
                 ParameterAnnotationsList.empty(),
                 code);
-        IRCode ir = code.buildIR(method, null, options, Origin.unknown());
+        IRCode ir =
+            code.buildIR(method, null, GraphLense.getIdentityLense(), options, Origin.unknown());
         RegisterAllocator allocator = new LinearScanRegisterAllocator(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 5cc07a4..ed95627 100644
--- a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
+++ b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
@@ -84,7 +84,9 @@
           new RootSetBuilder(appInfo, program, configuration.getRules(), options).run(executor);
     }
 
-    Enqueuer enqueuer = new Enqueuer(appInfo, options, options.forceProguardCompatibility);
+    Enqueuer enqueuer =
+        new Enqueuer(
+            appInfo, GraphLense.getIdentityLense(), options, options.forceProguardCompatibility);
     appInfo = enqueuer.traceApplication(rootSet, executor, timing);
     return new Minifier(appInfo.withLiveness(), rootSet, options).run(timing);
   }
diff --git a/src/test/java/com/android/tools/r8/regress/b69825683/Regress69825683Test.java b/src/test/java/com/android/tools/r8/regress/b69825683/Regress69825683Test.java
index 3421cfe..911ceb7 100644
--- a/src/test/java/com/android/tools/r8/regress/b69825683/Regress69825683Test.java
+++ b/src/test/java/com/android/tools/r8/regress/b69825683/Regress69825683Test.java
@@ -7,6 +7,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import com.android.tools.r8.ClassFileConsumer;
 import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.TestBase;
@@ -16,10 +17,25 @@
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
 import com.google.common.collect.ImmutableList;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
+@RunWith(Parameterized.class)
 public class Regress69825683Test extends TestBase {
+  private Backend backend;
+
+  @Parameterized.Parameters(name = "Backend: {0}")
+  public static Collection<Backend> data() {
+    return Arrays.asList(Backend.values());
+  }
+
+  public Regress69825683Test(Backend backend) {
+    this.backend = backend;
+  }
 
   @Test
   public void outerConstructsInner() throws Exception {
@@ -32,9 +48,18 @@
         "}",
         "-dontobfuscate"),
         Origin.unknown());
-    builder.setProgramConsumer(DexIndexedConsumer.emptyConsumer());
+    if (backend == Backend.DEX) {
+      builder
+          .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+          .addLibraryFiles(ToolHelper.getDefaultAndroidJar());
+    } else {
+      assert backend == Backend.CF;
+      builder
+          .setProgramConsumer(ClassFileConsumer.emptyConsumer())
+          .addLibraryFiles(ToolHelper.getJava8RuntimeJar());
+    }
     AndroidApp app = ToolHelper.runR8(builder.build(), o -> o.enableClassInlining = false);
-    CodeInspector inspector = new CodeInspector(app);
+    CodeInspector inspector = new CodeInspector(app, o -> o.enableCfFrontend = true);
     List<FoundClassSubject> classes = inspector.allClasses();
 
     // Check that the synthetic class is still present.
@@ -51,7 +76,9 @@
     String innerName = innerClass.getCanonicalName();
     int index = innerName.lastIndexOf('.');
     innerName = innerName.substring(0, index) + "$" + innerName.substring(index + 1);
-    assertTrue(runOnArt(app, mainClass).startsWith(innerName));
+    assertTrue(
+        (backend == Backend.DEX ? runOnArt(app, mainClass) : runOnJava(app, mainClass))
+            .startsWith(innerName));
   }
 
   @Test
@@ -65,9 +92,18 @@
         "}",
         "-dontobfuscate"),
         Origin.unknown());
-    builder.setProgramConsumer(DexIndexedConsumer.emptyConsumer());
+    if (backend == Backend.DEX) {
+      builder
+          .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+          .addLibraryFiles(ToolHelper.getDefaultAndroidJar());
+    } else {
+      assert backend == Backend.CF;
+      builder
+          .setProgramConsumer(ClassFileConsumer.emptyConsumer())
+          .addLibraryFiles(ToolHelper.getJava8RuntimeJar());
+    }
     AndroidApp app = ToolHelper.runR8(builder.build(), o -> o.enableClassInlining = false);
-    CodeInspector inspector = new CodeInspector(app);
+    CodeInspector inspector = new CodeInspector(app, o -> o.enableCfFrontend = true);
     List<FoundClassSubject> classes = inspector.allClasses();
 
     // Check that the synthetic class is still present.
@@ -79,6 +115,8 @@
             .count());
 
     // Run code to check that the constructor with synthetic class as argument is present.
-    assertTrue(runOnArt(app, mainClass).startsWith(mainClass.getCanonicalName()));
+    assertTrue(
+        (backend == Backend.DEX ? runOnArt(app, mainClass) : runOnJava(app, mainClass))
+            .startsWith(mainClass.getCanonicalName()));
   }
 }
diff --git a/src/test/java/com/android/tools/r8/regress/b71604169/Regress71604169Test.java b/src/test/java/com/android/tools/r8/regress/b71604169/Regress71604169Test.java
index f40ecfd..cc356c3 100644
--- a/src/test/java/com/android/tools/r8/regress/b71604169/Regress71604169Test.java
+++ b/src/test/java/com/android/tools/r8/regress/b71604169/Regress71604169Test.java
@@ -6,15 +6,32 @@
 
 import static junit.framework.TestCase.assertEquals;
 
+import com.android.tools.r8.ClassFileConsumer;
 import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.origin.Origin;
 import com.google.common.collect.ImmutableList;
+import java.util.Arrays;
+import java.util.Collection;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
+@RunWith(Parameterized.class)
 public class Regress71604169Test extends TestBase {
+  private Backend backend;
+
+  @Parameterized.Parameters(name = "Backend: {0}")
+  public static Collection<Backend> data() {
+    return Arrays.asList(Backend.values());
+  }
+
+  public Regress71604169Test(Backend backend) {
+    this.backend = backend;
+  }
+
   @Test
   public void test() throws Exception {
     R8Command.Builder builder = R8Command.builder();
@@ -28,7 +45,20 @@
     builder.addProguardConfiguration(
         ImmutableList.of(keepMainProguardConfiguration(mainClass, true, false)), Origin.unknown());
 
-    builder.setProgramConsumer(DexIndexedConsumer.emptyConsumer());
-    assertEquals("Hello, world!", runOnArt(ToolHelper.runR8(builder.build()), mainClass));
+    if (backend == Backend.DEX) {
+      builder
+          .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+          .addLibraryFiles(ToolHelper.getDefaultAndroidJar());
+    } else {
+      assert backend == Backend.CF;
+      builder
+          .setProgramConsumer(ClassFileConsumer.emptyConsumer())
+          .addLibraryFiles(ToolHelper.getJava8RuntimeJar());
+    }
+    assertEquals(
+        "Hello, world!",
+        backend == Backend.DEX
+            ? runOnArt(ToolHelper.runR8(builder.build()), mainClass)
+            : runOnJava(ToolHelper.runR8(builder.build()), mainClass));
   }
 }
diff --git a/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java b/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
index 22cab2a..23c8933 100644
--- a/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
@@ -11,6 +11,7 @@
 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.resolution.singletarget.Main;
 import com.android.tools.r8.resolution.singletarget.one.AbstractSubClass;
 import com.android.tools.r8.resolution.singletarget.one.AbstractTopClass;
@@ -107,8 +108,13 @@
     ExecutorService executor = Executors.newSingleThreadExecutor();
     RootSet rootSet = new RootSetBuilder(appInfoWithSubtyping, application,
         buildKeepRuleForClass(Main.class, application.dexItemFactory), options).run(executor);
-    appInfo = new Enqueuer(appInfoWithSubtyping, options, options.forceProguardCompatibility)
-        .traceApplication(rootSet, executor, timing);
+    appInfo =
+        new Enqueuer(
+                appInfoWithSubtyping,
+                GraphLense.getIdentityLense(),
+                options,
+                options.forceProguardCompatibility)
+            .traceApplication(rootSet, executor, timing);
     // We do not run the tree pruner to ensure that the hierarchy is as designed and not modified
     // due to liveness.
   }
diff --git a/src/test/java/com/android/tools/r8/shaking/defaultmethods/DefaultMethodsTest.java b/src/test/java/com/android/tools/r8/shaking/defaultmethods/DefaultMethodsTest.java
index eab5197..d753632 100644
--- a/src/test/java/com/android/tools/r8/shaking/defaultmethods/DefaultMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/defaultmethods/DefaultMethodsTest.java
@@ -7,6 +7,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import com.android.tools.r8.ClassFileConsumer;
 import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.TestBase;
@@ -19,18 +20,43 @@
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import com.google.common.collect.ImmutableList;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
+@RunWith(Parameterized.class)
 public class DefaultMethodsTest extends TestBase {
+
+  private Backend backend;
+
+  @Parameterized.Parameters(name = "Backend: {0}")
+  public static Collection<Backend> data() {
+    return Arrays.asList(Backend.values());
+  }
+
+  public DefaultMethodsTest(Backend backend) {
+    this.backend = backend;
+  }
+
   private void runTest(List<String> additionalKeepRules, Consumer<CodeInspector> inspection)
       throws Exception {
     R8Command.Builder builder = R8Command.builder();
     builder.addProgramFiles(ToolHelper.getClassFileForTestClass(InterfaceWithDefaultMethods.class));
     builder.addProgramFiles(ToolHelper.getClassFileForTestClass(ClassImplementingInterface.class));
     builder.addProgramFiles(ToolHelper.getClassFileForTestClass(TestClass.class));
-    builder.setProgramConsumer(DexIndexedConsumer.emptyConsumer());
-    builder.setMinApiLevel(AndroidApiLevel.O.getLevel());
+    if (backend == Backend.DEX) {
+      builder.setProgramConsumer(DexIndexedConsumer.emptyConsumer());
+      int apiLevel = AndroidApiLevel.O.getLevel();
+      builder.setMinApiLevel(apiLevel);
+      builder.addLibraryFiles(ToolHelper.getAndroidJar(apiLevel));
+    } else {
+      assert backend == Backend.CF;
+      builder.setProgramConsumer(ClassFileConsumer.emptyConsumer());
+      builder.addLibraryFiles(ToolHelper.getJava8RuntimeJar());
+    }
     // Always keep main in the test class, so the output never becomes empty.
     builder.addProguardConfiguration(ImmutableList.of(
         "-keep class " + TestClass.class.getCanonicalName() + "{",
diff --git a/src/test/java/com/android/tools/r8/shaking/proxy/ProxiesTest.java b/src/test/java/com/android/tools/r8/shaking/proxy/ProxiesTest.java
index 8d38aee..b22dc1e 100644
--- a/src/test/java/com/android/tools/r8/shaking/proxy/ProxiesTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/proxy/ProxiesTest.java
@@ -6,14 +6,11 @@
 
 import static org.junit.Assert.assertEquals;
 
+import com.android.tools.r8.ClassFileConsumer;
 import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.InvokeInterface;
-import com.android.tools.r8.code.InvokeVirtual;
-import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.invokesuper.Consumer;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
 import com.android.tools.r8.origin.Origin;
@@ -24,11 +21,32 @@
 import com.android.tools.r8.shaking.proxy.testclasses.TestClass;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.android.tools.r8.utils.codeinspector.InvokeInstructionSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Streams;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
+import java.util.function.Predicate;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
+@RunWith(Parameterized.class)
 public class ProxiesTest extends TestBase {
+  private Backend backend;
+
+  @Parameterized.Parameters(name = "Backend: {0}")
+  public static Collection<Backend> data() {
+    return Arrays.asList(Backend.values());
+  }
+
+  public ProxiesTest(Backend backend) {
+    this.backend = backend;
+  }
 
   private void runTest(List<String> additionalKeepRules, Consumer<CodeInspector> inspection,
       String expectedResult)
@@ -49,52 +67,89 @@
         Origin.unknown()
     );
     builder.addProguardConfiguration(additionalKeepRules, Origin.unknown());
-    builder.setProgramConsumer(DexIndexedConsumer.emptyConsumer());
+    if (backend == Backend.DEX) {
+      builder
+          .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+          .addLibraryFiles(ToolHelper.getDefaultAndroidJar());
+    } else {
+      assert backend == Backend.CF;
+      builder
+          .setProgramConsumer(ClassFileConsumer.emptyConsumer())
+          .addLibraryFiles(ToolHelper.getJava8RuntimeJar());
+    }
     AndroidApp app = ToolHelper.runR8(builder.build(), o -> o.enableDevirtualization = false);
-    inspection.accept(new CodeInspector(app));
-    assertEquals(expectedResult, runOnArt(app, mainClass));
+    inspection.accept(new CodeInspector(app, o -> o.enableCfFrontend = true));
+    assertEquals(
+        expectedResult,
+        backend == Backend.DEX ? runOnArt(app, mainClass) : runOnJava(app, mainClass));
   }
 
-  private int countInstructionInX(CodeInspector inspector, Class<? extends Instruction> invoke) {
+  private int countInstructionInX(CodeInspector inspector, Predicate<InstructionSubject> invoke) {
     MethodSignature signatureForX =
         new MethodSignature("x", "void", ImmutableList.of(BaseInterface.class.getCanonicalName()));
-    DexCode x = inspector.clazz(Main.class).method(signatureForX).getMethod().getCode().asDexCode();
-    return (int) filterInstructionKind(x, invoke).count();
+    MethodSubject method = inspector.clazz(Main.class).method(signatureForX);
+    assert method instanceof FoundMethodSubject;
+    FoundMethodSubject foundMethod = (FoundMethodSubject) method;
+    return (int) Streams.stream(foundMethod.iterateInstructions(invoke)).count();
   }
 
-  private int countInstructionInY(CodeInspector inspector, Class<? extends Instruction> invoke) {
+  private int countInstructionInY(CodeInspector inspector, Predicate<InstructionSubject> invoke) {
     MethodSignature signatureForY =
         new MethodSignature("y", "void", ImmutableList.of(SubInterface.class.getCanonicalName()));
-    DexCode y = inspector.clazz(Main.class).method(signatureForY).getMethod().getCode().asDexCode();
-    return (int) filterInstructionKind(y, invoke)
-        .filter(instruction -> instruction.getMethod().qualifiedName().endsWith("method"))
-        .count();
+    MethodSubject method = inspector.clazz(Main.class).method(signatureForY);
+    assert method instanceof FoundMethodSubject;
+    FoundMethodSubject foundMethod = (FoundMethodSubject) method;
+    return (int)
+        Streams.stream(foundMethod.iterateInstructions(invoke))
+            .filter(
+                instruction -> {
+                  InvokeInstructionSubject invokeInstruction =
+                      (InvokeInstructionSubject) instruction;
+                  return invokeInstruction.invokedMethod().qualifiedName().endsWith("method");
+                })
+            .count();
   }
 
-  private int countInstructionInZ(CodeInspector inspector, Class<? extends Instruction> invoke) {
+  private int countInstructionInZ(CodeInspector inspector, Predicate<InstructionSubject> invoke) {
     MethodSignature signatureForZ =
         new MethodSignature("z", "void", ImmutableList.of(TestClass.class.getCanonicalName()));
-    DexCode z = inspector.clazz(Main.class).method(signatureForZ).getMethod().getCode().asDexCode();
-    return (int) filterInstructionKind(z, invoke)
-        .filter(instruction -> instruction.getMethod().qualifiedName().endsWith("method"))
-        .count();
+    MethodSubject method = inspector.clazz(Main.class).method(signatureForZ);
+    assert method instanceof FoundMethodSubject;
+    FoundMethodSubject foundMethod = (FoundMethodSubject) method;
+    return (int)
+        Streams.stream(foundMethod.iterateInstructions(invoke))
+            .filter(
+                instruction -> {
+                  InvokeInstructionSubject invokeInstruction =
+                      (InvokeInstructionSubject) instruction;
+                  return invokeInstruction.invokedMethod().qualifiedName().endsWith("method");
+                })
+            .count();
   }
 
   private int countInstructionInZSubClass(
-      CodeInspector inspector, Class<? extends Instruction> invoke) {
+      CodeInspector inspector, Predicate<InstructionSubject> invoke) {
     MethodSignature signatureForZ =
         new MethodSignature("z", "void", ImmutableList.of(SubClass.class.getCanonicalName()));
-    DexCode z = inspector.clazz(Main.class).method(signatureForZ).getMethod().getCode().asDexCode();
-    return (int) filterInstructionKind(z, invoke)
-        .filter(instruction -> instruction.getMethod().qualifiedName().endsWith("method"))
-        .count();
+    MethodSubject method = inspector.clazz(Main.class).method(signatureForZ);
+    assert method instanceof FoundMethodSubject;
+    FoundMethodSubject foundMethod = (FoundMethodSubject) method;
+    return (int)
+        Streams.stream(foundMethod.iterateInstructions(invoke))
+            .filter(
+                instruction -> {
+                  InvokeInstructionSubject invokeInstruction =
+                      (InvokeInstructionSubject) instruction;
+                  return invokeInstruction.invokedMethod().qualifiedName().endsWith("method");
+                })
+            .count();
   }
 
   private void noInterfaceKept(CodeInspector inspector) {
     // Indirectly assert that method is inlined into x, y and z.
-    assertEquals(1, countInstructionInX(inspector, InvokeInterface.class));
-    assertEquals(1, countInstructionInY(inspector, InvokeInterface.class));
-    assertEquals(1, countInstructionInZ(inspector, InvokeVirtual.class));
+    assertEquals(1, countInstructionInX(inspector, InstructionSubject::isInvokeInterface));
+    assertEquals(1, countInstructionInY(inspector, InstructionSubject::isInvokeInterface));
+    assertEquals(1, countInstructionInZ(inspector, InstructionSubject::isInvokeVirtual));
   }
 
   @Test
@@ -106,11 +161,11 @@
 
   private void baseInterfaceKept(CodeInspector inspector) {
     // Indirectly assert that method is not inlined into x.
-    assertEquals(3, countInstructionInX(inspector, InvokeInterface.class));
+    assertEquals(3, countInstructionInX(inspector, InstructionSubject::isInvokeInterface));
     // Indirectly assert that method is inlined into y and z.
-    assertEquals(1, countInstructionInY(inspector, InvokeInterface.class));
-    assertEquals(1, countInstructionInZ(inspector, InvokeVirtual.class));
-    assertEquals(1, countInstructionInZSubClass(inspector, InvokeVirtual.class));
+    assertEquals(1, countInstructionInY(inspector, InstructionSubject::isInvokeInterface));
+    assertEquals(1, countInstructionInZ(inspector, InstructionSubject::isInvokeVirtual));
+    assertEquals(1, countInstructionInZSubClass(inspector, InstructionSubject::isInvokeVirtual));
   }
 
   @Test
@@ -126,11 +181,11 @@
 
   private void subInterfaceKept(CodeInspector inspector) {
     // Indirectly assert that method is not inlined into x or y.
-    assertEquals(3, countInstructionInX(inspector, InvokeInterface.class));
-    assertEquals(3, countInstructionInY(inspector, InvokeInterface.class));
+    assertEquals(3, countInstructionInX(inspector, InstructionSubject::isInvokeInterface));
+    assertEquals(3, countInstructionInY(inspector, InstructionSubject::isInvokeInterface));
     // Indirectly assert that method is inlined into z.
-    assertEquals(1, countInstructionInZ(inspector, InvokeVirtual.class));
-    assertEquals(1, countInstructionInZSubClass(inspector, InvokeVirtual.class));
+    assertEquals(1, countInstructionInZ(inspector, InstructionSubject::isInvokeVirtual));
+    assertEquals(1, countInstructionInZSubClass(inspector, InstructionSubject::isInvokeVirtual));
   }
 
   @Test
@@ -148,10 +203,10 @@
 
   private void classKept(CodeInspector inspector) {
     // Indirectly assert that method is not inlined into x, y or z.
-    assertEquals(3, countInstructionInX(inspector, InvokeInterface.class));
-    assertEquals(3, countInstructionInY(inspector, InvokeInterface.class));
-    assertEquals(3, countInstructionInZ(inspector, InvokeVirtual.class));
-    assertEquals(3, countInstructionInZSubClass(inspector, InvokeVirtual.class));
+    assertEquals(3, countInstructionInX(inspector, InstructionSubject::isInvokeInterface));
+    assertEquals(3, countInstructionInY(inspector, InstructionSubject::isInvokeInterface));
+    assertEquals(3, countInstructionInZ(inspector, InstructionSubject::isInvokeVirtual));
+    assertEquals(3, countInstructionInZSubClass(inspector, InstructionSubject::isInvokeVirtual));
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/shaking/testrules/ForceInlineTest.java b/src/test/java/com/android/tools/r8/shaking/testrules/ForceInlineTest.java
index 147b1b4..d12f41a 100644
--- a/src/test/java/com/android/tools/r8/shaking/testrules/ForceInlineTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/testrules/ForceInlineTest.java
@@ -13,6 +13,9 @@
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.fail;
 
+import com.android.tools.r8.ClassFileConsumer;
+import com.android.tools.r8.DexIndexedConsumer;
+import com.android.tools.r8.ProgramConsumer;
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.ToolHelper;
@@ -20,17 +23,45 @@
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.google.common.collect.ImmutableList;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
+@RunWith(Parameterized.class)
 public class ForceInlineTest extends TestBase {
+  private Backend backend;
+
+  @Parameterized.Parameters(name = "Backend: {0}")
+  public static Collection<Backend> data() {
+    return Arrays.asList(Backend.values());
+  }
+
+  public ForceInlineTest(Backend backend) {
+    this.backend = backend;
+  }
 
   private CodeInspector runTest(List<String> proguardConfiguration) throws Exception {
+    ProgramConsumer programConsumer;
+    Path library;
+    if (backend == Backend.DEX) {
+      programConsumer = DexIndexedConsumer.emptyConsumer();
+      library = ToolHelper.getDefaultAndroidJar();
+    } else {
+      assert backend == Backend.CF;
+      programConsumer = ClassFileConsumer.emptyConsumer();
+      library = ToolHelper.getJava8RuntimeJar();
+    }
     R8Command.Builder builder =
-        ToolHelper.prepareR8CommandBuilder(readClasses(Main.class, A.class, B.class, C.class));
+        ToolHelper.prepareR8CommandBuilder(
+                readClasses(Main.class, A.class, B.class, C.class), programConsumer)
+            .addLibraryFiles(library);
     ToolHelper.allowTestProguardOptions(builder);
     builder.addProguardConfiguration(proguardConfiguration, Origin.unknown());
-    return new CodeInspector(ToolHelper.runR8(builder.build()));
+    return new CodeInspector(ToolHelper.runR8(builder.build(), o -> o.enableCfFrontend = true));
   }
 
   @Test
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 6b90d88..00d385f 100644
--- a/src/test/java/com/android/tools/r8/smali/CatchSuccessorFallthroughTest.java
+++ b/src/test/java/com/android/tools/r8/smali/CatchSuccessorFallthroughTest.java
@@ -7,6 +7,7 @@
 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.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Phi;
@@ -68,7 +69,9 @@
 
     DexEncodedMethod method = getMethod(originalApplication, methodSig);
     // Get the IR pre-optimization.
-    IRCode code = method.buildIR(null, new InternalOptions(), Origin.unknown());
+    IRCode code =
+        method.buildIR(
+            null, GraphLense.getIdentityLense(), new InternalOptions(), Origin.unknown());
 
     // Find the exit block and assert that the value is a phi merging the exceptional edge
     // with the normal edge.