Don't inline into constructors when producing class files

This can lead to verification errors when the inlined code has control flow jumping over the super constructor call

Bug: 136250031
Change-Id: I67493805967237aa95a614d510f0f88df57b3bff
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 ff50f91..89adfc7 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
@@ -171,6 +171,14 @@
       return false;
     }
 
+    // We don't inline into constructors when producing class files since this can mess up
+    // the stackmap, see b/136250031
+    if (method.isInitializer()
+        && appView.options().isGeneratingClassFiles()
+        && reason != Reason.FORCE) {
+      return false;
+    }
+
     if (method == candidate) {
       // Cannot handle recursive inlining at this point.
       // Force inlined method should never be recursive.
diff --git a/src/test/examples/inlining/CheckDiscardedConstructor.java b/src/test/examples/inlining/CheckDiscardedConstructor.java
new file mode 100644
index 0000000..d7be28c
--- /dev/null
+++ b/src/test/examples/inlining/CheckDiscardedConstructor.java
@@ -0,0 +1,8 @@
+// Copyright (c) 2019, 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 inlining;
+
+public @interface CheckDiscardedConstructor {
+
+}
diff --git a/src/test/examples/inlining/InlineConstructorFinalField.java b/src/test/examples/inlining/InlineConstructorFinalField.java
index 093a2ac..a23c3dc 100644
--- a/src/test/examples/inlining/InlineConstructorFinalField.java
+++ b/src/test/examples/inlining/InlineConstructorFinalField.java
@@ -7,7 +7,7 @@
 
   public final int number;
 
-  @CheckDiscarded
+  @CheckDiscardedConstructor
   InlineConstructorFinalField(int value) {
     number = value;
   }
diff --git a/src/test/examples/inlining/InlineConstructorOfInner.java b/src/test/examples/inlining/InlineConstructorOfInner.java
index cec7d3f..6bc8abb 100644
--- a/src/test/examples/inlining/InlineConstructorOfInner.java
+++ b/src/test/examples/inlining/InlineConstructorOfInner.java
@@ -9,7 +9,7 @@
 
     int a;
 
-    @CheckDiscarded
+    @CheckDiscardedConstructor
     Inner(int a) {
       this.a = a;
     }
diff --git a/src/test/examples/inlining/keep-rules-discard-constructor.txt b/src/test/examples/inlining/keep-rules-discard-constructor.txt
new file mode 100644
index 0000000..fab5f5d
--- /dev/null
+++ b/src/test/examples/inlining/keep-rules-discard-constructor.txt
@@ -0,0 +1,8 @@
+# Copyright (c) 2019, 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.
+
+# Check that constructors have been inlined
+-checkdiscard class * {
+  @inlining.CheckDiscardedConstructor *;
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/Regress136250031.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/Regress136250031.java
new file mode 100644
index 0000000..fbc405e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/Regress136250031.java
@@ -0,0 +1,52 @@
+// Copyright (c) 2019, 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.ir.optimize.inliner;
+
+import com.android.tools.r8.TestBase;
+import org.junit.Test;
+
+public class Regress136250031 extends TestBase {
+
+  @Test
+  public void test() throws Exception {
+        testForR8(Backend.CF)
+            .addInnerClasses(Regress136250031.class)
+            .addKeepMainRule(TestClass.class)
+            .addKeepClassAndMembersRules(B.class)
+            .run(TestClass.class)
+            .assertSuccess();
+  }
+
+  static class TestClass {
+    public static void main(String[] args) {
+      new B(new C());
+    }
+  }
+
+  static class A {
+    A(String s) {
+      System.out.println(s);
+    }
+  }
+
+  static class B extends A {
+    B(C c) {
+      super(c.instance.toString());
+    }
+  }
+
+  static class C {
+    public C instance;
+
+    C() {
+      instance = System.currentTimeMillis() > 0 ? this : null;
+    }
+
+    @Override
+    public String toString() {
+      return "42";
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/regress/b69825683/innerconstructsouter/Outer.java b/src/test/java/com/android/tools/r8/regress/b69825683/innerconstructsouter/Outer.java
index 78d9d05..8be969a 100644
--- a/src/test/java/com/android/tools/r8/regress/b69825683/innerconstructsouter/Outer.java
+++ b/src/test/java/com/android/tools/r8/regress/b69825683/innerconstructsouter/Outer.java
@@ -23,7 +23,7 @@
     Inner builder = new Inner();
     builder.build();
     for (java.lang.reflect.Constructor m : Outer.class.getDeclaredConstructors()) {
-      System.out.println(m);
+      System.out.println(m.getName());
     }
   }
 }
diff --git a/src/test/java/com/android/tools/r8/regress/b69825683/outerconstructsinner/Outer.java b/src/test/java/com/android/tools/r8/regress/b69825683/outerconstructsinner/Outer.java
index 3222964..dfaf6f9 100644
--- a/src/test/java/com/android/tools/r8/regress/b69825683/outerconstructsinner/Outer.java
+++ b/src/test/java/com/android/tools/r8/regress/b69825683/outerconstructsinner/Outer.java
@@ -22,7 +22,7 @@
   public static void main(String args[]) {
     new Outer();
     for (java.lang.reflect.Constructor m : Outer.Inner.class.getDeclaredConstructors()) {
-      System.out.println(m);
+      System.out.println(m.getName());
     }
   }
 }
diff --git a/src/test/java/com/android/tools/r8/shaking/examples/TreeShakingInliningTest.java b/src/test/java/com/android/tools/r8/shaking/examples/TreeShakingInliningTest.java
index 2a53f1b..a6fb153 100644
--- a/src/test/java/com/android/tools/r8/shaking/examples/TreeShakingInliningTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/examples/TreeShakingInliningTest.java
@@ -38,7 +38,12 @@
 
   @Test
   public void testKeeprulesdiscard() throws Exception {
+    // On the cf backend, we don't inline into constructors, see: b/136250031
+    List<String> keepRules = getBackend() == Backend.CF
+        ? ImmutableList.of("src/test/examples/inlining/keep-rules-discard.txt")
+        : ImmutableList.of("src/test/examples/inlining/keep-rules-discard.txt",
+            "src/test/examples/inlining/keep-rules-discard-constructor.txt");
     runTest(
-        null, null, null, ImmutableList.of("src/test/examples/inlining/keep-rules-discard.txt"));
+        null, null, null, keepRules);
   }
 }