Store class tables in the image
Reduces how long it takes to load an application image.
N5 boot.art size
Before: 8007680
After: 8122368
Also reduces boot time by how long AddImageClassesToClassTable
used to take (~20ms).
Changed class hashes to be uint32_t to fix cross compilation. We need
serialized hash tables to be valid with different pointer sizes.
Bug: 22858531
Change-Id: I463fc83f499ff75f509e80c253a55b9116ee5b89
diff --git a/runtime/base/hash_set.h b/runtime/base/hash_set.h
index 95baa82..fc1a52f 100644
--- a/runtime/base/hash_set.h
+++ b/runtime/base/hash_set.h
@@ -236,7 +236,7 @@
// Returns how large the table is after being written. If target is null, then no writing happens
// but the size is still returned. Target must be 8 byte aligned.
- size_t WriteToMemory(uint8_t* ptr) {
+ size_t WriteToMemory(uint8_t* ptr) const {
size_t offset = 0;
offset = WriteToBytes(ptr, offset, static_cast<uint64_t>(num_elements_));
offset = WriteToBytes(ptr, offset, static_cast<uint64_t>(num_buckets_));
@@ -457,7 +457,7 @@
}
// Make sure that everything reinserts in the right spot. Returns the number of errors.
- size_t Verify() {
+ size_t Verify() NO_THREAD_SAFETY_ANALYSIS {
size_t errors = 0;
for (size_t i = 0; i < num_buckets_; ++i) {
T& element = data_[i];
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 2dd2a83..879544f 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1017,6 +1017,15 @@
mirror::Throwable::SetClass(GetClassRoot(kJavaLangThrowable));
mirror::StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement));
+ const ImageHeader& header = space->GetImageHeader();
+ const ImageSection& section = header.GetImageSection(ImageHeader::kSectionClassTable);
+ if (section.Size() > 0u) {
+ WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
+ ClassTable* const class_table = InsertClassTableForClassLoader(nullptr);
+ class_table->ReadFromMemory(space->Begin() + section.Offset());
+ dex_cache_boot_image_class_lookup_required_ = false;
+ }
+
FinishInit(self);
VLOG(startup) << "ClassLinker::InitFromImage exiting";
@@ -2786,9 +2795,11 @@
Thread* self = Thread::Current();
WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
ScopedAssertNoThreadSuspension ants(self, "Moving image classes to class table");
+
+ ClassTable* const class_table = InsertClassTableForClassLoader(class_loader);
+
mirror::ObjectArray<mirror::DexCache>* dex_caches = GetImageDexCaches(image_space);
std::string temp;
- ClassTable* const class_table = InsertClassTableForClassLoader(class_loader);
for (int32_t i = 0; i < dex_caches->GetLength(); i++) {
mirror::DexCache* dex_cache = dex_caches->Get(i);
GcRoot<mirror::Class>* types = dex_cache->GetResolvedTypes();
diff --git a/runtime/class_table.cc b/runtime/class_table.cc
index 3ed1c95..4656b74 100644
--- a/runtime/class_table.cc
+++ b/runtime/class_table.cc
@@ -115,7 +115,7 @@
return false;
}
-std::size_t ClassTable::ClassDescriptorHashEquals::operator()(const GcRoot<mirror::Class>& root)
+uint32_t ClassTable::ClassDescriptorHashEquals::operator()(const GcRoot<mirror::Class>& root)
const {
std::string temp;
return ComputeModifiedUtf8Hash(root.Read()->GetDescriptor(&temp));
@@ -133,7 +133,7 @@
return a.Read()->DescriptorEquals(descriptor);
}
-std::size_t ClassTable::ClassDescriptorHashEquals::operator()(const char* descriptor) const {
+uint32_t ClassTable::ClassDescriptorHashEquals::operator()(const char* descriptor) const {
return ComputeModifiedUtf8Hash(descriptor);
}
@@ -148,4 +148,25 @@
return true;
}
+size_t ClassTable::WriteToMemory(uint8_t* ptr) const {
+ size_t ret = 0;
+ for (const ClassSet& set : classes_) {
+ uint8_t* address = (ptr != nullptr) ? ptr + ret : nullptr;
+ ret += set.WriteToMemory(address);
+ // Sanity check 2.
+ if (kIsDebugBuild && ptr != nullptr) {
+ size_t read_count;
+ ClassSet class_set(ptr, /*make copy*/false, &read_count);
+ class_set.Verify();
+ }
+ }
+ return ret;
+}
+
+size_t ClassTable::ReadFromMemory(uint8_t* ptr) {
+ size_t read_count = 0;
+ classes_.insert(classes_.begin(), ClassSet(ptr, /*make copy*/false, &read_count));
+ return read_count;
+}
+
} // namespace art
diff --git a/runtime/class_table.h b/runtime/class_table.h
index 002bb56..219e2c6 100644
--- a/runtime/class_table.h
+++ b/runtime/class_table.h
@@ -104,17 +104,26 @@
REQUIRES(Locks::classlinker_classes_lock_)
SHARED_REQUIRES(Locks::mutator_lock_);
+ size_t WriteToMemory(uint8_t* ptr) const
+ REQUIRES(Locks::classlinker_classes_lock_)
+ SHARED_REQUIRES(Locks::mutator_lock_);
+ size_t ReadFromMemory(uint8_t* ptr)
+ REQUIRES(Locks::classlinker_classes_lock_)
+ SHARED_REQUIRES(Locks::mutator_lock_);
+
private:
class ClassDescriptorHashEquals {
public:
+ // uint32_t for cross compilation.
+ uint32_t operator()(const GcRoot<mirror::Class>& root) const NO_THREAD_SAFETY_ANALYSIS;
// Same class loader and descriptor.
- std::size_t operator()(const GcRoot<mirror::Class>& root) const NO_THREAD_SAFETY_ANALYSIS;
bool operator()(const GcRoot<mirror::Class>& a, const GcRoot<mirror::Class>& b) const
NO_THREAD_SAFETY_ANALYSIS;;
// Same descriptor.
bool operator()(const GcRoot<mirror::Class>& a, const char* descriptor) const
NO_THREAD_SAFETY_ANALYSIS;
- std::size_t operator()(const char* descriptor) const NO_THREAD_SAFETY_ANALYSIS;
+ // uint32_t for cross compilation.
+ uint32_t operator()(const char* descriptor) const NO_THREAD_SAFETY_ANALYSIS;
};
class GcRootEmptyFn {
public:
diff --git a/runtime/image.cc b/runtime/image.cc
index 1bc19ff..2eac3fb 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -24,7 +24,7 @@
namespace art {
const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const uint8_t ImageHeader::kImageVersion[] = { '0', '2', '2', '\0' };
+const uint8_t ImageHeader::kImageVersion[] = { '0', '2', '3', '\0' };
ImageHeader::ImageHeader(uint32_t image_begin,
uint32_t image_size,
diff --git a/runtime/image.h b/runtime/image.h
index 555cf5d..a16f3c9 100644
--- a/runtime/image.h
+++ b/runtime/image.h
@@ -170,6 +170,7 @@
kSectionArtMethods,
kSectionDexCacheArrays,
kSectionInternedStrings,
+ kSectionClassTable,
kSectionImageBitmap,
kSectionCount, // Number of elements in enum.
};
diff --git a/runtime/utf.cc b/runtime/utf.cc
index 5a11698..a2d6363 100644
--- a/runtime/utf.cc
+++ b/runtime/utf.cc
@@ -178,8 +178,8 @@
return static_cast<int32_t>(hash);
}
-size_t ComputeModifiedUtf8Hash(const char* chars) {
- size_t hash = 0;
+uint32_t ComputeModifiedUtf8Hash(const char* chars) {
+ uint32_t hash = 0;
while (*chars != '\0') {
hash = hash * 31 + *chars++;
}
diff --git a/runtime/utf.h b/runtime/utf.h
index 03158c4..4abd605 100644
--- a/runtime/utf.h
+++ b/runtime/utf.h
@@ -85,8 +85,8 @@
int32_t ComputeUtf16Hash(const uint16_t* chars, size_t char_count);
// Compute a hash code of a modified UTF-8 string. Not the standard java hash since it returns a
-// size_t and hashes individual chars instead of codepoint words.
-size_t ComputeModifiedUtf8Hash(const char* chars);
+// uint32_t and hashes individual chars instead of codepoint words.
+uint32_t ComputeModifiedUtf8Hash(const char* chars);
/*
* Retrieve the next UTF-16 character or surrogate pair from a UTF-8 string.