diff options
| -rw-r--r-- | compiler/image_writer.cc | 87 | ||||
| -rw-r--r-- | compiler/image_writer.h | 9 | ||||
| -rw-r--r-- | oatdump/oatdump.cc | 13 | ||||
| -rw-r--r-- | patchoat/patchoat.cc | 16 | ||||
| -rw-r--r-- | patchoat/patchoat.h | 2 | ||||
| -rw-r--r-- | runtime/base/hash_set.h | 4 | ||||
| -rw-r--r-- | runtime/class_linker.cc | 13 | ||||
| -rw-r--r-- | runtime/class_table.cc | 25 | ||||
| -rw-r--r-- | runtime/class_table.h | 13 | ||||
| -rw-r--r-- | runtime/image.cc | 2 | ||||
| -rw-r--r-- | runtime/image.h | 1 | ||||
| -rw-r--r-- | runtime/utf.cc | 4 | ||||
| -rw-r--r-- | runtime/utf.h | 4 |
13 files changed, 163 insertions, 30 deletions
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index 341742e4dc..bf1fcdd5f5 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -540,7 +540,10 @@ ImageWriter::BinSlot ImageWriter::GetImageBinSlot(mirror::Object* object) const } bool ImageWriter::AllocMemory() { - const size_t length = RoundUp(image_objects_offset_begin_ + GetBinSizeSum() + intern_table_bytes_, + const size_t length = RoundUp(image_objects_offset_begin_ + + GetBinSizeSum() + + intern_table_bytes_ + + class_table_bytes_, kPageSize); std::string error_msg; image_.reset(MemMap::MapAnonymous("image writer image", @@ -1030,6 +1033,14 @@ void ImageWriter::WalkFieldsInOrder(mirror::Object* obj) { WalkFieldsInOrder(value); } } + } else if (h_obj->IsClassLoader()) { + // Register the class loader if it has a class table. + // The fake boot class loader should not get registered and we should end up with only one + // class loader. + mirror::ClassLoader* class_loader = h_obj->AsClassLoader(); + if (class_loader->GetClassTable() != nullptr) { + class_loaders_.insert(class_loader); + } } } } @@ -1154,10 +1165,26 @@ void ImageWriter::CalculateNewObjectOffsets() { } // Calculate how big the intern table will be after being serialized. - auto* const intern_table = Runtime::Current()->GetInternTable(); + InternTable* const intern_table = runtime->GetInternTable(); CHECK_EQ(intern_table->WeakSize(), 0u) << " should have strong interned all the strings"; intern_table_bytes_ = intern_table->WriteToMemory(nullptr); + // 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); + } + if (!class_loaders_.empty()) { + CHECK_EQ(class_loaders_.size(), 1u) << "Should only have one real class loader in the image"; + 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_end_ is left at end of used mirror object section. } @@ -1199,6 +1226,12 @@ void ImageWriter::CreateHeader(size_t oat_loaded_size, size_t oat_data_offset) { auto* interned_strings_section = §ions[ImageHeader::kSectionInternedStrings]; *interned_strings_section = ImageSection(cur_pos, intern_table_bytes_); cur_pos = interned_strings_section->End(); + // Calculate the size of the class table section. + auto* class_table_section = §ions[ImageHeader::kSectionClassTable]; + *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. + const size_t image_end = static_cast<uint32_t>(cur_pos); // Finally bitmap section. const size_t bitmap_bytes = image_bitmap_->Size(); auto* bitmap_section = §ions[ImageHeader::kSectionImageBitmap]; @@ -1212,7 +1245,6 @@ void ImageWriter::CreateHeader(size_t oat_loaded_size, size_t oat_data_offset) { } LOG(INFO) << "Methods: clean=" << clean_methods_ << " dirty=" << dirty_methods_; } - const size_t image_end = static_cast<uint32_t>(interned_strings_section->End()); CHECK_EQ(AlignUp(image_begin_ + image_end, kPageSize), oat_file_begin) << "Oat file should be right after the image."; // Create the header. @@ -1323,23 +1355,48 @@ void ImageWriter::CopyAndFixupNativeData() { } image_header->SetImageMethod(static_cast<ImageHeader::ImageMethod>(i), method); } + FixupRootVisitor root_visitor(this); + // Write the intern table into the image. const ImageSection& intern_table_section = image_header->GetImageSection( ImageHeader::kSectionInternedStrings); - InternTable* const intern_table = Runtime::Current()->GetInternTable(); - uint8_t* const memory_ptr = image_->Begin() + intern_table_section.Offset(); - const size_t intern_table_bytes = intern_table->WriteToMemory(memory_ptr); + Runtime* const runtime = Runtime::Current(); + InternTable* const intern_table = runtime->GetInternTable(); + uint8_t* const intern_table_memory_ptr = image_->Begin() + intern_table_section.Offset(); + const size_t intern_table_bytes = intern_table->WriteToMemory(intern_table_memory_ptr); + CHECK_EQ(intern_table_bytes, intern_table_bytes_); // Fixup the pointers in the newly written intern table to contain image addresses. - InternTable temp_table; + InternTable temp_intern_table; // Note that we require that ReadFromMemory does not make an internal copy of the elements so that // the VisitRoots() will update the memory directly rather than the copies. // This also relies on visit roots not doing any verification which could fail after we update // the roots to be the image addresses. - temp_table.ReadFromMemory(memory_ptr); - CHECK_EQ(temp_table.Size(), intern_table->Size()); - FixupRootVisitor visitor(this); - temp_table.VisitRoots(&visitor, kVisitRootFlagAllRoots); - CHECK_EQ(intern_table_bytes, intern_table_bytes_); + temp_intern_table.ReadFromMemory(intern_table_memory_ptr); + CHECK_EQ(temp_intern_table.Size(), intern_table->Size()); + temp_intern_table.VisitRoots(&root_visitor, kVisitRootFlagAllRoots); + + // Write the class table(s) into the image. + ClassLinker* const class_linker = runtime->GetClassLinker(); + const ImageSection& class_table_section = image_header->GetImageSection( + ImageHeader::kSectionClassTable); + uint8_t* const class_table_memory_ptr = 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.NumNonZygoteClasses(), table->NumNonZygoteClasses()); + BufferedRootVisitor<kDefaultBufferedRootCount> buffered_visitor(&root_visitor, + RootInfo(kRootUnknown)); + temp_class_table.VisitRoots(buffered_visitor); + } + CHECK_EQ(class_table_bytes, class_table_bytes_); } void ImageWriter::CopyAndFixupObjects() { @@ -1553,8 +1610,7 @@ void ImageWriter::FixupObject(Object* orig, Object* copy) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); if (klass == class_linker->GetClassRoot(ClassLinker::kJavaLangDexCache)) { FixupDexCache(down_cast<mirror::DexCache*>(orig), down_cast<mirror::DexCache*>(copy)); - } else if (klass->IsSubClass(down_cast<mirror::Class*>( - class_linker->GetClassRoot(ClassLinker::kJavaLangClassLoader)))) { + } else if (klass->IsClassLoaderClass()) { // If src is a ClassLoader, set the class table to null so that it gets recreated by the // ClassLoader. down_cast<mirror::ClassLoader*>(copy)->SetClassTable(nullptr); @@ -1840,7 +1896,8 @@ uint8_t* ImageWriter::GetOatFileBegin() const { bin_slot_sizes_[kBinArtMethodDirty] + bin_slot_sizes_[kBinArtMethodClean] + bin_slot_sizes_[kBinDexCacheArray] + - intern_table_bytes_; + intern_table_bytes_ + + class_table_bytes_; return image_begin_ + RoundUp(image_end_ + native_sections_size, kPageSize); } diff --git a/compiler/image_writer.h b/compiler/image_writer.h index 889cd10dc4..386838fde0 100644 --- a/compiler/image_writer.h +++ b/compiler/image_writer.h @@ -72,7 +72,8 @@ class ImageWriter FINAL { intern_table_bytes_(0u), image_method_array_(ImageHeader::kImageMethodsCount), dirty_methods_(0u), - clean_methods_(0u) { + clean_methods_(0u), + class_table_bytes_(0u) { CHECK_NE(image_begin, 0U); std::fill_n(image_methods_, arraysize(image_methods_), nullptr); std::fill_n(oat_address_offsets_, arraysize(oat_address_offsets_), 0); @@ -453,6 +454,12 @@ class ImageWriter FINAL { // Prune class memoization table to speed up ContainsBootClassLoaderNonImageClass. std::unordered_map<mirror::Class*, bool> prune_class_memo_; + // Class loaders with a class table to write out. Should only be one currently. + std::unordered_set<mirror::ClassLoader*> class_loaders_; + + // Number of image class table bytes. + size_t class_table_bytes_; + friend class ContainsBootClassLoaderNonImageClassVisitor; friend class FixupClassVisitor; friend class FixupRootVisitor; diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index a99bb00979..58331296bf 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -1664,6 +1664,8 @@ class ImageDumper { ImageHeader::kSectionDexCacheArrays); const auto& intern_section = image_header_.GetImageSection( ImageHeader::kSectionInternedStrings); + const auto& class_table_section = image_header_.GetImageSection( + ImageHeader::kSectionClassTable); stats_.header_bytes = header_bytes; stats_.alignment_bytes += RoundUp(header_bytes, kObjectAlignment) - header_bytes; // Add padding between the field and method section. @@ -1680,6 +1682,7 @@ class ImageDumper { stats_.art_method_bytes += method_section.Size(); 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_.Dump(os, indent_os); os << "\n"; @@ -2070,6 +2073,7 @@ class ImageDumper { 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; @@ -2101,6 +2105,7 @@ class ImageDumper { 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), @@ -2263,6 +2268,7 @@ class ImageDumper { "art_method_bytes = %8zd (%2.0f%% of art file bytes)\n" "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" "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), @@ -2273,11 +2279,14 @@ class ImageDumper { PercentOfFileBytes(dex_cache_arrays_bytes), interned_strings_bytes, PercentOfFileBytes(interned_strings_bytes), + class_table_bytes, PercentOfFileBytes(class_table_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 + bitmap_bytes + alignment_bytes); + 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); } os << "object_bytes breakdown:\n"; diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc index 3d9f7dc2d5..7d2d89905a 100644 --- a/patchoat/patchoat.cc +++ b/patchoat/patchoat.cc @@ -526,6 +526,21 @@ void PatchOat::PatchInternedStrings(const ImageHeader* image_header) { temp_table.VisitRoots(&visitor, kVisitRootFlagAllRoots); } +void PatchOat::PatchClassTable(const ImageHeader* image_header) { + const auto& section = image_header->GetImageSection(ImageHeader::kSectionClassTable); + // ClassTable temp_table; + // Note that we require that ReadFromMemory does not make an internal copy of the elements. + // This also relies on visit roots not doing any verification which could fail after we update + // the roots to be the image addresses. + WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); + ClassTable temp_table; + temp_table.ReadFromMemory(image_->Begin() + section.Offset()); + FixupRootVisitor visitor(this); + BufferedRootVisitor<kDefaultBufferedRootCount> buffered_visitor(&visitor, RootInfo(kRootUnknown)); + temp_table.VisitRoots(buffered_visitor); +} + + class RelocatedPointerVisitor { public: explicit RelocatedPointerVisitor(PatchOat* patch_oat) : patch_oat_(patch_oat) {} @@ -606,6 +621,7 @@ bool PatchOat::PatchImage() { PatchArtFields(image_header); PatchArtMethods(image_header); PatchInternedStrings(image_header); + PatchClassTable(image_header); // Patch dex file int/long arrays which point to ArtFields. PatchDexFileArrays(img_roots); diff --git a/patchoat/patchoat.h b/patchoat/patchoat.h index 09150144ec..38bd865b22 100644 --- a/patchoat/patchoat.h +++ b/patchoat/patchoat.h @@ -116,6 +116,8 @@ class PatchOat { void PatchArtMethods(const ImageHeader* image_header) SHARED_REQUIRES(Locks::mutator_lock_); void PatchInternedStrings(const ImageHeader* image_header) SHARED_REQUIRES(Locks::mutator_lock_); + void PatchClassTable(const ImageHeader* image_header) + SHARED_REQUIRES(Locks::mutator_lock_); void PatchDexFileArrays(mirror::ObjectArray<mirror::Object>* img_roots) SHARED_REQUIRES(Locks::mutator_lock_); diff --git a/runtime/base/hash_set.h b/runtime/base/hash_set.h index 95baa822b1..fc1a52f807 100644 --- a/runtime/base/hash_set.h +++ b/runtime/base/hash_set.h @@ -236,7 +236,7 @@ class HashSet { // 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 @@ class HashSet { } // 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 2dd2a83888..879544f42f 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -1017,6 +1017,15 @@ bool ClassLinker::InitFromImage(std::string* error_msg) { 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 @@ void ClassLinker::AddImageClassesToClassTable(gc::space::ImageSpace* image_space 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 3ed1c9540d..4656b740b9 100644 --- a/runtime/class_table.cc +++ b/runtime/class_table.cc @@ -115,7 +115,7 @@ bool ClassTable::Remove(const char* descriptor) { 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 @@ bool ClassTable::ClassDescriptorHashEquals::operator()(const GcRoot<mirror::Clas 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 @@ bool ClassTable::InsertDexFile(mirror::Object* dex_file) { 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 002bb564ab..219e2c620a 100644 --- a/runtime/class_table.h +++ b/runtime/class_table.h @@ -104,17 +104,26 @@ class ClassTable { 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 1bc19ff656..2eac3fb873 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 555cf5ddb7..a16f3c98fb 100644 --- a/runtime/image.h +++ b/runtime/image.h @@ -170,6 +170,7 @@ class PACKED(4) ImageHeader { kSectionArtMethods, kSectionDexCacheArrays, kSectionInternedStrings, + kSectionClassTable, kSectionImageBitmap, kSectionCount, // Number of elements in enum. }; diff --git a/runtime/utf.cc b/runtime/utf.cc index 5a116980c9..a2d6363c6e 100644 --- a/runtime/utf.cc +++ b/runtime/utf.cc @@ -178,8 +178,8 @@ int32_t ComputeUtf16Hash(const uint16_t* chars, size_t char_count) { 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 03158c492d..4abd605f5a 100644 --- a/runtime/utf.h +++ b/runtime/utf.h @@ -85,8 +85,8 @@ int32_t ComputeUtf16Hash(mirror::CharArray* chars, int32_t offset, size_t char_c 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. |