ART: Add classes having intrinsics to boot image

Classes, which have intrinsics methods but are not in
boot-image-profile.txt, are not included into the boot image.
This causes the list of intrinsics to be a mix of methods from
the boot image and the framework. Intrinsics methods from the boot
image are already marked as intrinsics. Intrinsics methods from the
framework are not marked. The current implementation of InitializeIntrinsics
stops initializing intrinsics when it encounters an initialized
intrinsic on the list. This means uninitialized intrinsics must be
at the beginning of the list. Otherwise they won't be initialized.

Instead of rearranging the list, the CL adds classes having intrinsics
methods to the boot image. This guarantees all intrinsics to be marked.
The CL also adds DCHECK to InitializeIntrinsics to check that all
intrinsics have been initialized.

Test: test.py --host --optimizing --jit --gtest --interpreter
Test: test.py --target --optimizing --jit --interpreter
Test: run-gtests.sh
Change-Id: I82bc840bc2c07d3e4e527ee6e1f76c2015c59c21
diff --git a/dex2oat/driver/compiler_driver.cc b/dex2oat/driver/compiler_driver.cc
index 31e78aa..40b999b 100644
--- a/dex2oat/driver/compiler_driver.cc
+++ b/dex2oat/driver/compiler_driver.cc
@@ -63,6 +63,7 @@
 #include "gc/space/space.h"
 #include "handle_scope-inl.h"
 #include "intrinsics_enum.h"
+#include "intrinsics_list.h"
 #include "jni/jni_internal.h"
 #include "linker/linker_patch.h"
 #include "mirror/class-inl.h"
@@ -331,12 +332,6 @@
 
   CheckThreadPools();
 
-  if (GetCompilerOptions().IsBootImage()) {
-    // All intrinsics must be in the primary boot image, so we don't need to setup
-    // the intrinsics for any other compilation, as those compilations will pick up
-    // a boot image that have the ArtMethod already set with the intrinsics flag.
-    InitializeIntrinsics();
-  }
   // Compile:
   // 1) Compile all classes and methods enabled for compilation. May fall back to dex-to-dex
   //    compilation.
@@ -1069,6 +1064,15 @@
   HashSet<std::string>* const image_classes_;
 };
 
+// Add classes which contain intrinsics methods to the list of image classes.
+static void AddClassesContainingIntrinsics(/* out */ HashSet<std::string>* image_classes) {
+#define ADD_INTRINSIC_OWNER_CLASS(_, __, ___, ____, _____, ClassName, ______, _______) \
+  image_classes->insert(ClassName);
+
+  INTRINSICS_LIST(ADD_INTRINSIC_OWNER_CLASS)
+#undef ADD_INTRINSIC_OWNER_CLASS
+}
+
 // Make a list of descriptors for classes to include in the image
 void CompilerDriver::LoadImageClasses(TimingLogger* timings,
                                       /*inout*/ HashSet<std::string>* image_classes) {
@@ -1093,6 +1097,16 @@
   }
 
   TimingLogger::ScopedTiming t("LoadImageClasses", timings);
+
+  if (GetCompilerOptions().IsBootImage()) {
+    AddClassesContainingIntrinsics(image_classes);
+
+    // All intrinsics must be in the primary boot image, so we don't need to setup
+    // the intrinsics for any other compilation, as those compilations will pick up
+    // a boot image that have the ArtMethod already set with the intrinsics flag.
+    InitializeIntrinsics();
+  }
+
   // Make a first pass to load all classes explicitly listed in the file
   Thread* self = Thread::Current();
   ScopedObjectAccess soa(self);
diff --git a/runtime/runtime_intrinsics.cc b/runtime/runtime_intrinsics.cc
index 3295a86..1672c49 100644
--- a/runtime/runtime_intrinsics.cc
+++ b/runtime/runtime_intrinsics.cc
@@ -20,6 +20,7 @@
 #include "class_linker.h"
 #include "dex/invoke_type.h"
 #include "intrinsics_enum.h"
+#include "intrinsics_list.h"
 #include "mirror/class.h"
 #include "runtime.h"
 #include "scoped_thread_state_change-inl.h"
