Implement HLoadClass/kBssEntry for boot image.

Test: m test-art-host
Test: m test-art-host with CC
Test: m test-art-target on Nexus 9
Test: Nexus 9 boots.
Test: Build aosp_mips64-eng
Bug: 30627598
Change-Id: I168f24dedd5fb54a1e4215ecafb947ffb0dc3280
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index bb88d72..129c93f 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -351,7 +351,7 @@
       array_iftable_(nullptr),
       find_array_class_cache_next_victim_(0),
       init_done_(false),
-      log_new_class_table_roots_(false),
+      log_new_roots_(false),
       intern_table_(intern_table),
       quick_resolution_trampoline_(nullptr),
       quick_imt_conflict_trampoline_(nullptr),
@@ -1865,12 +1865,10 @@
                     << reinterpret_cast<const void*>(section_end);
       }
     }
-    if (!oat_file->GetBssGcRoots().empty()) {
-      // Insert oat file to class table for visiting .bss GC roots.
-      class_table->InsertOatFile(oat_file);
-    }
-  } else {
-    DCHECK(oat_file->GetBssGcRoots().empty());
+  }
+  if (!oat_file->GetBssGcRoots().empty()) {
+    // Insert oat file to class table for visiting .bss GC roots.
+    class_table->InsertOatFile(oat_file);
   }
   if (added_class_table) {
     WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
@@ -1934,14 +1932,27 @@
       // Concurrent moving GC marked new roots through the to-space invariant.
       CHECK_EQ(new_ref, old_ref);
     }
+    for (const OatFile* oat_file : new_bss_roots_boot_oat_files_) {
+      for (GcRoot<mirror::Object>& root : oat_file->GetBssGcRoots()) {
+        ObjPtr<mirror::Object> old_ref = root.Read<kWithoutReadBarrier>();
+        if (old_ref != nullptr) {
+          DCHECK(old_ref->IsClass());
+          root.VisitRoot(visitor, RootInfo(kRootStickyClass));
+          ObjPtr<mirror::Object> new_ref = root.Read<kWithoutReadBarrier>();
+          // Concurrent moving GC marked new roots through the to-space invariant.
+          CHECK_EQ(new_ref, old_ref);
+        }
+      }
+    }
   }
   if ((flags & kVisitRootFlagClearRootLog) != 0) {
     new_class_roots_.clear();
+    new_bss_roots_boot_oat_files_.clear();
   }
   if ((flags & kVisitRootFlagStartLoggingNewRoots) != 0) {
-    log_new_class_table_roots_ = true;
+    log_new_roots_ = true;
   } else if ((flags & kVisitRootFlagStopLoggingNewRoots) != 0) {
-    log_new_class_table_roots_ = false;
+    log_new_roots_ = false;
   }
   // We deliberately ignore the class roots in the image since we
   // handle image roots by using the MS/CMS rescanning of dirty cards.
@@ -3652,7 +3663,7 @@
       // This is necessary because we need to have the card dirtied for remembered sets.
       Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader);
     }
-    if (log_new_class_table_roots_) {
+    if (log_new_roots_) {
       new_class_roots_.push_back(GcRoot<mirror::Class>(klass));
     }
   }
@@ -3665,6 +3676,14 @@
   return nullptr;
 }
 
+void ClassLinker::WriteBarrierForBootOatFileBssRoots(const OatFile* oat_file) {
+  WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+  DCHECK(!oat_file->GetBssGcRoots().empty()) << oat_file->GetLocation();
+  if (log_new_roots_ && !ContainsElement(new_bss_roots_boot_oat_files_, oat_file)) {
+    new_bss_roots_boot_oat_files_.push_back(oat_file);
+  }
+}
+
 // TODO This should really be in mirror::Class.
 void ClassLinker::UpdateClassMethods(ObjPtr<mirror::Class> klass,
                                      LengthPrefixedArray<ArtMethod>* new_methods) {
@@ -5162,7 +5181,7 @@
         Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader);
       }
       CHECK_EQ(existing, klass.Get());
-      if (log_new_class_table_roots_) {
+      if (log_new_roots_) {
         new_class_roots_.push_back(GcRoot<mirror::Class>(h_new_class.Get()));
       }
     }
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 77322ed..580acb7 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -64,6 +64,7 @@
 template<typename T> class LengthPrefixedArray;
 template<class T> class MutableHandle;
 class InternTable;
+class OatFile;
 template<class T> class ObjectLock;
 class Runtime;
 class ScopedObjectAccessAlreadyRunnable;
@@ -535,6 +536,12 @@
       REQUIRES(!Locks::classlinker_classes_lock_)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
