Reland "Add clinit checks at entry for some boot image methods."

This reverts commit 0ae89052f7213701b8b3a782266e84b3d3600dbf.

Bug: 162110941
Bug: 238472973

Reason for revert: Remove code that forced using clinit entrypoints in
debug mode.

Change-Id: Ibc04e91b09deaa1ac23d32b9e45281f3299d2981
diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc
index 51cd999..a531bc9 100644
--- a/compiler/driver/compiler_options.cc
+++ b/compiler/driver/compiler_options.cc
@@ -23,6 +23,7 @@
 
 #include "arch/instruction_set.h"
 #include "arch/instruction_set_features.h"
+#include "art_method-inl.h"
 #include "base/runtime_debug.h"
 #include "base/string_view_cpp20.h"
 #include "base/variant_map.h"
@@ -146,14 +147,39 @@
 
 bool CompilerOptions::IsImageClass(const char* descriptor) const {
   // Historical note: We used to hold the set indirectly and there was a distinction between an
-  // empty set and a null, null meaning to include all classes. However, the distiction has been
+  // empty set and a null, null meaning to include all classes. However, the distinction has been
   // removed; if we don't have a profile, we treat it as an empty set of classes. b/77340429
   return image_classes_.find(std::string_view(descriptor)) != image_classes_.end();
 }
 
+bool CompilerOptions::IsPreloadedClass(const char* pretty_descriptor) const {
+  return preloaded_classes_.find(std::string_view(pretty_descriptor)) != preloaded_classes_.end();
+}
+
 const VerificationResults* CompilerOptions::GetVerificationResults() const {
   DCHECK(Runtime::Current()->IsAotCompiler());
   return verification_results_;
 }
 
+bool CompilerOptions::ShouldCompileWithClinitCheck(ArtMethod* method) const {
+  if (method != nullptr &&
+      Runtime::Current()->IsAotCompiler() &&
+      method->IsStatic() &&
+      !method->IsConstructor() &&
+      // Compiled code for native methods never do a clinit check, so we may put the resolution
+      // trampoline for native methods. This means that it's possible post zygote fork for the
+      // entry to be dirtied. We could resolve this by either:
+      // - Make these methods use the generic JNI entrypoint, but that's not
+      //   desirable for a method that is in the profile.
+      // - Ensure the declaring class of such native methods are always in the
+      //   preloaded-classes list.
+      // - Emit the clinit check in the compiled code of native methods.
+      !method->IsNative()) {
+    ScopedObjectAccess soa(Thread::Current());
+    ObjPtr<mirror::Class> cls = method->GetDeclaringClass<kWithoutReadBarrier>();
+    return cls->IsInBootImageAndNotInPreloadedClasses();
+  }
+  return false;
+}
+
 }  // namespace art
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index 1bffdb1..20f54bd 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -44,6 +44,7 @@
 class Arm64RelativePatcherTest;
 }  // namespace linker
 
+class ArtMethod;
 class DexFile;
 enum class InstructionSet;
 class InstructionSetFeatures;
@@ -300,6 +301,10 @@
 
   bool IsImageClass(const char* descriptor) const;
 
+  // Returns whether the given `pretty_descriptor` is in the list of preloaded
+  // classes. `pretty_descriptor` should be the result of calling `PrettyDescriptor`.
+  bool IsPreloadedClass(const char* pretty_descriptor) const;
+
   const VerificationResults* GetVerificationResults() const;
 
   bool ParseCompilerOptions(const std::vector<std::string>& options,
@@ -383,6 +388,12 @@
     return ContainsElement(GetDexFilesForOatFile(), dex_file);
   }
 
+  // If this is a static non-constructor method in the boot classpath, and its class isn't
+  // initialized at compile-time, or won't be initialized by the zygote, add
+  // initialization checks at entry. This will avoid the need of trampolines
+  // which at runtime we will need to dirty after initialization.
+  bool ShouldCompileWithClinitCheck(ArtMethod* method) const;
+
  private:
   bool ParseDumpInitFailures(const std::string& option, std::string* error_msg);
   bool ParseRegisterAllocationStrategy(const std::string& option, std::string* error_msg);
@@ -408,6 +419,10 @@
   // Must not be empty for real boot image, only for tests pretending to compile boot image.
   HashSet<std::string> image_classes_;
 
+  // Classes listed in the preloaded-classes file, used for boot image and
+  // boot image extension compilation.
+  HashSet<std::string> preloaded_classes_;
+
   // Results of AOT verification.
   const VerificationResults* verification_results_;