Merge "Always pass the is-interface bit when building invoke instructions."
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
index 3eda1b7..a84b916 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
@@ -45,6 +45,10 @@
     return opcode;
   }
 
+  public boolean isInterface() {
+    return itf;
+  }
+
   @Override
   public void write(MethodVisitor visitor, NamingLens lens) {
     String owner = lens.lookupInternalName(method.getHolder());
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 d45fd83..f956b53 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -638,14 +638,15 @@
     return builder.build();
   }
 
-  public DexEncodedMethod toForwardingMethod(DexClass holder, DexItemFactory itemFactory) {
+  public DexEncodedMethod toForwardingMethod(DexClass holder, AppInfo appInfo) {
     checkIfObsolete();
     // Clear the final flag, as this method is now overwritten. Do this before creating the builder
     // for the forwarding method, as the forwarding method will copy the access flags from this,
     // and if different forwarding methods are created in different subclasses the first could be
     // final.
     accessFlags.demoteFromFinal();
-    DexMethod newMethod = itemFactory.createMethod(holder.type, method.proto, method.name);
+    DexMethod newMethod =
+        appInfo.dexItemFactory.createMethod(holder.type, method.proto, method.name);
     Invoke.Type type = accessFlags.isStatic() ? Invoke.Type.STATIC : Invoke.Type.SUPER;
     Builder builder = builder(this);
     builder.setMethod(newMethod);
@@ -655,6 +656,7 @@
       builder.accessFlags.setAbstract();
     } else {
       // Create code that forwards the call to the target.
+      DexClass target = appInfo.definitionFor(method.holder);
       builder.setCode(
           new SynthesizedCode(
               callerPosition ->
@@ -665,7 +667,8 @@
                       accessFlags.isStatic() ? null : method.holder,
                       method,
                       type,
-                      callerPosition),
+                      callerPosition,
+                      target.isInterface()),
               registry -> {
                 if (accessFlags.isStatic()) {
                   registry.registerInvokeStatic(method);
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 8a46e1e..743f2a5 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
@@ -13,6 +13,7 @@
 import com.android.tools.r8.cf.code.CfFrame;
 import com.android.tools.r8.cf.code.CfFrame.FrameType;
 import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.cf.code.CfInvoke;
 import com.android.tools.r8.cf.code.CfLabel;
 import com.android.tools.r8.cf.code.CfPosition;
 import com.android.tools.r8.cf.code.CfTryCatch;
@@ -21,6 +22,7 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.CfCode.LocalVariableInfo;
 import com.android.tools.r8.graph.DebugLocalInfo;
+import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexField;
@@ -179,9 +181,23 @@
     CodeRewriter.collapseTrivialGotos(method, code);
     DexBuilder.removeRedundantDebugPositions(code);
     CfCode code = buildCfCode();
+    assert verifyInvokeInterface(code, appInfo);
     return code;
   }
 
+  private static boolean verifyInvokeInterface(CfCode code, AppInfo appInfo) {
+    for (CfInstruction instruction : code.instructions) {
+      if (instruction instanceof CfInvoke) {
+        CfInvoke invoke = (CfInvoke) instruction;
+        if (invoke.getMethod().holder.isClassType()) {
+          DexClass holder = appInfo.definitionFor(invoke.getMethod().holder);
+          assert holder == null || holder.isInterface() == invoke.isInterface();
+        }
+      }
+    }
+    return true;
+  }
+
   public DexField resolveField(DexField field) {
     DexEncodedField resolvedField = appInfo.resolveFieldOn(field.clazz, field);
     return resolvedField == null ? field : resolvedField.field;
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 31b0ec6..3f355c1 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
@@ -1405,19 +1405,6 @@
     add(Invoke.create(type, item, callSiteProto, null, arguments, itf));
   }
 
-  public void addInvoke(Type type, DexItem item, DexProto callSiteProto, List<Value> arguments) {
-    addInvoke(type, item, callSiteProto, arguments, false);
-  }
-
-  public void addInvoke(
-      Type type,
-      DexItem item,
-      DexProto callSiteProto,
-      List<ValueType> types,
-      List<Integer> registers) {
-    addInvoke(type, item, callSiteProto, types, registers, false);
-  }
-
   public void addInvoke(
       Type type,
       DexItem item,
@@ -1518,7 +1505,9 @@
       registerIndex += constraint.requiredRegisters();
     }
     checkInvokeArgumentRegisters(registerIndex, argumentRegisterCount);
-    addInvoke(type, method, callSiteProto, arguments);
+    // Note: We only call this register variant from DEX inputs where isInterface does not matter.
+    assert !isGeneratingClassFiles();
+    addInvoke(type, method, callSiteProto, arguments, false /* isInterface */);
   }
 
   public void addInvokeNewArray(DexType type, int argumentCount, int[] argumentRegisters) {
@@ -1538,7 +1527,7 @@
       registerIndex += constraint.requiredRegisters();
     }
     checkInvokeArgumentRegisters(registerIndex, argumentCount);
-    addInvoke(Invoke.Type.NEW_ARRAY, type, null, arguments);
+    addInvoke(Invoke.Type.NEW_ARRAY, type, null, arguments, false /* isInterface */);
   }
 
   public void addMultiNewArray(DexType type, int dest, int[] dimensions) {
@@ -1547,7 +1536,7 @@
     for (int dimension : dimensions) {
       arguments.add(readRegister(dimension, ValueTypeConstraint.INT));
     }
-    addInvoke(Invoke.Type.MULTI_NEW_ARRAY, type, null, arguments);
+    addInvoke(Invoke.Type.MULTI_NEW_ARRAY, type, null, arguments, false /* isInterface */);
     addMoveResult(dest);
   }
 
@@ -1581,7 +1570,9 @@
       register += valueTypeConstraint.requiredRegisters();
     }
     checkInvokeArgumentRegisters(register, firstArgumentRegister + argumentCount);
