Convert invokevirtual to invoke-direct when target is private method on current class.

R=sgjesse@google.com

Bug: 80124071
Change-Id: If68aecea04998525e109b64a3f6abce01fc6b354
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 61595b9..6e93a90 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -200,14 +200,19 @@
   }
 
   @Override
-  public IRCode buildIR(DexEncodedMethod encodedMethod, InternalOptions options, Origin origin)
+  public IRCode buildIR(
+      DexEncodedMethod encodedMethod,
+      AppInfo appInfo,
+      InternalOptions options,
+      Origin origin)
       throws ApiLevelException {
-    return internalBuild(encodedMethod, options, null, null, origin);
+    return internalBuild(encodedMethod, appInfo, options, null, null, origin);
   }
 
   @Override
   public IRCode buildInliningIR(
       DexEncodedMethod encodedMethod,
+      AppInfo appInfo,
       InternalOptions options,
       ValueNumberGenerator valueNumberGenerator,
       Position callerPosition,
@@ -215,11 +220,13 @@
       throws ApiLevelException {
     assert valueNumberGenerator != null;
     assert callerPosition != null;
-    return internalBuild(encodedMethod, options, valueNumberGenerator, callerPosition, origin);
+    return internalBuild(
+        encodedMethod, appInfo, options, valueNumberGenerator, callerPosition, origin);
   }
 
   private IRCode internalBuild(
       DexEncodedMethod encodedMethod,
+      AppInfo appInfo,
       InternalOptions options,
       ValueNumberGenerator generator,
       Position callerPosition,
@@ -230,8 +237,8 @@
     CfSourceCode source = new CfSourceCode(this, encodedMethod, callerPosition, origin);
     IRBuilder builder =
         (generator == null)
-            ? new IRBuilder(encodedMethod, source, options)
-            : new IRBuilder(encodedMethod, source, options, generator);
+            ? new IRBuilder(encodedMethod, appInfo, source, options)
+            : new IRBuilder(encodedMethod, appInfo, source, options, generator);
     return builder.build();
   }
 
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 5a4faff..6f86412 100644
--- a/src/main/java/com/android/tools/r8/graph/Code.java
+++ b/src/main/java/com/android/tools/r8/graph/Code.java
@@ -18,11 +18,15 @@
 public abstract class Code extends CachedHashValueDexItem {
 
   public abstract IRCode buildIR(
-      DexEncodedMethod encodedMethod, InternalOptions options, Origin origin)
+      DexEncodedMethod encodedMethod,
+      AppInfo appInfo,
+      InternalOptions options,
+      Origin origin)
       throws ApiLevelException;
 
   public IRCode buildInliningIR(
       DexEncodedMethod encodedMethod,
+      AppInfo appInfo,
       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 d9560c8..685f32e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -164,19 +164,20 @@
   }
 
   @Override
-  public IRCode buildIR(DexEncodedMethod encodedMethod, InternalOptions options, Origin origin)
+  public IRCode buildIR(DexEncodedMethod encodedMethod, AppInfo appInfo,
+      InternalOptions options, Origin origin)
       throws ApiLevelException {
     DexSourceCode source =
         new DexSourceCode(
             this, encodedMethod, null, options.lineNumberOptimization == LineNumberOptimization.ON);
-    IRBuilder builder = new IRBuilder(encodedMethod, source, options);
+    IRBuilder builder = new IRBuilder(encodedMethod, appInfo, source, options);
     return builder.build();
   }
 
   @Override
   public IRCode buildInliningIR(
       DexEncodedMethod encodedMethod,
-      InternalOptions options,
+      AppInfo appInfo, InternalOptions options,
       ValueNumberGenerator valueNumberGenerator,
       Position callerPosition,
       Origin origin)
@@ -187,7 +188,8 @@
             encodedMethod,
             callerPosition,
             options.lineNumberOptimization == LineNumberOptimization.ON);
-    IRBuilder builder = new IRBuilder(encodedMethod, source, options, valueNumberGenerator);
+    IRBuilder builder =
+        new IRBuilder(encodedMethod, appInfo, source, options, valueNumberGenerator);
     return builder.build();
   }
 
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 0cabaf1..c4b7713 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -228,23 +228,25 @@
     compilationState = CompilationState.NOT_PROCESSED;
   }
 
