Add PreResolved strings dex cache array

For app images, this dex cache may be prepopulated to speed up
application startup. This new dex cache array is created when
--resolve-startup-const-strings=true.

Test: test-art-host
Bug: 116059983
Bug: 118385560

Change-Id: I379dc15174281665d7f4ceb106f7fbf51f89b921
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index e240167..9b45b48 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1415,9 +1415,9 @@
   for (size_t offset_index = 0; offset_index < num_string_offsets; ++offset_index) {
     uint32_t base_offset = sro_base[offset_index].first;
 
-    if (HasDexCacheNativeRefTag(base_offset)) {
-      base_offset = ClearDexCacheNativeRefTag(base_offset);
-      DCHECK_ALIGNED(base_offset,  2);
+    if (HasDexCacheStringNativeRefTag(base_offset)) {
+      base_offset = ClearDexCacheNativeRefTags(base_offset);
+      DCHECK_ALIGNED(base_offset, 2);
 
       ObjPtr<mirror::DexCache> dex_cache =
           reinterpret_cast<mirror::DexCache*>(space->Begin() + base_offset);
@@ -1437,10 +1437,27 @@
         dex_cache->GetStrings()[string_index].store(
             mirror::StringDexCachePair(it->second, source.index));
       }
+    } else if (HasDexCachePreResolvedStringNativeRefTag(base_offset)) {
+      base_offset = ClearDexCacheNativeRefTags(base_offset);
+      DCHECK_ALIGNED(base_offset, 2);
 
+      ObjPtr<mirror::DexCache> dex_cache =
+          reinterpret_cast<mirror::DexCache*>(space->Begin() + base_offset);
+      uint32_t string_index = sro_base[offset_index].second;
+
+      ObjPtr<mirror::String> referred_string =
+          dex_cache->GetPreResolvedStrings()[string_index].Read();
+      DCHECK(referred_string != nullptr);
+
+      auto it = intern_remap.find(referred_string.Ptr());
+      if (it != intern_remap.end()) {
+        // Because we are not using a helper function we need to mark the GC card manually.
+        WriteBarrier::ForEveryFieldWrite(dex_cache);
+        dex_cache->GetPreResolvedStrings()[string_index] = GcRoot<mirror::String>(it->second);
+      }
     } else {
       uint32_t raw_member_offset = sro_base[offset_index].second;
-      DCHECK_ALIGNED(base_offset,  2);
+      DCHECK_ALIGNED(base_offset, 2);
       DCHECK_ALIGNED(raw_member_offset, 2);
 
       ObjPtr<mirror::Object> obj_ptr =
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 91636dc..56fdd06 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -662,12 +662,14 @@
   DexCacheOffsets() : CheckOffsets<mirror::DexCache>(false, "Ljava/lang/DexCache;") {
     addOffset(OFFSETOF_MEMBER(mirror::DexCache, dex_file_), "dexFile");
     addOffset(OFFSETOF_MEMBER(mirror::DexCache, location_), "location");
+    addOffset(OFFSETOF_MEMBER(mirror::DexCache, num_preresolved_strings_), "numPreResolvedStrings");
     addOffset(OFFSETOF_MEMBER(mirror::DexCache, num_resolved_call_sites_), "numResolvedCallSites");
     addOffset(OFFSETOF_MEMBER(mirror::DexCache, num_resolved_fields_), "numResolvedFields");
     addOffset(OFFSETOF_MEMBER(mirror::DexCache, num_resolved_method_types_), "numResolvedMethodTypes");
     addOffset(OFFSETOF_MEMBER(mirror::DexCache, num_resolved_methods_), "numResolvedMethods");
     addOffset(OFFSETOF_MEMBER(mirror::DexCache, num_resolved_types_), "numResolvedTypes");
     addOffset(OFFSETOF_MEMBER(mirror::DexCache, num_strings_), "numStrings");
+    addOffset(OFFSETOF_MEMBER(mirror::DexCache, preresolved_strings_), "preResolvedStrings");
     addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_call_sites_), "resolvedCallSites");
     addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_fields_), "resolvedFields");
     addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_method_types_), "resolvedMethodTypes");
