Store resolved Strings for AOT code in .bss.

And do some related refactorings.

Bug: 20323084
Bug: 30627598
Test: Run ART test suite including gcstress on host and Nexus 9.
Test: Run ART test suite including gcstress with baker CC on host and Nexus 9.
Test: Build aosp_mips64-eng.
Change-Id: I1b12c1570fee8e5da490b47f231050142afcbd1e
diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h
index 220979a..30bf390 100644
--- a/runtime/mirror/dex_cache-inl.h
+++ b/runtime/mirror/dex_cache-inl.h
@@ -25,6 +25,7 @@
 #include "base/enums.h"
 #include "base/logging.h"
 #include "mirror/class.h"
+#include "oat_file.h"
 #include "runtime.h"
 
 #include <atomic>
@@ -167,6 +168,11 @@
     for (size_t i = 0, num_types = NumResolvedTypes(); i != num_types; ++i) {
       visitor.VisitRootIfNonNull(resolved_types[i].AddressWithoutBarrier());
     }
+    if (GetDexFile() != nullptr && GetDexFile()->GetOatDexFile() != nullptr) {
+      for (GcRoot<Object>& root : OatFile::GetBssRoots(GetDexFile()->GetOatDexFile())) {
+        visitor.VisitRootIfNonNull(root.AddressWithoutBarrier());
+      }
+    }
   }
 }
 
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index ea692cd..52baddd 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -40,6 +40,7 @@
 #include "base/unix_file/fd_file.h"
 #include "elf_file.h"
 #include "elf_utils.h"
+#include "gc_root.h"
 #include "oat.h"
 #include "mem_map.h"
 #include "mirror/class.h"
@@ -239,6 +240,8 @@
     }
     // Readjust to be non-inclusive upper bound.
     bss_end_ += sizeof(uint32_t);
+    // Find bss roots if present.
+    bss_roots_ = const_cast<uint8_t*>(FindDynamicSymbolAddress("oatbssroots", &symbol_error_msg));
   }
 
   return true;
@@ -291,8 +294,31 @@
     return false;
   }
 
+  if (!IsAligned<alignof(GcRoot<mirror::Object>)>(bss_begin_) ||
+      !IsAligned<alignof(GcRoot<mirror::Object>)>(bss_roots_) ||
+      !IsAligned<alignof(GcRoot<mirror::Object>)>(bss_end_)) {
+    *error_msg = StringPrintf("In oat file '%s' found unaligned bss symbol(s): "
+                                  "begin = %p, roots = %p, end = %p",
+                              GetLocation().c_str(),
+                              bss_begin_,
+                              bss_roots_,
+                              bss_end_);
+    return false;
+  }
+
+  if (bss_roots_ != nullptr && (bss_roots_ < bss_begin_ || bss_roots_ > bss_end_)) {
+    *error_msg = StringPrintf("In oat file '%s' found bss roots outside .bss: "
+                                  "%p is outside range [%p, %p]",
+                              GetLocation().c_str(),
+                              bss_roots_,
+                              bss_begin_,
+                              bss_end_);
+    return false;
+  }
+
   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_;
   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++) {
@@ -469,13 +495,13 @@
     if (dex_cache_arrays != nullptr) {
       DexCacheArraysLayout layout(pointer_size, *header);
       if (layout.Size() != 0u) {
-        if (static_cast<size_t>(bss_end_ - dex_cache_arrays) < layout.Size()) {
+        if (static_cast<size_t>(dex_cache_arrays_end - dex_cache_arrays) < layout.Size()) {
           *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with "
                                         "truncated dex cache arrays, %zu < %zu.",
                                     GetLocation().c_str(),
                                     i,
                                     dex_file_location.c_str(),
-                                    static_cast<size_t>(bss_end_ - dex_cache_arrays),
+                                    static_cast<size_t>(dex_cache_arrays_end - dex_cache_arrays),
                                     layout.Size());
           return false;
         }
@@ -506,9 +532,9 @@
     }
   }
 
-  if (dex_cache_arrays != bss_end_) {
+  if (dex_cache_arrays != dex_cache_arrays_end) {
     // We expect the bss section to be either empty (dex_cache_arrays and bss_end_
-    // both null) or contain just the dex cache arrays and nothing else.
+    // both null) or contain just the dex cache arrays and optionally some GC roots.
     *error_msg = StringPrintf("In oat file '%s' found unexpected bss size bigger by %zu bytes.",
                               GetLocation().c_str(),
                               static_cast<size_t>(bss_end_ - dex_cache_arrays));
@@ -1082,6 +1108,7 @@
       end_(nullptr),
       bss_begin_(nullptr),
       bss_end_(nullptr),
+      bss_roots_(nullptr),
       is_executable_(is_executable),
       secondary_lookup_lock_("OatFile secondary lookup lock", kOatFileSecondaryLookupLock) {
   CHECK(!location_.empty());
@@ -1497,4 +1524,18 @@
   return true;
 }
 
+ArrayRef<GcRoot<mirror::Object>> OatFile::GetBssRoots(const OatDexFile* oat_dex_file) {
+  const OatFile* oat_file = oat_dex_file->GetOatFile();
+  DCHECK(ContainsElement(oat_file->oat_dex_files_storage_, oat_dex_file));
+  // Arbitrarily attribute all the roots to the first oat_dex_file.
+  if (oat_file->bss_roots_ != nullptr &&
+      oat_file->oat_dex_files_storage_.front() == oat_dex_file) {
+    auto* roots = reinterpret_cast<GcRoot<mirror::Object>*>(oat_file->bss_roots_);
+    auto* roots_end = reinterpret_cast<GcRoot<mirror::Object>*>(oat_file->bss_end_);
+    return ArrayRef<GcRoot<mirror::Object>>(roots, roots_end - roots);
+  } else {
+    return ArrayRef<GcRoot<mirror::Object>>();
+  }
+}
+
 }  // namespace art
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index a61b941..a4aef3a 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -21,6 +21,7 @@
 #include <string>
 #include <vector>
 
+#include "base/array_ref.h"
 #include "base/mutex.h"
 #include "base/stringpiece.h"
 #include "dex_file.h"
@@ -38,6 +39,7 @@
 
 class BitVector;
 class ElfFile;
+template <class MirrorType> class GcRoot;
 class MemMap;
 class OatMethodOffsets;
 class OatHeader;
@@ -253,6 +255,10 @@
     return BssEnd() - BssBegin();
   }
 
+  size_t BssRootsOffset() const {
+    return bss_roots_ - BssBegin();
+  }
+
   size_t DexSize() const {
     return DexEnd() - DexBegin();
   }
@@ -290,6 +296,8 @@
   static bool GetDexLocationsFromDependencies(const char* dex_dependencies,
                                               std::vector<std::string>* locations);
 
+  static ArrayRef<GcRoot<mirror::Object>> GetBssRoots(const OatDexFile* oat_dex_file);
+
  protected:
   OatFile(const std::string& filename, bool executable);
 
@@ -314,6 +322,9 @@
   // Pointer to the end of the .bss section, if present, otherwise null.
   uint8_t* bss_end_;
 
+  // Pointer to the beginning of the GC roots in .bss section, if present, otherwise null.
+  uint8_t* bss_roots_;
+
   // Was this oat_file loaded executable?
   const bool is_executable_;