-  public IRCode buildIR(InternalOptions options, Origin origin) throws ApiLevelException {
-    return code == null ? null : code.buildIR(this, options, origin);
+  public IRCode buildIR(
+      AppInfo appInfo, InternalOptions options, Origin origin) throws ApiLevelException {
+    return code == null ? null : code.buildIR(this, appInfo, options, origin);
   }
 
   public IRCode buildInliningIRForTesting(
       InternalOptions options, ValueNumberGenerator valueNumberGenerator)
       throws ApiLevelException {
-    return buildInliningIR(options, valueNumberGenerator, null, Origin.unknown());
+    return buildInliningIR(null, options, valueNumberGenerator, null, Origin.unknown());
   }
 
   public IRCode buildInliningIR(
-      InternalOptions options,
+      AppInfo appInfo, InternalOptions options,
       ValueNumberGenerator valueNumberGenerator,
       Position callerPosition,
       Origin origin)
       throws ApiLevelException {
-    return code.buildInliningIR(this, options, valueNumberGenerator, callerPosition, origin);
+    return code.buildInliningIR(
+        this, appInfo, 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 6c414ac..a992371 100644
--- a/src/main/java/com/android/tools/r8/graph/JarCode.java
+++ b/src/main/java/com/android/tools/r8/graph/JarCode.java
@@ -104,18 +104,19 @@
   }
 
   @Override
-  public IRCode buildIR(DexEncodedMethod encodedMethod, InternalOptions options, Origin origin)
+  public IRCode buildIR(DexEncodedMethod encodedMethod, AppInfo appInfo,
+      InternalOptions options, Origin origin)
       throws ApiLevelException {
     triggerDelayedParsingIfNeccessary();
     return options.debug
-        ? internalBuildWithLocals(encodedMethod, options, null, null)
-        : internalBuild(encodedMethod, options, null, null);
+        ? internalBuildWithLocals(encodedMethod, appInfo, options, null, null)
+        : internalBuild(encodedMethod, appInfo, options, null, null);
   }
 
   @Override
   public IRCode buildInliningIR(
       DexEncodedMethod encodedMethod,
-      InternalOptions options,
+      AppInfo appInfo, InternalOptions options,
       ValueNumberGenerator generator,
       Position callerPosition,
       Origin origin)
@@ -123,28 +124,28 @@
     assert generator != null;
     triggerDelayedParsingIfNeccessary();
     return options.debug
-        ? internalBuildWithLocals(encodedMethod, options, generator, callerPosition)
-        : internalBuild(encodedMethod, options, generator, callerPosition);
+        ? internalBuildWithLocals(encodedMethod, appInfo, options, generator, callerPosition)
+        : internalBuild(encodedMethod, appInfo, options, generator, callerPosition);
   }
 
   private IRCode internalBuildWithLocals(
       DexEncodedMethod encodedMethod,
-      InternalOptions options,
+      AppInfo appInfo, InternalOptions options,
       ValueNumberGenerator generator,
       Position callerPosition)
       throws ApiLevelException {
     try {
-      return internalBuild(encodedMethod, options, generator, callerPosition);
+      return internalBuild(encodedMethod, appInfo, options, generator, callerPosition);
     } catch (InvalidDebugInfoException e) {
       options.warningInvalidDebugInfo(encodedMethod, origin, e);
       node.localVariables.clear();
-      return internalBuild(encodedMethod, options, generator, callerPosition);
+      return internalBuild(encodedMethod, appInfo, options, generator, callerPosition);
     }
   }
 
   private IRCode internalBuild(
       DexEncodedMethod encodedMethod,
-      InternalOptions options,
+      AppInfo appInfo, InternalOptions options,
       ValueNumberGenerator generator,
       Position callerPosition)
       throws ApiLevelException {
@@ -155,8 +156,8 @@
         method.getHolder(), node, application, encodedMethod.method, callerPosition);
     IRBuilder builder =
         (generator == null)
-            ? new IRBuilder(encodedMethod, source, options)
-            : new IRBuilder(encodedMethod, source, options, generator);
+            ? new IRBuilder(encodedMethod, appInfo, source, options)
+            : new IRBuilder(encodedMethod, appInfo, source, options, generator);
     return builder.build();
   }
 
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 e816bd5..57932cc 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
@@ -151,21 +151,23 @@
   }
 
   @Override