@@ -29,14 +30,10 @@
 
 namespace {
 
-// Initialize an intrinsic. Returns true if the intrinsic is already
-// initialized, false otherwise.
-bool InitializeIntrinsic(Thread* self,
-                         Intrinsics intrinsic,
-                         InvokeType invoke_type,
-                         const char* class_name,
-                         const char* method_name,
-                         const char* signature)
+ArtMethod* FindIntrinsicMethod(Thread* self,
+                               const char* class_name,
+                               const char* method_name,
+                               const char* signature)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   PointerSize image_size = class_linker->GetImagePointerSize();
@@ -50,6 +47,19 @@
     LOG(FATAL) << "Could not find method of intrinsic "
                << class_name << " " << method_name << " " << signature;
   }
+  return method;
+}
+
+// Initialize an intrinsic. Returns true if the intrinsic is already
+// initialized, false otherwise.
+bool InitializeIntrinsic(Thread* self,
+                         Intrinsics intrinsic,
+                         InvokeType invoke_type,
+                         const char* class_name,
+                         const char* method_name,
+                         const char* signature)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  ArtMethod* method = FindIntrinsicMethod(self, class_name, method_name, signature);
 
   CHECK_EQ(method->GetInvokeType(), invoke_type);
   if (method->IsIntrinsic()) {
@@ -61,24 +71,55 @@
   }
 }
 
+// Returns true if the intrinsic is already initialized, false otherwise.
+bool IsIntrinsicInitialized(Thread* self,
+                            Intrinsics intrinsic,
+                            InvokeType invoke_type,
+                            const char* class_name,
+                            const char* method_name,
+                            const char* signature)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  ArtMethod* method = FindIntrinsicMethod(self, class_name, method_name, signature);
+
+  CHECK_EQ(method->GetInvokeType(), invoke_type);
+  if (method->IsIntrinsic()) {
+    CHECK_EQ(method->GetIntrinsic(), static_cast<uint32_t>(intrinsic));
+    return true;
+  } else {
+    return false;
+  }
+}
+
+bool AreAllIntrinsicsInitialized() {
+  ScopedObjectAccess soa(Thread::Current());
+#define IS_INTRINSIC_INITIALIZED(Name, InvokeType, _, __, ___, ClassName, MethodName, Signature) \
+  IsIntrinsicInitialized(soa.Self(),                                                             \
+                         Intrinsics::k##Name,                                                    \
+                         InvokeType,                                                             \
+                         ClassName,                                                              \
+                         MethodName,                                                             \
+                         Signature) &&
+  bool result = INTRINSICS_LIST(IS_INTRINSIC_INITIALIZED) true;
+#undef IS_INTRINSIC_INITIALIZED
+  return result;
+}
+
 }  // namespace
 
 void InitializeIntrinsics() {
   ScopedObjectAccess soa(Thread::Current());
   // Initialization here uses the short-circuit operator || to stop
   // initializing if there's an already initialized intrinsic.
-#define SETUP_INTRINSICS(Name, InvokeType, _, __, ___, ClassName, MethodName, Signature) \
-  InitializeIntrinsic(soa.Self(),                                                        \
-                      Intrinsics::k##Name,                                               \
-                      InvokeType,                                                        \
-                      ClassName,                                                         \
-                      MethodName,                                                        \
+#define INITIALIZE_INTRINSIC(Name, InvokeType, _, __, ___, ClassName, MethodName, Signature) \
+  InitializeIntrinsic(soa.Self(),                                                            \
+                      Intrinsics::k##Name,                                                   \
+                      InvokeType,                                                            \
+                      ClassName,                                                             \
+                      MethodName,                                                            \
                       Signature) ||
-#include "intrinsics_list.h"
-  INTRINSICS_LIST(SETUP_INTRINSICS)
-#undef INTRINSICS_LIST
-#undef SETUP_INTRINSICS
-      true;
+  INTRINSICS_LIST(INITIALIZE_INTRINSIC) true;
+#undef INITIALIZE_INTRINSIC
+  DCHECK(AreAllIntrinsicsInitialized());
 }
 
 }  // namespace art