diff --git a/runtime/gc/accounting/space_bitmap.h b/runtime/gc/accounting/space_bitmap.h
index 6a3faef..fcc3007 100644
--- a/runtime/gc/accounting/space_bitmap.h
+++ b/runtime/gc/accounting/space_bitmap.h
@@ -151,6 +151,12 @@
   void VisitMarkedRange(uintptr_t visit_begin, uintptr_t visit_end, Visitor&& visitor) const
       NO_THREAD_SAFETY_ANALYSIS;
 
+  // Visit all of the set bits in HeapBegin(), HeapLimit().
+  template <typename Visitor>
+  void VisitAllMarked(Visitor&& visitor) const {
+    VisitMarkedRange(HeapBegin(), HeapLimit(), visitor);
+  }
+
   // Visits set bits in address order.  The callback is not permitted to change the bitmap bits or
   // max during the traversal.
   template <typename Visitor>
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 9e67957..db4a48c 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -1172,6 +1172,19 @@
           }
           dex_cache->FixupResolvedCallSites<kWithoutReadBarrier>(new_call_sites, fixup_adapter);
         }
+
+        GcRoot<mirror::String>* preresolved_strings = dex_cache->GetPreResolvedStrings();
+        if (preresolved_strings != nullptr) {
+          GcRoot<mirror::String>* new_array = fixup_adapter.ForwardObject(preresolved_strings);
+          if (preresolved_strings != new_array) {
+            dex_cache->SetPreResolvedStrings(new_array);
+          }
+          const size_t num_preresolved_strings = dex_cache->NumPreResolvedStrings();
+          for (size_t j = 0; j < num_preresolved_strings; ++j) {
+            new_array[j] = GcRoot<mirror::String>(
+                fixup_adapter(new_array[j].Read<kWithoutReadBarrier>()));
+          }
+        }
       }
     }
     {
@@ -1731,6 +1744,10 @@
           dex_cache,
           mirror::DexCache::ResolvedCallSitesOffset(),
           dex_cache->NumResolvedCallSites<kVerifyNone>());
+      FixupDexCacheArray<GcRoot<mirror::String>>(
+          dex_cache,
+          mirror::DexCache::PreResolvedStringsOffset(),
+          dex_cache->NumPreResolvedStrings<kVerifyNone>());
     }
 
    private:
@@ -1775,6 +1792,11 @@
       PatchGcRoot(diff_, &array[index]);
     }
 