-    addInvoke(type, method, callSiteProto, arguments);
+    // Note: We only call this register variant from DEX inputs where isInterface does not matter.
+    assert !isGeneratingClassFiles();
+    addInvoke(type, method, callSiteProto, arguments, false /* isInterface */);
   }
 
   public void addInvokeRangeNewArray(DexType type, int argumentCount, int firstArgumentRegister) {
@@ -1597,7 +1588,9 @@
       register += constraint.requiredRegisters();
     }
     checkInvokeArgumentRegisters(register, firstArgumentRegister + argumentCount);
-    addInvoke(Invoke.Type.NEW_ARRAY, type, null, arguments);
+    // Note: We only call this register variant from DEX inputs where isInterface does not matter.
+    assert !isGeneratingClassFiles();
+    addInvoke(Invoke.Type.NEW_ARRAY, type, null, arguments, false /* isInterface */);
   }
 
   private void checkInvokeArgumentRegisters(int expected, int actual) {
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 1387f75..93e5355 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
@@ -2864,7 +2864,13 @@
     List<ValueType> argumentTypes = Arrays.asList(valueType(CLASS_TYPE), valueType(INT_ARRAY_TYPE));
     List<Integer> argumentRegisters = Arrays.asList(classDestTemp, dimensionsDestTemp);
     builder.ensureBlockForThrowingInstruction();
-    builder.addInvoke(Invoke.Type.STATIC, newInstance, null, argumentTypes, argumentRegisters);
+    builder.addInvoke(
+        Invoke.Type.STATIC,
+        newInstance,
+        null,
+        argumentTypes,
+        argumentRegisters,
+        false /* isInterface */);
     // Pop the temporaries and push the final result.
     state.pop(); // classDestTemp.
     state.pop(); // dimensionsDestTemp.
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/AccessorMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/AccessorMethodSourceCode.java
index 3554806..81f93a7 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/AccessorMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/AccessorMethodSourceCode.java
@@ -109,8 +109,17 @@
     }
 
     // Method call to the original impl-method.
