Re-enable class table for image writer
Changes, create one temporary class table per ImageInfo. Don't keep
track of class loaders.
Bug: 26317072
Change-Id: I4f9121194f39031fb8629d60b6feeb2747a77870
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 2985ca9..3134297 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -1070,6 +1070,13 @@
};
const char* oat_file = GetOatFilenameForDexCache(dex_cache);
ImageInfo& image_info = GetImageInfo(oat_file);
+ {
+ // Note: This table is only accessed from the image writer, so the lock is technically
+ // unnecessary.
+ WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+ // Insert in the class table for this iamge.
+ image_info.class_table_->Insert(as_klass);
+ }
for (LengthPrefixedArray<ArtField>* cur_fields : fields) {
// Total array length including header.
if (cur_fields != nullptr) {
@@ -1252,13 +1259,16 @@
// Calculate size of the dex cache arrays slot and prepare offsets.
PrepareDexCacheArraySlots();
- // Calculate the sizes of the intern tables.
+ // Calculate the sizes of the intern tables and class tables.
for (const char* oat_filename : oat_filenames_) {
ImageInfo& image_info = GetImageInfo(oat_filename);
// Calculate how big the intern table will be after being serialized.
InternTable* const intern_table = image_info.intern_table_.get();
CHECK_EQ(intern_table->WeakSize(), 0u) << " should have strong interned all the strings";
image_info.intern_table_bytes_ = intern_table->WriteToMemory(nullptr);
+ // Calculate the size of the class table.
+ ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
+ image_info.class_table_bytes_ += image_info.class_table_->WriteToMemory(nullptr);
}
// Calculate bin slot offsets.
@@ -1315,27 +1325,6 @@
relocation.offset += image_info.bin_slot_offsets_[bin_type];
}
- /* TODO: Reenable the class table. b/26317072
- // Write out the class table.
- ClassLinker* class_linker = runtime->GetClassLinker();
- if (boot_image_space_ == nullptr) {
- // Compiling the boot image, add null class loader.
- class_loaders_.insert(nullptr);
- }
- // class_loaders_ usually will not be empty, but may be empty if we attempt to create an image
- // with no classes.
- if (class_loaders_.size() == 1u) {
- // Only write the class table if we have exactly one class loader. There may be cases where
- // there are multiple class loaders if a class path is passed to dex2oat.
- ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
- for (mirror::ClassLoader* loader : class_loaders_) {
- ClassTable* table = class_linker->ClassTableForClassLoader(loader);
- CHECK(table != nullptr);
- class_table_bytes_ += table->WriteToMemory(nullptr);
- }
- }
- */
-
// Note that image_info.image_end_ is left at end of used mirror object section.
}
@@ -1375,8 +1364,7 @@
cur_pos = RoundUp(cur_pos, sizeof(uint64_t));
// Calculate the size of the class table section.
auto* class_table_section = &out_sections[ImageHeader::kSectionClassTable];
- // TODO: class_table_bytes_
- *class_table_section = ImageSection(cur_pos, 0u);
+ *class_table_section = ImageSection(cur_pos, class_table_bytes_);
cur_pos = class_table_section->End();
// Image end goes right before the start of the image bitmap.
return cur_pos;
@@ -1555,35 +1543,29 @@
CHECK_EQ(temp_intern_table.Size(), intern_table->Size());
temp_intern_table.VisitRoots(&root_visitor, kVisitRootFlagAllRoots);
}
- /* TODO: Reenable the class table writing.
// Write the class table(s) into the image. class_table_bytes_ may be 0 if there are multiple
// class loaders. Writing multiple class tables into the image is currently unsupported.
- if (class_table_bytes_ > 0u) {
- ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
+ if (image_info.class_table_bytes_ > 0u) {
const ImageSection& class_table_section = image_header->GetImageSection(
ImageHeader::kSectionClassTable);
uint8_t* const class_table_memory_ptr =
image_info.image_->Begin() + class_table_section.Offset();
ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
- size_t class_table_bytes = 0;
- for (mirror::ClassLoader* loader : class_loaders_) {
- ClassTable* table = class_linker->ClassTableForClassLoader(loader);
- CHECK(table != nullptr);
- uint8_t* memory_ptr = class_table_memory_ptr + class_table_bytes;
- class_table_bytes += table->WriteToMemory(memory_ptr);
- // Fixup the pointers in the newly written class table to contain image addresses. See
- // above comment for intern tables.
- ClassTable temp_class_table;
- temp_class_table.ReadFromMemory(memory_ptr);
- CHECK_EQ(temp_class_table.NumZygoteClasses(), table->NumNonZygoteClasses() +
- table->NumZygoteClasses());
- BufferedRootVisitor<kDefaultBufferedRootCount> buffered_visitor(&root_visitor,
- RootInfo(kRootUnknown));
- temp_class_table.VisitRoots(buffered_visitor);
- }
- CHECK_EQ(class_table_bytes, class_table_bytes_);
+
+ ClassTable* table = image_info.class_table_.get();
+ CHECK(table != nullptr);
+ const size_t class_table_bytes = table->WriteToMemory(class_table_memory_ptr);
+ CHECK_EQ(class_table_bytes, image_info.class_table_bytes_);
+ // Fixup the pointers in the newly written class table to contain image addresses. See
+ // above comment for intern tables.
+ ClassTable temp_class_table;
+ temp_class_table.ReadFromMemory(class_table_memory_ptr);
+ CHECK_EQ(temp_class_table.NumZygoteClasses(), table->NumNonZygoteClasses() +
+ table->NumZygoteClasses());
+ BufferedRootVisitor<kDefaultBufferedRootCount> buffered_visitor(&root_visitor,
+ RootInfo(kRootUnknown));
+ temp_class_table.VisitRoots(buffered_visitor);
}
- */
}
void ImageWriter::CopyAndFixupObjects() {
@@ -2215,7 +2197,6 @@
image_method_array_(ImageHeader::kImageMethodsCount),
dirty_methods_(0u),
clean_methods_(0u),
- class_table_bytes_(0u),
image_storage_mode_(image_storage_mode),
dex_file_oat_filename_map_(dex_file_oat_filename_map),
oat_filenames_(oat_filenames),
@@ -2227,6 +2208,8 @@
std::fill_n(image_methods_, arraysize(image_methods_), nullptr);
}
-ImageWriter::ImageInfo::ImageInfo() : intern_table_(new InternTable) {}
+ImageWriter::ImageInfo::ImageInfo()
+ : intern_table_(new InternTable),
+ class_table_(new ClassTable) {}
} // namespace art
diff --git a/compiler/image_writer.h b/compiler/image_writer.h
index d423799..f491a5a 100644
--- a/compiler/image_writer.h
+++ b/compiler/image_writer.h
@@ -47,6 +47,8 @@
} // namespace space
} // namespace gc
+class ClassTable;
+
static constexpr int kInvalidImageFd = -1;
// Write a Space built during compilation for use during execution.
@@ -263,8 +265,14 @@
// Cached size of the intern table for when we allocate memory.
size_t intern_table_bytes_ = 0;
- // Intern table associated with this for serialization.
+ // Number of image class table bytes.
+ size_t class_table_bytes_ = 0;
+
+ // Intern table associated with this image for serialization.
std::unique_ptr<InternTable> intern_table_;
+
+ // Class table associated with this image for serialization.
+ std::unique_ptr<ClassTable> class_table_;
};
// We use the lock word to store the offset of the object in the image.
@@ -504,9 +512,6 @@
// null is a valid entry.
std::unordered_set<mirror::ClassLoader*> class_loaders_;
- // Number of image class table bytes.
- size_t class_table_bytes_;
-
// Which mode the image is stored as, see image.h
const ImageHeader::StorageMode image_storage_mode_;
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index d995f28..67458cc 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1113,6 +1113,7 @@
mirror::Throwable::SetClass(GetClassRoot(kJavaLangThrowable));
mirror::StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement));
+ size_t class_tables_added = 0;
for (gc::space::ImageSpace* space : spaces) {
const ImageHeader& header = space->GetImageHeader();
const ImageSection& section = header.GetImageSection(ImageHeader::kSectionClassTable);
@@ -1120,9 +1121,17 @@
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;
+ ++class_tables_added;
}
}
+ if (class_tables_added != 0) {
+ // Either all of the image spaces have an empty class section or none do. In the case where
+ // an image space has no classes, it will still have a non-empty class section that contains
+ // metadata.
+ CHECK_EQ(spaces.size(), class_tables_added)
+ << "Expected non-empty class section for each image space.";
+ dex_cache_boot_image_class_lookup_required_ = false;
+ }
FinishInit(self);
diff --git a/runtime/class_table.h b/runtime/class_table.h
index c911365..911f3c2 100644
--- a/runtime/class_table.h
+++ b/runtime/class_table.h
@@ -106,8 +106,7 @@
// Combines all of the tables into one class set.
size_t WriteToMemory(uint8_t* ptr) const
- REQUIRES(Locks::classlinker_classes_lock_)
- SHARED_REQUIRES(Locks::mutator_lock_);
+ SHARED_REQUIRES(Locks::classlinker_classes_lock_, Locks::mutator_lock_);
size_t ReadFromMemory(uint8_t* ptr)
REQUIRES(Locks::classlinker_classes_lock_)
SHARED_REQUIRES(Locks::mutator_lock_);