Revert "Revert "Store resolved Strings for AOT code in .bss.""

Fixed oat_test to keep dex files alive. Fixed mips build.
Rewritten the .bss GC root visiting and added write barrier
to the artResolveStringFromCode().

Test: build aosp_mips-eng
Test: m ART_DEFAULT_GC_TYPE=SS test-art-target-host-gtest-oat_test
Test: Run ART test suite on host and Nexus 9.
Bug: 20323084
Bug: 30627598

This reverts commit 5f926055cb88089d8ca27243f35a9dfd89d981f0.

Change-Id: I07fa2278d82b8eb64964c9a4b66cb93726ccda6b
diff --git a/runtime/class_table-inl.h b/runtime/class_table-inl.h
index d52365d..3e54a64 100644
--- a/runtime/class_table-inl.h
+++ b/runtime/class_table-inl.h
@@ -18,6 +18,7 @@
 #define ART_RUNTIME_CLASS_TABLE_INL_H_
 
 #include "class_table.h"
+#include "oat_file.h"
 
 namespace art {
 
@@ -32,6 +33,11 @@
   for (GcRoot<mirror::Object>& root : strong_roots_) {
     visitor.VisitRoot(root.AddressWithoutBarrier());
   }
+  for (const OatFile* oat_file : oat_files_) {
+    for (GcRoot<mirror::Object>& root : oat_file->GetBssGcRoots()) {
+      visitor.VisitRootIfNonNull(root.AddressWithoutBarrier());
+    }
+  }
 }
 
 template<class Visitor>
@@ -45,6 +51,11 @@
   for (GcRoot<mirror::Object>& root : strong_roots_) {
     visitor.VisitRoot(root.AddressWithoutBarrier());
   }
+  for (const OatFile* oat_file : oat_files_) {
+    for (GcRoot<mirror::Object>& root : oat_file->GetBssGcRoots()) {
+      visitor.VisitRootIfNonNull(root.AddressWithoutBarrier());
+    }
+  }
 }
 
 template <typename Visitor>
diff --git a/runtime/class_table.cc b/runtime/class_table.cc
index 0600876..2ae7e8c 100644
--- a/runtime/class_table.cc
+++ b/runtime/class_table.cc
@@ -165,6 +165,16 @@
     }
   }
   strong_roots_.push_back(GcRoot<mirror::Object>(obj));
+  // If `obj` is a dex cache associated with a new oat file with GC roots, add it to oat_files_.
+  if (obj->IsDexCache()) {
+    const DexFile* dex_file = down_cast<mirror::DexCache*>(obj)->GetDexFile();
+    if (dex_file != nullptr && dex_file->GetOatDexFile() != nullptr) {
+      const OatFile* oat_file = dex_file->GetOatDexFile()->GetOatFile();
+      if (!oat_file->GetBssGcRoots().empty() && !ContainsElement(oat_files_, oat_file)) {
+        oat_files_.push_back(oat_file);
+      }
+    }
+  }
   return true;
 }
 
@@ -201,6 +211,7 @@
 
 void ClassTable::ClearStrongRoots() {
   WriterMutexLock mu(Thread::Current(), lock_);
+  oat_files_.clear();
   strong_roots_.clear();
 }
 }  // namespace art
diff --git a/runtime/class_table.h b/runtime/class_table.h
index 8c91806..acb15c7 100644
--- a/runtime/class_table.h
+++ b/runtime/class_table.h
@@ -32,6 +32,8 @@
 
 namespace art {
 
+class OatFile;
+
 namespace mirror {
   class ClassLoader;
 }  // namespace mirror
@@ -173,6 +175,8 @@
   // loader which may not be owned by the class loader must be held strongly live. Also dex caches
   // are held live to prevent them being unloading once they have classes in them.
   std::vector<GcRoot<mirror::Object>> strong_roots_ GUARDED_BY(lock_);
+  // Keep track of oat files with GC roots associated with dex caches in `strong_roots_`.
+  std::vector<const OatFile*> oat_files_ GUARDED_BY(lock_);
 
   friend class ImageWriter;  // for InsertWithoutLocks.
 };
diff --git a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
index 2cd0331..4311d19 100644
--- a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
@@ -18,10 +18,15 @@
 #include "callee_save_frame.h"
 #include "entrypoints/entrypoint_utils-inl.h"
 #include "class_linker-inl.h"
+#include "class_table-inl.h"
 #include "dex_file-inl.h"
-#include "gc/accounting/card_table-inl.h"
+#include "gc/heap.h"
+#include "mirror/class-inl.h"
+#include "mirror/class_loader.h"
 #include "mirror/object_array-inl.h"
 #include "mirror/object-inl.h"
+#include "oat_file.h"
+#include "runtime.h"
 
 namespace art {
 
@@ -56,7 +61,20 @@
     REQUIRES_SHARED(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
   auto* caller = GetCalleeSaveMethodCaller(self, Runtime::kSaveRefsOnly);
-  return ResolveStringFromCode(caller, string_idx);
+  mirror::String* result = ResolveStringFromCode(caller, string_idx);
+  if (LIKELY(result != nullptr)) {
+    // For AOT code, we need a write barrier for the dex cache that holds the GC roots in the .bss.
+    const DexFile* dex_file = caller->GetDexFile();
+    if (dex_file != nullptr &&
+        dex_file->GetOatDexFile() != nullptr &&
+        !dex_file->GetOatDexFile()->GetOatFile()->GetBssGcRoots().empty()) {
+      mirror::ClassLoader* class_loader = caller->GetDeclaringClass()->GetClassLoader();
+      // Note that we emit the barrier before the compiled code stores the string as GC root.
+      // This is OK as there is no suspend point point in between.
+      Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader);
+    }
+  }
+  return result;
 }
 
 }  // namespace art
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index ea692cd..5f37b82 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());
@@ -1121,6 +1148,16 @@
   return kIsVdexEnabled ? vdex_->End() : End();
 }
 
+ArrayRef<GcRoot<mirror::Object>> OatFile::GetBssGcRoots() const {
+  if (bss_roots_ != nullptr) {
+    auto* roots = reinterpret_cast<GcRoot<mirror::Object>*>(bss_roots_);
+    auto* roots_end = reinterpret_cast<GcRoot<mirror::Object>*>(bss_end_);
+    return ArrayRef<GcRoot<mirror::Object>>(roots, roots_end - roots);
+  } else {
+    return ArrayRef<GcRoot<mirror::Object>>();
+  }
+}
+
 const OatFile::OatDexFile* OatFile::GetOatDexFile(const char* dex_location,
                                                   const uint32_t* dex_location_checksum,
                                                   std::string* error_msg) const {
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index a61b941..c3188cb 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();
   }
@@ -266,6 +272,8 @@
   const uint8_t* DexBegin() const;
   const uint8_t* DexEnd() const;
 
+  ArrayRef<GcRoot<mirror::Object>> GetBssGcRoots() const;
+
   // Returns the absolute dex location for the encoded relative dex location.
   //
   // If not null, abs_dex_location is used to resolve the absolute dex
@@ -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_;