Fix HClinitCheck elimination in instruction builder.

To handle escaping instances of erroneous classes correctly,
we can omit the HClinitCheck only when using a class in the
static method of the very same class. Even for superclasses
we need to do the check. The new test exposes the cases
where we were previously diverging from the RI.

Also clean up the CompilerDriver by inlining one function
directly to the HInstructionBuild::IsInitialized(.) and
removing some related functions that are no longer used.

The size of the aosp_taimen-userdebug prebuilts:
  - before:
    arm/boot*.oat: 16891788
    arm64/boot*.oat: 19815520
    oat/arm64/services.odex: 20071624
  - after:
    arm/boot*.oat: 16949532 (+56.4KiB, +0.34%)
    arm64/boot*.oat: 19889752 (+72.5KiB, +0.37%)
    oat/arm64/services.odex: 20224328 (+149.1KiB, +0.76%)
with minor changes to other app prebuilts.

Note: Some of that could be reclaimed by reinstating the old
optimization for classes where no bytecode can be executed
during initialization (no <clinit> to execute in that class
or superclasses).

Test: 174-escaping-instance-of-bad-class
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Test: testrunner.py --jvm -t 174
Test: Pixel 2 XL boots.
Test: testrunner.py --target --optimizing
Bug: 62478025
Change-Id: I41f026ea7fecc615c06e87f3b6cb847de0ede8a6
diff --git a/test/174-escaping-instance-of-bad-class/src/Main.java b/test/174-escaping-instance-of-bad-class/src/Main.java
new file mode 100644
index 0000000..4346152
--- /dev/null
+++ b/test/174-escaping-instance-of-bad-class/src/Main.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+  public static void main(String args[]) {
+    simpleTest();
+    hierarchyTest();
+  }
+
+  public static void simpleTest() {
+    // Partial initialization of Bad; ignoring the error.
+    Error badClinit = null;
+    try {
+      new Bad(11);
+    } catch (Error e) {
+      badClinit = e;
+    }
+    // Call foo() on the escaped instance of Bad.
+    try {
+      bad.foo();
+    } catch (NoClassDefFoundError ncdfe) {
+      // On RI, the NCDFE has no cause. On ART, the badClinit is the cause.
+      if (ncdfe.getCause() == badClinit || ncdfe.getCause() == null) {
+        System.out.println("Caught NoClassDefFoundError.");
+      } else {
+        ncdfe.printStackTrace();
+      }
+    }
+  }
+
+  public static void hierarchyTest() {
+    // Partial initialization of BadSuper; ignoring the error. Fully initializes BadSub.
+    Error badClinit = null;
+    try {
+      new BadSuper(0);
+    } catch (Error e) {
+      badClinit = e;
+    }
+    // Call BadSuper.foo() on the escaped instance of BadSuper.
+    try {
+      badSuper.foo();
+    } catch (NoClassDefFoundError ncdfe) {
+      // On RI, the NCDFE has no cause. On ART, the badClinit is the cause.
+      if (ncdfe.getCause() == badClinit || ncdfe.getCause() == null) {
+        System.out.println("Caught NoClassDefFoundError.");
+      } else {
+        ncdfe.printStackTrace();
+      }
+    }
+
+    // Call BadSub.bar() on the escaped instance of BadSub.
+    try {
+      badSub.bar();
+    } catch (NoClassDefFoundError ncdfe) {
+      // On RI, the NCDFE has no cause. On ART, the badClinit is the cause.
+      if (ncdfe.getCause() == badClinit || ncdfe.getCause() == null) {
+        System.out.println("Caught NoClassDefFoundError.");
+      } else {
+        ncdfe.printStackTrace();
+      }
+    }
+
+    // Test that we can even create instances of BadSub with erroneous superclass BadSuper.
+    try {
+      new BadSub(-1, -2).bar();
+    } catch (NoClassDefFoundError ncdfe) {
+      // On RI, the NCDFE has no cause. On ART, the badClinit is the cause.
+      if (ncdfe.getCause() == badClinit || ncdfe.getCause() == null) {
+        System.out.println("Caught NoClassDefFoundError.");
+      } else {
+        ncdfe.printStackTrace();
+      }
+    }
+
+    // Test that we cannot create instances of BadSuper from BadSub.
+    try {
+      badSub.allocSuper(11111);  // Should throw.
+      System.out.println("Allocated BadSuper!");
+    } catch (NoClassDefFoundError ncdfe) {
+      // On RI, the NCDFE has no cause. On ART, the badClinit is the cause.
+      if (ncdfe.getCause() == badClinit || ncdfe.getCause() == null) {
+        System.out.println("Caught NoClassDefFoundError.");
+      } else {
+        ncdfe.printStackTrace();
+      }
+    }
+  }
+
+  public static Bad bad;
+
+  public static BadSuper badSuper;
+  public static BadSub badSub;
+}
+
+class Bad {
+  static {
+    // Create an instance of Bad and let it escape in Main.bad.
+    Main.bad = new Bad(33);
+    staticValue = 42;
+    if (true) { throw new Error("Bad <clinit>"); }
+  }
+  public void foo() {
+    System.out.println("Bad.foo()");
+    System.out.println("Bad.instanceValue = " + instanceValue);
+    System.out.println("Bad.staticValue = " + staticValue);
+  }
+  public Bad(int iv) { instanceValue = iv; }
+  public int instanceValue;
+  public static int staticValue;
+}
+
+class BadSuper {
+  static {
+    Main.badSuper = new BadSuper(1);
+    Main.badSub = new BadSub(11, 111);  // Fully initializes BadSub.
+    BadSuper.superStaticValue = 42;
+    BadSub.subStaticValue = 4242;
+    if (true) { throw new Error("Bad <clinit>"); }
+  }
+  public void foo() {
+    System.out.println("BadSuper.foo()");
+    System.out.println("BadSuper.superInstanceValue = " + superInstanceValue);
+    System.out.println("BadSuper.superStaticValue = " + superStaticValue);
+  }
+  public BadSuper(int superiv) { superInstanceValue = superiv; }
+  public int superInstanceValue;
+  public static int superStaticValue;
+}
+
+// Note: If we tried to initialize BadSub before BadSuper, it would end up erroneous
+// because the superclass fails initialization. However, since we start initializing the
+// BadSuper first, BadSub is initialized successfully while BadSuper is "initializing"
+// and remains initialized after the BadSuper's class initializer throws.
+class BadSub extends BadSuper {
+  public void bar() {
+    System.out.println("BadSub.bar()");
+    System.out.println("BadSub.subInstanceValue = " + subInstanceValue);
+    System.out.println("BadSub.subStaticValue = " + subStaticValue);
+    System.out.println("BadSuper.superInstanceValue = " + superInstanceValue);
+    System.out.println("BadSuper.superStaticValue = " + superStaticValue);
+  }
+  public BadSuper allocSuper(int superiv) {
+    System.out.println("BadSub.allocSuper(.)");
+    return new BadSuper(superiv);
+  }
+  public BadSub(int subiv, int superiv) {
+    super(superiv);
+    subInstanceValue = subiv;
+  }
+  public int subInstanceValue;
+  public static int subStaticValue;
+}