-  public IRCode buildIR(DexEncodedMethod encodedMethod, InternalOptions options, Origin origin)
+  public IRCode buildIR(DexEncodedMethod encodedMethod, AppInfo appInfo,
+      InternalOptions options, Origin origin)
       throws ApiLevelException {
-    return asCfCode().buildIR(encodedMethod, options, origin);
+    return asCfCode().buildIR(encodedMethod, appInfo, options, origin);
   }
 
   @Override
   public IRCode buildInliningIR(
       DexEncodedMethod encodedMethod,
+      AppInfo appInfo,
       InternalOptions options,
       ValueNumberGenerator valueNumberGenerator,
       Position callerPosition,
       Origin origin)
       throws ApiLevelException {
     return asCfCode().buildInliningIR(
-        encodedMethod, options, valueNumberGenerator, callerPosition, origin);
+        encodedMethod, appInfo, options, valueNumberGenerator, callerPosition, origin);
   }
 
   @Override
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 1a210b2..d2ba632 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
@@ -8,6 +8,7 @@
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.errors.InternalCompilerError;
 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.DexCallSite;
 import com.android.tools.r8.graph.DexEncodedMethod;
@@ -295,18 +296,15 @@
   private final LinkedList<BasicBlock> blocks = new LinkedList<>();
 
   private BasicBlock currentBlock = null;
-
   private final List<BasicBlock.Pair> needGotoToCatchBlocks = new ArrayList<>();
-
   final private ValueNumberGenerator valueNumberGenerator;
-
   private final DexEncodedMethod method;
+  private final AppInfo appInfo;
 
   // Source code to build IR from. Null if already built.
   private SourceCode source;
 
-  boolean throwingInstructionInCurrentBlock = false;
-
+  private boolean throwingInstructionInCurrentBlock = false;
   private final InternalOptions options;
 
   // Pending local reads.
@@ -315,16 +313,17 @@
 
   private int nextBlockNumber = 0;
 
