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/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 731accd..3cc20b3 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -1143,32 +1143,48 @@
       MethodCompilationStat::kConstructorFenceGeneratedNew);
 }
 
-static bool IsSubClass(ObjPtr<mirror::Class> to_test, ObjPtr<mirror::Class> super_class)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  return to_test != nullptr && !to_test->IsInterface() && to_test->IsSubClass(super_class);
-}
-
 bool HInstructionBuilder::IsInitialized(Handle<mirror::Class> cls) const {
   if (cls == nullptr) {
     return false;
   }
 
-  // `CanAssumeClassIsLoaded` will return true if we're JITting, or will
-  // check whether the class is in an image for the AOT compilation.
-  if (cls->IsInitialized() &&
-      compiler_driver_->CanAssumeClassIsLoaded(cls.Get())) {
+  // Check if the class will be initialized at runtime.
+  if (cls->IsInitialized()) {
+    Runtime* runtime = Runtime::Current();
+    if (!runtime->IsAotCompiler()) {
+      DCHECK(runtime->UseJitCompilation());
+      // For JIT, the class cannot revert to an uninitialized state.
+      return true;
+    }
+    // Assume loaded only if klass is in the boot image. App classes cannot be assumed
+    // loaded because we don't even know what class loader will be used to load them.
+    const CompilerOptions& compiler_options = compiler_driver_->GetCompilerOptions();
+    if (compiler_options.IsBootImage()) {
+      std::string temp;
+      const char* descriptor = cls->GetDescriptor(&temp);
+      if (compiler_options.IsImageClass(descriptor)) {
+        return true;
+      }
+    } else {
+      if (runtime->GetHeap()->FindSpaceFromObject(cls.Get(), false)->IsImageSpace()) {
+        return true;
+      }
+    }
+  }
+
+  // We can avoid the class initialization check for `cls` only in static methods in the
+  // very same class. Instance methods of the same class can run on an escaped instance
+  // of an erroneous class. Even a superclass may need to be checked as the subclass
+  // can be completely initialized while the superclass is initializing and the subclass
+  // remains initialized when the superclass initializer throws afterwards. b/62478025
+  // Note: The HClinitCheck+HInvokeStaticOrDirect merging can still apply.
+  if ((dex_compilation_unit_->GetAccessFlags() & kAccStatic) != 0u &&
+      GetOutermostCompilingClass() == cls.Get()) {
     return true;
   }
 
-  if (IsSubClass(GetOutermostCompilingClass(), cls.Get())) {
-    return true;
-  }
-
-  // TODO: We should walk over the inlined methods, but we don't pass
-  //       that information to the builder.
-  if (IsSubClass(GetCompilingClass(), cls.Get())) {
-    return true;
-  }
+  // Note: We could walk over the inlined methods to avoid allocating excessive
+  // `HClinitCheck`s in inlined static methods but they shall be eliminated by GVN.
 
   return false;
 }
@@ -1922,11 +1938,6 @@
   }
 }
 
-bool HInstructionBuilder::NeedsAccessCheck(dex::TypeIndex type_index, bool* finalizable) const {
-  return !compiler_driver_->CanAccessInstantiableTypeWithoutChecks(
-      LookupReferrerClass(), LookupResolvedType(type_index, *dex_compilation_unit_), finalizable);
-}
-
 bool HInstructionBuilder::CanDecodeQuickenedInfo() const {
   return !quicken_info_.IsNull();
 }