+    void FixupDexCacheArrayEntry(GcRoot<mirror::String>* array, uint32_t index)
+        REQUIRES_SHARED(Locks::mutator_lock_) {
+      PatchGcRoot(diff_, &array[index]);
+    }
+
     template <typename EntryType>
     void FixupDexCacheArray(mirror::DexCache* dex_cache,
                             MemberOffset array_offset,
diff --git a/runtime/image.cc b/runtime/image.cc
index e7f4486..376742a 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -26,7 +26,7 @@
 namespace art {
 
 const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const uint8_t ImageHeader::kImageVersion[] = { '0', '6', '5', '\0' };  // Remove relocation section.
+const uint8_t ImageHeader::kImageVersion[] = { '0', '6', '6', '\0' };  // Add metadata section.
 
 ImageHeader::ImageHeader(uint32_t image_begin,
                          uint32_t image_size,
diff --git a/runtime/image.h b/runtime/image.h
index 0dec5f7..d925956 100644
--- a/runtime/image.h
+++ b/runtime/image.h
@@ -236,6 +236,7 @@
     kSectionInternedStrings,
     kSectionClassTable,
     kSectionStringReferenceOffsets,
+    kSectionMetadata,
     kSectionImageBitmap,
     kSectionCount,  // Number of elements in enum.
   };
@@ -293,6 +294,10 @@
     return GetImageSection(kSectionStringReferenceOffsets);
   }
 
+  const ImageSection& GetMetadataSection() const {
+    return GetImageSection(kSectionMetadata);
+  }
+
   const ImageSection& GetImageBitmapSection() const {
     return GetImageSection(kSectionImageBitmap);
   }
@@ -462,22 +467,45 @@
  * to managed objects and pointers to native reference arrays.
  */
 template<typename T>
-T SetDexCacheNativeRefTag(T val) {
+T SetDexCacheStringNativeRefTag(T val) {
   static_assert(std::is_integral<T>::value, "Expected integral type.");
 
   return val | 1u;
 }
 
 /*
+ * Tags the second last bit.  Used by AppImage logic to differentiate between pointers
+ * to managed objects and pointers to native reference arrays.
+ */
+template<typename T>
+T SetDexCachePreResolvedStringNativeRefTag(T val) {
+  static_assert(std::is_integral<T>::value, "Expected integral type.");
+
+  return val | 2u;
+}
+
+/*
  * Retrieves the value of the last bit.  Used by AppImage logic to
  * differentiate between pointers to managed objects and pointers to native
  * reference arrays.
  */
 template<typename T>
-bool HasDexCacheNativeRefTag(T val) {
+bool HasDexCacheStringNativeRefTag(T val) {
   static_assert(std::is_integral<T>::value, "Expected integral type.");
 
-  return (val & 1u) == 1u;
+  return (val & 1u) != 0u;
+}
+
+/*
+ * Retrieves the value of the second last bit.  Used by AppImage logic to
+ * differentiate between pointers to managed objects and pointers to native
+ * reference arrays.
+ */
+template<typename T>
+bool HasDexCachePreResolvedStringNativeRefTag(T val) {
+  static_assert(std::is_integral<T>::value, "Expected integral type.");
+
+  return (val & 2u) != 0u;
 }
 
 /*
@@ -486,10 +514,10 @@
  * reference arrays.
  */
 template<typename T>
-T ClearDexCacheNativeRefTag(T val) {
+T ClearDexCacheNativeRefTags(T val) {
   static_assert(std::is_integral<T>::value, "Expected integral type.");
 
-  return val & ~1u;
+  return val & ~3u;
 }
 
 std::ostream& operator<<(std::ostream& os, const ImageHeader::ImageMethod& policy);
diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h
index 13eaf3d..47b621a 100644
--- a/runtime/mirror/dex_cache-inl.h
+++ b/runtime/mirror/dex_cache-inl.h
@@ -84,6 +84,15 @@
 }
 
 inline String* DexCache::GetResolvedString(dex::StringIndex string_idx) {
+  const uint32_t num_preresolved_strings = NumPreResolvedStrings();
+  if (num_preresolved_strings != 0u) {
+    DCHECK_LT(string_idx.index_, num_preresolved_strings);
+    DCHECK_EQ(num_preresolved_strings, GetDexFile()->NumStringIds());
+    mirror::String* string = GetPreResolvedStrings()[string_idx.index_].Read();
+    if (LIKELY(string != nullptr)) {
+      return string;
+    }
+  }
   return GetStrings()[StringSlotIndex(string_idx)].load(
       std::memory_order_relaxed).GetObjectForIndex(string_idx.index_);
 }
@@ -101,6 +110,18 @@
   WriteBarrier::ForEveryFieldWrite(this);
 }
 
+inline void DexCache::SetPreResolvedString(dex::StringIndex string_idx,
+                                           ObjPtr<String> resolved) {
+  DCHECK(resolved != nullptr);
+  DCHECK_LT(string_idx.index_, GetDexFile()->NumStringIds());
+  GetPreResolvedStrings()[string_idx.index_] = GcRoot<mirror::String>(resolved);
+  Runtime* const runtime = Runtime::Current();
+  CHECK(runtime->IsAotCompiler());
+  CHECK(!runtime->IsActiveTransaction());
+  // TODO: Fine-grained marking, so that we don't need to go through all arrays in full.
+  WriteBarrier::ForEveryFieldWrite(this);
+}
+
 inline void DexCache::ClearString(dex::StringIndex string_idx) {
   DCHECK(Runtime::Current()->IsAotCompiler());
   uint32_t slot_idx = StringSlotIndex(string_idx);
@@ -344,6 +365,12 @@
     for (size_t i = 0; i != num_call_sites; ++i) {
       visitor.VisitRootIfNonNull(resolved_call_sites[i].AddressWithoutBarrier());
     }
+
+    GcRoot<mirror::String>* const preresolved_strings = GetPreResolvedStrings();
+    const size_t num_preresolved_strings = NumPreResolvedStrings();
+    for (size_t i = 0; i != num_preresolved_strings; ++i) {
+      visitor.VisitRootIfNonNull(preresolved_strings[i].AddressWithoutBarrier());
+    }
   }
 }
 
diff --git a/runtime/mirror/dex_cache.cc b/runtime/mirror/dex_cache.cc
index 661f954..8d2b838 100644
--- a/runtime/mirror/dex_cache.cc
+++ b/runtime/mirror/dex_cache.cc
@@ -172,6 +172,21 @@
                   dex_file->NumCallSiteIds());
 }
 