+  // Add an oat file with .bss GC roots to be visited again at the end of GC
+  // for collector types that need it.
+  void WriteBarrierForBootOatFileBssRoots(const OatFile* oat_file)
+      REQUIRES(!Locks::classlinker_classes_lock_)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
   mirror::ObjectArray<mirror::Class>* GetClassRoots() REQUIRES_SHARED(Locks::mutator_lock_) {
     mirror::ObjectArray<mirror::Class>* class_roots = class_roots_.Read();
     DCHECK(class_roots != nullptr);
@@ -1138,6 +1145,10 @@
   // New class roots, only used by CMS since the GC needs to mark these in the pause.
   std::vector<GcRoot<mirror::Class>> new_class_roots_ GUARDED_BY(Locks::classlinker_classes_lock_);
 
+  // Boot image oat files with new .bss GC roots to be visited in the pause by CMS.
+  std::vector<const OatFile*> new_bss_roots_boot_oat_files_
+      GUARDED_BY(Locks::classlinker_classes_lock_);
+
   // Number of times we've searched dex caches for a class. After a certain number of misses we move
   // the classes into the class_table_ to avoid dex cache based searches.
   Atomic<uint32_t> failed_dex_cache_class_lookups_;
@@ -1155,7 +1166,7 @@
   size_t find_array_class_cache_next_victim_;
 
   bool init_done_;
-  bool log_new_class_table_roots_ GUARDED_BY(Locks::classlinker_classes_lock_);
+  bool log_new_roots_ GUARDED_BY(Locks::classlinker_classes_lock_);
 
   InternTable* intern_table_;
 
diff --git a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
index 63340c0..5b1b287 100644
--- a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
@@ -39,13 +39,17 @@
       dex_file->GetOatDexFile() != nullptr &&
       !dex_file->GetOatDexFile()->GetOatFile()->GetBssGcRoots().empty()) {
     mirror::ClassLoader* class_loader = outer_method->GetClassLoader();
-    DCHECK(class_loader != nullptr);  // We do not use .bss GC roots for boot image.
-    DCHECK(!class_loader->GetClassTable()->InsertOatFile(dex_file->GetOatDexFile()->GetOatFile()))
-        << "Oat file with .bss GC roots was not registered in class table: "
-        << dex_file->GetOatDexFile()->GetOatFile()->GetLocation();
-    // Note that we emit the barrier before the compiled code stores the String or Class
-    // as a GC root. This is OK as there is no suspend point point in between.
-    Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader);
+    if (class_loader != nullptr) {
+      DCHECK(!class_loader->GetClassTable()->InsertOatFile(dex_file->GetOatDexFile()->GetOatFile()))
+          << "Oat file with .bss GC roots was not registered in class table: "
+          << dex_file->GetOatDexFile()->GetOatFile()->GetLocation();
+      // Note that we emit the barrier before the compiled code stores the String or Class
+      // as a GC root. This is OK as there is no suspend point point in between.
+      Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader);
+    } else {
+      Runtime::Current()->GetClassLinker()->WriteBarrierForBootOatFileBssRoots(
+          dex_file->GetOatDexFile()->GetOatFile());
+    }
   }
 }
 
diff --git a/runtime/oat.h b/runtime/oat.h
index 685aa04..f2d457c 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,7 +32,7 @@
 class PACKED(4) OatHeader {
  public:
   static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
-  static constexpr uint8_t kOatVersion[] = { '0', '9', '6', '\0' };  // invoke-polymorphic entry
+  static constexpr uint8_t kOatVersion[] = { '0', '9', '7', '\0' };  // HLoadClass/kBssEntry change
 
   static constexpr const char* kImageLocationKey = "image-location";
   static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 38df427..d47f1b5 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -323,8 +323,10 @@
   }
 
   PointerSize pointer_size = GetInstructionSetPointerSize(GetOatHeader().GetInstructionSet());
-  uint8_t* dex_cache_arrays = bss_begin_;
-  uint8_t* dex_cache_arrays_end = (bss_roots_ != nullptr) ? bss_roots_ : bss_end_;
+  uint8_t* dex_cache_arrays = (bss_begin_ == bss_roots_) ? nullptr : bss_begin_;
+  uint8_t* dex_cache_arrays_end =
+      (bss_begin_ == bss_roots_) ? nullptr : (bss_roots_ != nullptr) ? bss_roots_ : bss_end_;
+  DCHECK_EQ(dex_cache_arrays != nullptr, dex_cache_arrays_end != nullptr);
   uint32_t dex_file_count = GetOatHeader().GetDexFileCount();
   oat_dex_files_storage_.reserve(dex_file_count);
   for (size_t i = 0; i < dex_file_count; i++) {