-    add(builder -> builder.addInvoke(inferInvokeType(),
-        implMethod, implMethod.proto, argValueTypes, argRegisters));
+    // Mirroring assert in constructor, we never need accessors to interfaces.
+    assert !descriptor().implHandle.type.isInvokeInterface();
+    add(
+        builder ->
+            builder.addInvoke(
+                inferInvokeType(),
+                implMethod,
+                implMethod.proto,
+                argValueTypes,
+                argRegisters,
+                false /* isInterface */));
 
     // Does the method have return value?
     if (proto.returnType == factory().voidType) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
index d2a233b..bff3ca1 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
@@ -100,10 +100,10 @@
 
   private DexEncodedMethod addForwardingMethod(DexEncodedMethod defaultMethod, DexClass clazz) {
     DexMethod method = defaultMethod.method;
+    DexClass target = rewriter.findDefinitionFor(method.holder);
     // NOTE: Never add a forwarding method to methods of classes unknown or coming from android.jar
     // even if this results in invalid code, these classes are never desugared.
-    assert rewriter.findDefinitionFor(method.holder) != null
-        && !rewriter.findDefinitionFor(method.holder).isLibraryClass();
+    assert target != null && !target.isLibraryClass();
     // New method will have the same name, proto, and also all the flags of the
     // default method, including bridge flag.
     DexMethod newMethod = rewriter.factory.createMethod(clazz.type, method.proto, method.name);
@@ -124,7 +124,8 @@
                     null /* static method */,
                     rewriter.defaultAsMethodOfCompanionClass(method),
                     Invoke.Type.STATIC,
-                    callerPosition)));
+                    callerPosition,
+                    target.isInterface())));
   }
 
   // For a given class `clazz` inspects all interfaces it implements directly or
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java b/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java
index 955abf0..466dc83 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CovariantReturnTypeAnnotationTransformer.java
@@ -175,7 +175,8 @@
                         method.method,
                         Invoke.Type.VIRTUAL,
                         callerPosition,
-                        true)));
+                        false /* isInterface */,
+                        true /* castResult */)));
     // Optimize to generate DexCode instead of SynthesizedCode.
     converter.optimizeSynthesizedMethod(newVirtualMethod);
     return newVirtualMethod;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
index 01b647b..fd875af 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
@@ -252,7 +252,8 @@
                           null,
                           origMethod,
                           Type.STATIC,
-                          callerPosition)));
+                          callerPosition,
+                          true /* isInterface */)));
       newEncodedMethod.getMutableOptimizationInfo().markNeverInline();
       dispatchMethods.add(newEncodedMethod);
     }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaBridgeMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaBridgeMethodSourceCode.java
index 7e5cd81..9507471 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaBridgeMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaBridgeMethodSourceCode.java
@@ -46,8 +46,15 @@
     }
 
     // Method call to the main functional interface method.
-    add(builder -> builder.addInvoke(Invoke.Type.VIRTUAL,
-        this.mainMethod, this.mainMethod.proto, argValueTypes, argRegisters));
+    add(
+        builder ->
+            builder.addInvoke(
+                Invoke.Type.VIRTUAL,
+                this.mainMethod,
+                this.mainMethod.proto,
+                argValueTypes,
+                argRegisters,
+                false /* isInterface */));
 
     // Does the method have return value?
     if (proto.returnType == factory().voidType) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassConstructorSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassConstructorSourceCode.java
index 2aa4630..cec70bb 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassConstructorSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClassConstructorSourceCode.java
@@ -24,12 +24,15 @@
     // Create and initialize an instance.
     int instance = nextRegister(ValueType.OBJECT);
     add(builder -> builder.addNewInstance(instance, lambda.type));
