Account for extra arguments in reverse constructor inlining

Change-Id: Id2b0164c0cf92bb2f4bf3d375267e94c4a294da0
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java b/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
index 46e1cb9..2a3568d 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
@@ -56,6 +56,10 @@
     return getDefinition().getAccessFlags();
   }
 
+  public int getArity() {
+    return getReference().getArity();
+  }
+
   public MethodReference getMethodReference() {
     return getReference().asMethodReference();
   }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/UndoConstructorInlining.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/UndoConstructorInlining.java
index 47f55800..a6fd8bf 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/UndoConstructorInlining.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/UndoConstructorInlining.java
@@ -21,8 +21,15 @@
 import com.android.tools.r8.graph.ImmediateProgramSubtypingInfo;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadataProvider;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.InstructionListIterator;
+import com.android.tools.r8.ir.code.InvokeDirect;
+import com.android.tools.r8.ir.code.NewInstance;
 import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.conversion.IRToLirFinalizer;
 import com.android.tools.r8.lightir.ByteArrayWriter;
 import com.android.tools.r8.lightir.ByteUtils;
 import com.android.tools.r8.lightir.LirBuilder;
@@ -241,6 +248,10 @@
                     newConstructor ->
                         profileCollectionAdditions.addMethodIfContextIsInProfile(
                             newConstructor, method));
+        if (newInvokedMethod.getArity() != info.getInvokedMethod().getArity()) {
+          assert newInvokedMethod.getArity() > info.getInvokedMethod().getArity();
+          return rewriteIR(method, code);
+        }
         int constantIndex =
             methodIndices.computeIfAbsent(
                 newInvokedMethod.getReference(),
@@ -266,6 +277,65 @@
               byteWriter.toByteArray());
     }
 
+    private LirCode<Integer> rewriteIR(ProgramMethod method, LirCode<Integer> code) {
+      IRCode irCode = code.buildIR(method, appView);
+      InstructionListIterator instructionIterator = irCode.instructionListIterator();
+      InvokeDirect invoke;
+      while ((invoke = instructionIterator.nextUntil(Instruction::isInvokeDirect)) != null) {
+        DexType newType;
+        if (invoke
+            .getReceiver()
+            .getAliasedValue()
+            .isDefinedByInstructionSatisfying(Instruction::isNewInstance)) {
+          NewInstance newInstance =
+              invoke.getReceiver().getAliasedValue().getDefinition().asNewInstance();
+          newType = newInstance.getType();
+        } else if (invoke.getReceiver().isThis()
+            && method.getDefinition().isInstanceInitializer()) {
+          newType = method.getHolder().getSuperType();
+        } else {
+          continue;
+        }
+        DexMethod invokedMethod = invoke.getInvokedMethod();
+        if (ensureConstructorsOnClasses.containsKey(newType)
+            && isConstructorInlined(newType, invokedMethod)
+            && !isForwardingConstructorCall(method, invokedMethod, invoke.getReceiver().isThis())
+            && isSkippingRequiredConstructor(newType, invokedMethod)) {
+          DexProgramClass noSkipClass = ensureConstructorsOnClasses.get(newType);
+          ProgramMethod newInvokedMethod =
+              getStronglyConnectedComponent(noSkipClass)
+                  .getOrCreateConstructor(
+                      noSkipClass,
+                      invokedMethod,
+                      ensureConstructorsOnClasses,
+                      newConstructor ->
+                          profileCollectionAdditions.addMethodIfContextIsInProfile(
+                              newConstructor, method));
+          InvokeDirect.Builder invokeDirectBuilder =
+              InvokeDirect.builder()
+                  .setArguments(invoke.arguments())
+                  .setMethod(newInvokedMethod.getReference());
+          if (newInvokedMethod.getArity() > invokedMethod.getArity()) {
+            instructionIterator.previous();
+            Value zeroValue =
+                instructionIterator.insertConstIntInstruction(irCode, appView.options(), 0);
+            List<Value> newArguments =
+                new ArrayList<>(newInvokedMethod.getDefinition().getNumberOfArguments());
+            newArguments.addAll(invoke.arguments());
+            while (newArguments.size() < newInvokedMethod.getDefinition().getNumberOfArguments()) {
+              newArguments.add(zeroValue);
+            }
+            Instruction next = instructionIterator.next();
+            assert next == invoke;
+            invokeDirectBuilder.setArguments(newArguments);
+          }
+          instructionIterator.replaceCurrentInstruction(invokeDirectBuilder.build());
+        }
+      }
+      return new IRToLirFinalizer(appView)
+          .finalizeCode(irCode, BytecodeMetadataProvider.empty(), Timing.empty());
+    }
+
     private Int2ReferenceMap<DexType> getAllocationsOfInterest(
         ProgramMethod method, LirCode<Integer> code) {
       Int2ReferenceMap<DexType> allocationsOfInterest = new Int2ReferenceOpenHashMap<>();
@@ -318,7 +388,7 @@
           DexType newType = allocationsOfInterest.get(receiver);
           if (newType != null
               && isConstructorInlined(newType, invokedMethod)
-              && !isForwardingConstructorCall(method, invokedMethod, receiver)
+              && !isForwardingConstructorCall(method, invokedMethod, receiver == 0)
               && isSkippingRequiredConstructor(newType, invokedMethod)) {
             return new InvokeDirectInfo(
                 invokedMethod, firstValue, ensureConstructorsOnClasses.get(newType));
@@ -345,11 +415,11 @@
     }
 
     private boolean isForwardingConstructorCall(
-        ProgramMethod method, DexMethod invokedMethod, int receiver) {
+        ProgramMethod method, DexMethod invokedMethod, boolean isThisReceiver) {
       assert invokedMethod.isInstanceInitializer(appView.dexItemFactory());
       return method.getDefinition().isInstanceInitializer()
           && invokedMethod.getHolderType().isIdenticalTo(method.getHolderType())
-          && receiver == 0;
+          && isThisReceiver;
     }
 
     private boolean isSkippingRequiredConstructor(DexType newType, DexMethod invokedMethod) {