From 8e2478d23e89a7022c93ddc608dcbba7b29b91e6 Mon Sep 17 00:00:00 2001 From: Mathieu Chartier Date: Wed, 27 Apr 2016 21:03:42 +0000 Subject: [PATCH] Revert "Write conflict tables in image" Some strange issues on angler. This reverts commit cda9386add68d94697449c6cb08b356747e55c21. Change-Id: Iba3a8bac6ce40ee16d83163823356951fecb6787 --- compiler/driver/compiler_driver.cc | 14 +- compiler/image_writer.cc | 229 ++++++++------------- compiler/image_writer.h | 24 +-- oatdump/oatdump.cc | 23 +-- patchoat/patchoat.cc | 19 +- patchoat/patchoat.h | 2 - runtime/arch/stub_test.cc | 10 +- runtime/art_method.h | 138 ++++--------- runtime/class_linker.cc | 153 ++++++-------- runtime/class_linker.h | 30 +-- .../quick/quick_trampoline_entrypoints.cc | 3 +- runtime/gc/space/image_space.cc | 37 +--- runtime/image-inl.h | 16 -- runtime/image.cc | 26 +-- runtime/image.h | 30 +-- runtime/runtime.cc | 31 +-- runtime/runtime.h | 1 - runtime/stack.cc | 6 +- runtime/thread.cc | 8 +- runtime/thread.h | 7 +- 20 files changed, 278 insertions(+), 529 deletions(-) diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 9c3aceb59..6cba8b744 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -2440,7 +2440,7 @@ void CompilerDriver::InitializeClasses(jobject jni_class_loader, context.ForAll(0, dex_file.NumClassDefs(), &visitor, init_thread_count); } -class InitializeArrayClassesAndCreateConflictTablesVisitor : public ClassVisitor { +class InitializeArrayClassVisitor : public ClassVisitor { public: virtual bool operator()(mirror::Class* klass) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) { if (klass->IsArrayClass()) { @@ -2450,10 +2450,6 @@ class InitializeArrayClassesAndCreateConflictTablesVisitor : public ClassVisitor true, true); } - // Create the conflict tables. - if (klass->ShouldHaveEmbeddedImtAndVTable()) { - Runtime::Current()->GetClassLinker()->FillIMTAndConflictTables(klass); - } return true; } }; @@ -2466,15 +2462,13 @@ void CompilerDriver::InitializeClasses(jobject class_loader, CHECK(dex_file != nullptr); InitializeClasses(class_loader, *dex_file, dex_files, timings); } - if (image_classes_ != nullptr) { + { // Make sure that we call EnsureIntiailized on all the array classes to call // SetVerificationAttempted so that the access flags are set. If we do not do this they get // changed at runtime resulting in more dirty image pages. - // Also create conflict tables. - // Only useful if we are compiling an image (image_classes_ is not null). ScopedObjectAccess soa(Thread::Current()); - InitializeArrayClassesAndCreateConflictTablesVisitor visitor; - Runtime::Current()->GetClassLinker()->VisitClassesWithoutClassesLock(&visitor); + InitializeArrayClassVisitor visitor; + Runtime::Current()->GetClassLinker()->VisitClasses(&visitor); } if (IsBootImage()) { // Prune garbage objects created during aborted transactions. diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index 00ff522c9..8bb462c66 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -653,7 +653,8 @@ bool ImageWriter::AllocMemory() { for (ImageInfo& image_info : image_infos_) { ImageSection unused_sections[ImageHeader::kSectionCount]; const size_t length = RoundUp( - image_info.CreateImageSections(unused_sections), kPageSize); + image_info.CreateImageSections(target_ptr_size_, unused_sections), + kPageSize); std::string error_msg; image_info.image_.reset(MemMap::MapAnonymous("image writer image", @@ -1213,20 +1214,6 @@ void ImageWriter::WalkFieldsInOrder(mirror::Object* obj) { AssignMethodOffset(&m, type, oat_index); } (any_dirty ? dirty_methods_ : clean_methods_) += num_methods; - - // Assign offsets for all runtime methods in the IMT since these may hold conflict tables - // live. - if (as_klass->ShouldHaveEmbeddedImtAndVTable()) { - for (size_t i = 0; i < mirror::Class::kImtSize; ++i) { - ArtMethod* imt_method = as_klass->GetEmbeddedImTableEntry(i, target_ptr_size_); - DCHECK(imt_method != nullptr); - if (imt_method->IsRuntimeMethod() && - !IsInBootImage(imt_method) && - !NativeRelocationAssigned(imt_method)) { - AssignMethodOffset(imt_method, kNativeObjectRelocationTypeRuntimeMethod, oat_index); - } - } - } } } else if (h_obj->IsObjectArray()) { // Walk elements of an object array. @@ -1250,37 +1237,13 @@ void ImageWriter::WalkFieldsInOrder(mirror::Object* obj) { } } -bool ImageWriter::NativeRelocationAssigned(void* ptr) const { - return native_object_relocations_.find(ptr) != native_object_relocations_.end(); -} - -void ImageWriter::TryAssignConflictTableOffset(ImtConflictTable* table, size_t oat_index) { - // No offset, or already assigned. - if (table == nullptr || NativeRelocationAssigned(table)) { - return; - } - CHECK(!IsInBootImage(table)); - // If the method is a conflict method we also want to assign the conflict table offset. - ImageInfo& image_info = GetImageInfo(oat_index); - const size_t size = table->ComputeSize(target_ptr_size_); - native_object_relocations_.emplace( - table, - NativeObjectRelocation { - oat_index, - image_info.bin_slot_sizes_[kBinIMTConflictTable], - kNativeObjectRelocationTypeIMTConflictTable}); - image_info.bin_slot_sizes_[kBinIMTConflictTable] += size; -} - void ImageWriter::AssignMethodOffset(ArtMethod* method, NativeObjectRelocationType type, size_t oat_index) { DCHECK(!IsInBootImage(method)); - CHECK(!NativeRelocationAssigned(method)) << "Method " << method << " already assigned " + auto it = native_object_relocations_.find(method); + CHECK(it == native_object_relocations_.end()) << "Method " << method << " already assigned " << PrettyMethod(method); - if (method->IsRuntimeMethod()) { - TryAssignConflictTableOffset(method->GetImtConflictTable(target_ptr_size_), oat_index); - } ImageInfo& image_info = GetImageInfo(oat_index); size_t& offset = image_info.bin_slot_sizes_[BinTypeForNativeRelocationType(type)]; native_object_relocations_.emplace(method, NativeObjectRelocation { oat_index, offset, type }); @@ -1329,7 +1292,8 @@ void ImageWriter::CalculateNewObjectOffsets() { // know where image_roots is going to end up image_objects_offset_begin_ = RoundUp(sizeof(ImageHeader), kObjectAlignment); // 64-bit-alignment - const size_t method_alignment = ArtMethod::Alignment(target_ptr_size_); + // Clear any pre-existing monitors which may have been in the monitor words, assign bin slots. + heap->VisitObjects(WalkFieldsCallback, this); // Write the image runtime methods. image_methods_[ImageHeader::kResolutionMethod] = runtime->GetResolutionMethod(); image_methods_[ImageHeader::kImtConflictMethod] = runtime->GetImtConflictMethod(); @@ -1339,19 +1303,31 @@ void ImageWriter::CalculateNewObjectOffsets() { runtime->GetCalleeSaveMethod(Runtime::kRefsOnly); image_methods_[ImageHeader::kRefsAndArgsSaveMethod] = runtime->GetCalleeSaveMethod(Runtime::kRefsAndArgs); - // Visit image methods first to have the main runtime methods in the first image. + + // Add room for fake length prefixed array for holding the image methods. + const auto image_method_type = kNativeObjectRelocationTypeArtMethodArrayClean; + auto it = native_object_relocations_.find(&image_method_array_); + CHECK(it == native_object_relocations_.end()); + ImageInfo& default_image_info = GetImageInfo(GetDefaultOatIndex()); + size_t& offset = + default_image_info.bin_slot_sizes_[BinTypeForNativeRelocationType(image_method_type)]; + if (!compile_app_image_) { + native_object_relocations_.emplace(&image_method_array_, + NativeObjectRelocation { GetDefaultOatIndex(), offset, image_method_type }); + } + size_t method_alignment = ArtMethod::Alignment(target_ptr_size_); + const size_t array_size = LengthPrefixedArray::ComputeSize( + 0, ArtMethod::Size(target_ptr_size_), method_alignment); + CHECK_ALIGNED_PARAM(array_size, method_alignment); + offset += array_size; for (auto* m : image_methods_) { CHECK(m != nullptr); CHECK(m->IsRuntimeMethod()); DCHECK_EQ(compile_app_image_, IsInBootImage(m)) << "Trampolines should be in boot image"; if (!IsInBootImage(m)) { - AssignMethodOffset(m, kNativeObjectRelocationTypeRuntimeMethod, GetDefaultOatIndex()); + AssignMethodOffset(m, kNativeObjectRelocationTypeArtMethodClean, GetDefaultOatIndex()); } } - - // Clear any pre-existing monitors which may have been in the monitor words, assign bin slots. - heap->VisitObjects(WalkFieldsCallback, this); - // Calculate size of the dex cache arrays slot and prepare offsets. PrepareDexCacheArraySlots(); @@ -1370,22 +1346,15 @@ void ImageWriter::CalculateNewObjectOffsets() { for (ImageInfo& image_info : image_infos_) { size_t bin_offset = image_objects_offset_begin_; for (size_t i = 0; i != kBinSize; ++i) { - switch (i) { - case kBinArtMethodClean: - case kBinArtMethodDirty: { - bin_offset = RoundUp(bin_offset, method_alignment); - break; - } - case kBinIMTConflictTable: { - bin_offset = RoundUp(bin_offset, target_ptr_size_); - break; - } - default: { - // Normal alignment. - } - } image_info.bin_slot_offsets_[i] = bin_offset; bin_offset += image_info.bin_slot_sizes_[i]; + if (i == kBinArtField) { + static_assert(kBinArtField + 1 == kBinArtMethodClean, "Methods follow fields."); + static_assert(alignof(ArtField) == 4u, "ArtField alignment is 4."); + DCHECK_ALIGNED(bin_offset, 4u); + DCHECK(method_alignment == 4u || method_alignment == 8u); + bin_offset = RoundUp(bin_offset, method_alignment); + } } // NOTE: There may be additional padding between the bin slots and the intern table. DCHECK_EQ(image_info.image_end_, @@ -1398,7 +1367,9 @@ void ImageWriter::CalculateNewObjectOffsets() { image_info.image_begin_ = global_image_begin_ + image_offset; image_info.image_offset_ = image_offset; ImageSection unused_sections[ImageHeader::kSectionCount]; - image_info.image_size_ = RoundUp(image_info.CreateImageSections(unused_sections), kPageSize); + image_info.image_size_ = RoundUp( + image_info.CreateImageSections(target_ptr_size_, unused_sections), + kPageSize); // There should be no gaps until the next image. image_offset += image_info.image_size_; } @@ -1425,52 +1396,42 @@ void ImageWriter::CalculateNewObjectOffsets() { // Note that image_info.image_end_ is left at end of used mirror object section. } -size_t ImageWriter::ImageInfo::CreateImageSections(ImageSection* out_sections) const { +size_t ImageWriter::ImageInfo::CreateImageSections(size_t target_ptr_size, + ImageSection* out_sections) const { DCHECK(out_sections != nullptr); - - // Do not round up any sections here that are represented by the bins since it will break - // offsets. - // Objects section - ImageSection* objects_section = &out_sections[ImageHeader::kSectionObjects]; + auto* objects_section = &out_sections[ImageHeader::kSectionObjects]; *objects_section = ImageSection(0u, image_end_); - + size_t cur_pos = objects_section->End(); // Add field section. - ImageSection* field_section = &out_sections[ImageHeader::kSectionArtFields]; - *field_section = ImageSection(bin_slot_offsets_[kBinArtField], bin_slot_sizes_[kBinArtField]); + auto* field_section = &out_sections[ImageHeader::kSectionArtFields]; + *field_section = ImageSection(cur_pos, bin_slot_sizes_[kBinArtField]); CHECK_EQ(bin_slot_offsets_[kBinArtField], field_section->Offset()); - + cur_pos = field_section->End(); + // Round up to the alignment the required by the method section. + cur_pos = RoundUp(cur_pos, ArtMethod::Alignment(target_ptr_size)); // Add method section. - ImageSection* methods_section = &out_sections[ImageHeader::kSectionArtMethods]; - *methods_section = ImageSection( - bin_slot_offsets_[kBinArtMethodClean], - bin_slot_sizes_[kBinArtMethodClean] + bin_slot_sizes_[kBinArtMethodDirty]); - - // Conflict tables section. - ImageSection* imt_conflict_tables_section = &out_sections[ImageHeader::kSectionIMTConflictTables]; - *imt_conflict_tables_section = ImageSection(bin_slot_offsets_[kBinIMTConflictTable], - bin_slot_sizes_[kBinIMTConflictTable]); - - // Runtime methods section. - ImageSection* runtime_methods_section = &out_sections[ImageHeader::kSectionRuntimeMethods]; - *runtime_methods_section = ImageSection(bin_slot_offsets_[kBinRuntimeMethod], - bin_slot_sizes_[kBinRuntimeMethod]); - + auto* methods_section = &out_sections[ImageHeader::kSectionArtMethods]; + *methods_section = ImageSection(cur_pos, + bin_slot_sizes_[kBinArtMethodClean] + + bin_slot_sizes_[kBinArtMethodDirty]); + CHECK_EQ(bin_slot_offsets_[kBinArtMethodClean], methods_section->Offset()); + cur_pos = methods_section->End(); // Add dex cache arrays section. - ImageSection* dex_cache_arrays_section = &out_sections[ImageHeader::kSectionDexCacheArrays]; - *dex_cache_arrays_section = ImageSection(bin_slot_offsets_[kBinDexCacheArray], - bin_slot_sizes_[kBinDexCacheArray]); - + auto* dex_cache_arrays_section = &out_sections[ImageHeader::kSectionDexCacheArrays]; + *dex_cache_arrays_section = ImageSection(cur_pos, bin_slot_sizes_[kBinDexCacheArray]); + CHECK_EQ(bin_slot_offsets_[kBinDexCacheArray], dex_cache_arrays_section->Offset()); + cur_pos = dex_cache_arrays_section->End(); // Round up to the alignment the string table expects. See HashSet::WriteToMemory. - size_t cur_pos = RoundUp(dex_cache_arrays_section->End(), sizeof(uint64_t)); + cur_pos = RoundUp(cur_pos, sizeof(uint64_t)); // Calculate the size of the interned strings. - ImageSection* interned_strings_section = &out_sections[ImageHeader::kSectionInternedStrings]; + auto* interned_strings_section = &out_sections[ImageHeader::kSectionInternedStrings]; *interned_strings_section = ImageSection(cur_pos, intern_table_bytes_); cur_pos = interned_strings_section->End(); // Round up to the alignment the class table expects. See HashSet::WriteToMemory. cur_pos = RoundUp(cur_pos, sizeof(uint64_t)); // Calculate the size of the class table section. - ImageSection* class_table_section = &out_sections[ImageHeader::kSectionClassTable]; + auto* class_table_section = &out_sections[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. @@ -1485,7 +1446,7 @@ void ImageWriter::CreateHeader(size_t oat_index) { // Create the image sections. ImageSection sections[ImageHeader::kSectionCount]; - const size_t image_end = image_info.CreateImageSections(sections); + const size_t image_end = image_info.CreateImageSections(target_ptr_size_, sections); // Finally bitmap section. const size_t bitmap_bytes = image_info.image_bitmap_->Size(); @@ -1570,20 +1531,8 @@ class FixupRootVisitor : public RootVisitor { ImageWriter* const image_writer_; }; -void ImageWriter::CopyAndFixupImtConflictTable(ImtConflictTable* orig, ImtConflictTable* copy) { - const size_t count = orig->NumEntries(target_ptr_size_); - for (size_t i = 0; i < count; ++i) { - ArtMethod* interface_method = orig->GetInterfaceMethod(i, target_ptr_size_); - ArtMethod* implementation_method = orig->GetImplementationMethod(i, target_ptr_size_); - copy->SetInterfaceMethod(i, target_ptr_size_, NativeLocationInImage(interface_method)); - copy->SetImplementationMethod(i, - target_ptr_size_, - NativeLocationInImage(implementation_method)); - } -} - void ImageWriter::CopyAndFixupNativeData(size_t oat_index) { - const ImageInfo& image_info = GetImageInfo(oat_index); + ImageInfo& image_info = GetImageInfo(oat_index); // Copy ArtFields and methods to their locations and update the array for convenience. for (auto& pair : native_object_relocations_) { NativeObjectRelocation& relocation = pair.second; @@ -1601,7 +1550,6 @@ void ImageWriter::CopyAndFixupNativeData(size_t oat_index) { GetImageAddress(reinterpret_cast(pair.first)->GetDeclaringClass())); break; } - case kNativeObjectRelocationTypeRuntimeMethod: case kNativeObjectRelocationTypeArtMethodClean: case kNativeObjectRelocationTypeArtMethodDirty: { CopyAndFixupMethod(reinterpret_cast(pair.first), @@ -1627,22 +1575,26 @@ void ImageWriter::CopyAndFixupNativeData(size_t oat_index) { case kNativeObjectRelocationTypeDexCacheArray: // Nothing to copy here, everything is done in FixupDexCache(). break; - case kNativeObjectRelocationTypeIMTConflictTable: { - auto* orig_table = reinterpret_cast(pair.first); - CopyAndFixupImtConflictTable( - orig_table, - new(dest)ImtConflictTable(orig_table->NumEntries(target_ptr_size_), target_ptr_size_)); - break; - } } } // Fixup the image method roots. auto* image_header = reinterpret_cast(image_info.image_->Begin()); + const ImageSection& methods_section = image_header->GetMethodsSection(); for (size_t i = 0; i < ImageHeader::kImageMethodsCount; ++i) { ArtMethod* method = image_methods_[i]; CHECK(method != nullptr); + // Only place runtime methods in the image of the default oat file. + if (method->IsRuntimeMethod() && oat_index != GetDefaultOatIndex()) { + continue; + } if (!IsInBootImage(method)) { - method = NativeLocationInImage(method); + auto it = native_object_relocations_.find(method); + CHECK(it != native_object_relocations_.end()) << "No forwarding for " << PrettyMethod(method); + NativeObjectRelocation& relocation = it->second; + CHECK(methods_section.Contains(relocation.offset)) << relocation.offset << " not in " + << methods_section; + CHECK(relocation.IsArtMethodRelocation()) << relocation.type; + method = reinterpret_cast(global_image_begin_ + it->second.offset); } image_header->SetImageMethod(static_cast(i), method); } @@ -2105,28 +2057,24 @@ void ImageWriter::CopyAndFixupMethod(ArtMethod* orig, // The resolution method has a special trampoline to call. Runtime* runtime = Runtime::Current(); - if (orig->IsRuntimeMethod()) { - ImtConflictTable* orig_table = orig->GetImtConflictTable(target_ptr_size_); - if (orig_table != nullptr) { - // Special IMT conflict method, normal IMT conflict method or unimplemented IMT method. - copy->SetEntryPointFromQuickCompiledCodePtrSize( - GetOatAddress(kOatAddressQuickIMTConflictTrampoline), target_ptr_size_); - copy->SetImtConflictTable(NativeLocationInImage(orig_table), target_ptr_size_); - } else if (UNLIKELY(orig == runtime->GetResolutionMethod())) { - copy->SetEntryPointFromQuickCompiledCodePtrSize( - GetOatAddress(kOatAddressQuickResolutionTrampoline), target_ptr_size_); - } else { - bool found_one = false; - for (size_t i = 0; i < static_cast(Runtime::kLastCalleeSaveType); ++i) { - auto idx = static_cast(i); - if (runtime->HasCalleeSaveMethod(idx) && runtime->GetCalleeSaveMethod(idx) == orig) { - found_one = true; - break; - } + if (UNLIKELY(orig == runtime->GetResolutionMethod())) { + copy->SetEntryPointFromQuickCompiledCodePtrSize( + GetOatAddress(kOatAddressQuickResolutionTrampoline), target_ptr_size_); + } else if (UNLIKELY(orig == runtime->GetImtConflictMethod() || + orig == runtime->GetImtUnimplementedMethod())) { + copy->SetEntryPointFromQuickCompiledCodePtrSize( + GetOatAddress(kOatAddressQuickIMTConflictTrampoline), target_ptr_size_); + } else if (UNLIKELY(orig->IsRuntimeMethod())) { + bool found_one = false; + for (size_t i = 0; i < static_cast(Runtime::kLastCalleeSaveType); ++i) { + auto idx = static_cast(i); + if (runtime->HasCalleeSaveMethod(idx) && runtime->GetCalleeSaveMethod(idx) == orig) { + found_one = true; + break; } - CHECK(found_one) << "Expected to find callee save method but got " << PrettyMethod(orig); - CHECK(copy->IsRuntimeMethod()); } + CHECK(found_one) << "Expected to find callee save method but got " << PrettyMethod(orig); + CHECK(copy->IsRuntimeMethod()); } else { // We assume all methods have code. If they don't currently then we set them to the use the // resolution trampoline. Abstract methods never have code and so we need to make sure their @@ -2193,10 +2141,6 @@ ImageWriter::Bin ImageWriter::BinTypeForNativeRelocationType(NativeObjectRelocat return kBinArtMethodDirty; case kNativeObjectRelocationTypeDexCacheArray: return kBinDexCacheArray; - case kNativeObjectRelocationTypeRuntimeMethod: - return kBinRuntimeMethod; - case kNativeObjectRelocationTypeIMTConflictTable: - return kBinIMTConflictTable; } UNREACHABLE(); } @@ -2298,6 +2242,7 @@ ImageWriter::ImageWriter( compile_app_image_(compile_app_image), target_ptr_size_(InstructionSetPointerSize(compiler_driver_.GetInstructionSet())), image_infos_(oat_filenames.size()), + image_method_array_(ImageHeader::kImageMethodsCount), dirty_methods_(0u), clean_methods_(0u), image_storage_mode_(image_storage_mode), diff --git a/compiler/image_writer.h b/compiler/image_writer.h index 51976c511..0cb6aea9b 100644 --- a/compiler/image_writer.h +++ b/compiler/image_writer.h @@ -169,10 +169,6 @@ class ImageWriter FINAL { // ArtMethods may be dirty if the class has native methods or a declaring class that isn't // initialized. kBinArtMethodDirty, - // Conflict tables (clean). - kBinIMTConflictTable, - // Runtime methods (always clean, do not have a length prefix array). - kBinRuntimeMethod, // 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. @@ -190,8 +186,6 @@ class ImageWriter FINAL { kNativeObjectRelocationTypeArtMethodArrayClean, kNativeObjectRelocationTypeArtMethodDirty, kNativeObjectRelocationTypeArtMethodArrayDirty, - kNativeObjectRelocationTypeRuntimeMethod, - kNativeObjectRelocationTypeIMTConflictTable, kNativeObjectRelocationTypeDexCacheArray, }; friend std::ostream& operator<<(std::ostream& stream, const NativeObjectRelocationType& type); @@ -246,7 +240,7 @@ class ImageWriter FINAL { // Create the image sections into the out sections variable, returns the size of the image // excluding the bitmap. - size_t CreateImageSections(ImageSection* out_sections) const; + size_t CreateImageSections(size_t target_ptr_size, ImageSection* out_sections) const; std::unique_ptr image_; // Memory mapped for generating the image. @@ -401,8 +395,6 @@ class ImageWriter FINAL { void CopyAndFixupObject(mirror::Object* obj) SHARED_REQUIRES(Locks::mutator_lock_); void CopyAndFixupMethod(ArtMethod* orig, ArtMethod* copy, const ImageInfo& image_info) SHARED_REQUIRES(Locks::mutator_lock_); - void CopyAndFixupImtConflictTable(ImtConflictTable* orig, ImtConflictTable* copy) - SHARED_REQUIRES(Locks::mutator_lock_); void FixupClass(mirror::Class* orig, mirror::Class* copy) SHARED_REQUIRES(Locks::mutator_lock_); void FixupObject(mirror::Object* orig, mirror::Object* copy) @@ -433,11 +425,6 @@ class ImageWriter FINAL { size_t oat_index) SHARED_REQUIRES(Locks::mutator_lock_); - // Assign the offset for an IMT conflict table. Does nothing if the table already has a native - // relocation. - void TryAssignConflictTableOffset(ImtConflictTable* table, size_t oat_index) - SHARED_REQUIRES(Locks::mutator_lock_); - // Return true if klass is loaded by the boot class loader but not in the boot image. bool IsBootClassLoaderNonImageClass(mirror::Class* klass) SHARED_REQUIRES(Locks::mutator_lock_); @@ -494,9 +481,6 @@ class ImageWriter FINAL { // remove duplicates in the multi image and app image case. mirror::String* FindInternedString(mirror::String* string) SHARED_REQUIRES(Locks::mutator_lock_); - // Return true if there already exists a native allocation for an object. - bool NativeRelocationAssigned(void* ptr) const; - const CompilerDriver& compiler_driver_; // Beginning target image address for the first image. @@ -533,14 +517,16 @@ class ImageWriter FINAL { bool IsArtMethodRelocation() const { return type == kNativeObjectRelocationTypeArtMethodClean || - type == kNativeObjectRelocationTypeArtMethodDirty || - type == kNativeObjectRelocationTypeRuntimeMethod; + type == kNativeObjectRelocationTypeArtMethodDirty; } }; std::unordered_map native_object_relocations_; // Runtime ArtMethods which aren't reachable from any Class but need to be copied into the image. ArtMethod* image_methods_[ImageHeader::kImageMethodsCount]; + // Fake length prefixed array for image methods. This array does not contain the actual + // ArtMethods. We only use it for the header and relocation addresses. + LengthPrefixedArray image_method_array_; // Counters for measurements, used for logging only. uint64_t dirty_methods_; diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 6ecfc74e8..3c6a05d97 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -1416,10 +1416,11 @@ class ImageDumper { indent_os << "\n"; // TODO: Dump fields. // Dump methods after. + const auto& methods_section = image_header_.GetMethodsSection(); DumpArtMethodVisitor visitor(this); - image_header_.VisitPackedArtMethods(&visitor, - image_space_.Begin(), - image_header_.GetPointerSize()); + methods_section.VisitPackedArtMethods(&visitor, + image_space_.Begin(), + image_header_.GetPointerSize()); // Dump the large objects separately. heap->GetLargeObjectsSpace()->GetLiveBitmap()->Walk(ImageDumper::Callback, this); indent_os << "\n"; @@ -1778,7 +1779,6 @@ class ImageDumper { DCHECK(method != nullptr); const void* quick_oat_code_begin = GetQuickOatCodeBegin(method); const void* quick_oat_code_end = GetQuickOatCodeEnd(method); - const size_t pointer_size = image_header_.GetPointerSize(); OatQuickMethodHeader* method_header = reinterpret_cast( reinterpret_cast(quick_oat_code_begin) - sizeof(OatQuickMethodHeader)); if (method->IsNative()) { @@ -1792,16 +1792,13 @@ class ImageDumper { image_header_.GetPointerSize())) { indent_os << StringPrintf("OAT CODE: %p\n", quick_oat_code_begin); } - } else if (method->IsAbstract() || method->IsClassInitializer()) { + } else if (method->IsAbstract() || + method->IsCalleeSaveMethod() || + method->IsResolutionMethod() || + (method == Runtime::Current()->GetImtConflictMethod()) || + method->IsImtUnimplementedMethod() || + method->IsClassInitializer()) { // Don't print information for these. - } else if (method->IsRuntimeMethod()) { - ImtConflictTable* table = method->GetImtConflictTable(image_header_.GetPointerSize()); - if (table != nullptr) { - indent_os << "IMT conflict table " << table << " method: "; - for (size_t i = 0, count = table->NumEntries(pointer_size); i < count; ++i) { - indent_os << PrettyMethod(table->GetImplementationMethod(i, pointer_size)) << " "; - } - } } else { const DexFile::CodeItem* code_item = method->GetCodeItem(); size_t dex_instruction_bytes = code_item->insns_size_in_code_units_ * 2; diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc index 0a7ffda3b..93e40afea 100644 --- a/patchoat/patchoat.cc +++ b/patchoat/patchoat.cc @@ -472,7 +472,8 @@ class PatchOatArtFieldVisitor : public ArtFieldVisitor { void PatchOat::PatchArtFields(const ImageHeader* image_header) { PatchOatArtFieldVisitor visitor(this); - image_header->VisitPackedArtFields(&visitor, heap_->Begin()); + const auto& section = image_header->GetImageSection(ImageHeader::kSectionArtFields); + section.VisitPackedArtFields(&visitor, heap_->Begin()); } class PatchOatArtMethodVisitor : public ArtMethodVisitor { @@ -489,20 +490,10 @@ class PatchOatArtMethodVisitor : public ArtMethodVisitor { }; void PatchOat::PatchArtMethods(const ImageHeader* image_header) { + const auto& section = image_header->GetMethodsSection(); const size_t pointer_size = InstructionSetPointerSize(isa_); PatchOatArtMethodVisitor visitor(this); - image_header->VisitPackedArtMethods(&visitor, heap_->Begin(), pointer_size); -} - -void PatchOat::PatchImtConflictTables(const ImageHeader* image_header) { - const size_t pointer_size = InstructionSetPointerSize(isa_); - // We can safely walk target image since the conflict tables are independent. - image_header->VisitPackedImtConflictTables( - [this](ArtMethod* method) { - return RelocatedAddressOfPointer(method); - }, - image_->Begin(), - pointer_size); + section.VisitPackedArtMethods(&visitor, heap_->Begin(), pointer_size); } class FixupRootVisitor : public RootVisitor { @@ -636,7 +627,6 @@ bool PatchOat::PatchImage(bool primary_image) { PatchArtFields(image_header); PatchArtMethods(image_header); - PatchImtConflictTables(image_header); PatchInternedStrings(image_header); PatchClassTable(image_header); // Patch dex file int/long arrays which point to ArtFields. @@ -735,7 +725,6 @@ void PatchOat::FixupMethod(ArtMethod* object, ArtMethod* copy) { RelocatedAddressOfPointer(object->GetDexCacheResolvedTypes(pointer_size)), pointer_size); copy->SetEntryPointFromQuickCompiledCodePtrSize(RelocatedAddressOfPointer( object->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size)), pointer_size); - // No special handling for IMT conflict table since all pointers are moved by the same offset. copy->SetEntryPointFromJniPtrSize(RelocatedAddressOfPointer( object->GetEntryPointFromJniPtrSize(pointer_size)), pointer_size); } diff --git a/patchoat/patchoat.h b/patchoat/patchoat.h index 3ef837fde..510ff1e5b 100644 --- a/patchoat/patchoat.h +++ b/patchoat/patchoat.h @@ -117,8 +117,6 @@ class PatchOat { bool PatchImage(bool primary_image) SHARED_REQUIRES(Locks::mutator_lock_); void PatchArtFields(const ImageHeader* image_header) SHARED_REQUIRES(Locks::mutator_lock_); void PatchArtMethods(const ImageHeader* image_header) SHARED_REQUIRES(Locks::mutator_lock_); - void PatchImtConflictTables(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) diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc index 3cdff5567..75d9073cf 100644 --- a/runtime/arch/stub_test.cc +++ b/runtime/arch/stub_test.cc @@ -2010,14 +2010,14 @@ TEST_F(StubTest, DISABLED_IMT) { // that will create it: the runtime stub expects to be called by compiled code. LinearAlloc* linear_alloc = Runtime::Current()->GetLinearAlloc(); ArtMethod* conflict_method = Runtime::Current()->CreateImtConflictMethod(linear_alloc); - ImtConflictTable* empty_conflict_table = - Runtime::Current()->GetClassLinker()->CreateImtConflictTable(/*count*/0u, linear_alloc); + static ImtConflictTable::Entry empty_entry = { nullptr, nullptr }; + ImtConflictTable* empty_conflict_table = reinterpret_cast(&empty_entry); void* data = linear_alloc->Alloc( self, - ImtConflictTable::ComputeSizeWithOneMoreEntry(empty_conflict_table, sizeof(void*))); + ImtConflictTable::ComputeSizeWithOneMoreEntry(empty_conflict_table)); ImtConflictTable* new_table = new (data) ImtConflictTable( - empty_conflict_table, inf_contains, contains_amethod, sizeof(void*)); - conflict_method->SetImtConflictTable(new_table, sizeof(void*)); + empty_conflict_table, inf_contains, contains_amethod); + conflict_method->SetImtConflictTable(new_table); size_t result = Invoke3WithReferrerAndHidden(reinterpret_cast(conflict_method), diff --git a/runtime/art_method.h b/runtime/art_method.h index d239b423c..ae60447c4 100644 --- a/runtime/art_method.h +++ b/runtime/art_method.h @@ -41,7 +41,6 @@ class ShadowFrame; namespace mirror { class Array; class Class; -class IfTable; class PointerArray; } // namespace mirror @@ -51,151 +50,97 @@ class PointerArray; // with the last entry being null to make an assembly implementation of a lookup // faster. class ImtConflictTable { - enum MethodIndex { - kMethodInterface, - kMethodImplementation, - kMethodCount, // Number of elements in enum. - }; - public: // Build a new table copying `other` and adding the new entry formed of // the pair { `interface_method`, `implementation_method` } ImtConflictTable(ImtConflictTable* other, ArtMethod* interface_method, - ArtMethod* implementation_method, - size_t pointer_size) { - const size_t count = other->NumEntries(pointer_size); - for (size_t i = 0; i < count; ++i) { - SetInterfaceMethod(i, pointer_size, other->GetInterfaceMethod(i, pointer_size)); - SetImplementationMethod(i, pointer_size, other->GetImplementationMethod(i, pointer_size)); + ArtMethod* implementation_method) { + size_t index = 0; + while (other->entries_[index].interface_method != nullptr) { + entries_[index] = other->entries_[index]; + index++; } - SetInterfaceMethod(count, pointer_size, interface_method); - SetImplementationMethod(count, pointer_size, implementation_method); + entries_[index].interface_method = interface_method; + entries_[index].implementation_method = implementation_method; // Add the null marker. - SetInterfaceMethod(count + 1, pointer_size, nullptr); - SetImplementationMethod(count + 1, pointer_size, nullptr); + entries_[index + 1].interface_method = nullptr; + entries_[index + 1].implementation_method = nullptr; } // num_entries excludes the header. - ImtConflictTable(size_t num_entries, size_t pointer_size) { - SetInterfaceMethod(num_entries, pointer_size, nullptr); - SetImplementationMethod(num_entries, pointer_size, nullptr); + explicit ImtConflictTable(size_t num_entries) { + entries_[num_entries].interface_method = nullptr; + entries_[num_entries].implementation_method = nullptr; } // Set an entry at an index. - void SetInterfaceMethod(size_t index, size_t pointer_size, ArtMethod* method) { - SetMethod(index * kMethodCount + kMethodInterface, pointer_size, method); + void SetInterfaceMethod(size_t index, ArtMethod* method) { + entries_[index].interface_method = method; } - void SetImplementationMethod(size_t index, size_t pointer_size, ArtMethod* method) { - SetMethod(index * kMethodCount + kMethodImplementation, pointer_size, method); + void SetImplementationMethod(size_t index, ArtMethod* method) { + entries_[index].implementation_method = method; } - ArtMethod* GetInterfaceMethod(size_t index, size_t pointer_size) const { - return GetMethod(index * kMethodCount + kMethodInterface, pointer_size); + ArtMethod* GetInterfaceMethod(size_t index) const { + return entries_[index].interface_method; } - ArtMethod* GetImplementationMethod(size_t index, size_t pointer_size) const { - return GetMethod(index * kMethodCount + kMethodImplementation, pointer_size); - } - - // Visit all of the entries. - // NO_THREAD_SAFETY_ANALYSIS for calling with held locks. Visitor is passed a pair of ArtMethod* - // and also returns one. The order is . - template - void Visit(const Visitor& visitor, size_t pointer_size) NO_THREAD_SAFETY_ANALYSIS { - uint32_t table_index = 0; - for (;;) { - ArtMethod* interface_method = GetInterfaceMethod(table_index, pointer_size); - if (interface_method == nullptr) { - break; - } - ArtMethod* implementation_method = GetImplementationMethod(table_index, pointer_size); - auto input = std::make_pair(interface_method, implementation_method); - std::pair updated = visitor(input); - if (input.first != updated.first) { - SetInterfaceMethod(table_index, pointer_size, updated.first); - } - if (input.second != updated.second) { - SetImplementationMethod(table_index, pointer_size, updated.second); - } - ++table_index; - } + ArtMethod* GetImplementationMethod(size_t index) const { + return entries_[index].implementation_method; } // Lookup the implementation ArtMethod associated to `interface_method`. Return null // if not found. - ArtMethod* Lookup(ArtMethod* interface_method, size_t pointer_size) const { + ArtMethod* Lookup(ArtMethod* interface_method) const { uint32_t table_index = 0; - for (;;) { - ArtMethod* current_interface_method = GetInterfaceMethod(table_index, pointer_size); - if (current_interface_method == nullptr) { - break; - } + ArtMethod* current_interface_method; + while ((current_interface_method = entries_[table_index].interface_method) != nullptr) { if (current_interface_method == interface_method) { - return GetImplementationMethod(table_index, pointer_size); + return entries_[table_index].implementation_method; } - ++table_index; + table_index++; } return nullptr; } // Compute the number of entries in this table. - size_t NumEntries(size_t pointer_size) const { + size_t NumEntries() const { uint32_t table_index = 0; - while (GetInterfaceMethod(table_index, pointer_size) != nullptr) { - ++table_index; + while (entries_[table_index].interface_method != nullptr) { + table_index++; } return table_index; } // Compute the size in bytes taken by this table. - size_t ComputeSize(size_t pointer_size) const { + size_t ComputeSize() const { // Add the end marker. - return ComputeSize(NumEntries(pointer_size), pointer_size); + return ComputeSize(NumEntries()); } // Compute the size in bytes needed for copying the given `table` and add // one more entry. - static size_t ComputeSizeWithOneMoreEntry(ImtConflictTable* table, size_t pointer_size) { - return table->ComputeSize(pointer_size) + EntrySize(pointer_size); + static size_t ComputeSizeWithOneMoreEntry(ImtConflictTable* table) { + return table->ComputeSize() + sizeof(Entry); } // Compute size with a fixed number of entries. - static size_t ComputeSize(size_t num_entries, size_t pointer_size) { - return (num_entries + 1) * EntrySize(pointer_size); // Add one for null terminator. + static size_t ComputeSize(size_t num_entries) { + return (num_entries + 1) * sizeof(Entry); // Add one for null terminator. } - static size_t EntrySize(size_t pointer_size) { - return pointer_size * static_cast(kMethodCount); - } + struct Entry { + ArtMethod* interface_method; + ArtMethod* implementation_method; + }; private: - ArtMethod* GetMethod(size_t index, size_t pointer_size) const { - if (pointer_size == 8) { - return reinterpret_cast(static_cast(data64_[index])); - } else { - DCHECK_EQ(pointer_size, 4u); - return reinterpret_cast(static_cast(data32_[index])); - } - } - - void SetMethod(size_t index, size_t pointer_size, ArtMethod* method) { - if (pointer_size == 8) { - data64_[index] = dchecked_integral_cast(reinterpret_cast(method)); - } else { - DCHECK_EQ(pointer_size, 4u); - data32_[index] = dchecked_integral_cast(reinterpret_cast(method)); - } - } - // Array of entries that the assembly stubs will iterate over. Note that this is // not fixed size, and we allocate data prior to calling the constructor // of ImtConflictTable. - union { - uint32_t data32_[0]; - uint64_t data64_[0]; - }; + Entry entries_[0]; DISALLOW_COPY_AND_ASSIGN(ImtConflictTable); }; @@ -437,6 +382,7 @@ class ArtMethod FINAL { // Find the method that this method overrides. ArtMethod* FindOverriddenMethod(size_t pointer_size) + REQUIRES(Roles::uninterruptible_) SHARED_REQUIRES(Locks::mutator_lock_); // Find the method index for this method within other_dexfile. If this method isn't present then @@ -502,8 +448,8 @@ class ArtMethod FINAL { return reinterpret_cast(GetEntryPointFromJniPtrSize(pointer_size)); } - ALWAYS_INLINE void SetImtConflictTable(ImtConflictTable* table, size_t pointer_size) { - SetEntryPointFromJniPtrSize(table, pointer_size); + ALWAYS_INLINE void SetImtConflictTable(ImtConflictTable* table) { + SetEntryPointFromJniPtrSize(table, sizeof(void*)); } ALWAYS_INLINE void SetProfilingInfo(ProfilingInfo* info) { diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 774d0df0f..dc01d5221 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -687,9 +687,6 @@ bool ClassLinker::InitWithoutImage(std::vector> b self->AssertNoPendingException(); } - // Create conflict tables that depend on the class linker. - runtime->FixupConflictTables(); - FinishInit(self); VLOG(startup) << "ClassLinker::InitFromCompiler exiting"; @@ -776,13 +773,9 @@ static void SanityCheckArtMethod(ArtMethod* m, bool contains = false; for (gc::space::ImageSpace* space : spaces) { auto& header = space->GetImageHeader(); - size_t offset = reinterpret_cast(m) - space->Begin(); - - const ImageSection& methods = header.GetMethodsSection(); - contains = contains || methods.Contains(offset); - - const ImageSection& runtime_methods = header.GetRuntimeMethodsSection(); - contains = contains || runtime_methods.Contains(offset); + auto& methods = header.GetMethodsSection(); + auto offset = reinterpret_cast(m) - space->Begin(); + contains |= methods.Contains(offset); } CHECK(contains) << m << " not found"; } @@ -1445,14 +1438,29 @@ bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( if (*out_forward_dex_cache_array) { ScopedTrace timing("Fixup ArtMethod dex cache arrays"); FixupArtMethodArrayVisitor visitor(header); - header.VisitPackedArtMethods(&visitor, space->Begin(), sizeof(void*)); + header.GetImageSection(ImageHeader::kSectionArtMethods).VisitPackedArtMethods( + &visitor, + space->Begin(), + sizeof(void*)); Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader.Get()); } if (kVerifyArtMethodDeclaringClasses) { ScopedTrace timing("Verify declaring classes"); ReaderMutexLock rmu(self, *Locks::heap_bitmap_lock_); VerifyDeclaringClassVisitor visitor; - header.VisitPackedArtMethods(&visitor, space->Begin(), sizeof(void*)); + header.GetImageSection(ImageHeader::kSectionArtMethods).VisitPackedArtMethods( + &visitor, + space->Begin(), + sizeof(void*)); + } + if (kVerifyArtMethodDeclaringClasses) { + ScopedTrace timing("Verify declaring classes"); + ReaderMutexLock rmu(self, *Locks::heap_bitmap_lock_); + VerifyDeclaringClassVisitor visitor; + header.GetImageSection(ImageHeader::kSectionArtMethods).VisitPackedArtMethods( + &visitor, + space->Begin(), + sizeof(void*)); } return true; } @@ -1730,8 +1738,9 @@ bool ClassLinker::AddImageSpace( // Set entry point to interpreter if in InterpretOnly mode. if (!runtime->IsAotCompiler() && runtime->GetInstrumentation()->InterpretOnly()) { + const ImageSection& methods = header.GetMethodsSection(); SetInterpreterEntrypointArtMethodVisitor visitor(image_pointer_size_); - header.VisitPackedArtMethods(&visitor, space->Begin(), image_pointer_size_); + methods.VisitPackedArtMethods(&visitor, space->Begin(), image_pointer_size_); } ClassTable* class_table = nullptr; @@ -1800,7 +1809,10 @@ bool ClassLinker::AddImageSpace( // This verification needs to happen after the classes have been added to the class loader. // Since it ensures classes are in the class table. VerifyClassInTableArtMethodVisitor visitor2(class_table); - header.VisitPackedArtMethods(&visitor2, space->Begin(), sizeof(void*)); + header.GetImageSection(ImageHeader::kSectionArtMethods).VisitPackedArtMethods( + &visitor2, + space->Begin(), + sizeof(void*)); } VLOG(class_linker) << "Adding image space took " << PrettyDuration(NanoTime() - start_time); return true; @@ -5978,16 +5990,14 @@ ArtMethod* ClassLinker::AddMethodToConflictTable(mirror::Class* klass, // Allocate a new table. Note that we will leak this table at the next conflict, // but that's a tradeoff compared to making the table fixed size. void* data = linear_alloc->Alloc( - Thread::Current(), ImtConflictTable::ComputeSizeWithOneMoreEntry(current_table, - image_pointer_size_)); + Thread::Current(), ImtConflictTable::ComputeSizeWithOneMoreEntry(current_table)); if (data == nullptr) { LOG(ERROR) << "Failed to allocate conflict table"; return conflict_method; } ImtConflictTable* new_table = new (data) ImtConflictTable(current_table, interface_method, - method, - image_pointer_size_); + method); // Do a fence to ensure threads see the data in the table before it is assigned // to the conflict method. @@ -5995,7 +6005,7 @@ ArtMethod* ClassLinker::AddMethodToConflictTable(mirror::Class* klass, // memory from the LinearAlloc, but that's a tradeoff compared to using // atomic operations. QuasiAtomic::ThreadFenceRelease(); - new_conflict_method->SetImtConflictTable(new_table, image_pointer_size_); + new_conflict_method->SetImtConflictTable(new_table); return new_conflict_method; } @@ -6027,52 +6037,18 @@ void ClassLinker::SetIMTRef(ArtMethod* unimplemented_method, } } -void ClassLinker::FillIMTAndConflictTables(mirror::Class* klass) { - DCHECK(klass->ShouldHaveEmbeddedImtAndVTable()); - ArtMethod* imt[mirror::Class::kImtSize]; - Runtime* const runtime = Runtime::Current(); - ArtMethod* const unimplemented_method = runtime->GetImtUnimplementedMethod(); - ArtMethod* const conflict_method = runtime->GetImtConflictMethod(); - std::fill_n(imt, arraysize(imt), unimplemented_method); - if (klass->GetIfTable() != nullptr) { - FillIMTFromIfTable(klass->GetIfTable(), - unimplemented_method, - conflict_method, - klass, - true, - false, - &imt[0]); - } - for (size_t i = 0; i < mirror::Class::kImtSize; ++i) { - klass->SetEmbeddedImTableEntry(i, imt[i], image_pointer_size_); - } -} - static inline uint32_t GetIMTIndex(ArtMethod* interface_method) SHARED_REQUIRES(Locks::mutator_lock_) { return interface_method->GetDexMethodIndex() % mirror::Class::kImtSize; } -ImtConflictTable* ClassLinker::CreateImtConflictTable(size_t count, - LinearAlloc* linear_alloc, - size_t image_pointer_size) { - void* data = linear_alloc->Alloc(Thread::Current(), - ImtConflictTable::ComputeSize(count, - image_pointer_size)); - return (data != nullptr) ? new (data) ImtConflictTable(count, image_pointer_size) : nullptr; -} - -ImtConflictTable* ClassLinker::CreateImtConflictTable(size_t count, LinearAlloc* linear_alloc) { - return CreateImtConflictTable(count, linear_alloc, image_pointer_size_); -} - -void ClassLinker::FillIMTFromIfTable(mirror::IfTable* if_table, - ArtMethod* unimplemented_method, - ArtMethod* imt_conflict_method, - mirror::Class* klass, - bool create_conflict_tables, - bool ignore_copied_methods, - ArtMethod** imt) { +void ClassLinker::ConstructIMTFromIfTable(mirror::IfTable* if_table, + ArtMethod* unimplemented_method, + ArtMethod* imt_conflict_method, + mirror::Class* klass, + bool create_conflict_tables, + bool ignore_copied_methods, + ArtMethod** out_imt) { uint32_t conflict_counts[mirror::Class::kImtSize] = {}; for (size_t i = 0, length = if_table->Count(); i < length; ++i) { mirror::Class* interface = if_table->GetInterface(i); @@ -6115,7 +6091,7 @@ void ClassLinker::FillIMTFromIfTable(mirror::IfTable* if_table, SetIMTRef(unimplemented_method, imt_conflict_method, implementation_method, - /*out*/&imt[imt_index]); + /*out*/&out_imt[imt_index]); } } @@ -6124,22 +6100,24 @@ void ClassLinker::FillIMTFromIfTable(mirror::IfTable* if_table, LinearAlloc* linear_alloc = GetAllocatorForClassLoader(klass->GetClassLoader()); for (size_t i = 0; i < mirror::Class::kImtSize; ++i) { size_t conflicts = conflict_counts[i]; - if (imt[i] == imt_conflict_method) { - ImtConflictTable* new_table = CreateImtConflictTable(conflicts, linear_alloc); - if (new_table != nullptr) { - ArtMethod* new_conflict_method = - Runtime::Current()->CreateImtConflictMethod(linear_alloc); - new_conflict_method->SetImtConflictTable(new_table, image_pointer_size_); - imt[i] = new_conflict_method; + if (conflicts > 1) { + void* data = linear_alloc->Alloc(Thread::Current(), + ImtConflictTable::ComputeSize(conflicts)); + if (data != nullptr) { + ImtConflictTable* new_table = new (data) ImtConflictTable(conflicts); + ArtMethod* new_conflict_method = Runtime::Current()->CreateImtConflictMethod(linear_alloc); + new_conflict_method->SetImtConflictTable(new_table); + out_imt[i] = new_conflict_method; } else { LOG(ERROR) << "Failed to allocate conflict table"; - imt[i] = imt_conflict_method; + out_imt[i] = imt_conflict_method; } } else { - DCHECK_NE(imt[i], imt_conflict_method); + DCHECK_NE(out_imt[i], imt_conflict_method); } } + // No imt in the super class, need to reconstruct from the iftable. for (size_t i = 0, length = if_table->Count(); i < length; ++i) { mirror::Class* interface = if_table->GetInterface(i); const size_t method_array_count = if_table->GetMethodArrayCount(i); @@ -6157,15 +6135,18 @@ void ClassLinker::FillIMTFromIfTable(mirror::IfTable* if_table, DCHECK(implementation_method != nullptr); ArtMethod* interface_method = interface->GetVirtualMethod(j, image_pointer_size_); const uint32_t imt_index = GetIMTIndex(interface_method); - if (!imt[imt_index]->IsRuntimeMethod() || - imt[imt_index] == unimplemented_method || - imt[imt_index] == imt_conflict_method) { + if (conflict_counts[imt_index] <= 1) { continue; // Only care about the conflicts. } - ImtConflictTable* table = imt[imt_index]->GetImtConflictTable(image_pointer_size_); - const size_t num_entries = table->NumEntries(image_pointer_size_); - table->SetInterfaceMethod(num_entries, image_pointer_size_, interface_method); - table->SetImplementationMethod(num_entries, image_pointer_size_, implementation_method); + DCHECK_NE(out_imt[imt_index], unimplemented_method) << PrettyMethod(out_imt[imt_index]); + DCHECK_NE(out_imt[imt_index], imt_conflict_method) << PrettyMethod(out_imt[imt_index]); + DCHECK(out_imt[imt_index]->IsRuntimeMethod()) << PrettyMethod(out_imt[imt_index]); + ImtConflictTable* table = out_imt[imt_index]->GetImtConflictTable(image_pointer_size_); + // Add to the end of the conflict table. + const size_t current_count = table->NumEntries(); + CHECK_LT(current_count, conflict_counts[imt_index]); + table->SetInterfaceMethod(current_count, interface_method); + table->SetImplementationMethod(current_count, implementation_method); } } } @@ -6409,25 +6390,25 @@ static void SanityCheckVTable(Handle klass, uint32_t pointer_size void ClassLinker::FillImtFromSuperClass(Handle klass, ArtMethod* unimplemented_method, ArtMethod* imt_conflict_method, - ArtMethod** imt) { + ArtMethod** out_imt) { DCHECK(klass->HasSuperClass()); mirror::Class* super_class = klass->GetSuperClass(); if (super_class->ShouldHaveEmbeddedImtAndVTable()) { for (size_t i = 0; i < mirror::Class::kImtSize; ++i) { - imt[i] = super_class->GetEmbeddedImTableEntry(i, image_pointer_size_); + out_imt[i] = super_class->GetEmbeddedImTableEntry(i, image_pointer_size_); } } else { // No imt in the super class, need to reconstruct from the iftable. mirror::IfTable* if_table = super_class->GetIfTable(); if (if_table != nullptr) { // Ignore copied methods since we will handle these in LinkInterfaceMethods. - FillIMTFromIfTable(if_table, - unimplemented_method, - imt_conflict_method, - klass.Get(), - /*create_conflict_table*/false, - /*ignore_copied_methods*/true, - /*out*/imt); + ConstructIMTFromIfTable(if_table, + unimplemented_method, + imt_conflict_method, + klass.Get(), + /*create_conflict_table*/false, + /*ignore_copied_methods*/true, + out_imt); } } } diff --git a/runtime/class_linker.h b/runtime/class_linker.h index ece171c9a..274392162 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -53,7 +53,6 @@ namespace mirror { class StackTraceElement; } // namespace mirror -class ImtConflictTable; template class Handle; template class MutableHandle; class InternTable; @@ -618,19 +617,6 @@ class ClassLinker { bool force_new_conflict_method) SHARED_REQUIRES(Locks::mutator_lock_); - // Create a conflict table with a specified capacity. - ImtConflictTable* CreateImtConflictTable(size_t count, LinearAlloc* linear_alloc); - - // Static version for when the class linker is not yet created. - static ImtConflictTable* CreateImtConflictTable(size_t count, - LinearAlloc* linear_alloc, - size_t pointer_size); - - - // Create the IMT and conflict tables for a class. - void FillIMTAndConflictTables(mirror::Class* klass) SHARED_REQUIRES(Locks::mutator_lock_); - - struct DexCacheData { // Weak root to the DexCache. Note: Do not decode this unnecessarily or else class unloading may // not work properly. @@ -1087,18 +1073,18 @@ class ClassLinker { ArtMethod* current_method, /*out*/ArtMethod** imt_ref) SHARED_REQUIRES(Locks::mutator_lock_); - void FillIMTFromIfTable(mirror::IfTable* if_table, - ArtMethod* unimplemented_method, - ArtMethod* imt_conflict_method, - mirror::Class* klass, - bool create_conflict_tables, - bool ignore_copied_methods, - ArtMethod** imt) SHARED_REQUIRES(Locks::mutator_lock_); + void ConstructIMTFromIfTable(mirror::IfTable* if_table, + ArtMethod* unimplemented_method, + ArtMethod* imt_conflict_method, + mirror::Class* klass, + bool create_conflict_tables, + bool ignore_copied_methods, + ArtMethod** out_imt) SHARED_REQUIRES(Locks::mutator_lock_); void FillImtFromSuperClass(Handle klass, ArtMethod* unimplemented_method, ArtMethod* imt_conflict_method, - ArtMethod** imt) SHARED_REQUIRES(Locks::mutator_lock_); + ArtMethod** out_imt) SHARED_REQUIRES(Locks::mutator_lock_); std::vector boot_class_path_; std::vector> boot_dex_files_; diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index e9cdbb743..278c4a304 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -2174,8 +2174,7 @@ extern "C" TwoWordReturn artInvokeInterfaceTrampoline(uint32_t deadbeef ATTRIBUT imt_index % mirror::Class::kImtSize, sizeof(void*)); if (LIKELY(conflict_method->IsRuntimeMethod())) { ImtConflictTable* current_table = conflict_method->GetImtConflictTable(sizeof(void*)); - DCHECK(current_table != nullptr); - method = current_table->Lookup(interface_method, sizeof(void*)); + method = current_table->Lookup(interface_method); } else { // It seems we aren't really a conflict method! method = cls->FindVirtualMethodForInterface(interface_method, sizeof(void*)); diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index 1a33d1f89..d386c7435 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -914,26 +914,10 @@ class FixupArtMethodVisitor : public FixupVisitor, public ArtMethodVisitor { pointer_size_(pointer_size) {} virtual void Visit(ArtMethod* method) NO_THREAD_SAFETY_ANALYSIS { - // TODO: Separate visitor for runtime vs normal methods. - if (UNLIKELY(method->IsRuntimeMethod())) { - ImtConflictTable* table = method->GetImtConflictTable(pointer_size_); - if (table != nullptr) { - ImtConflictTable* new_table = ForwardObject(table); - if (table != new_table) { - method->SetImtConflictTable(new_table, pointer_size_); - } - } - const void* old_code = method->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_); - const void* new_code = ForwardCode(old_code); - if (old_code != new_code) { - method->SetEntryPointFromQuickCompiledCodePtrSize(new_code, pointer_size_); - } - } else { - if (fixup_heap_objects_) { - method->UpdateObjectsForImageRelocation(ForwardObjectAdapter(this), pointer_size_); - } - method->UpdateEntrypoints(ForwardCodeAdapter(this), pointer_size_); + if (fixup_heap_objects_) { + method->UpdateObjectsForImageRelocation(ForwardObjectAdapter(this), pointer_size_); } + method->UpdateEntrypoints(ForwardCodeAdapter(this), pointer_size_); } private: @@ -1034,7 +1018,6 @@ static bool RelocateInPlace(ImageHeader& image_header, const ImageSection& objects_section = image_header.GetImageSection(ImageHeader::kSectionObjects); uintptr_t objects_begin = reinterpret_cast(target_base + objects_section.Offset()); uintptr_t objects_end = reinterpret_cast(target_base + objects_section.End()); - FixupObjectAdapter fixup_adapter(boot_image, boot_oat, app_image, app_oat); if (fixup_image) { // Two pass approach, fix up all classes first, then fix up non class-objects. // The visited bitmap is used to ensure that pointer arrays are not forwarded twice. @@ -1054,6 +1037,7 @@ static bool RelocateInPlace(ImageHeader& image_header, ScopedObjectAccess soa(Thread::Current()); timing.NewTiming("Fixup objects"); bitmap->VisitMarkedRange(objects_begin, objects_end, fixup_object_visitor); + FixupObjectAdapter fixup_adapter(boot_image, boot_oat, app_image, app_oat); // Fixup image roots. CHECK(app_image.InSource(reinterpret_cast( image_header.GetImageRoots()))); @@ -1120,18 +1104,19 @@ static bool RelocateInPlace(ImageHeader& image_header, boot_oat, app_image, app_oat); - image_header.VisitPackedArtMethods(&method_visitor, target_base, pointer_size); + image_header.GetImageSection(ImageHeader::kSectionArtMethods).VisitPackedArtMethods( + &method_visitor, + target_base, + pointer_size); } if (fixup_image) { { // Only touches objects in the app image, no need for mutator lock. TimingLogger::ScopedTiming timing("Fixup fields", &logger); FixupArtFieldVisitor field_visitor(boot_image, boot_oat, app_image, app_oat); - image_header.VisitPackedArtFields(&field_visitor, target_base); - } - { - TimingLogger::ScopedTiming timing("Fixup conflict tables", &logger); - image_header.VisitPackedImtConflictTables(fixup_adapter, target_base, pointer_size); + image_header.GetImageSection(ImageHeader::kSectionArtFields).VisitPackedArtFields( + &field_visitor, + target_base); } // In the app image case, the image methods are actually in the boot image. image_header.RelocateImageMethods(boot_image.Delta()); diff --git a/runtime/image-inl.h b/runtime/image-inl.h index ea75a622c..e3307d87b 100644 --- a/runtime/image-inl.h +++ b/runtime/image-inl.h @@ -19,8 +19,6 @@ #include "image.h" -#include "art_method.h" - namespace art { template @@ -44,20 +42,6 @@ inline mirror::ObjectArray* ImageHeader::GetImageRoots() const { return image_roots; } -template -inline void ImageHeader::VisitPackedImtConflictTables(const Visitor& visitor, - uint8_t* base, - size_t pointer_size) const { - const ImageSection& section = GetImageSection(kSectionIMTConflictTables); - for (size_t pos = 0; pos < section.Size(); ) { - auto* table = reinterpret_cast(base + section.Offset() + pos); - table->Visit([&visitor](const std::pair& methods) { - return std::make_pair(visitor(methods.first), visitor(methods.second)); - }, pointer_size); - pos += table->ComputeSize(pointer_size); - } -} - } // namespace art #endif // ART_RUNTIME_IMAGE_INL_H_ diff --git a/runtime/image.cc b/runtime/image.cc index a9552c27d..1f54e3e6a 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', '9', '\0' }; +const uint8_t ImageHeader::kImageVersion[] = { '0', '2', '7', '\0' }; ImageHeader::ImageHeader(uint32_t image_begin, uint32_t image_size, @@ -147,10 +147,9 @@ std::ostream& operator<<(std::ostream& os, const ImageSection& section) { return os << "size=" << section.Size() << " range=" << section.Offset() << "-" << section.End(); } -void ImageHeader::VisitPackedArtFields(ArtFieldVisitor* visitor, uint8_t* base) const { - const ImageSection& fields = GetFieldsSection(); - for (size_t pos = 0; pos < fields.Size(); ) { - auto* array = reinterpret_cast*>(base + fields.Offset() + pos); +void ImageSection::VisitPackedArtFields(ArtFieldVisitor* visitor, uint8_t* base) const { + for (size_t pos = 0; pos < Size(); ) { + auto* array = reinterpret_cast*>(base + Offset() + pos); for (size_t i = 0; i < array->size(); ++i) { visitor->Visit(&array->At(i, sizeof(ArtField))); } @@ -158,25 +157,18 @@ void ImageHeader::VisitPackedArtFields(ArtFieldVisitor* visitor, uint8_t* base) } } -void ImageHeader::VisitPackedArtMethods(ArtMethodVisitor* visitor, - uint8_t* base, - size_t pointer_size) const { +void ImageSection::VisitPackedArtMethods(ArtMethodVisitor* visitor, + uint8_t* base, + size_t pointer_size) const { const size_t method_alignment = ArtMethod::Alignment(pointer_size); const size_t method_size = ArtMethod::Size(pointer_size); - const ImageSection& methods = GetMethodsSection(); - for (size_t pos = 0; pos < methods.Size(); ) { - auto* array = reinterpret_cast*>(base + methods.Offset() + pos); + for (size_t pos = 0; pos < Size(); ) { + auto* array = reinterpret_cast*>(base + Offset() + pos); for (size_t i = 0; i < array->size(); ++i) { visitor->Visit(&array->At(i, method_size, method_alignment)); } pos += array->ComputeSize(array->size(), method_size, method_alignment); } - const ImageSection& runtime_methods = GetRuntimeMethodsSection(); - for (size_t pos = 0; pos < runtime_methods.Size(); ) { - auto* method = reinterpret_cast(base + runtime_methods.Offset() + pos); - visitor->Visit(method); - pos += method_size; - } } } // namespace art diff --git a/runtime/image.h b/runtime/image.h index 2ea9af772..8e5dbad57 100644 --- a/runtime/image.h +++ b/runtime/image.h @@ -64,6 +64,12 @@ class PACKED(4) ImageSection { return offset - offset_ < size_; } + // Visit ArtMethods in the section starting at base. + void VisitPackedArtMethods(ArtMethodVisitor* visitor, uint8_t* base, size_t pointer_size) const; + + // Visit ArtMethods in the section starting at base. + void VisitPackedArtFields(ArtFieldVisitor* visitor, uint8_t* base) const; + private: uint32_t offset_; uint32_t size_; @@ -194,8 +200,6 @@ class PACKED(4) ImageHeader { kSectionObjects, kSectionArtFields, kSectionArtMethods, - kSectionRuntimeMethods, - kSectionIMTConflictTables, kSectionDexCacheArrays, kSectionInternedStrings, kSectionClassTable, @@ -207,19 +211,10 @@ class PACKED(4) ImageHeader { void SetImageMethod(ImageMethod index, ArtMethod* method); const ImageSection& GetImageSection(ImageSections index) const; - const ImageSection& GetMethodsSection() const { return GetImageSection(kSectionArtMethods); } - const ImageSection& GetRuntimeMethodsSection() const { - return GetImageSection(kSectionRuntimeMethods); - } - - const ImageSection& GetFieldsSection() const { - return GetImageSection(ImageHeader::kSectionArtFields); - } - template mirror::Object* GetImageRoot(ImageRoot image_root) const SHARED_REQUIRES(Locks::mutator_lock_); @@ -270,19 +265,6 @@ class PACKED(4) ImageHeader { return boot_image_size_ != 0u; } - // Visit ArtMethods in the section starting at base. Includes runtime methods. - // TODO: Delete base parameter if it is always equal to GetImageBegin. - void VisitPackedArtMethods(ArtMethodVisitor* visitor, uint8_t* base, size_t pointer_size) const; - - // Visit ArtMethods in the section starting at base. - // TODO: Delete base parameter if it is always equal to GetImageBegin. - void VisitPackedArtFields(ArtFieldVisitor* visitor, uint8_t* base) const; - - template - void VisitPackedImtConflictTables(const Visitor& visitor, - uint8_t* base, - size_t pointer_size) const; - private: static const uint8_t kImageMagic[4]; static const uint8_t kImageVersion[4]; diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 58a5e1e19..6ba47e072 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -1624,19 +1624,18 @@ void Runtime::VisitImageRoots(RootVisitor* visitor) { } } +static ImtConflictTable::Entry empty_entry = { nullptr, nullptr }; + ArtMethod* Runtime::CreateImtConflictMethod(LinearAlloc* linear_alloc) { - ClassLinker* const class_linker = GetClassLinker(); - ArtMethod* method = class_linker->CreateRuntimeMethod(linear_alloc); + auto* method = Runtime::Current()->GetClassLinker()->CreateRuntimeMethod(linear_alloc); // When compiling, the code pointer will get set later when the image is loaded. - const size_t pointer_size = GetInstructionSetPointerSize(instruction_set_); if (IsAotCompiler()) { + size_t pointer_size = GetInstructionSetPointerSize(instruction_set_); method->SetEntryPointFromQuickCompiledCodePtrSize(nullptr, pointer_size); } else { method->SetEntryPointFromQuickCompiledCode(GetQuickImtConflictStub()); + method->SetImtConflictTable(reinterpret_cast(&empty_entry)); } - // Create empty conflict table. - method->SetImtConflictTable(class_linker->CreateImtConflictTable(/*count*/0u, linear_alloc), - pointer_size); return method; } @@ -1644,6 +1643,9 @@ void Runtime::SetImtConflictMethod(ArtMethod* method) { CHECK(method != nullptr); CHECK(method->IsRuntimeMethod()); imt_conflict_method_ = method; + if (!IsAotCompiler()) { + method->SetImtConflictTable(reinterpret_cast(&empty_entry)); + } } ArtMethod* Runtime::CreateResolutionMethod() { @@ -1953,21 +1955,8 @@ void Runtime::SetImtUnimplementedMethod(ArtMethod* method) { CHECK(method != nullptr); CHECK(method->IsRuntimeMethod()); imt_unimplemented_method_ = method; -} - -void Runtime::FixupConflictTables() { - // We can only do this after the class linker is created. - const size_t pointer_size = GetClassLinker()->GetImagePointerSize(); - // Ones in image wont have correct tables. TODO: Fix. - if (imt_unimplemented_method_->GetImtConflictTable(pointer_size) == nullptr || (true)) { - imt_unimplemented_method_->SetImtConflictTable( - ClassLinker::CreateImtConflictTable(/*count*/0u, GetLinearAlloc(), pointer_size), - pointer_size); - } - if (imt_conflict_method_->GetImtConflictTable(pointer_size) == nullptr || (true)) { - imt_conflict_method_->SetImtConflictTable( - ClassLinker::CreateImtConflictTable(/*count*/0u, GetLinearAlloc(), pointer_size), - pointer_size); + if (!IsAotCompiler()) { + method->SetImtConflictTable(reinterpret_cast(&empty_entry)); } } diff --git a/runtime/runtime.h b/runtime/runtime.h index 1394462fd..908b2952b 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -383,7 +383,6 @@ class Runtime { return imt_conflict_method_ != nullptr; } - void FixupConflictTables(); void SetImtConflictMethod(ArtMethod* method) SHARED_REQUIRES(Locks::mutator_lock_); void SetImtUnimplementedMethod(ArtMethod* method) SHARED_REQUIRES(Locks::mutator_lock_); diff --git a/runtime/stack.cc b/runtime/stack.cc index e56d35a91..6fac0ba7c 100644 --- a/runtime/stack.cc +++ b/runtime/stack.cc @@ -678,10 +678,8 @@ void StackVisitor::SanityCheckFrame() const { if (space->IsImageSpace()) { auto* image_space = space->AsImageSpace(); const auto& header = image_space->GetImageHeader(); - const ImageSection& methods = header.GetMethodsSection(); - const ImageSection& runtime_methods = header.GetRuntimeMethodsSection(); - const size_t offset = reinterpret_cast(method) - image_space->Begin(); - if (methods.Contains(offset) || runtime_methods.Contains(offset)) { + const auto* methods = &header.GetMethodsSection(); + if (methods->Contains(reinterpret_cast(method) - image_space->Begin())) { in_image = true; break; } diff --git a/runtime/thread.cc b/runtime/thread.cc index 78f70d020..a46203606 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -3011,6 +3011,7 @@ size_t Thread::NumberOfHeldMutexes() const { return count; } + void Thread::DeoptimizeWithDeoptimizationException(JValue* result) { DCHECK_EQ(GetException(), Thread::GetDeoptimizationException()); ClearException(); @@ -3031,11 +3032,4 @@ void Thread::DeoptimizeWithDeoptimizationException(JValue* result) { interpreter::EnterInterpreterFromDeoptimize(this, shadow_frame, from_code, result); } -void Thread::SetException(mirror::Throwable* new_exception) { - CHECK(new_exception != nullptr); - // TODO: DCHECK(!IsExceptionPending()); - tlsPtr_.exception = new_exception; - // LOG(ERROR) << new_exception->Dump(); -} - } // namespace art diff --git a/runtime/thread.h b/runtime/thread.h index 582a0cdbd..922b4f76c 100644 --- a/runtime/thread.h +++ b/runtime/thread.h @@ -363,7 +363,12 @@ class Thread { void AssertNoPendingException() const; void AssertNoPendingExceptionForNewException(const char* msg) const; - void SetException(mirror::Throwable* new_exception) SHARED_REQUIRES(Locks::mutator_lock_); + void SetException(mirror::Throwable* new_exception) + SHARED_REQUIRES(Locks::mutator_lock_) { + CHECK(new_exception != nullptr); + // TODO: DCHECK(!IsExceptionPending()); + tlsPtr_.exception = new_exception; + } void ClearException() SHARED_REQUIRES(Locks::mutator_lock_) { tlsPtr_.exception = nullptr; -- 2.11.0