-    add(builder -> builder.addInvoke(
-        Invoke.Type.DIRECT,
-        lambda.constructor,
-        lambda.constructor.proto,
-        ImmutableList.of(ValueType.OBJECT),
-        ImmutableList.of(instance)));
+    add(
+        builder ->
+            builder.addInvoke(
+                Invoke.Type.DIRECT,
+                lambda.constructor,
+                lambda.constructor.proto,
+                ImmutableList.of(ValueType.OBJECT),
+                ImmutableList.of(instance),
+                false /* isInterface */));
 
     // Assign to a field.
     add(builder -> builder.addStaticPut(instance, lambda.instanceField));
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaConstructorSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaConstructorSourceCode.java
index 7f2acc3..b2b9486 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaConstructorSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaConstructorSourceCode.java
@@ -23,8 +23,14 @@
   protected void prepareInstructions() {
     // Super constructor call (always java.lang.Object.<init>()).
     DexMethod objectInitMethod = lambda.rewriter.objectInitMethod;
-    add(builder -> builder.addInvoke(Invoke.Type.DIRECT, objectInitMethod,
-        objectInitMethod.proto, Collections.singletonList(getReceiverValue())));
+    add(
+        builder ->
+            builder.addInvoke(
+                Invoke.Type.DIRECT,
+                objectInitMethod,
+                objectInitMethod.proto,
+                Collections.singletonList(getReceiverValue()),
+                false /* isInterface */));
 
     // Assign capture fields.
     DexType[] capturedTypes = captures();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
index fb06f31..99112d7 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
@@ -224,8 +224,15 @@
     }
 
     // Method call to the method implementing lambda or method-ref.