-  public IRBuilder(DexEncodedMethod method, SourceCode source, InternalOptions options) {
-    this(method, source, options, new ValueNumberGenerator());
+  public IRBuilder(DexEncodedMethod method, AppInfo appInfo,
+      SourceCode source, InternalOptions options) {
+    this(method, appInfo, source, options, new ValueNumberGenerator());
   }
 
   public IRBuilder(
-      DexEncodedMethod method,
-      SourceCode source,
+      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.options = options;
@@ -1043,7 +1042,7 @@
   public void addInvoke(
       Type type, DexItem item, DexProto callSiteProto, List<Value> arguments, boolean itf)
       throws ApiLevelException {
-    if (type == Invoke.Type.POLYMORPHIC) {
+    if (type == Type.POLYMORPHIC) {
       assert item instanceof DexMethod;
       if (!options.canUseInvokePolymorphic()) {
         throw new ApiLevelException(
@@ -1058,6 +1057,16 @@
             null /* sourceString */);
       }
     }
+    if (appInfo != null && 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 method = (DexMethod) item;
+      if (appInfo.lookupDirectTarget(method) != null) {
+        type = Type.DIRECT;
+      }
+    }
     add(Invoke.create(type, item, callSiteProto, null, arguments, itf));
   }
 
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 20cbd10..6a3ef1f 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
@@ -578,7 +578,7 @@
       feedback.markProcessed(method, Constraint.NEVER);
       return;
     }
-    IRCode code = method.buildIR(options, appInfo.originFor(method.method.holder));
+    IRCode code = method.buildIR(appInfo, options, appInfo.originFor(method.method.holder));
     if (code == null) {
       feedback.markProcessed(method, Constraint.NEVER);
       return;
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 c2af6ea..59ddc36 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
@@ -56,7 +56,7 @@
       return;
     }
     DexEncodedMethod initializer = clazz.getClassInitializer();
-    IRCode code = initializer.getCode().buildIR(initializer, options, clazz.origin);
+    IRCode code = initializer.getCode().buildIR(initializer, appInfo, 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 d6efdbb..bb4d6ed 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
@@ -270,7 +270,7 @@
         throws ApiLevelException {
       // 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(options, generator, callerPosition, origin);
+      IRCode code = target.buildInliningIR(appInfo, options, generator, callerPosition, origin);
       if (!target.isProcessed()) {
         new LensCodeRewriter(graphLense, appInfo).rewrite(code, target);
       }
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 7af555c..9462354 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
@@ -7,6 +7,7 @@
 import com.android.tools.r8.ApiLevelException;
 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.ClassAccessFlags;
 import com.android.tools.r8.graph.Code;
 import com.android.tools.r8.graph.DebugLocalInfo;
@@ -1003,10 +1004,11 @@
     }
 
     @Override
-    public IRCode buildIR(DexEncodedMethod encodedMethod, InternalOptions options, Origin origin)
+    public IRCode buildIR(DexEncodedMethod encodedMethod,
+        AppInfo appInfo, InternalOptions options, Origin origin)
         throws ApiLevelException {
       OutlineSourceCode source = new OutlineSourceCode(outline);
-      IRBuilder builder = new IRBuilder(encodedMethod, source, options);
+      IRBuilder builder = new IRBuilder(encodedMethod, appInfo, source, options);
       return builder.build();
     }
 
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 bd85615..1284671 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
@@ -93,7 +93,7 @@
     List<DexEncodedField> switchMapFields = Arrays.stream(clazz.staticFields())
         .filter(this::maybeIsSwitchMap).collect(Collectors.toList());
     if (!switchMapFields.isEmpty()) {
-      IRCode initializer = clazz.getClassInitializer().buildIR(options, clazz.origin);
+      IRCode initializer = clazz.getClassInitializer().buildIR(appInfo, 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 b2100e2..f8134f4 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
@@ -6,6 +6,7 @@
 
 import com.android.tools.r8.ApiLevelException;
 import com.android.tools.r8.errors.Unreachable;
+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.UseRegistry;
@@ -39,9 +40,10 @@
 
   @Override
   public final IRCode buildIR(
-      DexEncodedMethod encodedMethod, InternalOptions options, Origin origin)
+      DexEncodedMethod encodedMethod, AppInfo appInfo,
+      InternalOptions options, Origin origin)
       throws ApiLevelException {
-    return new IRBuilder(encodedMethod, sourceCode, options).build();
+    return new IRBuilder(encodedMethod, appInfo, sourceCode, options).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 c359fc7..a87de4b 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -1344,7 +1344,7 @@
 
   private void handleProguardReflectiveBehavior(DexEncodedMethod method) {
     try {
-      IRCode code = method.buildIR(options, appInfo.originFor(method.method.holder));
+      IRCode code = method.buildIR(appInfo, options, appInfo.originFor(method.method.holder));
       code.instructionIterator().forEachRemaining(this::handleProguardReflectiveBehavior);
     } catch (ApiLevelException e) {
       // Ignore this exception here. It will be hit again further in the pipeline when
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 443a20e..16785f6 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
@@ -58,7 +58,7 @@
     AppInfo appInfo = new AppInfo(dexApplication);
     DexInspector dexInspector = new DexInspector(appInfo.app);
     DexEncodedMethod foo = dexInspector.clazz(mainClass.getName()).method(signature).getMethod();
-    IRCode irCode = foo.buildIR(TEST_OPTIONS, Origin.unknown());
+    IRCode irCode = foo.buildIR(appInfo, 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 509b922..967b33e 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
@@ -125,7 +125,7 @@
                 new MethodSignature("subtractConstants8bitRegisters", "int", ImmutableList.of()))
             .getMethod();
     try {
-      IRCode irCode = subtract.buildIR(TEST_OPTIONS, Origin.unknown());
+      IRCode irCode = subtract.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
       TypeAnalysis analysis = new TypeAnalysis(appInfo, subtract, irCode);
       analysis.forEach((v, l) -> {
         assertEither(l, PRIMITIVE, NULL, TOP);
@@ -143,7 +143,7 @@
             .method(new MethodSignature("fibonacci", "int", ImmutableList.of("int")))
             .getMethod();
     try {
-      IRCode irCode = fib.buildIR(TEST_OPTIONS, Origin.unknown());
+      IRCode irCode = fib.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
       TypeAnalysis analysis = new TypeAnalysis(appInfo, fib, irCode);
       analysis.forEach((v, l) -> {
         assertEither(l, PRIMITIVE, NULL);
@@ -161,7 +161,7 @@
             .method(new MethodSignature("test1", "int[]", ImmutableList.of()))
             .getMethod();
     try {
-      IRCode irCode = test1.buildIR(TEST_OPTIONS, Origin.unknown());
+      IRCode irCode = test1.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
       TypeAnalysis analysis = new TypeAnalysis(appInfo, test1, irCode);
       Value array = null;
       InstructionIterator iterator = irCode.instructionIterator();
@@ -196,7 +196,7 @@
             .method(new MethodSignature("test4", "int[]", ImmutableList.of()))
             .getMethod();
     try {
-      IRCode irCode = test4.buildIR(TEST_OPTIONS, Origin.unknown());
+      IRCode irCode = test4.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
       TypeAnalysis analysis = new TypeAnalysis(appInfo, test4, irCode);
       Value array = null;
       InstructionIterator iterator = irCode.instructionIterator();
@@ -231,7 +231,7 @@
             .method(new MethodSignature("loop2", "void", ImmutableList.of()))
             .getMethod();
     try {
-      IRCode irCode = loop2.buildIR(TEST_OPTIONS, Origin.unknown());
+      IRCode irCode = loop2.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
       TypeAnalysis analysis = new TypeAnalysis(appInfo, loop2, irCode);
       analysis.forEach((v, l) -> {
         if (l.isClassTypeLatticeElement()) {
@@ -254,7 +254,7 @@
             .method(new MethodSignature("test2_throw", "int", ImmutableList.of()))
             .getMethod();
     try {
-      IRCode irCode = test2.buildIR(TEST_OPTIONS, Origin.unknown());
+      IRCode irCode = test2.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
       TypeAnalysis analysis = new TypeAnalysis(appInfo, test2, irCode);
       analysis.forEach((v, l) -> {
         if (l.isClassTypeLatticeElement()) {
@@ -284,7 +284,7 @@
         CheckCast.class, new ClassTypeLatticeElement(test, true),
         NewInstance.class, new ClassTypeLatticeElement(test, false));
     try {
-      IRCode irCode = method.buildIR(TEST_OPTIONS, Origin.unknown());
+      IRCode irCode = method.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
       TypeAnalysis analysis = new TypeAnalysis(appInfo, method, irCode);
       analysis.forEach((v, l) -> verifyTypeEnvironment(expectedLattices, v, l));
     } catch (ApiLevelException e) {
@@ -306,7 +306,7 @@
       InstanceOf.class, PRIMITIVE,
       StaticGet.class, new ClassTypeLatticeElement(test, true));
     try {
-      IRCode irCode = method.buildIR(TEST_OPTIONS, Origin.unknown());
+      IRCode irCode = method.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
       TypeAnalysis analysis = new TypeAnalysis(appInfo, method, irCode);
       analysis.forEach((v, l) -> verifyTypeEnvironment(expectedLattices, v, l));
     } catch (ApiLevelException e) {
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 fac2ca0..7c90976 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
@@ -48,7 +48,7 @@
     AppInfo appInfo = new AppInfo(dexApplication);
     DexInspector dexInspector = new DexInspector(appInfo.app);
     DexEncodedMethod foo = dexInspector.clazz(testClass.getName()).method(signature).getMethod();
-    IRCode irCode = foo.buildIR(TEST_OPTIONS, Origin.unknown());
+    IRCode irCode = foo.buildIR(appInfo, TEST_OPTIONS, Origin.unknown());
     checkCountOfNonNull(irCode, 0);
 
     NonNullTracker nonNullTracker = new NonNullTracker();
diff --git a/src/test/java/com/android/tools/r8/jasmin/Regress80124071.java b/src/test/java/com/android/tools/r8/jasmin/Regress80124071.java
new file mode 100644
index 0000000..0eda515
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/jasmin/Regress80124071.java
@@ -0,0 +1,71 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.jasmin;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.jasmin.JasminBuilder.ClassFileVersion;
+import com.google.common.collect.ImmutableList;
+import org.junit.Test;
+
+public class Regress80124071 extends JasminTestBase {
+
+  private JasminBuilder buildClass() {
+    JasminBuilder builder = new JasminBuilder(ClassFileVersion.JDK_1_4);
+    JasminBuilder.ClassBuilder clazz = builder.addClass("Test");
+
+    clazz.addPrivateVirtualMethod("privateMethod", ImmutableList.of(), "V",
+        ".limit stack 2",
+        ".limit locals 1",
+        "getstatic java/lang/System/out Ljava/io/PrintStream;",
+        "ldc \"privateMethod\"",
+        "invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V",
+        "return");
+
+    clazz.addDefaultConstructor();
+
+    clazz.addMainMethod(
+        ".limit stack 3",
+        ".limit locals 1",
+        "new Test",
+        "dup",
+        "invokespecial Test/<init>()V",
+        // Should have been invokespecial but JVM is OK with it so we need to transform
+        // to invoke-direct to be able to run on Art.
+        "invokevirtual Test/privateMethod()V",
+        "new TestSub",
+        "dup",
+        "dup",
+        "invokespecial TestSub/<init>()V",
+        // Should have been invokespecial but JVM is OK with it and invokes the private method
+        // on the Test class. Therefore, there is no virtual dispatch and we need to transform
+        // to invoke-direct to be able to run on Art.
+        "invokevirtual Test/privateMethod()V",
+        "invokevirtual TestSub/privateMethod()V",
+        "return");
+
+    JasminBuilder.ClassBuilder subclazz = builder.addClass("TestSub", "Test");
+
+    subclazz.addVirtualMethod("privateMethod", ImmutableList.of(), "V",
+        ".limit stack 2",
+        ".limit locals 1",
+        "getstatic java/lang/System/out Ljava/io/PrintStream;",
+        "ldc \"privateMethod2\"",
+        "invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V",
+        "return");
+
+    return builder;
+  }
+
+  @Test
+  public void test() throws Exception {
+    JasminBuilder builder = buildClass();
+    String jvm = runOnArtDx(builder, "Test");
+    String dx = runOnJava(builder, "Test");
+    assertEquals(jvm, dx);
+    String d8 = runOnArtD8(builder, "Test");
+    assertEquals(jvm, d8);
+  }
+}
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 9de9f5a..590baa6 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -25,6 +25,7 @@
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.errors.DexOverflowException;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.ClassAccessFlags;
 import com.android.tools.r8.graph.Code;
 import com.android.tools.r8.graph.DebugLocalInfo;
@@ -619,7 +620,7 @@
                 DexAnnotationSet.empty(),
                 ParameterAnnotationsList.empty(),
                 code);
-        IRCode ir = code.buildIR(method, options, Origin.unknown());
+        IRCode ir = code.buildIR(method, null, 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/smali/CatchSuccessorFallthroughTest.java b/src/test/java/com/android/tools/r8/smali/CatchSuccessorFallthroughTest.java
index 31abcf1..6b90d88 100644
--- a/src/test/java/com/android/tools/r8/smali/CatchSuccessorFallthroughTest.java
+++ b/src/test/java/com/android/tools/r8/smali/CatchSuccessorFallthroughTest.java
@@ -68,7 +68,7 @@
 
     DexEncodedMethod method = getMethod(originalApplication, methodSig);
     // Get the IR pre-optimization.
-    IRCode code = method.buildIR(new InternalOptions(), Origin.unknown());
+    IRCode code = method.buildIR(null, new InternalOptions(), Origin.unknown());
 
     // Find the exit block and assert that the value is a phi merging the exceptional edge
     // with the normal edge.