Fix instance-put to uninitialized-object after inlining check

Change-Id: I22bd0465f0dec1384cbc1b9a220e8cd21aaa522d
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
index 05c83da..6f524f6 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
@@ -522,27 +522,24 @@
 
     List<InvokeDirect> initCallsOnThis = new ArrayList<>();
     for (Instruction instruction : inlinee.instructions()) {
-      if (instruction.isInvokeDirect()) {
+      if (instruction.isInvokeConstructor(appView.dexItemFactory())) {
         InvokeDirect initCall = instruction.asInvokeDirect();
-        DexMethod invokedMethod = initCall.getInvokedMethod();
-        if (appView.dexItemFactory().isConstructor(invokedMethod)) {
-          Value receiver = initCall.getReceiver().getAliasedValue();
-          if (receiver == thisValue) {
-            // The <init>() call of the constructor must be on the same class.
-            if (calleeMethodHolder != invokedMethod.holder) {
-              whyAreYouNotInliningReporter
-                  .reportUnsafeConstructorInliningDueToIndirectConstructorCall(initCall);
-              return false;
-            }
-            initCallsOnThis.add(initCall);
+        Value receiver = initCall.getReceiver().getAliasedValue();
+        if (receiver == thisValue) {
+          // The <init>() call of the constructor must be on the same class.
+          if (calleeMethodHolder != initCall.getInvokedMethod().getHolderType()) {
+            whyAreYouNotInliningReporter
+                .reportUnsafeConstructorInliningDueToIndirectConstructorCall(initCall);
+            return false;
           }
+          initCallsOnThis.add(initCall);
         }
       } else if (instruction.isInstancePut()) {
         // Final fields may not be initialized outside of a constructor in the enclosing class.
         InstancePut instancePut = instruction.asInstancePut();
         DexField field = instancePut.getField();
         DexEncodedField target = appView.appInfo().lookupInstanceTarget(field);
-        if (target == null || target.accessFlags.isFinal()) {
+        if (target == null || target.isFinal()) {
           whyAreYouNotInliningReporter.reportUnsafeConstructorInliningDueToFinalFieldAssignment(
               instancePut);
           return false;
@@ -550,29 +547,22 @@
       }
     }
 
-    // Check that there are no uses of the uninitialized object before it gets initialized.
-    int markingColor = inlinee.reserveMarkingColor();
-    for (InvokeDirect initCallOnThis : initCallsOnThis) {
-      BasicBlock block = initCallOnThis.getBlock();
-      for (Instruction instruction : block.instructionsBefore(initCallOnThis)) {
-        for (Value inValue : instruction.inValues()) {
-          Value root = inValue.getAliasedValue();
-          if (root == thisValue) {
-            inlinee.returnMarkingColor(markingColor);
-            whyAreYouNotInliningReporter.reportUnsafeConstructorInliningDueToUninitializedObjectUse(
-                instruction);
-            return false;
-          }
+    if (initCallsOnThis.isEmpty()) {
+      // In the unusual case where there is no parent/forwarding constructor call, there must be no
+      // instance-put instructions that assign fields on the receiver.
+      for (Instruction user : thisValue.uniqueUsers()) {
+        if (user.isInstancePut() && user.asInstancePut().object().getAliasedValue() == thisValue) {
+          whyAreYouNotInliningReporter.reportUnsafeConstructorInliningDueToUninitializedObjectUse(
+              user);
+          return false;
         }
       }
-      for (BasicBlock predecessor : block.getPredecessors()) {
-        inlinee.markTransitivePredecessors(predecessor, markingColor);
-      }
-    }
-
-    for (BasicBlock block : inlinee.blocks) {
-      if (block.isMarked(markingColor)) {
-        for (Instruction instruction : block.getInstructions()) {
+    } else {
+      // Check that there are no uses of the uninitialized object before it gets initialized.
+      int markingColor = inlinee.reserveMarkingColor();
+      for (InvokeDirect initCallOnThis : initCallsOnThis) {
+        BasicBlock block = initCallOnThis.getBlock();
+        for (Instruction instruction : block.instructionsBefore(initCallOnThis)) {
           for (Value inValue : instruction.inValues()) {
             Value root = inValue.getAliasedValue();
             if (root == thisValue) {
@@ -583,10 +573,29 @@
             }
           }
         }
+        for (BasicBlock predecessor : block.getPredecessors()) {
+          inlinee.markTransitivePredecessors(predecessor, markingColor);
+        }
       }
+
+      for (BasicBlock block : inlinee.getBlocks()) {
+        if (block.isMarked(markingColor)) {
+          for (Instruction instruction : block.getInstructions()) {
+            for (Value inValue : instruction.inValues()) {
+              Value root = inValue.getAliasedValue();
+              if (root == thisValue) {
+                inlinee.returnMarkingColor(markingColor);
+                whyAreYouNotInliningReporter
+                    .reportUnsafeConstructorInliningDueToUninitializedObjectUse(instruction);
+                return false;
+              }
+            }
+          }
+        }
+      }
+      inlinee.returnMarkingColor(markingColor);
     }
 
-    inlinee.returnMarkingColor(markingColor);
     inliningIRProvider.cacheInliningIR(invoke, inlinee);
     return true;
   }