-    add(builder -> builder.addInvoke(target.invokeType,
-        methodToCall, methodToCall.proto, argValueTypes, argRegisters));
+    add(
+        builder ->
+            builder.addInvoke(
+                target.invokeType,
+                methodToCall,
+                methodToCall.proto,
+                argValueTypes,
+                argRegisters,
+                false /* isInterface */));
 
     // Does the method have return value?
     if (enforcedReturnType.isVoidType()) {
@@ -446,8 +453,15 @@
 
     List<ValueType> argValueTypes = ImmutableList.of(ValueType.OBJECT);
     List<Integer> argRegisters = Collections.singletonList(register);
-    add(builder -> builder.addInvoke(Invoke.Type.VIRTUAL,
-        method, method.proto, argValueTypes, argRegisters));
+    add(
+        builder ->
+            builder.addInvoke(
+                Invoke.Type.VIRTUAL,
+                method,
+                method.proto,
+                argValueTypes,
+                argRegisters,
+                false /* isInterface */));
 
     ValueType valueType = ValueType.fromDexType(primitiveType);
     int result = nextRegister(valueType);
@@ -469,8 +483,15 @@
     ValueType valueType = ValueType.fromDexType(primitiveType);
     List<ValueType> argValueTypes = ImmutableList.of(valueType);
     List<Integer> argRegisters = Collections.singletonList(register);
-    add(builder -> builder.addInvoke(Invoke.Type.STATIC,
-        method, method.proto, argValueTypes, argRegisters));
+    add(
+        builder ->
+            builder.addInvoke(
+                Invoke.Type.STATIC,
+                method,
+                method.proto,
+                argValueTypes,
+                argRegisters,
+                false /* isInterface */));
 
     int result = nextRegister(ValueType.OBJECT);
     add(builder -> builder.addMoveResult(result));
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/ClassInitializerSourceCode.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/ClassInitializerSourceCode.java
index 5177e4a..c6aecbb 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/ClassInitializerSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/ClassInitializerSourceCode.java
@@ -41,18 +41,27 @@
     List<ValueType> argTypes = Lists.newArrayList(ValueType.OBJECT, ValueType.INT);
     List<Integer> argRegisters = Lists.newArrayList(instance, lambdaId);
 
-    group.forEachLambda(info -> {
-      DexType lambda = info.clazz.type;
-      if (group.isSingletonLambda(lambda)) {
-        int id = group.lambdaId(lambda);
-        add(builder -> builder.addNewInstance(instance, groupClassType));
-        add(builder -> builder.addConst(TypeLatticeElement.INT, lambdaId, id));
-        add(builder -> builder.addInvoke(Type.DIRECT,
-            lambdaConstructorMethod, lambdaConstructorMethod.proto, argTypes, argRegisters));
-        add(builder -> builder.addStaticPut(
-            instance, group.getSingletonInstanceField(factory, id)));
-      }
-    });
+    group.forEachLambda(
+        info -> {
+          DexType lambda = info.clazz.type;
+          if (group.isSingletonLambda(lambda)) {
+            int id = group.lambdaId(lambda);
+            add(builder -> builder.addNewInstance(instance, groupClassType));
+            add(builder -> builder.addConst(TypeLatticeElement.INT, lambdaId, id));
+            add(
+                builder ->
+                    builder.addInvoke(
+                        Type.DIRECT,
+                        lambdaConstructorMethod,
+                        lambdaConstructorMethod.proto,
+                        argTypes,
+                        argRegisters,
+                        false /* isInterface*/));
+            add(
+                builder ->
+                    builder.addStaticPut(instance, group.getSingletonInstanceField(factory, id)));
+          }
+        });
 
     assert this.nextInstructionIndex() > 0 : "no single field initialized";
     add(IRBuilder::addReturn);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/JStyleLambdaGroup.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/JStyleLambdaGroup.java
index e8fcd40..2bdc441 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/JStyleLambdaGroup.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/JStyleLambdaGroup.java
@@ -215,8 +215,15 @@
 
     @Override
     void prepareSuperConstructorCall(int receiverRegister) {
-      add(builder -> builder.addInvoke(Type.DIRECT, objectInitializer, objectInitializer.proto,
-          Lists.newArrayList(ValueType.OBJECT), Lists.newArrayList(receiverRegister)));
+      add(
+          builder ->
+              builder.addInvoke(
+                  Type.DIRECT,
+                  objectInitializer,
+                  objectInitializer.proto,
+                  Lists.newArrayList(ValueType.OBJECT),
+                  Lists.newArrayList(receiverRegister),
+                  false /* isInterface */));
     }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KStyleLambdaGroup.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KStyleLambdaGroup.java
index f677b46..ee0b800 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KStyleLambdaGroup.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KStyleLambdaGroup.java
@@ -233,9 +233,15 @@
     void prepareSuperConstructorCall(int receiverRegister) {
       int arityRegister = nextRegister(ValueType.INT);
       add(builder -> builder.addConst(TypeLatticeElement.INT, arityRegister, arity));
-      add(builder -> builder.addInvoke(Type.DIRECT, lambdaInitializer, lambdaInitializer.proto,
-          Lists.newArrayList(ValueType.OBJECT, ValueType.INT),
-          Lists.newArrayList(receiverRegister, arityRegister)));
+      add(
+          builder ->
+              builder.addInvoke(
+                  Type.DIRECT,
+                  lambdaInitializer,
+                  lambdaInitializer.proto,
+                  Lists.newArrayList(ValueType.OBJECT, ValueType.INT),
+                  Lists.newArrayList(receiverRegister, arityRegister),
+                  false /* isInterface */));
     }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaVirtualMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaVirtualMethodSourceCode.java
index 82acf49..bcd0a75 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaVirtualMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaVirtualMethodSourceCode.java
@@ -85,16 +85,18 @@
       offsets[i] = nextInstructionIndex();
 
       // Emit fake call on `this` receiver.
-      add(builder -> {
-        if (arguments.isEmpty()) {
-          // Late initialization of argument list.
-          arguments.add(getReceiverValue());
-          for (int index = 0; index < paramCount; index++) {
-            arguments.add(getParamValue(index));
-          }
-        }
-        builder.addInvoke(Type.VIRTUAL, impl.method, impl.method.proto, arguments);
-      });
+      add(
+          builder -> {
+            if (arguments.isEmpty()) {
+              // Late initialization of argument list.
+              arguments.add(getReceiverValue());
+              for (int index = 0; index < paramCount; index++) {
+                arguments.add(getParamValue(index));
+              }
+            }
+            builder.addInvoke(
+                Type.VIRTUAL, impl.method, impl.method.proto, arguments, false /* isInterface */);
+          });
 
       // Handle return value if needed.
       if (returnsValue) {
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
index 37341fb..76dba16 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
@@ -23,6 +23,7 @@
   private final DexMethod target;
   private final Invoke.Type invokeType;
   private final boolean castResult;
+  private final boolean isInterface;
 
   public ForwardMethodSourceCode(
       DexType receiver,
@@ -31,7 +32,8 @@
       DexType targetReceiver,
       DexMethod target,
       Type invokeType,
-      Position callerPosition) {
+      Position callerPosition,
+      boolean isInterface) {
     this(
         receiver,
         method,
@@ -40,6 +42,7 @@
         target,
         invokeType,
         callerPosition,
+        isInterface,
         false);
   }
 
@@ -51,6 +54,7 @@
       DexMethod target,
       Type invokeType,
       Position callerPosition,
+      boolean isInterface,
       boolean castResult) {
     super(receiver, method, callerPosition, originalMethod);
     assert (targetReceiver == null) == (invokeType == Invoke.Type.STATIC);
@@ -58,6 +62,7 @@
     this.target = target;
     this.targetReceiver = targetReceiver;
     this.invokeType = invokeType;
+    this.isInterface = isInterface;
     this.castResult = castResult;
     assert checkSignatures();
 
@@ -119,8 +124,15 @@
     }
 
     // Method call to the target method.
-    add(builder -> builder.addInvoke(this.invokeType,
-        this.target, this.target.proto, argValueTypes, argRegisters));
+    add(
+        builder ->
+            builder.addInvoke(
+                this.invokeType,
+                this.target,
+                this.target.proto,
+                argValueTypes,
+                argRegisters,
+                this.isInterface));
 
     // Does the method return value?
     if (proto.returnType.isVoidType()) {
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
index 608f915..3ff88b9 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
@@ -191,7 +191,7 @@
         findHolderForInterfaceMethodBridge(originalClass, targetClass.type);
     assert bridgeHolder != null;
     assert bridgeHolder != targetClass;
-    DexEncodedMethod bridgeMethod = target.toForwardingMethod(bridgeHolder, appInfo.dexItemFactory);
+    DexEncodedMethod bridgeMethod = target.toForwardingMethod(bridgeHolder, appInfo);
     bridgeHolder.addMethod(bridgeMethod);
     assert lookupTarget.apply(method) == bridgeMethod;
     return bridgeMethod;
@@ -242,8 +242,7 @@
       DexProgramClass bridgeHolder =
           findHolderForVisibilityBridge(originalClass, targetClass, packageDescriptor);
       assert bridgeHolder != null;
-      DexEncodedMethod bridgeMethod =
-          target.toForwardingMethod(bridgeHolder, appInfo.dexItemFactory);
+      DexEncodedMethod bridgeMethod = target.toForwardingMethod(bridgeHolder, appInfo);
       bridgeHolder.addMethod(bridgeMethod);
       assert lookupTarget.apply(method) == bridgeMethod;
       return bridgeMethod;
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index fe10045..03be595 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -1191,7 +1191,8 @@
               newMethod,
               graphLense.getOriginalMethodSignature(method.method),
               invocationTarget.method,
-              invocationTarget.isPrivateMethod() ? DIRECT : STATIC);
+              invocationTarget.isPrivateMethod() ? DIRECT : STATIC,
+              target.isInterface());
 
       // Add the bridge to the list of synthesized bridges such that the method signatures will
       // be updated by the end of vertical class merging.
@@ -1873,13 +1874,19 @@
     private DexMethod originalMethod;
     private DexMethod invocationTarget;
     private Type type;
+    private final boolean isInterface;
 
     public SynthesizedBridgeCode(
-        DexMethod method, DexMethod originalMethod, DexMethod invocationTarget, Type type) {
+        DexMethod method,
+        DexMethod originalMethod,
+        DexMethod invocationTarget,
+        Type type,
+        boolean isInterface) {
       this.method = method;
       this.originalMethod = originalMethod;
       this.invocationTarget = invocationTarget;
       this.type = type;
+      this.isInterface = isInterface;
     }
 
     // By the time the synthesized code object is created, vertical class merging still has not
@@ -1908,7 +1915,8 @@
               type == DIRECT ? method.holder : null,
               invocationTarget,
               type,
-              callerPosition);
+              callerPosition,
+              isInterface);
     }
 
     @Override