Merge "Add PreResolved strings dex cache array"
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 864b215..df6e8a8 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -719,6 +719,10 @@
for (const DexFile* dex_file : dex_files) {
dex_cache.Assign(class_linker->FindDexCache(soa.Self(), *dex_file));
+ if (only_startup_strings) {
+ // When resolving startup strings, create the preresolved strings array.
+ dex_cache->AddPreResolvedStringsArray();
+ }
TimingLogger::ScopedTiming t("Resolve const-string Strings", timings);
for (ClassAccessor accessor : dex_file->GetClasses()) {
@@ -757,6 +761,10 @@
: inst->VRegB_31c());
ObjPtr<mirror::String> string = class_linker->ResolveString(string_index, dex_cache);
CHECK(string != nullptr) << "Could not allocate a string when forcing determinism";
+ if (only_startup_strings) {
+ dex_cache->GetPreResolvedStrings()[string_index.index_] =
+ GcRoot<mirror::String>(string);
+ }
++num_instructions;
break;
}
diff --git a/compiler/driver/compiler_options_map.def b/compiler/driver/compiler_options_map.def
index a593240..1ec34ec 100644
--- a/compiler/driver/compiler_options_map.def
+++ b/compiler/driver/compiler_options_map.def
@@ -52,7 +52,7 @@
COMPILER_OPTIONS_KEY (double, TopKProfileThreshold)
COMPILER_OPTIONS_KEY (bool, AbortOnHardVerifierFailure)
COMPILER_OPTIONS_KEY (bool, AbortOnSoftVerifierFailure)
-COMPILER_OPTIONS_KEY (bool, ResolveStartupConstStrings, false)
+COMPILER_OPTIONS_KEY (bool, ResolveStartupConstStrings, kIsDebugBuild)
COMPILER_OPTIONS_KEY (std::string, DumpInitFailures)
COMPILER_OPTIONS_KEY (std::string, DumpCFG)
COMPILER_OPTIONS_KEY (Unit, DumpCFGAppend)
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index 770b696..10d2b6f 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -2080,8 +2080,8 @@
ScratchFile profile_file;
std::vector<uint16_t> methods;
std::vector<dex::TypeIndex> classes;
+ std::unique_ptr<const DexFile> dex(OpenTestDexFile("StringLiterals"));
{
- std::unique_ptr<const DexFile> dex(OpenTestDexFile("StringLiterals"));
for (ClassAccessor accessor : dex->GetClasses()) {
if (accessor.GetDescriptor() == std::string("LStringLiterals$StartupClass;")) {
classes.push_back(accessor.GetClassIdx());
@@ -2141,15 +2141,43 @@
seen.insert(str.Read()->ToModifiedUtf8());
}
});
+ // Ensure that the dex cache has a preresolved string array.
+ std::set<std::string> preresolved_seen;
+ bool saw_dexcache = false;
+ space->GetLiveBitmap()->VisitAllMarked(
+ [&](mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (obj->IsDexCache<kVerifyNone>()) {
+ ObjPtr<mirror::DexCache> dex_cache = obj->AsDexCache();
+ GcRoot<mirror::String>* preresolved_strings = dex_cache->GetPreResolvedStrings();
+ ASSERT_EQ(dex->NumStringIds(), dex_cache->NumPreResolvedStrings());
+ for (size_t i = 0; i < dex_cache->NumPreResolvedStrings(); ++i) {
+ ObjPtr<mirror::String> string = preresolved_strings[i].Read<kWithoutReadBarrier>();
+ if (string != nullptr) {
+ preresolved_seen.insert(string->ToModifiedUtf8());
+ }
+ }
+ saw_dexcache = true;
+ }
+ });
+ ASSERT_TRUE(saw_dexcache);
+ // Everything in the preresolved array should also be in the intern table.
+ for (const std::string& str : preresolved_seen) {
+ EXPECT_TRUE(seen.find(str) != seen.end());
+ }
// Normal methods
- EXPECT_TRUE(seen.find("Loading ") != seen.end());
- EXPECT_TRUE(seen.find("Starting up") != seen.end());
- EXPECT_TRUE(seen.find("abcd.apk") != seen.end());
+ EXPECT_TRUE(preresolved_seen.find("Loading ") != preresolved_seen.end());
+ EXPECT_TRUE(preresolved_seen.find("Starting up") != preresolved_seen.end());
+ EXPECT_TRUE(preresolved_seen.find("abcd.apk") != preresolved_seen.end());
EXPECT_TRUE(seen.find("Unexpected error") == seen.end());
EXPECT_TRUE(seen.find("Shutting down!") == seen.end());
+ EXPECT_TRUE(preresolved_seen.find("Unexpected error") == preresolved_seen.end());
+ EXPECT_TRUE(preresolved_seen.find("Shutting down!") == preresolved_seen.end());
// Classes initializers
- EXPECT_TRUE(seen.find("Startup init") != seen.end());
+ EXPECT_TRUE(preresolved_seen.find("Startup init") != preresolved_seen.end());
EXPECT_TRUE(seen.find("Other class init") == seen.end());
+ EXPECT_TRUE(preresolved_seen.find("Other class init") == preresolved_seen.end());
+ // Expect the sets match.
+ EXPECT_GE(seen.size(), preresolved_seen.size());
}
}
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index 4ddbf74..fd10b6b 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -288,11 +288,16 @@
for (const HeapReferencePointerInfo& ref_info : string_ref_info) {
uint32_t base_offset;
- if (HasDexCacheNativeRefTag(ref_info.first)) {
+ if (HasDexCacheStringNativeRefTag(ref_info.first)) {
++native_string_refs;
- auto* obj_ptr = reinterpret_cast<mirror::Object*>(ClearDexCacheNativeRefTag(
+ auto* obj_ptr = reinterpret_cast<mirror::Object*>(ClearDexCacheNativeRefTags(
ref_info.first));
- base_offset = SetDexCacheNativeRefTag(GetImageOffset(obj_ptr));
+ base_offset = SetDexCacheStringNativeRefTag(GetImageOffset(obj_ptr));
+ } else if (HasDexCachePreResolvedStringNativeRefTag(ref_info.first)) {
+ ++native_string_refs;
+ auto* obj_ptr = reinterpret_cast<mirror::Object*>(ClearDexCacheNativeRefTags(
+ ref_info.first));
+ base_offset = SetDexCachePreResolvedStringNativeRefTag(GetImageOffset(obj_ptr));
} else {
++managed_string_refs;
base_offset = GetImageOffset(reinterpret_cast<mirror::Object*>(ref_info.first));
@@ -447,7 +452,19 @@
if (IsValidAppImageStringReference(referred_string)) {
++string_info_collected;
visitor.AddStringRefInfo(
- SetDexCacheNativeRefTag(reinterpret_cast<uintptr_t>(object.Ptr())), index);
+ SetDexCacheStringNativeRefTag(reinterpret_cast<uintptr_t>(object.Ptr())), index);
+ }
+ }
+
+ // Visit all of the preinitialized strings.
+ GcRoot<mirror::String>* preresolved_strings = dex_cache->GetPreResolvedStrings();
+ for (size_t index = 0; index < dex_cache->NumPreResolvedStrings(); ++index) {
+ ObjPtr<mirror::String> referred_string = preresolved_strings[index].Read();
+ if (IsValidAppImageStringReference(referred_string)) {
+ ++string_info_collected;
+ visitor.AddStringRefInfo(SetDexCachePreResolvedStringNativeRefTag(
+ reinterpret_cast<uintptr_t>(object.Ptr())),
+ index);
}
}
@@ -852,15 +869,27 @@
DCHECK_EQ(dex_file->NumStringIds() != 0u, dex_cache->GetStrings() != nullptr);
AddDexCacheArrayRelocation(dex_cache->GetStrings(), start + layout.StringsOffset(), oat_index);
- if (dex_cache->GetResolvedMethodTypes() != nullptr) {
- AddDexCacheArrayRelocation(dex_cache->GetResolvedMethodTypes(),
- start + layout.MethodTypesOffset(),
- oat_index);
- }
- if (dex_cache->GetResolvedCallSites() != nullptr) {
- AddDexCacheArrayRelocation(dex_cache->GetResolvedCallSites(),
- start + layout.CallSitesOffset(),
- oat_index);
+ AddDexCacheArrayRelocation(dex_cache->GetResolvedMethodTypes(),
+ start + layout.MethodTypesOffset(),
+ oat_index);
+ AddDexCacheArrayRelocation(dex_cache->GetResolvedCallSites(),
+ start + layout.CallSitesOffset(),
+ oat_index);
+
+ // Preresolved strings aren't part of the special layout.
+ GcRoot<mirror::String>* preresolved_strings = dex_cache->GetPreResolvedStrings();
+ if (preresolved_strings != nullptr) {
+ DCHECK(!IsInBootImage(preresolved_strings));
+ // Add the array to the metadata section.
+ const size_t count = dex_cache->NumPreResolvedStrings();
+ auto bin = BinTypeForNativeRelocationType(NativeObjectRelocationType::kGcRootPointer);
+ for (size_t i = 0; i < count; ++i) {
+ native_object_relocations_.emplace(&preresolved_strings[i],
+ NativeObjectRelocation { oat_index,
+ image_info.GetBinSlotSize(bin),
+ NativeObjectRelocationType::kGcRootPointer });
+ image_info.IncrementBinSlotSize(bin, sizeof(GcRoot<mirror::Object>));
+ }
}
}
}
@@ -2339,9 +2368,21 @@
sizeof(typename decltype(string_reference_offsets_)::value_type) *
num_string_references_);
+ /*
+ * Metadata section.
+ */
+
+ // Round up to the alignment of the offsets we are going to store.
+ cur_pos = RoundUp(string_reference_offsets.End(),
+ mirror::DexCache::PreResolvedStringsAlignment());
+
+ const ImageSection& metadata_section =
+ sections[ImageHeader::kSectionMetadata] =
+ ImageSection(cur_pos, GetBinSlotSize(Bin::kMetadata));
+
// Return the number of bytes described by these sections, and the sections
// themselves.
- return make_pair(string_reference_offsets.End(), std::move(sections));
+ return make_pair(metadata_section.End(), std::move(sections));
}
void ImageWriter::CreateHeader(size_t oat_index) {
@@ -2545,6 +2586,12 @@
new(dest)ImtConflictTable(orig_table->NumEntries(target_ptr_size_), target_ptr_size_));
break;
}
+ case NativeObjectRelocationType::kGcRootPointer: {
+ auto* orig_pointer = reinterpret_cast<GcRoot<mirror::Object>*>(pair.first);
+ auto* dest_pointer = reinterpret_cast<GcRoot<mirror::Object>*>(dest);
+ CopyAndFixupReference(dest_pointer->AddressWithoutBarrier(), orig_pointer->Read());
+ break;
+ }
}
}
// Fixup the image method roots.
@@ -2965,6 +3012,12 @@
copy_dex_cache,
DexCache::ResolvedCallSitesOffset(),
orig_dex_cache->NumResolvedCallSites());
+ if (orig_dex_cache->GetPreResolvedStrings() != nullptr) {
+ CopyAndFixupPointer(copy_dex_cache,
+ DexCache::PreResolvedStringsOffset(),
+ orig_dex_cache->GetPreResolvedStrings(),
+ PointerSize::k64);
+ }
// Remove the DexFile pointers. They will be fixed up when the runtime loads the oat file. Leaving
// compiler pointers in here will make the output non-deterministic.
@@ -3178,6 +3231,8 @@
return Bin::kImTable;
case NativeObjectRelocationType::kIMTConflictTable:
return Bin::kIMTConflictTable;
+ case NativeObjectRelocationType::kGcRootPointer:
+ return Bin::kMetadata;
}
UNREACHABLE();
}
diff --git a/dex2oat/linker/image_writer.h b/dex2oat/linker/image_writer.h
index e019a50..06c694c 100644
--- a/dex2oat/linker/image_writer.h
+++ b/dex2oat/linker/image_writer.h
@@ -209,6 +209,8 @@
kIMTConflictTable,
// Runtime methods (always clean, do not have a length prefix array).
kRuntimeMethod,
+ // Metadata bin for data that is temporary during image lifetime.
+ kMetadata,
// Dex cache arrays have a special slot for PC-relative addressing. Since they are
// huge, and as such their dirtiness is not important for the clean/dirty separation,
// we arbitrarily keep them at the end of the native data.
@@ -226,6 +228,7 @@
kArtMethodArrayClean,
kArtMethodDirty,
kArtMethodArrayDirty,
+ kGcRootPointer,
kRuntimeMethod,
kIMTable,
kIMTConflictTable,
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 358b7ba..e26ec95 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -1950,6 +1950,8 @@
const auto& dex_cache_arrays_section = image_header_.GetDexCacheArraysSection();
const auto& intern_section = image_header_.GetInternedStringsSection();
const auto& class_table_section = image_header_.GetClassTableSection();
+ const auto& sro_section = image_header_.GetImageStringReferenceOffsetsSection();
+ const auto& metadata_section = image_header_.GetMetadataSection();
const auto& bitmap_section = image_header_.GetImageBitmapSection();
stats_.header_bytes = header_bytes;
@@ -1996,6 +1998,9 @@
stats_.dex_cache_arrays_bytes += dex_cache_arrays_section.Size();
stats_.interned_strings_bytes += intern_section.Size();
stats_.class_table_bytes += class_table_section.Size();
+ stats_.sro_offset_bytes += sro_section.Size();
+ stats_.metadata_bytes += metadata_section.Size();
+
stats_.Dump(os, indent_os);
os << "\n";
@@ -2412,55 +2417,38 @@
public:
struct Stats {
- size_t oat_file_bytes;
- size_t file_bytes;
+ size_t oat_file_bytes = 0u;
+ size_t file_bytes = 0u;
- size_t header_bytes;
- size_t object_bytes;
- size_t art_field_bytes;
- size_t art_method_bytes;
- size_t dex_cache_arrays_bytes;
- size_t interned_strings_bytes;
- size_t class_table_bytes;
- size_t bitmap_bytes;
- size_t alignment_bytes;
+ size_t header_bytes = 0u;
+ size_t object_bytes = 0u;
+ size_t art_field_bytes = 0u;
+ size_t art_method_bytes = 0u;
+ size_t dex_cache_arrays_bytes = 0u;
+ size_t interned_strings_bytes = 0u;
+ size_t class_table_bytes = 0u;
+ size_t sro_offset_bytes = 0u;
+ size_t metadata_bytes = 0u;
+ size_t bitmap_bytes = 0u;
+ size_t alignment_bytes = 0u;
- size_t managed_code_bytes;
- size_t managed_code_bytes_ignoring_deduplication;
- size_t native_to_managed_code_bytes;
- size_t class_initializer_code_bytes;
- size_t large_initializer_code_bytes;
- size_t large_method_code_bytes;
+ size_t managed_code_bytes = 0u;
+ size_t managed_code_bytes_ignoring_deduplication = 0u;
+ size_t native_to_managed_code_bytes = 0u;
+ size_t class_initializer_code_bytes = 0u;
+ size_t large_initializer_code_bytes = 0u;
+ size_t large_method_code_bytes = 0u;
- size_t vmap_table_bytes;
+ size_t vmap_table_bytes = 0u;
- size_t dex_instruction_bytes;
+ size_t dex_instruction_bytes = 0u;
std::vector<ArtMethod*> method_outlier;
std::vector<size_t> method_outlier_size;
std::vector<double> method_outlier_expansion;
std::vector<std::pair<std::string, size_t>> oat_dex_file_sizes;
- Stats()
- : oat_file_bytes(0),
- file_bytes(0),
- header_bytes(0),
- object_bytes(0),
- art_field_bytes(0),
- art_method_bytes(0),
- dex_cache_arrays_bytes(0),
- interned_strings_bytes(0),
- class_table_bytes(0),
- bitmap_bytes(0),
- alignment_bytes(0),
- managed_code_bytes(0),
- managed_code_bytes_ignoring_deduplication(0),
- native_to_managed_code_bytes(0),
- class_initializer_code_bytes(0),
- large_initializer_code_bytes(0),
- large_method_code_bytes(0),
- vmap_table_bytes(0),
- dex_instruction_bytes(0) {}
+ Stats() {}
struct SizeAndCount {
SizeAndCount(size_t bytes_in, size_t count_in) : bytes(bytes_in), count(count_in) {}
@@ -2614,6 +2602,8 @@
"dex_cache_arrays_bytes = %8zd (%2.0f%% of art file bytes)\n"
"interned_string_bytes = %8zd (%2.0f%% of art file bytes)\n"
"class_table_bytes = %8zd (%2.0f%% of art file bytes)\n"
+ "sro_bytes = %8zd (%2.0f%% of art file bytes)\n"
+ "metadata_bytes = %8zd (%2.0f%% of art file bytes)\n"
"bitmap_bytes = %8zd (%2.0f%% of art file bytes)\n"
"alignment_bytes = %8zd (%2.0f%% of art file bytes)\n\n",
header_bytes, PercentOfFileBytes(header_bytes),
@@ -2625,13 +2615,15 @@
interned_strings_bytes,
PercentOfFileBytes(interned_strings_bytes),
class_table_bytes, PercentOfFileBytes(class_table_bytes),
+ sro_offset_bytes, PercentOfFileBytes(sro_offset_bytes),
+ metadata_bytes, PercentOfFileBytes(metadata_bytes),
bitmap_bytes, PercentOfFileBytes(bitmap_bytes),
alignment_bytes, PercentOfFileBytes(alignment_bytes))
<< std::flush;
CHECK_EQ(file_bytes,
header_bytes + object_bytes + art_field_bytes + art_method_bytes +
dex_cache_arrays_bytes + interned_strings_bytes + class_table_bytes +
- bitmap_bytes + alignment_bytes);
+ sro_offset_bytes + metadata_bytes + bitmap_bytes + alignment_bytes);
}
os << "object_bytes breakdown:\n";
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 151f7b8..f43791a 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 875efe2..96a2cea 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -1170,6 +1170,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>()));
+ }
+ }
}
}
{
@@ -1729,6 +1742,10 @@
dex_cache,
mirror::DexCache::ResolvedCallSitesOffset(),
dex_cache->NumResolvedCallSites<kVerifyNone>());
+ FixupDexCacheArray<GcRoot<mirror::String>>(
+ dex_cache,
+ mirror::DexCache::PreResolvedStringsOffset(),
+ dex_cache->NumPreResolvedStrings<kVerifyNone>());
}
private:
@@ -1773,6 +1790,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.