Group dirty images objects together in the image.

Adds --dirty-image-objects switch to dex2oat to pass to image writer,
which takes in a list of dirty objects dumped by the new imgdump switch
--dump-dirty-objects. Currently that list of dirty objects contains
classes with dirty static fields.

Bins these classes into kBinKnownDirty, which are image objects that are
known to be dirty.

Measured fewer dirty pages at runtime via showmap:
systemui private dirty memory (kB):
492 -> 352 in boot-framework.art
204 -> 192 in boot.art
 96 ->  88 in boot-core-libart.art
systemserver private dirty memory (kB):
412 -> 304 in boot-framework.art
148 -> 132 in boot.art
100 ->  96 in boot-core-libart.art

Bug: 62554875
Test: mm test-art-host
Change-Id: If8293da07a97a2051c33890faa9b5d3b283b8e6d
diff --git a/compiler/image_test.h b/compiler/image_test.h
index 57d0987..daa4b11 100644
--- a/compiler/image_test.h
+++ b/compiler/image_test.h
@@ -214,7 +214,8 @@
                                                       /*compile_app_image*/false,
                                                       storage_mode,
                                                       oat_filename_vector,
-                                                      dex_file_to_oat_index_map));
+                                                      dex_file_to_oat_index_map,
+                                                      /*dirty_image_objects*/nullptr));
   {
     {
       jobject class_loader = nullptr;
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index f4e8a89..9e4971c 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -579,7 +579,12 @@
         }
       }
 
-      if (klass->GetStatus() == Class::kStatusInitialized) {
+      // Move known dirty objects into their own sections. This includes:
+      //   - classes with dirty static fields.
+      if (dirty_image_objects_ != nullptr &&
+          dirty_image_objects_->find(klass->PrettyDescriptor()) != dirty_image_objects_->end()) {
+        bin = kBinKnownDirty;
+      } else if (klass->GetStatus() == Class::kStatusInitialized) {
         bin = kBinClassInitialized;
 
         // If the class's static fields are all final, put it into a separate bin
@@ -2774,7 +2779,8 @@
     bool compile_app_image,
     ImageHeader::StorageMode image_storage_mode,
     const std::vector<const char*>& oat_filenames,
-    const std::unordered_map<const DexFile*, size_t>& dex_file_oat_index_map)
+    const std::unordered_map<const DexFile*, size_t>& dex_file_oat_index_map,
+    const std::unordered_set<std::string>* dirty_image_objects)
     : compiler_driver_(compiler_driver),
       global_image_begin_(reinterpret_cast<uint8_t*>(image_begin)),
       image_objects_offset_begin_(0),
@@ -2786,7 +2792,8 @@
       clean_methods_(0u),
       image_storage_mode_(image_storage_mode),
       oat_filenames_(oat_filenames),
-      dex_file_oat_index_map_(dex_file_oat_index_map) {
+      dex_file_oat_index_map_(dex_file_oat_index_map),
+      dirty_image_objects_(dirty_image_objects) {
   CHECK_NE(image_begin, 0U);
   std::fill_n(image_methods_, arraysize(image_methods_), nullptr);
   CHECK_EQ(compile_app_image, !Runtime::Current()->GetHeap()->GetBootImageSpaces().empty())
diff --git a/compiler/image_writer.h b/compiler/image_writer.h
index 34bbbad..866e204 100644
--- a/compiler/image_writer.h
+++ b/compiler/image_writer.h
@@ -75,7 +75,8 @@
               bool compile_app_image,
               ImageHeader::StorageMode image_storage_mode,
               const std::vector<const char*>& oat_filenames,
-              const std::unordered_map<const DexFile*, size_t>& dex_file_oat_index_map);
+              const std::unordered_map<const DexFile*, size_t>& dex_file_oat_index_map,
+              const std::unordered_set<std::string>* dirty_image_objects);
 
   bool PrepareImageAddressSpace();
 
@@ -159,6 +160,7 @@
   // Classify different kinds of bins that objects end up getting packed into during image writing.
   // Ordered from dirtiest to cleanest (until ArtMethods).
   enum Bin {
+    kBinKnownDirty,               // Known dirty objects from --dirty-image-objects list
     kBinMiscDirty,                // Dex caches, object locks, etc...
     kBinClassVerified,            // Class verified, but initializers haven't been run
     // Unknown mix of clean/dirty:
@@ -599,6 +601,9 @@
   // Map of dex files to the indexes of oat files that they were compiled into.
   const std::unordered_map<const DexFile*, size_t>& dex_file_oat_index_map_;
 
+  // Set of objects known to be dirty in the image. Can be nullptr if there are none.
+  const std::unordered_set<std::string>* dirty_image_objects_;
+
   class ComputeLazyFieldsForClassesVisitor;
   class FixupClassVisitor;
   class FixupRootVisitor;