+void DexCache::AddPreResolvedStringsArray() {
+  DCHECK_EQ(NumPreResolvedStrings(), 0u);
+  Thread* const self = Thread::Current();
+  LinearAlloc* linear_alloc = Runtime::Current()->GetLinearAlloc();
+  const size_t num_strings = GetDexFile()->NumStringIds();
+  SetField32<false>(NumPreResolvedStringsOffset(), num_strings);
+  GcRoot<mirror::String>* strings =
+      linear_alloc->AllocArray<GcRoot<mirror::String>>(self, num_strings);
+  CHECK(strings != nullptr);
+  SetPreResolvedStrings(strings);
+  for (size_t i = 0; i < GetDexFile()->NumStringIds(); ++i) {
+    CHECK(GetPreResolvedStrings()[i].Read() == nullptr);
+  }
+}
+
 void DexCache::Init(const DexFile* dex_file,
                     ObjPtr<String> location,
                     StringDexCacheType* strings,
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index 6149f9c..58b199d 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -217,6 +217,10 @@
     return OFFSET_OF_OBJECT_MEMBER(DexCache, strings_);
   }
 
+  static constexpr MemberOffset PreResolvedStringsOffset() {
+    return OFFSET_OF_OBJECT_MEMBER(DexCache, preresolved_strings_);
+  }
+
   static constexpr MemberOffset ResolvedTypesOffset() {
     return OFFSET_OF_OBJECT_MEMBER(DexCache, resolved_types_);
   }
@@ -241,6 +245,10 @@
     return OFFSET_OF_OBJECT_MEMBER(DexCache, num_strings_);
   }
 
+  static constexpr MemberOffset NumPreResolvedStringsOffset() {
+    return OFFSET_OF_OBJECT_MEMBER(DexCache, num_preresolved_strings_);
+  }
+
   static constexpr MemberOffset NumResolvedTypesOffset() {
     return OFFSET_OF_OBJECT_MEMBER(DexCache, num_resolved_types_);
   }
@@ -261,12 +269,20 @@
     return OFFSET_OF_OBJECT_MEMBER(DexCache, num_resolved_call_sites_);
   }
 
+  static constexpr size_t PreResolvedStringsAlignment() {
+    return alignof(GcRoot<mirror::String>);
+  }
+
   String* GetResolvedString(dex::StringIndex string_idx) ALWAYS_INLINE
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   void SetResolvedString(dex::StringIndex string_idx, ObjPtr<mirror::String> resolved) ALWAYS_INLINE
       REQUIRES_SHARED(Locks::mutator_lock_);
 
+  void SetPreResolvedString(dex::StringIndex string_idx,
+                            ObjPtr<mirror::String> resolved)
+      ALWAYS_INLINE REQUIRES_SHARED(Locks::mutator_lock_);
+
   // Clear a string for a string_idx, used to undo string intern transactions to make sure
   // the string isn't kept live.
   void ClearString(dex::StringIndex string_idx) REQUIRES_SHARED(Locks::mutator_lock_);
@@ -318,10 +334,21 @@
     return GetFieldPtr64<StringDexCacheType*, kVerifyFlags>(StringsOffset());
   }
 
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  GcRoot<mirror::String>* GetPreResolvedStrings() ALWAYS_INLINE
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    return GetFieldPtr64<GcRoot<mirror::String>*, kVerifyFlags>(PreResolvedStringsOffset());
+  }
+
   void SetStrings(StringDexCacheType* strings) ALWAYS_INLINE REQUIRES_SHARED(Locks::mutator_lock_) {
     SetFieldPtr<false>(StringsOffset(), strings);
   }
 
+  void SetPreResolvedStrings(GcRoot<mirror::String>* strings)
+      ALWAYS_INLINE REQUIRES_SHARED(Locks::mutator_lock_) {
+    SetFieldPtr<false>(PreResolvedStringsOffset(), strings);
+  }
+
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   TypeDexCacheType* GetResolvedTypes() ALWAYS_INLINE REQUIRES_SHARED(Locks::mutator_lock_) {
     return GetFieldPtr<TypeDexCacheType*, kVerifyFlags>(ResolvedTypesOffset());
@@ -384,6 +411,11 @@
   }
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  size_t NumPreResolvedStrings() REQUIRES_SHARED(Locks::mutator_lock_) {
+    return GetField32<kVerifyFlags>(NumPreResolvedStringsOffset());
+  }
+
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   size_t NumResolvedTypes() REQUIRES_SHARED(Locks::mutator_lock_) {
     return GetField32<kVerifyFlags>(NumResolvedTypesOffset());
   }
@@ -429,12 +461,18 @@
                                    NativeDexCachePair<T> pair,
                                    PointerSize ptr_size);
 
+  static size_t PreResolvedStringsSize(size_t num_strings) {
+    return sizeof(GcRoot<mirror::String>) * num_strings;
+  }
+
   uint32_t StringSlotIndex(dex::StringIndex string_idx) REQUIRES_SHARED(Locks::mutator_lock_);
   uint32_t TypeSlotIndex(dex::TypeIndex type_idx) REQUIRES_SHARED(Locks::mutator_lock_);
   uint32_t FieldSlotIndex(uint32_t field_idx) REQUIRES_SHARED(Locks::mutator_lock_);
   uint32_t MethodSlotIndex(uint32_t method_idx) REQUIRES_SHARED(Locks::mutator_lock_);
   uint32_t MethodTypeSlotIndex(dex::ProtoIndex proto_idx) REQUIRES_SHARED(Locks::mutator_lock_);
 
+  void AddPreResolvedStringsArray() REQUIRES_SHARED(Locks::mutator_lock_);
+
  private:
   void Init(const DexFile* dex_file,
             ObjPtr<String> location,
@@ -516,22 +554,25 @@
 #endif
 
   HeapReference<String> location_;
-  // Number of elements in the call_sites_ array. Note that this appears here
-  // because of our packing logic for 32 bit fields.
-  uint32_t num_resolved_call_sites_;
+  // Number of elements in the preresolved_strings_ array. Note that this appears here because of
+  // our packing logic for 32 bit fields.
+  uint32_t num_preresolved_strings_;
 
-  uint64_t dex_file_;               // const DexFile*
-  uint64_t resolved_call_sites_;    // GcRoot<CallSite>* array with num_resolved_call_sites_
-                                    // elements.
-  uint64_t resolved_fields_;        // std::atomic<FieldDexCachePair>*, array with
-                                    // num_resolved_fields_ elements.
-  uint64_t resolved_method_types_;  // std::atomic<MethodTypeDexCachePair>* array with
-                                    // num_resolved_method_types_ elements.
-  uint64_t resolved_methods_;       // ArtMethod*, array with num_resolved_methods_ elements.
-  uint64_t resolved_types_;         // TypeDexCacheType*, array with num_resolved_types_ elements.
-  uint64_t strings_;                // std::atomic<StringDexCachePair>*, array with num_strings_
-                                    // elements.
+  uint64_t dex_file_;                // const DexFile*
+  uint64_t preresolved_strings_;     // GcRoot<mirror::String*> array with num_preresolved_strings
+                                     // elements.
+  uint64_t resolved_call_sites_;     // GcRoot<CallSite>* array with num_resolved_call_sites_
+                                     // elements.
+  uint64_t resolved_fields_;         // std::atomic<FieldDexCachePair>*, array with
+                                     // num_resolved_fields_ elements.
+  uint64_t resolved_method_types_;   // std::atomic<MethodTypeDexCachePair>* array with
+                                     // num_resolved_method_types_ elements.
+  uint64_t resolved_methods_;        // ArtMethod*, array with num_resolved_methods_ elements.
+  uint64_t resolved_types_;          // TypeDexCacheType*, array with num_resolved_types_ elements.
+  uint64_t strings_;                 // std::atomic<StringDexCachePair>*, array with num_strings_
+                                     // elements.
 
+  uint32_t num_resolved_call_sites_;    // Number of elements in the call_sites_ array.
   uint32_t num_resolved_fields_;        // Number of elements in the resolved_fields_ array.
   uint32_t num_resolved_method_types_;  // Number of elements in the resolved_method_types_ array.
   uint32_t num_resolved_methods_;       // Number of elements in the resolved_methods_ array.