diff options
author | Nicolas Geoffray <ngeoffray@google.com> | 2016-01-23 14:15:49 +0000 |
---|---|---|
committer | Nicolas Geoffray <ngeoffray@google.com> | 2016-01-23 14:15:49 +0000 |
commit | 1bc977cf2f8199311a97f2ba9431a184540e3e9c (patch) | |
tree | 580a02752d8e447f6dce7cce01386c7e2a9a87f4 | |
parent | f7fd970244f143b1abb956e29794c446e4d57f46 (diff) | |
download | art-1bc977cf2f8199311a97f2ba9431a184540e3e9c.tar.gz art-1bc977cf2f8199311a97f2ba9431a184540e3e9c.tar.bz2 art-1bc977cf2f8199311a97f2ba9431a184540e3e9c.zip |
Revert "Load app images"
Fails when a method is duplicated (see test 097-duplicate-method)
Bug: 22858531
This reverts commit f7fd970244f143b1abb956e29794c446e4d57f46.
Change-Id: Ib30ae5be00cc568e799290be6b3c8f29cbbe4c20
54 files changed, 479 insertions, 2136 deletions
diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h index 97c672c560..6c0a0e1f4f 100644 --- a/cmdline/cmdline_types.h +++ b/cmdline/cmdline_types.h @@ -616,8 +616,6 @@ struct CmdlineType<LogVerbosity> : CmdlineTypeParser<LogVerbosity> { log_verbosity.threads = true; } else if (verbose_options[j] == "verifier") { log_verbosity.verifier = true; - } else if (verbose_options[j] == "image") { - log_verbosity.image = true; } else { return Result::Usage(std::string("Unknown -verbose option ") + verbose_options[j]); } diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 818d50a994..d0215255e8 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -730,8 +730,8 @@ void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const De bool CompilerDriver::IsImageClass(const char* descriptor) const { if (!IsBootImage()) { - // NOTE: Currently only reachable from InitImageMethodVisitor for the app image case. - return true; + // NOTE: Currently unreachable, all callers check IsImage(). + return false; } else { return image_classes_->find(descriptor) != image_classes_->end(); } diff --git a/compiler/image_test.cc b/compiler/image_test.cc index b8416751c5..12132c0cd0 100644 --- a/compiler/image_test.cc +++ b/compiler/image_test.cc @@ -155,11 +155,7 @@ void ImageTest::TestWriteRead(ImageHeader::StorageMode storage_mode) { { std::vector<const char*> dup_oat_filename(1, dup_oat->GetPath().c_str()); std::vector<const char*> dup_image_filename(1, image_file.GetFilename().c_str()); - bool success_image = writer->Write(kInvalidFd, - dup_image_filename, - kInvalidFd, - dup_oat_filename, - dup_oat_filename[0]); + bool success_image = writer->Write(kInvalidImageFd, dup_image_filename, dup_oat_filename); ASSERT_TRUE(success_image); bool success_fixup = ElfWriter::Fixup(dup_oat.get(), writer->GetOatDataBegin(dup_oat_filename[0])); @@ -296,17 +292,11 @@ TEST_F(ImageTest, ImageHeaderIsValid) { oat_data_begin, oat_data_end, oat_file_end, - /*boot_image_begin*/0U, - /*boot_image_size*/0U, - /*boot_oat_begin*/0U, - /*boot_oat_size_*/0U, sizeof(void*), /*compile_pic*/false, - /*is_pic*/false, ImageHeader::kDefaultStorageMode, /*data_size*/0u); ASSERT_TRUE(image_header.IsValid()); - ASSERT_TRUE(!image_header.IsAppImage()); char* magic = const_cast<char*>(image_header.GetMagic()); strcpy(magic, ""); // bad magic diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index 72c615e4bc..d0bb201d69 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -159,45 +159,17 @@ bool ImageWriter::PrepareImageAddressSpace() { bool ImageWriter::Write(int image_fd, const std::vector<const char*>& image_filenames, - int oat_fd, - const std::vector<const char*>& oat_filenames, - const std::string& oat_location) { - // If image_fd or oat_fd are not kInvalidFd then we may have empty strings in image_filenames or - // oat_filenames. + const std::vector<const char*>& oat_filenames) { CHECK(!image_filenames.empty()); - if (image_fd != kInvalidFd) { - CHECK_EQ(image_filenames.size(), 1u); - } CHECK(!oat_filenames.empty()); - if (oat_fd != kInvalidFd) { - CHECK_EQ(oat_filenames.size(), 1u); - } CHECK_EQ(image_filenames.size(), oat_filenames.size()); size_t oat_file_offset = 0; for (size_t i = 0; i < oat_filenames.size(); ++i) { const char* oat_filename = oat_filenames[i]; - std::unique_ptr<File> oat_file; - - if (oat_fd != -1) { - if (strlen(oat_filename) == 0u) { - oat_file.reset(new File(oat_fd, false)); - } else { - oat_file.reset(new File(oat_fd, oat_filename, false)); - } - int length = oat_file->GetLength(); - if (length < 0) { - PLOG(ERROR) << "Oat file has negative length " << length; - return false; - } else { - // Leave the fd open since dex2oat still needs to write out the oat file with the fd. - oat_file->DisableAutoClose(); - } - } else { - oat_file.reset(OS::OpenFileReadWrite(oat_filename)); - } - if (oat_file == nullptr) { + std::unique_ptr<File> oat_file(OS::OpenFileReadWrite(oat_filename)); + if (oat_file.get() == nullptr) { PLOG(ERROR) << "Failed to open oat file " << oat_filename; return false; } @@ -209,7 +181,7 @@ bool ImageWriter::Write(int image_fd, return false; } Runtime::Current()->GetOatFileManager().RegisterOatFile( - std::unique_ptr<const OatFile>(oat_file_)); + std::unique_ptr<const OatFile>(oat_file_)); const OatHeader& oat_header = oat_file_->GetOatHeader(); ImageInfo& image_info = GetImageInfo(oat_filename); @@ -248,15 +220,8 @@ bool ImageWriter::Write(int image_fd, SetOatChecksumFromElfFile(oat_file.get()); - if (oat_fd != -1) { - // Leave fd open for caller. - if (oat_file->Flush() != 0) { - LOG(ERROR) << "Failed to flush oat file " << oat_filename << " for " << oat_location; - return false; - } - } else if (oat_file->FlushCloseOrErase() != 0) { - LOG(ERROR) << "Failed to flush and close oat file " << oat_filename - << " for " << oat_location; + if (oat_file->FlushCloseOrErase() != 0) { + LOG(ERROR) << "Failed to flush and close oat file " << oat_filename; return false; } } @@ -273,22 +238,16 @@ bool ImageWriter::Write(int image_fd, const char* oat_filename = oat_filenames[i]; ImageInfo& image_info = GetImageInfo(oat_filename); std::unique_ptr<File> image_file; - if (image_fd != kInvalidFd) { - if (strlen(image_filename) == 0u) { - image_file.reset(new File(image_fd, unix_file::kCheckSafeUsage)); - } else { - LOG(ERROR) << "image fd " << image_fd << " name " << image_filename; - } + if (image_fd != kInvalidImageFd) { + image_file.reset(new File(image_fd, image_filename, unix_file::kCheckSafeUsage)); } else { image_file.reset(OS::CreateEmptyFile(image_filename)); } - if (image_file == nullptr) { LOG(ERROR) << "Failed to open image file " << image_filename; return false; } - - if (!compile_app_image_ && fchmod(image_file->Fd(), 0644) != 0) { + if (fchmod(image_file->Fd(), 0644) != 0) { PLOG(ERROR) << "Failed to make image file world readable: " << image_filename; image_file->Erase(); return EXIT_FAILURE; @@ -742,7 +701,6 @@ bool ImageWriter::ContainsBootClassLoaderNonImageClassInternal( std::unordered_set<mirror::Class*>* visited) { DCHECK(early_exit != nullptr); DCHECK(visited != nullptr); - DCHECK(compile_app_image_); if (klass == nullptr) { return false; } @@ -759,13 +717,6 @@ bool ImageWriter::ContainsBootClassLoaderNonImageClassInternal( visited->emplace(klass); bool result = IsBootClassLoaderNonImageClass(klass); bool my_early_exit = false; // Only for ourselves, ignore caller. - // Remove classes that failed to verify since we don't want to have java.lang.VerifyError in the - // app image. - if (klass->GetStatus() == mirror::Class::kStatusError) { - result = true; - } else { - CHECK(klass->GetVerifyError() == nullptr) << PrettyClass(klass); - } if (!result) { // Check interfaces since these wont be visited through VisitReferences.) mirror::IfTable* if_table = klass->GetIfTable(); @@ -776,12 +727,6 @@ bool ImageWriter::ContainsBootClassLoaderNonImageClassInternal( visited); } } - if (klass->IsObjectArrayClass()) { - result = result || ContainsBootClassLoaderNonImageClassInternal( - klass->GetComponentType(), - &my_early_exit, - visited); - } // Check static fields and their classes. size_t num_static_fields = klass->NumReferenceStaticFields(); if (num_static_fields != 0 && klass->IsResolved()) { @@ -835,9 +780,7 @@ bool ImageWriter::KeepClass(Class* klass) { if (compile_app_image_) { // For app images, we need to prune boot loader classes that are not in the boot image since // these may have already been loaded when the app image is loaded. - // Keep classes in the boot image space since we don't want to re-resolve these. - return Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(klass) || - !ContainsBootClassLoaderNonImageClass(klass); + return !ContainsBootClassLoaderNonImageClass(klass); } std::string temp; return compiler_driver_.IsImageClass(klass->GetDescriptor(&temp)); @@ -900,25 +843,25 @@ void ImageWriter::PruneNonImageClasses() { for (size_t i = 0, num = dex_cache->NumResolvedMethods(); i != num; ++i) { ArtMethod* method = mirror::DexCache::GetElementPtrSize(resolved_methods, i, target_ptr_size_); - DCHECK(method != nullptr) << "Expected resolution method instead of null method"; - mirror::Class* declaring_class = method->GetDeclaringClass(); - // Miranda methods may be held live by a class which was not an image class but have a - // declaring class which is an image class. Set it to the resolution method to be safe and - // prevent dangling pointers. - if (method->IsMiranda() || !KeepClass(declaring_class)) { - mirror::DexCache::SetElementPtrSize(resolved_methods, - i, - resolution_method, - target_ptr_size_); - } else { - // Check that the class is still in the classes table. - DCHECK(class_linker->ClassInClassTable(declaring_class)) << "Class " - << PrettyClass(declaring_class) << " not in class linker table"; + if (method != nullptr) { + auto* declaring_class = method->GetDeclaringClass(); + // Miranda methods may be held live by a class which was not an image class but have a + // declaring class which is an image class. Set it to the resolution method to be safe and + // prevent dangling pointers. + if (method->IsMiranda() || !KeepClass(declaring_class)) { + mirror::DexCache::SetElementPtrSize(resolved_methods, + i, + resolution_method, + target_ptr_size_); + } else { + // Check that the class is still in the classes table. + DCHECK(class_linker->ClassInClassTable(declaring_class)) << "Class " + << PrettyClass(declaring_class) << " not in class linker table"; + } } } - ArtField** resolved_fields = dex_cache->GetResolvedFields(); for (size_t i = 0; i < dex_cache->NumResolvedFields(); i++) { - ArtField* field = mirror::DexCache::GetElementPtrSize(resolved_fields, i, target_ptr_size_); + ArtField* field = dex_cache->GetResolvedField(i, target_ptr_size_); if (field != nullptr && !KeepClass(field->GetDeclaringClass())) { dex_cache->SetResolvedField(i, nullptr, target_ptr_size_); } @@ -963,32 +906,6 @@ void ImageWriter::DumpImageClasses() { } } -mirror::String* ImageWriter::FindInternedString(mirror::String* string) { - Thread* const self = Thread::Current(); - for (auto& pair : image_info_map_) { - const ImageInfo& image_info = pair.second; - mirror::String* const found = image_info.intern_table_->LookupStrong(self, string); - DCHECK(image_info.intern_table_->LookupWeak(self, string) == nullptr) - << string->ToModifiedUtf8(); - if (found != nullptr) { - return found; - } - } - if (compile_app_image_) { - Runtime* const runtime = Runtime::Current(); - mirror::String* found = runtime->GetInternTable()->LookupStrong(self, string); - // If we found it in the runtime intern table it could either be in the boot image or interned - // during app image compilation. If it was in the boot image return that, otherwise return null - // since it belongs to another image space. - if (found != nullptr && runtime->GetHeap()->ObjectIsInBootImageSpace(found)) { - return found; - } - DCHECK(runtime->GetInternTable()->LookupWeak(self, string) == nullptr) - << string->ToModifiedUtf8(); - } - return nullptr; -} - void ImageWriter::CalculateObjectBinSlots(Object* obj) { DCHECK(obj != nullptr); // if it is a string, we want to intern it if its not interned. @@ -998,16 +915,13 @@ void ImageWriter::CalculateObjectBinSlots(Object* obj) { // we must be an interned string that was forward referenced and already assigned if (IsImageBinSlotAssigned(obj)) { - DCHECK_EQ(obj, FindInternedString(obj->AsString())); + DCHECK_EQ(obj, image_info.intern_table_->InternStrongImageString(obj->AsString())); return; } - // Need to check if the string is already interned in another image info so that we don't have - // the intern tables of two different images contain the same string. - mirror::String* interned = FindInternedString(obj->AsString()); - if (interned == nullptr) { - // Not in another image space, insert to our table. - interned = image_info.intern_table_->InternStrongImageString(obj->AsString()); - } + // InternImageString allows us to intern while holding the heap bitmap lock. This is safe since + // we are guaranteed to not have GC during image writing. + mirror::String* const interned = image_info.intern_table_->InternStrongImageString( + obj->AsString()); if (obj != interned) { if (!IsImageBinSlotAssigned(interned)) { // interned obj is after us, allocate its location early @@ -1152,11 +1066,6 @@ void ImageWriter::WalkFieldsInOrder(mirror::Object* obj) { // Visit and assign offsets for fields and field arrays. auto* as_klass = h_obj->AsClass(); mirror::DexCache* dex_cache = as_klass->GetDexCache(); - DCHECK_NE(klass->GetStatus(), mirror::Class::kStatusError); - if (compile_app_image_) { - // Extra sanity, no boot loader classes should be left! - CHECK(!IsBootClassLoaderClass(as_klass)) << PrettyClass(as_klass); - } LengthPrefixedArray<ArtField>* fields[] = { as_klass->GetSFieldsPtr(), as_klass->GetIFieldsPtr(), }; @@ -1496,13 +1405,6 @@ void ImageWriter::CreateHeader(size_t oat_loaded_size, size_t oat_data_offset) { << " Oat data end=" << reinterpret_cast<uintptr_t>(oat_data_end) << " Oat file end=" << reinterpret_cast<uintptr_t>(oat_file_end); } - // Store boot image info for app image so that we can relocate. - uint32_t boot_image_begin = 0; - uint32_t boot_image_end = 0; - uint32_t boot_oat_begin = 0; - uint32_t boot_oat_end = 0; - gc::Heap* const heap = Runtime::Current()->GetHeap(); - heap->GetBootImagesSize(&boot_image_begin, &boot_image_end, &boot_oat_begin, &boot_oat_end); // Create the header, leave 0 for data size since we will fill this in as we are writing the // image. @@ -1515,13 +1417,8 @@ void ImageWriter::CreateHeader(size_t oat_loaded_size, size_t oat_data_offset) { PointerToLowMemUInt32(image_info.oat_data_begin_), PointerToLowMemUInt32(oat_data_end), PointerToLowMemUInt32(oat_file_end), - boot_image_begin, - boot_image_end - boot_image_begin, - boot_oat_begin, - boot_oat_end - boot_oat_begin, target_ptr_size_, compile_pic_, - /*is_pic*/compile_app_image_, image_storage_mode_, /*data_size*/0u); } @@ -1908,14 +1805,13 @@ void ImageWriter::FixupObject(Object* orig, Object* copy) { if (klass == class_linker->GetClassRoot(ClassLinker::kJavaLangDexCache)) { FixupDexCache(down_cast<mirror::DexCache*>(orig), down_cast<mirror::DexCache*>(copy)); } else if (klass->IsClassLoaderClass()) { - mirror::ClassLoader* copy_loader = down_cast<mirror::ClassLoader*>(copy); // If src is a ClassLoader, set the class table to null so that it gets recreated by the // ClassLoader. - copy_loader->SetClassTable(nullptr); + down_cast<mirror::ClassLoader*>(copy)->SetClassTable(nullptr); // Also set allocator to null to be safe. The allocator is created when we create the class // table. We also never expect to unload things in the image since they are held live as // roots. - copy_loader->SetAllocator(nullptr); + down_cast<mirror::ClassLoader*>(copy)->SetAllocator(nullptr); } } FixupVisitor visitor(this, copy); @@ -2000,7 +1896,7 @@ const uint8_t* ImageWriter::GetOatAddress(OatAddress type) const { // If we are compiling an app image, we need to use the stubs of the boot image. if (compile_app_image_) { // Use the current image pointers. - const std::vector<gc::space::ImageSpace*>& image_spaces = + std::vector<gc::space::ImageSpace*> image_spaces = Runtime::Current()->GetHeap()->GetBootImageSpaces(); DCHECK(!image_spaces.empty()); const OatFile* oat_file = image_spaces[0]->GetOatFile(); diff --git a/compiler/image_writer.h b/compiler/image_writer.h index 622eb1985b..ad690389e9 100644 --- a/compiler/image_writer.h +++ b/compiler/image_writer.h @@ -49,7 +49,7 @@ class ImageSpace; class ClassTable; -static constexpr int kInvalidFd = -1; +static constexpr int kInvalidImageFd = -1; // Write a Space built during compilation for use during execution. class ImageWriter FINAL { @@ -103,15 +103,11 @@ class ImageWriter FINAL { uint8_t* GetOatFileBegin(const char* oat_filename) const; - // If image_fd is not kInvalidFd, then we use that for the image file. Otherwise we open + // If image_fd is not kInvalidImageFd, then we use that for the file. Otherwise we open // the names in image_filenames. - // If oat_fd is not kInvalidFd, then we use that for the oat file. Otherwise we open - // the names in oat_filenames. bool Write(int image_fd, const std::vector<const char*>& image_filenames, - int oat_fd, - const std::vector<const char*>& oat_filenames, - const std::string& oat_location) + const std::vector<const char*>& oat_filenames) REQUIRES(!Locks::mutator_lock_); uintptr_t GetOatDataBegin(const char* oat_filename) { @@ -451,10 +447,6 @@ class ImageWriter FINAL { const ImageInfo& GetConstImageInfo(const char* oat_filename) const; const ImageInfo& GetImageInfo(size_t index) const; - // Find an already strong interned string in the other images or in the boot image. Used to - // remove duplicates in the multi image and app image case. - mirror::String* FindInternedString(mirror::String* string) SHARED_REQUIRES(Locks::mutator_lock_); - const CompilerDriver& compiler_driver_; // Beginning target image address for the first image. diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index 1e405dbb1a..c74c41f0c9 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -958,40 +958,30 @@ class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor { } ClassLinker* linker = Runtime::Current()->GetClassLinker(); + InvokeType invoke_type = it.GetMethodInvokeType(dex_file_->GetClassDef(class_def_index_)); // Unchecked as we hold mutator_lock_ on entry. ScopedObjectAccessUnchecked soa(Thread::Current()); StackHandleScope<1> hs(soa.Self()); Handle<mirror::DexCache> dex_cache(hs.NewHandle(linker->FindDexCache( Thread::Current(), *dex_file_))); - ArtMethod* method; - if (writer_->HasBootImage()) { - const InvokeType invoke_type = it.GetMethodInvokeType( - dex_file_->GetClassDef(class_def_index_)); - method = linker->ResolveMethod<ClassLinker::kNoICCECheckForCache>( - *dex_file_, - it.GetMemberIndex(), - dex_cache, - ScopedNullHandle<mirror::ClassLoader>(), - nullptr, - invoke_type); - if (method == nullptr) { - LOG(INTERNAL_FATAL) << "Unexpected failure to resolve a method: " - << PrettyMethod(it.GetMemberIndex(), *dex_file_, true); - soa.Self()->AssertPendingException(); - mirror::Throwable* exc = soa.Self()->GetException(); - std::string dump = exc->Dump(); - LOG(FATAL) << dump; - UNREACHABLE(); - } - } else { - // Should already have been resolved by the compiler, just peek into the dex cache. - // It may not be resolved if the class failed to verify, in this case, don't set the - // entrypoint. This is not fatal since the dex cache will contain a resolution method. - method = dex_cache->GetResolvedMethod(it.GetMemberIndex(), linker->GetImagePointerSize()); + ArtMethod* method = linker->ResolveMethod<ClassLinker::kNoICCECheckForCache>( + *dex_file_, + it.GetMemberIndex(), + dex_cache, + ScopedNullHandle<mirror::ClassLoader>(), + nullptr, + invoke_type); + if (method == nullptr) { + LOG(INTERNAL_FATAL) << "Unexpected failure to resolve a method: " + << PrettyMethod(it.GetMemberIndex(), *dex_file_, true); + soa.Self()->AssertPendingException(); + mirror::Throwable* exc = soa.Self()->GetException(); + std::string dump = exc->Dump(); + LOG(FATAL) << dump; + UNREACHABLE(); } - if (method != nullptr && - compiled_method != nullptr && - compiled_method->GetQuickCode().size() != 0) { + + if (compiled_method != nullptr && compiled_method->GetQuickCode().size() != 0) { method->SetEntryPointFromQuickCompiledCodePtrSize( reinterpret_cast<void*>(offsets.code_offset_), pointer_size_); } @@ -1477,7 +1467,7 @@ size_t OatWriter::InitOatCodeDexFiles(size_t offset) { } while (false) VISIT(InitCodeMethodVisitor); - if (HasImage()) { + if (compiler_driver_->IsBootImage()) { VISIT(InitImageMethodVisitor); } diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 86f51e1131..918a01b088 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -553,7 +553,7 @@ class Dex2Oat FINAL { dump_timing_(false), dump_slow_timing_(kIsDebugBuild), swap_fd_(-1), - app_image_fd_(kInvalidFd), + app_image_fd_(kInvalidImageFd), timings_(timings) {} ~Dex2Oat() { @@ -1442,11 +1442,6 @@ class Dex2Oat FINAL { return true; } - // If we need to keep the oat file open for the image writer. - bool ShouldKeepOatFileOpen() const { - return IsImage() && oat_fd_ != kInvalidFd; - } - // Create and invoke the compiler driver. This will compile all the dex files. void Compile() { TimingLogger::ScopedTiming t("dex2oat Compile", timings_); @@ -1598,17 +1593,13 @@ class Dex2Oat FINAL { if (IsImage()) { if (app_image_ && image_base_ == 0) { - gc::Heap* const heap = Runtime::Current()->GetHeap(); - for (gc::space::ImageSpace* image_space : heap->GetBootImageSpaces()) { + std::vector<gc::space::ImageSpace*> image_spaces = + Runtime::Current()->GetHeap()->GetBootImageSpaces(); + for (gc::space::ImageSpace* image_space : image_spaces) { image_base_ = std::max(image_base_, RoundUp( reinterpret_cast<uintptr_t>(image_space->GetImageHeader().GetOatFileEnd()), kPageSize)); } - // The non moving space is right after the oat file. Put the preferred app image location - // right after the non moving space so that we ideally get a continuous immune region for - // the GC. - const size_t non_moving_space_capacity = heap->GetNonMovingSpace()->Capacity(); - image_base_ += non_moving_space_capacity; VLOG(compiler) << "App image base=" << reinterpret_cast<void*>(image_base_); } @@ -2148,14 +2139,9 @@ class Dex2Oat FINAL { REQUIRES(!Locks::mutator_lock_) { CHECK(image_writer_ != nullptr); if (!IsBootImage()) { - CHECK(image_filenames_.empty()); image_filenames_.push_back(app_image_file_name_.c_str()); } - if (!image_writer_->Write(app_image_fd_, - image_filenames_, - oat_fd_, - oat_filenames_, - oat_location_)) { + if (!image_writer_->Write(app_image_fd_, image_filenames_, oat_filenames_)) { LOG(ERROR) << "Failure during image file creation"; return false; } @@ -2437,14 +2423,9 @@ static int CompileImage(Dex2Oat& dex2oat) { return EXIT_FAILURE; } - // Flush boot.oat. We always expect the output file by name, and it will be re-opened from the - // unstripped name. Do not close the file if we are compiling the image with an oat fd since the - // image writer will require this fd to generate the image. - if (dex2oat.ShouldKeepOatFileOpen()) { - if (!dex2oat.FlushOatFiles()) { - return EXIT_FAILURE; - } - } else if (!dex2oat.FlushCloseOatFiles()) { + // Close the image oat files. We always expect the output file by name, and it will be + // re-opened from the unstripped name. Note: it's easier to *flush* and close... + if (!dex2oat.FlushCloseOatFiles()) { return EXIT_FAILURE; } diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc index 7e4ce917db..d836532ed2 100644 --- a/patchoat/patchoat.cc +++ b/patchoat/patchoat.cc @@ -547,9 +547,6 @@ void PatchOat::PatchInternedStrings(const ImageHeader* image_header) { void PatchOat::PatchClassTable(const ImageHeader* image_header) { const auto& section = image_header->GetImageSection(ImageHeader::kSectionClassTable); - if (section.Size() == 0) { - return; - } // 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. diff --git a/runtime/art_field-inl.h b/runtime/art_field-inl.h index 3463b0d842..4166e22daa 100644 --- a/runtime/art_field-inl.h +++ b/runtime/art_field-inl.h @@ -37,7 +37,7 @@ inline mirror::Class* ArtField::GetDeclaringClass() { GcRootSource gc_root_source(this); mirror::Class* result = declaring_class_.Read(&gc_root_source); DCHECK(result != nullptr); - DCHECK(result->IsLoaded() || result->IsErroneous()) << result->GetStatus(); + DCHECK(result->IsLoaded() || result->IsErroneous()); return result; } @@ -334,15 +334,6 @@ inline void ArtField::VisitRoots(RootVisitorType& visitor) { visitor.VisitRoot(declaring_class_.AddressWithoutBarrier()); } -template <typename Visitor> -inline void ArtField::UpdateObjects(const Visitor& visitor) { - mirror::Class* old_class = DeclaringClassRoot().Read<kWithoutReadBarrier>(); - mirror::Class* new_class = visitor(old_class); - if (old_class != new_class) { - SetDeclaringClass(new_class); - } -} - } // namespace art #endif // ART_RUNTIME_ART_FIELD_INL_H_ diff --git a/runtime/art_field.h b/runtime/art_field.h index ee1ba1fb53..a943a34174 100644 --- a/runtime/art_field.h +++ b/runtime/art_field.h @@ -190,11 +190,6 @@ class ArtField FINAL { return declaring_class_; } - // Update the declaring class with the passed in visitor. Does not use read barrier. - template <typename Visitor> - ALWAYS_INLINE void UpdateObjects(const Visitor& visitor) - SHARED_REQUIRES(Locks::mutator_lock_); - private: mirror::Class* ProxyFindSystemClass(const char* descriptor) SHARED_REQUIRES(Locks::mutator_lock_); diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h index 74eb7227dc..a5f5c49068 100644 --- a/runtime/art_method-inl.h +++ b/runtime/art_method-inl.h @@ -467,43 +467,6 @@ void ArtMethod::VisitRoots(RootVisitorType& visitor, size_t pointer_size) { } } -template <typename Visitor> -inline void ArtMethod::UpdateObjectsForImageRelocation(const Visitor& visitor) { - mirror::Class* old_class = GetDeclaringClassNoBarrier(); - mirror::Class* new_class = visitor(old_class); - if (old_class != new_class) { - SetDeclaringClass(new_class); - } - ArtMethod** old_methods = GetDexCacheResolvedMethods(sizeof(void*)); - ArtMethod** new_methods = visitor(old_methods); - if (old_methods != new_methods) { - SetDexCacheResolvedMethods(new_methods, sizeof(void*)); - } - GcRoot<mirror::Class>* old_types = GetDexCacheResolvedTypes(sizeof(void*)); - GcRoot<mirror::Class>* new_types = visitor(old_types); - if (old_types != new_types) { - SetDexCacheResolvedTypes(new_types, sizeof(void*)); - } -} - -template <typename Visitor> -inline void ArtMethod::UpdateEntrypoints(const Visitor& visitor) { - if (IsNative()) { - const void* old_native_code = GetEntryPointFromJni(); - const void* new_native_code = visitor(old_native_code); - if (old_native_code != new_native_code) { - SetEntryPointFromJni(new_native_code); - } - } else { - DCHECK(GetEntryPointFromJni() == nullptr); - } - const void* old_code = GetEntryPointFromQuickCompiledCode(); - const void* new_code = visitor(old_code); - if (old_code != new_code) { - SetEntryPointFromQuickCompiledCode(new_code); - } -} - } // namespace art #endif // ART_RUNTIME_ART_METHOD_INL_H_ diff --git a/runtime/art_method.h b/runtime/art_method.h index 440e796f46..0be2fa20ac 100644 --- a/runtime/art_method.h +++ b/runtime/art_method.h @@ -477,17 +477,6 @@ class ArtMethod FINAL { // Returns whether the method has any compiled code, JIT or AOT. bool HasAnyCompiledCode() SHARED_REQUIRES(Locks::mutator_lock_); - - // Update heap objects and non-entrypoint pointers by the passed in visitor for image relocation. - // Does not use read barrier. - template <typename Visitor> - ALWAYS_INLINE void UpdateObjectsForImageRelocation(const Visitor& visitor) - SHARED_REQUIRES(Locks::mutator_lock_); - - // Update entry points by passing them through the visitor. - template <typename Visitor> - ALWAYS_INLINE void UpdateEntrypoints(const Visitor& visitor); - protected: // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". // The class we are a part of. diff --git a/runtime/base/logging.h b/runtime/base/logging.h index de46b0c118..115c26073d 100644 --- a/runtime/base/logging.h +++ b/runtime/base/logging.h @@ -53,7 +53,6 @@ struct LogVerbosity { bool third_party_jni; // Enabled with "-verbose:third-party-jni". bool threads; bool verifier; - bool image; }; // Global log verbosity setting, initialized by InitLogging. diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index be9310abd8..ed833c4335 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -336,10 +336,6 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b // Use the pointer size from the runtime since we are probably creating the image. image_pointer_size_ = InstructionSetPointerSize(runtime->GetInstructionSet()); - if (!ValidPointerSize(image_pointer_size_)) { - *error_msg = StringPrintf("Invalid image pointer size: %zu", image_pointer_size_); - return false; - } // java_lang_Class comes first, it's needed for AllocClass // The GC can't handle an object with a null class since we can't get the size of this object. @@ -493,7 +489,7 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b return false; } AppendToBootClassPath(self, *dex_file); - boot_dex_files_.push_back(std::move(dex_file)); + opened_dex_files_.push_back(std::move(dex_file)); } // now we can use FindSystemClass @@ -882,7 +878,6 @@ struct TrampolineCheckData { ArtMethod* m; bool error; }; - static void CheckTrampolines(mirror::Object* obj, void* arg) NO_THREAD_SAFETY_ANALYSIS { if (obj->IsClass()) { mirror::Class* klass = obj->AsClass(); @@ -901,8 +896,8 @@ static void CheckTrampolines(mirror::Object* obj, void* arg) NO_THREAD_SAFETY_AN } } -bool ClassLinker::InitFromBootImage(std::string* error_msg) { - VLOG(startup) << __FUNCTION__ << " entering"; +bool ClassLinker::InitFromImage(std::string* error_msg) { + VLOG(startup) << "ClassLinker::InitFromImage entering"; CHECK(!init_done_); Runtime* const runtime = Runtime::Current(); @@ -911,21 +906,6 @@ bool ClassLinker::InitFromBootImage(std::string* error_msg) { std::vector<gc::space::ImageSpace*> spaces = heap->GetBootImageSpaces(); CHECK(!spaces.empty()); image_pointer_size_ = spaces[0]->GetImageHeader().GetPointerSize(); - if (!ValidPointerSize(image_pointer_size_)) { - *error_msg = StringPrintf("Invalid image pointer size: %zu", image_pointer_size_); - return false; - } - if (!runtime->IsAotCompiler()) { - // Only the Aot compiler supports having an image with a different pointer size than the - // runtime. This happens on the host for compiling 32 bit tests since we use a 64 bit libart - // compiler. We may also use 32 bit dex2oat on a system with 64 bit apps. - if (image_pointer_size_ != sizeof(void*)) { - *error_msg = StringPrintf("Runtime must use current image pointer size: %zu vs %zu", - image_pointer_size_, - sizeof(void*)); - return false; - } - } dex_cache_boot_image_class_lookup_required_ = true; std::vector<const OatFile*> oat_files = runtime->GetOatFileManager().RegisterImageOatFiles(spaces); @@ -977,10 +957,19 @@ bool ClassLinker::InitFromBootImage(std::string* error_msg) { } } - class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class>>( - down_cast<mirror::ObjectArray<mirror::Class>*>( - spaces[0]->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots))); - mirror::Class::SetClassClass(class_roots_.Read()->Get(kJavaLangClass)); + StackHandleScopeCollection handles(self); + std::vector<Handle<mirror::ObjectArray<mirror::DexCache>>> dex_caches_vector; + for (gc::space::ImageSpace* space : spaces) { + Handle<mirror::ObjectArray<mirror::DexCache>> dex_caches(handles.NewHandle( + space->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches)-> + AsObjectArray<mirror::DexCache>())); + dex_caches_vector.push_back(dex_caches); + } + + Handle<mirror::ObjectArray<mirror::Class>> class_roots(handles.NewHandle( + spaces[0]->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots)-> + AsObjectArray<mirror::Class>())); + class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class>>(class_roots.Get()); // Special case of setting up the String class early so that we can test arbitrary objects // as being Strings or not @@ -993,595 +982,162 @@ bool ClassLinker::InitFromBootImage(std::string* error_msg) { runtime->SetSentinel(heap->AllocNonMovableObject<true>( self, java_lang_Object, java_lang_Object->GetObjectSize(), VoidFunctor())); - // reinit array_iftable_ from any array class instance, they should be == - array_iftable_ = GcRoot<mirror::IfTable>(GetClassRoot(kObjectArrayClass)->GetIfTable()); - DCHECK_EQ(array_iftable_.Read(), GetClassRoot(kBooleanArrayClass)->GetIfTable()); - // String class root was set above - mirror::Field::SetClass(GetClassRoot(kJavaLangReflectField)); - mirror::Field::SetArrayClass(GetClassRoot(kJavaLangReflectFieldArrayClass)); - mirror::Constructor::SetClass(GetClassRoot(kJavaLangReflectConstructor)); - mirror::Constructor::SetArrayClass(GetClassRoot(kJavaLangReflectConstructorArrayClass)); - mirror::Method::SetClass(GetClassRoot(kJavaLangReflectMethod)); - mirror::Method::SetArrayClass(GetClassRoot(kJavaLangReflectMethodArrayClass)); - mirror::Reference::SetClass(GetClassRoot(kJavaLangRefReference)); - mirror::BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass)); - mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass)); - mirror::CharArray::SetArrayClass(GetClassRoot(kCharArrayClass)); - mirror::DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass)); - mirror::FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass)); - mirror::IntArray::SetArrayClass(GetClassRoot(kIntArrayClass)); - mirror::LongArray::SetArrayClass(GetClassRoot(kLongArrayClass)); - mirror::ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass)); - mirror::Throwable::SetClass(GetClassRoot(kJavaLangThrowable)); - mirror::StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement)); - - for (gc::space::ImageSpace* image_space : spaces) { - // Boot class loader, use a null handle. - std::vector<std::unique_ptr<const DexFile>> dex_files; - if (!AddImageSpace(image_space, - ScopedNullHandle<mirror::ClassLoader>(), - /*dex_elements*/nullptr, - /*dex_location*/nullptr, - /*out*/&dex_files, - error_msg)) { - return false; - } - // Append opened dex files at the end. - boot_dex_files_.insert(boot_dex_files_.end(), - std::make_move_iterator(dex_files.begin()), - std::make_move_iterator(dex_files.end())); + uint32_t dex_file_count = 0; + for (const OatFile* oat_file : oat_files) { + dex_file_count += oat_file->GetOatHeader().GetDexFileCount(); } - FinishInit(self); - - VLOG(startup) << __FUNCTION__ << " exiting"; - return true; -} - -static bool IsBootClassLoader(ScopedObjectAccessAlreadyRunnable& soa, - mirror::ClassLoader* class_loader) - SHARED_REQUIRES(Locks::mutator_lock_) { - return class_loader == nullptr || - class_loader->GetClass() == - soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_BootClassLoader); -} - -static mirror::String* GetDexPathListElementName(ScopedObjectAccessUnchecked& soa, - mirror::Object* element) - SHARED_REQUIRES(Locks::mutator_lock_) { - ArtField* const dex_file_field = - soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile); - ArtField* const dex_file_name_field = - soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_fileName); - DCHECK(dex_file_field != nullptr); - DCHECK(dex_file_name_field != nullptr); - DCHECK(element != nullptr); - CHECK_EQ(dex_file_field->GetDeclaringClass(), element->GetClass()) << PrettyTypeOf(element); - mirror::Object* dex_file = dex_file_field->GetObject(element); - if (dex_file == nullptr) { - return nullptr; + uint32_t dex_caches_count = 0; + for (auto dex_caches : dex_caches_vector) { + dex_caches_count += dex_caches->GetLength(); } - mirror::Object* const name_object = dex_file_name_field->GetObject(dex_file); - if (name_object != nullptr) { - return name_object->AsString(); + if (dex_file_count != dex_caches_count) { + *error_msg = "Dex cache count and dex file count mismatch while trying to initialize from " + "image"; + return false; } - return nullptr; -} - -static bool FlattenPathClassLoader(mirror::ClassLoader* class_loader, - std::list<mirror::String*>* out_dex_file_names, - std::string* error_msg) - SHARED_REQUIRES(Locks::mutator_lock_) { - DCHECK(out_dex_file_names != nullptr); - DCHECK(error_msg != nullptr); - ScopedObjectAccessUnchecked soa(Thread::Current()); - ArtField* const dex_path_list_field = - soa.DecodeField(WellKnownClasses::dalvik_system_PathClassLoader_pathList); - ArtField* const dex_elements_field = - soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList_dexElements); - CHECK(dex_path_list_field != nullptr); - CHECK(dex_elements_field != nullptr); - while (!IsBootClassLoader(soa, class_loader)) { - if (class_loader->GetClass() != - soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader)) { - *error_msg = StringPrintf("Unknown class loader type %s", PrettyTypeOf(class_loader).c_str()); - // Unsupported class loader. - return false; - } - mirror::Object* dex_path_list = dex_path_list_field->GetObject(class_loader); - if (dex_path_list != nullptr) { - // DexPathList has an array dexElements of Elements[] which each contain a dex file. - mirror::Object* dex_elements_obj = dex_elements_field->GetObject(dex_path_list); - // Loop through each dalvik.system.DexPathList$Element's dalvik.system.DexFile and look - // at the mCookie which is a DexFile vector. - if (dex_elements_obj != nullptr) { - mirror::ObjectArray<mirror::Object>* dex_elements = - dex_elements_obj->AsObjectArray<mirror::Object>(); - // Reverse order since we insert the parent at the front. - for (int32_t i = dex_elements->GetLength() - 1; i >= 0; --i) { - mirror::Object* const element = dex_elements->GetWithoutChecks(i); - if (element == nullptr) { - *error_msg = StringPrintf("Null dex element at index %d", i); - return false; - } - mirror::String* const name = GetDexPathListElementName(soa, element); - if (name == nullptr) { - *error_msg = StringPrintf("Null name for dex element at index %d", i); - return false; - } - out_dex_file_names->push_front(name); + for (auto dex_caches : dex_caches_vector) { + for (int32_t i = 0; i < dex_caches->GetLength(); i++) { + StackHandleScope<1> hs2(self); + Handle<mirror::DexCache> dex_cache(hs2.NewHandle(dex_caches->Get(i))); + const std::string& dex_file_location(dex_cache->GetLocation()->ToModifiedUtf8()); + const OatFile::OatDexFile* oat_dex_file = nullptr; + for (const OatFile* oat_file : oat_files) { + const OatFile::OatDexFile* oat_dex = + oat_file->GetOatDexFile(dex_file_location.c_str(), nullptr, false); + if (oat_dex != nullptr) { + DCHECK(oat_dex_file == nullptr); + oat_dex_file = oat_dex; } } - } - class_loader = class_loader->GetParent(); - } - return true; -} -class FixupArtMethodArrayVisitor : public ArtMethodVisitor { - public: - explicit FixupArtMethodArrayVisitor(const ImageHeader& header) : header_(header) {} - - virtual void Visit(ArtMethod* method) SHARED_REQUIRES(Locks::mutator_lock_) { - GcRoot<mirror::Class>* resolved_types = method->GetDexCacheResolvedTypes(sizeof(void*)); - const bool is_miranda = method->IsMiranda(); - if (resolved_types != nullptr) { - bool in_image_space = false; - if (kIsDebugBuild || is_miranda) { - in_image_space = header_.GetImageSection(ImageHeader::kSectionDexCacheArrays).Contains( - reinterpret_cast<const uint8_t*>(resolved_types) - header_.GetImageBegin()); - } - // Must be in image space for non-miranda method. - DCHECK(is_miranda || in_image_space) - << resolved_types << " is not in image starting at " - << reinterpret_cast<void*>(header_.GetImageBegin()); - if (!is_miranda || in_image_space) { - // Go through the array so that we don't need to do a slow map lookup. - method->SetDexCacheResolvedTypes(*reinterpret_cast<GcRoot<mirror::Class>**>(resolved_types), - sizeof(void*)); - } - } - ArtMethod** resolved_methods = method->GetDexCacheResolvedMethods(sizeof(void*)); - if (resolved_methods != nullptr) { - bool in_image_space = false; - if (kIsDebugBuild || is_miranda) { - in_image_space = header_.GetImageSection(ImageHeader::kSectionDexCacheArrays).Contains( - reinterpret_cast<const uint8_t*>(resolved_methods) - header_.GetImageBegin()); + if (oat_dex_file == nullptr) { + *error_msg = StringPrintf("Failed finding oat dex file for %s", + dex_file_location.c_str()); + return false; } - // Must be in image space for non-miranda method. - DCHECK(is_miranda || in_image_space) - << resolved_methods << " is not in image starting at " - << reinterpret_cast<void*>(header_.GetImageBegin()); - if (!is_miranda || in_image_space) { - // Go through the array so that we don't need to do a slow map lookup. - method->SetDexCacheResolvedMethods(*reinterpret_cast<ArtMethod***>(resolved_methods), - sizeof(void*)); + std::string inner_error_msg; + std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&inner_error_msg); + if (dex_file == nullptr) { + *error_msg = StringPrintf("Failed to open dex file %s error '%s'", + dex_file_location.c_str(), + inner_error_msg.c_str()); + return false; } - } - } - private: - const ImageHeader& header_; -}; - -class VerifyClassInTableArtMethodVisitor : public ArtMethodVisitor { - public: - explicit VerifyClassInTableArtMethodVisitor(ClassTable* table) : table_(table) {} - - virtual void Visit(ArtMethod* method) - SHARED_REQUIRES(Locks::mutator_lock_, Locks::classlinker_classes_lock_) { - mirror::Class* klass = method->GetDeclaringClass(); - if (klass != nullptr && !Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(klass)) { - CHECK_EQ(table_->LookupByDescriptor(klass), klass) << PrettyClass(klass); - } - } - - private: - ClassTable* const table_; -}; - -void ClassLinker::UpdateAppImageClassLoadersAndDexCaches( - gc::space::ImageSpace* space, - Handle<mirror::ClassLoader> class_loader, - Handle<mirror::ObjectArray<mirror::DexCache>> dex_caches, - bool added_class_table) { - Thread* const self = Thread::Current(); - gc::Heap* const heap = Runtime::Current()->GetHeap(); - const ImageHeader& header = space->GetImageHeader(); - // Add image classes into the class table for the class loader, and fixup the dex caches and - // class loader fields. - WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); - ClassTable* table = InsertClassTableForClassLoader(class_loader.Get()); - // TODO: Store class table in the image to avoid manually adding the classes. - for (int32_t i = 0, num_dex_caches = dex_caches->GetLength(); i < num_dex_caches; i++) { - mirror::DexCache* const dex_cache = dex_caches->Get(i); - const DexFile* const dex_file = dex_cache->GetDexFile(); - // If the oat file expects the dex cache arrays to be in the BSS, then allocate there and - // copy over the arrays. - DCHECK(dex_file != nullptr); - const size_t num_strings = dex_file->NumStringIds(); - const size_t num_types = dex_file->NumTypeIds(); - const size_t num_methods = dex_file->NumMethodIds(); - const size_t num_fields = dex_file->NumFieldIds(); - CHECK_EQ(num_strings, dex_cache->NumStrings()); - CHECK_EQ(num_types, dex_cache->NumResolvedTypes()); - CHECK_EQ(num_methods, dex_cache->NumResolvedMethods()); - CHECK_EQ(num_fields, dex_cache->NumResolvedFields()); - if (dex_file->GetOatDexFile() != nullptr && - dex_file->GetOatDexFile()->GetDexCacheArrays() != nullptr) { - DexCacheArraysLayout layout(image_pointer_size_, dex_file); - uint8_t* const raw_arrays = dex_file->GetOatDexFile()->GetDexCacheArrays(); - // The space is not yet visible to the GC, we can avoid the read barriers and use - // std::copy_n. - if (num_strings != 0u) { - GcRoot<mirror::String>* const strings = - reinterpret_cast<GcRoot<mirror::String>*>(raw_arrays + layout.StringsOffset()); - for (size_t j = 0; kIsDebugBuild && j < num_strings; ++j) { - DCHECK(strings[j].IsNull()); - } - std::copy_n(dex_cache->GetStrings(), num_strings, strings); - dex_cache->SetStrings(strings); + if (kSanityCheckObjects) { + SanityCheckArtMethodPointerArray(dex_cache->GetResolvedMethods(), + dex_cache->NumResolvedMethods(), + image_pointer_size_, + spaces); } - if (num_types != 0u) { - GcRoot<mirror::Class>* const image_resolved_types = dex_cache->GetResolvedTypes(); - GcRoot<mirror::Class>* const types = - reinterpret_cast<GcRoot<mirror::Class>*>(raw_arrays + layout.TypesOffset()); - for (size_t j = 0; kIsDebugBuild && j < num_types; ++j) { - DCHECK(types[j].IsNull()); - } - std::copy_n(image_resolved_types, num_types, types); - // Store a pointer to the new location for fast ArtMethod patching without requiring map. - // This leaves random garbage at the start of the dex cache array, but nobody should ever - // read from it again. - *reinterpret_cast<GcRoot<mirror::Class>**>(image_resolved_types) = types; - dex_cache->SetResolvedTypes(types); - } - if (num_methods != 0u) { - ArtMethod** const methods = reinterpret_cast<ArtMethod**>( - raw_arrays + layout.MethodsOffset()); - ArtMethod** const image_resolved_methods = dex_cache->GetResolvedMethods(); - for (size_t j = 0; kIsDebugBuild && j < num_methods; ++j) { - DCHECK(methods[j] == nullptr); - } - std::copy_n(image_resolved_methods, num_methods, methods); - // Store a pointer to the new location for fast ArtMethod patching without requiring map. - *reinterpret_cast<ArtMethod***>(image_resolved_methods) = methods; - dex_cache->SetResolvedMethods(methods); - } - if (num_fields != 0u) { - ArtField** const fields = reinterpret_cast<ArtField**>(raw_arrays + layout.FieldsOffset()); - for (size_t j = 0; kIsDebugBuild && j < num_fields; ++j) { - DCHECK(fields[j] == nullptr); - } - std::copy_n(dex_cache->GetResolvedFields(), num_fields, fields); - dex_cache->SetResolvedFields(fields); - } - } - { - WriterMutexLock mu2(self, dex_lock_); - // Make sure to do this after we update the arrays since we store the resolved types array - // in DexCacheData in RegisterDexFileLocked. We need the array pointer to be the one in the - // BSS. - mirror::DexCache* existing_dex_cache = FindDexCacheLocked(self, - *dex_file, - /*allow_failure*/true); - CHECK(existing_dex_cache == nullptr); - StackHandleScope<1> hs3(self); - RegisterDexFileLocked(*dex_file, hs3.NewHandle(dex_cache)); - } - GcRoot<mirror::Class>* const types = dex_cache->GetResolvedTypes(); - if (!added_class_table) { - for (int32_t j = 0; j < static_cast<int32_t>(num_types); j++) { - // The image space is not yet added to the heap, avoid read barriers. - mirror::Class* klass = types[j].Read<kWithoutReadBarrier>(); - if (klass != nullptr) { - DCHECK_NE(klass->GetStatus(), mirror::Class::kStatusError); - // Update the class loader from the one in the image class loader to the one that loaded - // the app image. - klass->SetClassLoader(class_loader.Get()); - // If there are multiple dex caches, there may be the same class multiple times - // in different dex caches. Check for this since inserting will add duplicates - // otherwise. - if (num_dex_caches > 1) { - mirror::Class* existing = table->LookupByDescriptor(klass); - if (existing != nullptr) { - DCHECK_EQ(existing, klass) << PrettyClass(klass); - } else { - table->Insert(klass); - } - } else { - table->Insert(klass); - } - // Double checked VLOG to avoid overhead. - if (VLOG_IS_ON(image)) { - VLOG(image) << PrettyClass(klass) << " " << klass->GetStatus(); - if (!klass->IsArrayClass()) { - VLOG(image) << "From " << klass->GetDexCache()->GetDexFile()->GetBaseLocation(); - } - VLOG(image) << "Direct methods"; - for (ArtMethod& m : klass->GetDirectMethods(sizeof(void*))) { - VLOG(image) << PrettyMethod(&m); - } - VLOG(image) << "Virtual methods"; - for (ArtMethod& m : klass->GetVirtualMethods(sizeof(void*))) { - VLOG(image) << PrettyMethod(&m); - } - } - } - } - } - if (kIsDebugBuild) { - for (int32_t j = 0; j < static_cast<int32_t>(num_types); j++) { - // The image space is not yet added to the heap, avoid read barriers. - mirror::Class* klass = types[j].Read<kWithoutReadBarrier>(); - if (klass != nullptr) { - DCHECK_NE(klass->GetStatus(), mirror::Class::kStatusError); - if (kIsDebugBuild) { - DCHECK_EQ(table->LookupByDescriptor(klass), klass); - mirror::Class* super_class = klass->GetSuperClass(); - if (super_class != nullptr && !heap->ObjectIsInBootImageSpace(super_class)) { - CHECK_EQ(table->LookupByDescriptor(super_class), super_class); - } - } - DCHECK_EQ(klass->GetClassLoader(), class_loader.Get()); - if (kIsDebugBuild) { - for (ArtMethod& m : klass->GetDirectMethods(sizeof(void*))) { - const void* code = m.GetEntryPointFromQuickCompiledCode(); - const void* oat_code = m.IsInvokable() ? GetQuickOatCodeFor(&m) : code; - if (!IsQuickResolutionStub(code) && - !IsQuickGenericJniStub(code) && - !IsQuickToInterpreterBridge(code) && - !m.IsNative()) { - DCHECK_EQ(code, oat_code) << PrettyMethod(&m); - } - } - VLOG(image) << "Virtual methods"; - for (ArtMethod& m : klass->GetVirtualMethods(sizeof(void*))) { - const void* code = m.GetEntryPointFromQuickCompiledCode(); - const void* oat_code = m.IsInvokable() ? GetQuickOatCodeFor(&m) : code; - if (!IsQuickResolutionStub(code) && - !IsQuickGenericJniStub(code) && - !IsQuickToInterpreterBridge(code) && - !m.IsNative()) { - DCHECK_EQ(code, oat_code) << PrettyMethod(&m); - } - } - } - } + if (dex_file->GetLocationChecksum() != oat_dex_file->GetDexFileLocationChecksum()) { + *error_msg = StringPrintf("Checksums do not match for %s: %x vs %x", + dex_file_location.c_str(), + dex_file->GetLocationChecksum(), + oat_dex_file->GetDexFileLocationChecksum()); + return false; } - } - } - { - FixupArtMethodArrayVisitor visitor(header); - header.GetImageSection(ImageHeader::kSectionArtMethods).VisitPackedArtMethods( - &visitor, space->Begin(), sizeof(void*)); - Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader.Get()); - } - if (kIsDebugBuild) { - ClassTable* const class_table = class_loader.Get()->GetClassTable(); - VerifyClassInTableArtMethodVisitor visitor2(class_table); - header.GetImageSection(ImageHeader::kSectionArtMethods).VisitPackedArtMethods( - &visitor2, space->Begin(), sizeof(void*)); - } -} -bool ClassLinker::AddImageSpace( - gc::space::ImageSpace* space, - Handle<mirror::ClassLoader> class_loader, - jobjectArray dex_elements, - const char* dex_location, - std::vector<std::unique_ptr<const DexFile>>* out_dex_files, - std::string* error_msg) { - DCHECK(out_dex_files != nullptr); - DCHECK(error_msg != nullptr); - const uint64_t start_time = NanoTime(); - const bool app_image = class_loader.Get() != nullptr; - const ImageHeader& header = space->GetImageHeader(); - mirror::Object* dex_caches_object = header.GetImageRoot(ImageHeader::kDexCaches); - DCHECK(dex_caches_object != nullptr); - Runtime* const runtime = Runtime::Current(); - gc::Heap* const heap = runtime->GetHeap(); - Thread* const self = Thread::Current(); - StackHandleScope<2> hs(self); - Handle<mirror::ObjectArray<mirror::DexCache>> dex_caches( - hs.NewHandle(dex_caches_object->AsObjectArray<mirror::DexCache>())); - Handle<mirror::ObjectArray<mirror::Class>> class_roots(hs.NewHandle( - header.GetImageRoot(ImageHeader::kClassRoots)->AsObjectArray<mirror::Class>())); - const OatFile* oat_file = space->GetOatFile(); - std::unordered_set<mirror::ClassLoader*> image_class_loaders; - // Check that the image is what we are expecting. - if (image_pointer_size_ != space->GetImageHeader().GetPointerSize()) { - *error_msg = StringPrintf("Application image pointer size does not match runtime: %zu vs %zu", - static_cast<size_t>(space->GetImageHeader().GetPointerSize()), - image_pointer_size_); - return false; - } - DCHECK(class_roots.Get() != nullptr); - if (class_roots->GetLength() != static_cast<int32_t>(kClassRootsMax)) { - *error_msg = StringPrintf("Expected %d class roots but got %d", - class_roots->GetLength(), - static_cast<int32_t>(kClassRootsMax)); - return false; - } - // Check against existing class roots to make sure they match the ones in the boot image. - for (size_t i = 0; i < kClassRootsMax; i++) { - if (class_roots->Get(i) != GetClassRoot(static_cast<ClassRoot>(i))) { - *error_msg = "App image class roots must have pointer equality with runtime ones."; - return false; + AppendToBootClassPath(*dex_file.get(), dex_cache); + opened_dex_files_.push_back(std::move(dex_file)); } } - if (oat_file->GetOatHeader().GetDexFileCount() != - static_cast<uint32_t>(dex_caches->GetLength())) { - *error_msg = "Dex cache count and dex file count mismatch while trying to initialize from " - "image"; + + if (!ValidPointerSize(image_pointer_size_)) { + *error_msg = StringPrintf("Invalid image pointer size: %zu", image_pointer_size_); return false; } - StackHandleScope<1> hs2(self); - MutableHandle<mirror::DexCache> h_dex_cache(hs2.NewHandle<mirror::DexCache>(nullptr)); - for (int32_t i = 0; i < dex_caches->GetLength(); i++) { - h_dex_cache.Assign(dex_caches->Get(i)); - std::string dex_file_location(h_dex_cache->GetLocation()->ToModifiedUtf8()); - // TODO: Only store qualified paths. - // If non qualified, qualify it. - if (dex_file_location.find('/') == std::string::npos) { - std::string dex_location_path = dex_location; - const size_t pos = dex_location_path.find_last_of('/'); - CHECK_NE(pos, std::string::npos); - dex_location_path = dex_location_path.substr(0, pos + 1); // Keep trailing '/' - dex_file_location = dex_location_path + dex_file_location; - } - const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file_location.c_str(), - nullptr); - if (oat_dex_file == nullptr) { - *error_msg = StringPrintf("Failed finding oat dex file for %s %s", - oat_file->GetLocation().c_str(), - dex_file_location.c_str()); - return false; - } - std::string inner_error_msg; - std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&inner_error_msg); - if (dex_file == nullptr) { - *error_msg = StringPrintf("Failed to open dex file %s from within oat file %s error '%s'", - dex_file_location.c_str(), - oat_file->GetLocation().c_str(), - inner_error_msg.c_str()); - return false; - } - - if (dex_file->GetLocationChecksum() != oat_dex_file->GetDexFileLocationChecksum()) { - *error_msg = StringPrintf("Checksums do not match for %s: %x vs %x", - dex_file_location.c_str(), - dex_file->GetLocationChecksum(), - oat_dex_file->GetDexFileLocationChecksum()); + // Set classes on AbstractMethod early so that IsMethod tests can be performed during the live + // bitmap walk. + if (!runtime->IsAotCompiler()) { + // Only the Aot compiler supports having an image with a different pointer size than the + // runtime. This happens on the host for compile 32 bit tests since we use a 64 bit libart + // compiler. We may also use 32 bit dex2oat on a system with 64 bit apps. + if (image_pointer_size_ != sizeof(void*)) { + *error_msg = StringPrintf("Runtime must use current image pointer size: %zu vs %zu", + image_pointer_size_ , + sizeof(void*)); return false; } - - if (app_image) { - // The current dex file field is bogus, overwrite it so that we can get the dex file in the - // loop below. - h_dex_cache->SetDexFile(dex_file.get()); - // Check that each class loader resolved the same way. - // TODO: Store image class loaders as image roots. - GcRoot<mirror::Class>* const types = h_dex_cache->GetResolvedTypes(); - for (int32_t j = 0, num_types = h_dex_cache->NumResolvedTypes(); j < num_types; j++) { - mirror::Class* klass = types[j].Read(); - if (klass != nullptr) { - DCHECK_NE(klass->GetStatus(), mirror::Class::kStatusError); - mirror::ClassLoader* image_class_loader = klass->GetClassLoader(); - image_class_loaders.insert(image_class_loader); - } - } - } else { - if (kSanityCheckObjects) { - SanityCheckArtMethodPointerArray(h_dex_cache->GetResolvedMethods(), - h_dex_cache->NumResolvedMethods(), - image_pointer_size_, - heap->GetBootImageSpaces()); - } - // Register dex files, keep track of existing ones that are conflicts. - AppendToBootClassPath(*dex_file.get(), h_dex_cache); - } - out_dex_files->push_back(std::move(dex_file)); - } - - if (app_image) { - ScopedObjectAccessUnchecked soa(Thread::Current()); - // Check that the class loader resolves the same way as the ones in the image. - // Image class loader [A][B][C][image dex files] - // Class loader = [???][dex_elements][image dex files] - // Need to ensure that [???][dex_elements] == [A][B][C]. - // For each class loader, PathClassLoader, the laoder checks the parent first. Also the logic - // for PathClassLoader does this by looping through the array of dex files. To ensure they - // resolve the same way, simply flatten the hierarchy in the way the resolution order would be, - // and check that the dex file names are the same. - for (mirror::ClassLoader* image_class_loader : image_class_loaders) { - std::list<mirror::String*> image_dex_file_names; - std::string temp_error_msg; - if (!FlattenPathClassLoader(image_class_loader, &image_dex_file_names, &temp_error_msg)) { - *error_msg = StringPrintf("Failed to flatten image class loader hierarchy '%s'", - temp_error_msg.c_str()); - return false; - } - std::list<mirror::String*> loader_dex_file_names; - if (!FlattenPathClassLoader(class_loader.Get(), &loader_dex_file_names, &temp_error_msg)) { - *error_msg = StringPrintf("Failed to flatten class loader hierarchy '%s'", - temp_error_msg.c_str()); - return false; - } - // Add the temporary dex path list elements at the end. - auto* elements = soa.Decode<mirror::ObjectArray<mirror::Object>*>(dex_elements); - for (size_t i = 0, num_elems = elements->GetLength(); i < num_elems; ++i) { - mirror::Object* element = elements->GetWithoutChecks(i); - if (element != nullptr) { - // If we are somewhere in the middle of the array, there may be nulls at the end. - loader_dex_file_names.push_back(GetDexPathListElementName(soa, element)); - } - } - // Ignore the number of image dex files since we are adding those to the class loader anyways. - CHECK_GE(static_cast<size_t>(image_dex_file_names.size()), - static_cast<size_t>(dex_caches->GetLength())); - size_t image_count = image_dex_file_names.size() - dex_caches->GetLength(); - // Check that the dex file names match. - bool equal = image_count == loader_dex_file_names.size(); - if (equal) { - auto it1 = image_dex_file_names.begin(); - auto it2 = loader_dex_file_names.begin(); - for (size_t i = 0; equal && i < image_count; ++i, ++it1, ++it2) { - equal = equal && (*it1)->Equals(*it2); - } - } - if (!equal) { - *error_msg = "Rejecting application image due to class loader mismatch"; - return false; - } - } } if (kSanityCheckObjects) { - for (int32_t i = 0; i < dex_caches->GetLength(); i++) { - auto* dex_cache = dex_caches->Get(i); - for (size_t j = 0; j < dex_cache->NumResolvedFields(); ++j) { - auto* field = dex_cache->GetResolvedField(j, image_pointer_size_); - if (field != nullptr) { - CHECK(field->GetDeclaringClass()->GetClass() != nullptr); + for (auto dex_caches : dex_caches_vector) { + for (int32_t i = 0; i < dex_caches->GetLength(); i++) { + auto* dex_cache = dex_caches->Get(i); + for (size_t j = 0; j < dex_cache->NumResolvedFields(); ++j) { + auto* field = dex_cache->GetResolvedField(j, image_pointer_size_); + if (field != nullptr) { + CHECK(field->GetDeclaringClass()->GetClass() != nullptr); + } } } } - if (!app_image) { - heap->VisitObjects(SanityCheckObjectsCallback, nullptr); - } + heap->VisitObjects(SanityCheckObjectsCallback, nullptr); } // 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_); - methods.VisitPackedArtMethods(&visitor, space->Begin(), image_pointer_size_); - } - - const ImageSection& class_table_section = header.GetImageSection(ImageHeader::kSectionClassTable); - bool added_class_table = false; - if (app_image) { - GetOrCreateAllocatorForClassLoader(class_loader.Get()); // Make sure we have a linear alloc. - } - if (class_table_section.Size() > 0u) { - const uint64_t start_time2 = NanoTime(); - WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); - ClassTable* const class_table = InsertClassTableForClassLoader(class_loader.Get()); - class_table->ReadFromMemory(space->Begin() + class_table_section.Offset()); - if (app_image) { - class_table->SetClassLoader(class_loader.Get()); - } else { - dex_cache_boot_image_class_lookup_required_ = false; + for (gc::space::ImageSpace* space : spaces) { + const ImageHeader& header = space->GetImageHeader(); + const ImageSection& methods = header.GetMethodsSection(); + SetInterpreterEntrypointArtMethodVisitor visitor(image_pointer_size_); + methods.VisitPackedArtMethods(&visitor, space->Begin(), image_pointer_size_); } - VLOG(image) << "Adding class table classes took " << PrettyDuration(NanoTime() - start_time2); - added_class_table = true; } - if (app_image) { - UpdateAppImageClassLoadersAndDexCaches(space, class_loader, dex_caches, added_class_table); + + // reinit class_roots_ + mirror::Class::SetClassClass(class_roots->Get(kJavaLangClass)); + class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class>>(class_roots.Get()); + + // reinit array_iftable_ from any array class instance, they should be == + array_iftable_ = GcRoot<mirror::IfTable>(GetClassRoot(kObjectArrayClass)->GetIfTable()); + DCHECK_EQ(array_iftable_.Read(), GetClassRoot(kBooleanArrayClass)->GetIfTable()); + // String class root was set above + mirror::Field::SetClass(GetClassRoot(kJavaLangReflectField)); + mirror::Field::SetArrayClass(GetClassRoot(kJavaLangReflectFieldArrayClass)); + mirror::Constructor::SetClass(GetClassRoot(kJavaLangReflectConstructor)); + mirror::Constructor::SetArrayClass(GetClassRoot(kJavaLangReflectConstructorArrayClass)); + mirror::Method::SetClass(GetClassRoot(kJavaLangReflectMethod)); + mirror::Method::SetArrayClass(GetClassRoot(kJavaLangReflectMethodArrayClass)); + mirror::Reference::SetClass(GetClassRoot(kJavaLangRefReference)); + mirror::BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass)); + mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass)); + mirror::CharArray::SetArrayClass(GetClassRoot(kCharArrayClass)); + mirror::DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass)); + mirror::FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass)); + mirror::IntArray::SetArrayClass(GetClassRoot(kIntArrayClass)); + mirror::LongArray::SetArrayClass(GetClassRoot(kLongArrayClass)); + mirror::ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass)); + 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); + if (section.Size() > 0u) { + WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); + ClassTable* const class_table = InsertClassTableForClassLoader(nullptr); + class_table->ReadFromMemory(space->Begin() + section.Offset()); + ++class_tables_added; + } } - VLOG(class_linker) << "Adding image space took " << PrettyDuration(NanoTime() - start_time); + 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); + + VLOG(startup) << "ClassLinker::InitFromImage exiting"; + return true; } @@ -1971,6 +1527,14 @@ ClassPathEntry FindInClassPath(const char* descriptor, return ClassPathEntry(nullptr, nullptr); } +static bool IsBootClassLoader(ScopedObjectAccessAlreadyRunnable& soa, + mirror::ClassLoader* class_loader) + SHARED_REQUIRES(Locks::mutator_lock_) { + return class_loader == nullptr || + class_loader->GetClass() == + soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_BootClassLoader); +} + bool ClassLinker::FindClassInPathClassLoader(ScopedObjectAccessAlreadyRunnable& soa, Thread* self, const char* descriptor, @@ -2256,7 +1820,6 @@ mirror::Class* ClassLinker::DefineClass(Thread* self, // inserted before we allocate / fill in these fields. LoadClass(self, dex_file, dex_class_def, klass); if (self->IsExceptionPending()) { - VLOG(class_linker) << self->GetException()->Dump(); // An exception occured during load, set status to erroneous while holding klass' lock in case // notification is necessary. if (!klass->IsErroneous()) { @@ -2924,20 +2487,7 @@ void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, Thread* const self = Thread::Current(); dex_lock_.AssertExclusiveHeld(self); CHECK(dex_cache.Get() != nullptr) << dex_file.GetLocation(); - // For app images, the dex cache location may be a suffix of the dex file location since the - // dex file location is an absolute path. - const size_t dex_cache_length = dex_cache->GetLocation()->GetLength(); - CHECK_GT(dex_cache_length, 0u) << dex_file.GetLocation(); - std::string dex_file_location = dex_file.GetLocation(); - CHECK_GE(dex_file_location.length(), dex_cache_length) - << dex_cache->GetLocation()->ToModifiedUtf8() << " " << dex_file.GetLocation(); - // Take suffix. - const std::string dex_file_suffix = dex_file_location.substr( - dex_file_location.length() - dex_cache_length, - dex_cache_length); - // Example dex_cache location is SettingsProvider.apk and - // dex file location is /system/priv-app/SettingsProvider/SettingsProvider.apk - CHECK(dex_cache->GetLocation()->Equals(dex_file_suffix)) + CHECK(dex_cache->GetLocation()->Equals(dex_file.GetLocation())) << dex_cache->GetLocation()->ToModifiedUtf8() << " " << dex_file.GetLocation(); // Clean up pass to remove null dex caches. // Null dex caches can occur due to class unloading and we are lazily removing null entries. @@ -7381,13 +6931,10 @@ jobject ClassLinker::CreatePathClassLoader(Thread* self, std::vector<const DexFi ArtField* cookie_field = soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_cookie); DCHECK_EQ(cookie_field->GetDeclaringClass(), element_file_field->GetType<false>()); - ArtField* file_name_field = soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_fileName); - DCHECK_EQ(file_name_field->GetDeclaringClass(), element_file_field->GetType<false>()); - // Fill the elements array. int32_t index = 0; for (const DexFile* dex_file : dex_files) { - StackHandleScope<4> hs2(self); + StackHandleScope<3> hs2(self); // CreatePathClassLoader is only used by gtests. Index 0 of h_long_array is supposed to be the // oat file but we can leave it null. @@ -7402,11 +6949,6 @@ jobject ClassLinker::CreatePathClassLoader(Thread* self, std::vector<const DexFi DCHECK(h_dex_file.Get() != nullptr); cookie_field->SetObject<false>(h_dex_file.Get(), h_long_array.Get()); - Handle<mirror::String> h_file_name = hs2.NewHandle( - mirror::String::AllocFromModifiedUtf8(self, dex_file->GetLocation().c_str())); - DCHECK(h_file_name.Get() != nullptr); - file_name_field->SetObject<false>(h_dex_file.Get(), h_file_name.Get()); - Handle<mirror::Object> h_element = hs2.NewHandle(h_dex_element_class->AllocObject(self)); DCHECK(h_element.Get() != nullptr); element_file_field->SetObject<false>(h_element.Get(), h_dex_file.Get()); @@ -7506,7 +7048,6 @@ void ClassLinker::CleanupClassLoaders() { if (class_loader != nullptr) { ++it; } else { - VLOG(class_linker) << "Freeing class loader"; DeleteClassLoader(self, data); it = class_loaders_.erase(it); } diff --git a/runtime/class_linker.h b/runtime/class_linker.h index d503dd4704..f1fd0c38f1 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -120,25 +120,11 @@ class ClassLinker { SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); - // Initialize class linker from one or more boot images. - bool InitFromBootImage(std::string* error_msg) + // Initialize class linker from one or more images. + bool InitFromImage(std::string* error_msg) SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_); - // Add an image space to the class linker, may fix up classloader fields and dex cache fields. - // The dex files that were newly opened for the space are placed in the out argument - // out_dex_files. Returns true if the operation succeeded. - // The space must be already added to the heap before calling AddImageSpace since we need to - // properly handle read barriers and object marking. - bool AddImageSpace(gc::space::ImageSpace* space, - Handle<mirror::ClassLoader> class_loader, - jobjectArray dex_elements, - const char* dex_location, - std::vector<std::unique_ptr<const DexFile>>* out_dex_files, - std::string* error_msg) - REQUIRES(!dex_lock_) - SHARED_REQUIRES(Locks::mutator_lock_); - // Finds a class by its descriptor, loading it if necessary. // If class_loader is null, searches boot_class_path_. mirror::Class* FindClass(Thread* self, @@ -999,16 +985,8 @@ class ClassLinker { SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Locks::classlinker_classes_lock_); - void UpdateAppImageClassLoadersAndDexCaches( - gc::space::ImageSpace* space, - Handle<mirror::ClassLoader> class_loader, - Handle<mirror::ObjectArray<mirror::DexCache>> dex_caches, - bool added_class_table) - REQUIRES(!dex_lock_) - SHARED_REQUIRES(Locks::mutator_lock_); - std::vector<const DexFile*> boot_class_path_; - std::vector<std::unique_ptr<const DexFile>> boot_dex_files_; + std::vector<std::unique_ptr<const DexFile>> opened_dex_files_; mutable ReaderWriterMutex dex_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; // JNI weak globals and side data to allow dex caches to get unloaded. We lazily delete weak diff --git a/runtime/class_table.cc b/runtime/class_table.cc index 2a4f0e01af..df2dbf416c 100644 --- a/runtime/class_table.cc +++ b/runtime/class_table.cc @@ -40,16 +40,6 @@ bool ClassTable::Contains(mirror::Class* klass) { return false; } -mirror::Class* ClassTable::LookupByDescriptor(mirror::Class* klass) { - for (ClassSet& class_set : classes_) { - auto it = class_set.Find(GcRoot<mirror::Class>(klass)); - if (it != class_set.end()) { - return it->Read(); - } - } - return nullptr; -} - mirror::Class* ClassTable::UpdateClass(const char* descriptor, mirror::Class* klass, size_t hash) { // Should only be updating latest table. auto existing_it = classes_.back().FindWithHash(descriptor, hash); @@ -183,12 +173,4 @@ size_t ClassTable::ReadFromMemory(uint8_t* ptr) { return read_count; } -void ClassTable::SetClassLoader(mirror::ClassLoader* class_loader) { - for (const ClassSet& class_set : classes_) { - for (const GcRoot<mirror::Class>& root : class_set) { - root.Read()->SetClassLoader(class_loader); - } - } -} - } // namespace art diff --git a/runtime/class_table.h b/runtime/class_table.h index 0b420352c3..911f3c22db 100644 --- a/runtime/class_table.h +++ b/runtime/class_table.h @@ -84,14 +84,9 @@ class ClassTable { bool Visit(ClassVisitor* visitor) SHARED_REQUIRES(Locks::classlinker_classes_lock_, Locks::mutator_lock_); - // Return the first class that matches the descriptor. Returns null if there are none. mirror::Class* Lookup(const char* descriptor, size_t hash) SHARED_REQUIRES(Locks::classlinker_classes_lock_, Locks::mutator_lock_); - // Return the first class that matches the descriptor of klass. Returns null if there are none. - mirror::Class* LookupByDescriptor(mirror::Class* klass) - SHARED_REQUIRES(Locks::classlinker_classes_lock_, Locks::mutator_lock_); - void Insert(mirror::Class* klass) REQUIRES(Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_); @@ -112,17 +107,10 @@ class ClassTable { // Combines all of the tables into one class set. size_t WriteToMemory(uint8_t* ptr) const SHARED_REQUIRES(Locks::classlinker_classes_lock_, Locks::mutator_lock_); - - // Read a table from ptr and put it at the front of the class set. size_t ReadFromMemory(uint8_t* ptr) REQUIRES(Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_); - // Change the class loader of all the contained classes. - void SetClassLoader(mirror::ClassLoader* class_loader) - REQUIRES(Locks::classlinker_classes_lock_) - SHARED_REQUIRES(Locks::mutator_lock_); - private: class ClassDescriptorHashEquals { public: diff --git a/runtime/gc/accounting/card_table.h b/runtime/gc/accounting/card_table.h index b6af90806b..88a6c6c6e4 100644 --- a/runtime/gc/accounting/card_table.h +++ b/runtime/gc/accounting/card_table.h @@ -115,8 +115,6 @@ class CardTable { // Resets all of the bytes in the card table to clean. void ClearCardTable(); - - // Clear a range of cards that covers start to end, start and end must be aligned to kCardSize. void ClearCardRange(uint8_t* start, uint8_t* end); // Resets all of the bytes in the card table which do not map to the image space. diff --git a/runtime/gc/accounting/space_bitmap-inl.h b/runtime/gc/accounting/space_bitmap-inl.h index 4cf5b4f643..61c67f86c4 100644 --- a/runtime/gc/accounting/space_bitmap-inl.h +++ b/runtime/gc/accounting/space_bitmap-inl.h @@ -167,12 +167,8 @@ inline bool SpaceBitmap<kAlignment>::Modify(const mirror::Object* obj) { uintptr_t* address = &bitmap_begin_[index]; uintptr_t old_word = *address; if (kSetBit) { - // Check the bit before setting the word incase we are trying to mark a read only bitmap - // like an image space bitmap. This bitmap is mapped as read only and will fault if we - // attempt to change any words. Since all of the objects are marked, this will never - // occur if we check before setting the bit. This also prevents dirty pages that would - // occur if the bitmap was read write and we did not check the bit. if ((old_word & mask) == 0) { + // Avoid dirtying the page if possible. *address = old_word | mask; } } else { diff --git a/runtime/gc/collector/immune_spaces_test.cc b/runtime/gc/collector/immune_spaces_test.cc index ea290dd07d..4884e668c2 100644 --- a/runtime/gc/collector/immune_spaces_test.cc +++ b/runtime/gc/collector/immune_spaces_test.cc @@ -112,13 +112,8 @@ class DummyImageSpace : public space::ImageSpace { /*oat_data_begin*/PointerToLowMemUInt32(map->End()), /*oat_data_end*/PointerToLowMemUInt32(map->End() + oat_size), /*oat_file_end*/PointerToLowMemUInt32(map->End() + oat_size), - /*boot_image_begin*/0u, - /*boot_image_size*/0u, - /*boot_oat_begin*/0u, - /*boot_oat_size*/0u, /*pointer_size*/sizeof(void*), /*compile_pic*/false, - /*is_pic*/false, ImageHeader::kStorageModeUncompressed, /*storage_size*/0u); return new DummyImageSpace(map.release(), live_bitmap.release()); diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index 767d8ad907..d6c1817f13 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -273,11 +273,10 @@ Heap::Heap(size_t initial_size, std::string& image_name = image_file_names[index]; ATRACE_BEGIN("ImageSpace::Create"); std::string error_msg; - space::ImageSpace* boot_image_space = space::ImageSpace::CreateBootImage( - image_name.c_str(), - image_instruction_set, - index > 0, - &error_msg); + space::ImageSpace* boot_image_space = space::ImageSpace::Create(image_name.c_str(), + image_instruction_set, + index > 0, + &error_msg); ATRACE_END(); if (boot_image_space != nullptr) { AddSpace(boot_image_space); @@ -376,13 +375,12 @@ Heap::Heap(size_t initial_size, } // Attempt to create 2 mem maps at or after the requested begin. if (foreground_collector_type_ != kCollectorTypeCC) { - if (separate_non_moving_space || !is_zygote) { + if (separate_non_moving_space) { main_mem_map_1.reset(MapAnonymousPreferredAddress(kMemMapSpaceName[0], request_begin, capacity_, &error_str)); } else { - // If no separate non-moving space and we are the zygote, the main space must come right - // after the image space to avoid a gap. This is required since we want the zygote space to - // be adjacent to the image space. + // If no separate non-moving space, the main space must come + // right after the image space to avoid a gap. main_mem_map_1.reset(MemMap::MapAnonymous(kMemMapSpaceName[0], request_begin, capacity_, PROT_READ | PROT_WRITE, true, false, &error_str)); @@ -490,15 +488,7 @@ Heap::Heap(size_t initial_size, ATRACE_END(); // Allocate the card table. ATRACE_BEGIN("Create card table"); - // We currently don't support dynamically resizing the card table. - // Since we don't know where in the low_4gb the app image will be located, make the card table - // cover the whole low_4gb. TODO: Extend the card table in AddSpace. - UNUSED(heap_capacity); - // Start at 64 KB, we can be sure there are no spaces mapped this low since the address range is - // reserved by the kernel. - static constexpr size_t kMinHeapAddress = 4 * KB; - card_table_.reset(accounting::CardTable::Create(reinterpret_cast<uint8_t*>(kMinHeapAddress), - 4 * GB - kMinHeapAddress)); + card_table_.reset(accounting::CardTable::Create(heap_begin, heap_capacity)); CHECK(card_table_.get() != nullptr) << "Failed to create card table"; ATRACE_END(); if (foreground_collector_type_ == kCollectorTypeCC && kUseTableLookupReadBarrier) { @@ -1259,6 +1249,10 @@ space::Space* Heap::FindSpaceFromObject(const mirror::Object* obj, bool fail_ok) return FindDiscontinuousSpaceFromObject(obj, fail_ok); } +std::vector<space::ImageSpace*> Heap::GetBootImageSpaces() const { + return boot_image_spaces_; +} + void Heap::ThrowOutOfMemoryError(Thread* self, size_t byte_count, AllocatorType allocator_type) { std::ostringstream oss; size_t total_bytes_free = GetFreeMemory(); @@ -3197,13 +3191,7 @@ void Heap::ProcessCards(TimingLogger* timings, } else if (process_alloc_space_cards) { TimingLogger::ScopedTiming t2("AllocSpaceClearCards", timings); if (clear_alloc_space_cards) { - uint8_t* end = space->End(); - if (space->IsImageSpace()) { - // Image space end is the end of the mirror objects, it is not necessarily page or card - // aligned. Align up so that the check in ClearCardRange does not fail. - end = AlignUp(end, accounting::CardTable::kCardSize); - } - card_table_->ClearCardRange(space->Begin(), end); + card_table_->ClearCardRange(space->Begin(), space->End()); } else { // No mod union table for the AllocSpace. Age the cards so that the GC knows that these // cards were dirty before the GC started. @@ -3998,43 +3986,5 @@ void Heap::DisableGCForShutdown() { gc_disabled_for_shutdown_ = true; } -bool Heap::ObjectIsInBootImageSpace(mirror::Object* obj) const { - for (gc::space::ImageSpace* space : boot_image_spaces_) { - if (space->HasAddress(obj)) { - return true; - } - } - return false; -} - -void Heap::GetBootImagesSize(uint32_t* boot_image_begin, - uint32_t* boot_image_end, - uint32_t* boot_oat_begin, - uint32_t* boot_oat_end) { - DCHECK(boot_image_begin != nullptr); - DCHECK(boot_image_end != nullptr); - DCHECK(boot_oat_begin != nullptr); - DCHECK(boot_oat_end != nullptr); - *boot_image_begin = 0u; - *boot_image_end = 0u; - *boot_oat_begin = 0u; - *boot_oat_end = 0u; - for (gc::space::ImageSpace* space_ : GetBootImageSpaces()) { - const uint32_t image_begin = PointerToLowMemUInt32(space_->Begin()); - const uint32_t image_size = space_->GetImageHeader().GetImageSize(); - if (*boot_image_begin == 0 || image_begin < *boot_image_begin) { - *boot_image_begin = image_begin; - } - *boot_image_end = std::max(*boot_image_end, image_begin + image_size); - const OatFile* boot_oat_file = space_->GetOatFile(); - const uint32_t oat_begin = PointerToLowMemUInt32(boot_oat_file->Begin()); - const uint32_t oat_size = boot_oat_file->Size(); - if (*boot_oat_begin == 0 || oat_begin < *boot_oat_begin) { - *boot_oat_begin = oat_begin; - } - *boot_oat_end = std::max(*boot_oat_end, oat_begin + oat_size); - } -} - } // namespace gc } // namespace art diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h index 1b7e2c9f0d..7b531ba322 100644 --- a/runtime/gc/heap.h +++ b/runtime/gc/heap.h @@ -580,17 +580,7 @@ class Heap { void UnBindBitmaps() REQUIRES(Locks::heap_bitmap_lock_); // Returns the boot image spaces. There may be multiple boot image spaces. - const std::vector<space::ImageSpace*>& GetBootImageSpaces() const { - return boot_image_spaces_; - } - - bool ObjectIsInBootImageSpace(mirror::Object* obj) const - SHARED_REQUIRES(Locks::mutator_lock_); - - void GetBootImagesSize(uint32_t* boot_image_begin, - uint32_t* boot_image_end, - uint32_t* boot_oat_begin, - uint32_t* boot_oat_end); + std::vector<space::ImageSpace*> GetBootImageSpaces() const; // Permenantly disable moving garbage collection. void DisableMovingGc() REQUIRES(!*gc_complete_lock_); diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index 9ff3d8db75..5f6bb8ee4b 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -475,10 +475,10 @@ static bool CheckSpace(const std::string& cache_filename, std::string* error_msg return true; } -ImageSpace* ImageSpace::CreateBootImage(const char* image_location, - const InstructionSet image_isa, - bool secondary_image, - std::string* error_msg) { +ImageSpace* ImageSpace::Create(const char* image_location, + const InstructionSet image_isa, + bool secondary_image, + std::string* error_msg) { std::string system_filename; bool has_system = false; std::string cache_filename; @@ -584,13 +584,8 @@ ImageSpace* ImageSpace::CreateBootImage(const char* image_location, // assume this if we are using a relocated image (i.e. image checksum // matches) since this is only different by the offset. We need this to // make sure that host tests continue to work. - // Since we are the boot image, pass null since we load the oat file from the boot image oat - // file name. - space = ImageSpace::Init(image_filename->c_str(), - image_location, - !(is_system || relocated_version_used), - /* oat_file */nullptr, - error_msg); + space = ImageSpace::Init(image_filename->c_str(), image_location, + !(is_system || relocated_version_used), error_msg); } if (space != nullptr) { return space; @@ -651,7 +646,7 @@ ImageSpace* ImageSpace::CreateBootImage(const char* image_location, // we leave Create. ScopedFlock image_lock; image_lock.Init(cache_filename.c_str(), error_msg); - space = ImageSpace::Init(cache_filename.c_str(), image_location, true, nullptr, error_msg); + space = ImageSpace::Init(cache_filename.c_str(), image_location, true, error_msg); if (space == nullptr) { *error_msg = StringPrintf("Failed to load generated image '%s': %s", cache_filename.c_str(), error_msg->c_str()); @@ -674,494 +669,34 @@ void ImageSpace::VerifyImageAllocations() { } } -// Helper class for relocating from one range of memory to another. -class RelocationRange { - public: - RelocationRange() = default; - RelocationRange(const RelocationRange&) = default; - RelocationRange(uintptr_t source, uintptr_t dest, uintptr_t length) - : source_(source), - dest_(dest), - length_(length) {} - - bool ContainsSource(uintptr_t address) const { - return address - source_ < length_; - } - - // Translate a source address to the destination space. - uintptr_t ToDest(uintptr_t address) const { - DCHECK(ContainsSource(address)); - return address + Delta(); - } - - // Returns the delta between the dest from the source. - off_t Delta() const { - return dest_ - source_; - } - - uintptr_t Source() const { - return source_; - } - - uintptr_t Dest() const { - return dest_; - } - - uintptr_t Length() const { - return length_; - } - - private: - const uintptr_t source_; - const uintptr_t dest_; - const uintptr_t length_; -}; - -class FixupVisitor : public ValueObject { - public: - FixupVisitor(const RelocationRange& boot_image, - const RelocationRange& boot_oat, - const RelocationRange& app_image, - const RelocationRange& app_oat) - : boot_image_(boot_image), - boot_oat_(boot_oat), - app_image_(app_image), - app_oat_(app_oat) {} - - // Return the relocated address of a heap object. - template <typename T> - ALWAYS_INLINE T* ForwardObject(T* src) const { - const uintptr_t uint_src = reinterpret_cast<uintptr_t>(src); - if (boot_image_.ContainsSource(uint_src)) { - return reinterpret_cast<T*>(boot_image_.ToDest(uint_src)); - } - if (app_image_.ContainsSource(uint_src)) { - return reinterpret_cast<T*>(app_image_.ToDest(uint_src)); - } - return src; - } - - // Return the relocated address of a code pointer (contained by an oat file). - ALWAYS_INLINE const void* ForwardCode(const void* src) const { - const uintptr_t uint_src = reinterpret_cast<uintptr_t>(src); - if (boot_oat_.ContainsSource(uint_src)) { - return reinterpret_cast<const void*>(boot_oat_.ToDest(uint_src)); - } - if (app_oat_.ContainsSource(uint_src)) { - return reinterpret_cast<const void*>(app_oat_.ToDest(uint_src)); - } - return src; - } - - protected: - // Source section. - const RelocationRange boot_image_; - const RelocationRange boot_oat_; - const RelocationRange app_image_; - const RelocationRange app_oat_; -}; - -std::ostream& operator<<(std::ostream& os, const RelocationRange& reloc) { - return os << "(" << reinterpret_cast<const void*>(reloc.Source()) << "-" - << reinterpret_cast<const void*>(reloc.Source() + reloc.Length()) << ")->(" - << reinterpret_cast<const void*>(reloc.Dest()) << "-" - << reinterpret_cast<const void*>(reloc.Dest() + reloc.Length()) << ")"; -} - -// Adapt for mirror::Class::FixupNativePointers. -class FixupObjectAdapter : public FixupVisitor { - public: - template<typename... Args> - explicit FixupObjectAdapter(Args... args) : FixupVisitor(args...) {} - - template <typename T> - T* operator()(T* obj) const { - return ForwardObject(obj); - } -}; - -class FixupClassVisitor : public FixupVisitor { - public: - template<typename... Args> - explicit FixupClassVisitor(Args... args) : FixupVisitor(args...) {} - - // The image space is contained so the GC doesn't need to know about it. Avoid requiring mutator - // lock to prevent possible pauses. - ALWAYS_INLINE void operator()(mirror::Object* obj) const NO_THREAD_SAFETY_ANALYSIS { - mirror::Class* klass = obj->GetClass<kVerifyNone, kWithoutReadBarrier>(); - DCHECK(klass != nullptr) << "Null class in image"; - // No AsClass since our fields aren't quite fixed up yet. - mirror::Class* new_klass = down_cast<mirror::Class*>(ForwardObject(klass)); - // Keep clean if possible. - if (klass != new_klass) { - obj->SetClass<kVerifyNone>(new_klass); - } - } -}; - -class FixupRootVisitor : public FixupVisitor { - public: - template<typename... Args> - explicit FixupRootVisitor(Args... args) : FixupVisitor(args...) {} - - ALWAYS_INLINE void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root) const - SHARED_REQUIRES(Locks::mutator_lock_) { - if (!root->IsNull()) { - VisitRoot(root); - } - } - - ALWAYS_INLINE void VisitRoot(mirror::CompressedReference<mirror::Object>* root) const - SHARED_REQUIRES(Locks::mutator_lock_) { - mirror::Object* ref = root->AsMirrorPtr(); - mirror::Object* new_ref = ForwardObject(ref); - if (ref != new_ref) { - root->Assign(new_ref); - } - } -}; - -class FixupObjectVisitor : public FixupVisitor { - public: - template<typename... Args> - explicit FixupObjectVisitor(Args... args) : FixupVisitor(args...) {} - - // Fix up separately since we also need to fix up method entrypoints. - ALWAYS_INLINE void VisitRootIfNonNull( - mirror::CompressedReference<mirror::Object>* root ATTRIBUTE_UNUSED) const {} - - ALWAYS_INLINE void VisitRoot(mirror::CompressedReference<mirror::Object>* root ATTRIBUTE_UNUSED) - const {} - - ALWAYS_INLINE void operator()(mirror::Object* obj, - MemberOffset offset, - bool is_static ATTRIBUTE_UNUSED) const - NO_THREAD_SAFETY_ANALYSIS { - // There could be overlap between ranges, we must avoid visiting the same reference twice. - // Avoid the class field since we already fixed it up in FixupClassVisitor. - if (offset.Uint32Value() != mirror::Object::ClassOffset().Uint32Value()) { - // Space is not yet added to the heap, don't do a read barrier. - mirror::Object* ref = obj->GetFieldObject<mirror::Object, kVerifyNone, kWithoutReadBarrier>( - offset); - // Use SetFieldObjectWithoutWriteBarrier to avoid card marking since we are writing to the - // image. - obj->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>(offset, ForwardObject(ref)); - } - } - - // java.lang.ref.Reference visitor. - void operator()(mirror::Class* klass ATTRIBUTE_UNUSED, mirror::Reference* ref) const - SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(Locks::heap_bitmap_lock_) { - mirror::Object* obj = ref->GetReferent<kWithoutReadBarrier>(); - ref->SetFieldObjectWithoutWriteBarrier<false, true, kVerifyNone>( - mirror::Reference::ReferentOffset(), - ForwardObject(obj)); - } - - ALWAYS_INLINE void operator()(mirror::Object* obj) const NO_THREAD_SAFETY_ANALYSIS { - obj->VisitReferences</*visit native roots*/false, kVerifyNone, kWithoutReadBarrier>( - *this, - *this); - // We want to use our own class loader and not the one in the image. - if (obj->IsClass<kVerifyNone, kWithoutReadBarrier>()) { - mirror::Class* klass = obj->AsClass<kVerifyNone, kWithoutReadBarrier>(); - FixupObjectAdapter visitor(boot_image_, boot_oat_, app_image_, app_oat_); - klass->FixupNativePointers(klass, sizeof(void*), visitor); - // Deal with the arrays. - mirror::PointerArray* vtable = klass->GetVTable<kVerifyNone, kWithoutReadBarrier>(); - if (vtable != nullptr) { - vtable->Fixup(vtable, sizeof(void*), visitor); - } - mirror::IfTable* iftable = klass->GetIfTable<kVerifyNone, kWithoutReadBarrier>(); - if (iftable != nullptr) { - for (int32_t i = 0; i < klass->GetIfTableCount(); ++i) { - if (iftable->GetMethodArrayCount(i) > 0) { - mirror::PointerArray* methods = - iftable->GetMethodArray<kVerifyNone, kWithoutReadBarrier>(i); - DCHECK(methods != nullptr); - methods->Fixup(methods, sizeof(void*), visitor); - } - } - } - } - } -}; - -class ForwardObjectAdapter { - public: - ALWAYS_INLINE ForwardObjectAdapter(const FixupVisitor* visitor) : visitor_(visitor) {} - - template <typename T> - ALWAYS_INLINE T* operator()(T* src) const { - return visitor_->ForwardObject(src); - } - - private: - const FixupVisitor* const visitor_; -}; - -class ForwardCodeAdapter { - public: - ALWAYS_INLINE ForwardCodeAdapter(const FixupVisitor* visitor) : visitor_(visitor) {} - - template <typename T> - ALWAYS_INLINE T* operator()(T* src) const { - return visitor_->ForwardCode(src); - } - - private: - const FixupVisitor* const visitor_; -}; - -class FixupArtMethodVisitor : public FixupVisitor, public ArtMethodVisitor { - public: - template<typename... Args> - explicit FixupArtMethodVisitor(bool fixup_heap_objects, Args... args) - : FixupVisitor(args...), - fixup_heap_objects_(fixup_heap_objects) {} - - virtual void Visit(ArtMethod* method) NO_THREAD_SAFETY_ANALYSIS { - if (fixup_heap_objects_) { - method->UpdateObjectsForImageRelocation(ForwardObjectAdapter(this)); - } - method->UpdateEntrypoints(ForwardCodeAdapter(this)); - } - - private: - const bool fixup_heap_objects_; -}; - -class FixupArtFieldVisitor : public FixupVisitor, public ArtFieldVisitor { - public: - template<typename... Args> - explicit FixupArtFieldVisitor(Args... args) : FixupVisitor(args...) {} - - virtual void Visit(ArtField* field) NO_THREAD_SAFETY_ANALYSIS { - field->UpdateObjects(ForwardObjectAdapter(this)); - } -}; - -// Relocate an image space mapped at target_base which possibly used to be at a different base -// address. Only needs a single image space, not one for both source and destination. -// In place means modifying a single ImageSpace in place rather than relocating from one ImageSpace -// to another. -static bool RelocateInPlace(ImageHeader& image_header, - uint8_t* target_base, - accounting::ContinuousSpaceBitmap* bitmap, - const OatFile* app_oat_file, - std::string* error_msg) { - DCHECK(error_msg != nullptr); - if (!image_header.IsPic()) { - if (image_header.GetImageBegin() == target_base) { - return true; - } - *error_msg = StringPrintf("Cannot relocate non-pic image for oat file %s", - (app_oat_file != nullptr) ? app_oat_file->GetLocation().c_str() : ""); - return false; - } - // Set up sections. - uint32_t boot_image_begin = 0; - uint32_t boot_image_end = 0; - uint32_t boot_oat_begin = 0; - uint32_t boot_oat_end = 0; - gc::Heap* const heap = Runtime::Current()->GetHeap(); - heap->GetBootImagesSize(&boot_image_begin, &boot_image_end, &boot_oat_begin, &boot_oat_end); - CHECK_NE(boot_image_begin, boot_image_end) - << "Can not relocate app image without boot image space"; - CHECK_NE(boot_oat_begin, boot_oat_end) << "Can not relocate app image without boot oat file"; - const uint32_t boot_image_size = boot_image_end - boot_image_begin; - const uint32_t boot_oat_size = boot_oat_end - boot_oat_begin; - const uint32_t image_header_boot_image_size = image_header.GetBootImageSize(); - const uint32_t image_header_boot_oat_size = image_header.GetBootOatSize(); - if (boot_image_size != image_header_boot_image_size) { - *error_msg = StringPrintf("Boot image size %" PRIu64 " does not match expected size %" - PRIu64, - static_cast<uint64_t>(boot_image_size), - static_cast<uint64_t>(image_header_boot_image_size)); - return false; - } - if (boot_oat_size != image_header_boot_oat_size) { - *error_msg = StringPrintf("Boot oat size %" PRIu64 " does not match expected size %" - PRIu64, - static_cast<uint64_t>(boot_oat_size), - static_cast<uint64_t>(image_header_boot_oat_size)); - return false; - } - TimingLogger logger(__FUNCTION__, true, false); - RelocationRange boot_image(image_header.GetBootImageBegin(), - boot_image_begin, - boot_image_size); - RelocationRange boot_oat(image_header.GetBootOatBegin(), - boot_oat_begin, - boot_oat_size); - RelocationRange app_image(reinterpret_cast<uintptr_t>(image_header.GetImageBegin()), - reinterpret_cast<uintptr_t>(target_base), - image_header.GetImageSize()); - // Use the oat data section since this is where the OatFile::Begin is. - RelocationRange app_oat(reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin()), - // Not necessarily in low 4GB. - reinterpret_cast<uintptr_t>(app_oat_file->Begin()), - image_header.GetOatDataEnd() - image_header.GetOatDataBegin()); - VLOG(image) << "App image " << app_image; - VLOG(image) << "App oat " << app_oat; - VLOG(image) << "Boot image " << boot_image; - VLOG(image) << "Boot oat " << boot_oat; - // True if we need to fixup any heap pointers, otherwise only code pointers. - const bool fixup_image = boot_image.Delta() != 0 || app_image.Delta() != 0; - const bool fixup_code = boot_oat.Delta() != 0 || app_oat.Delta() != 0; - if (!fixup_image && !fixup_code) { - // Nothing to fix up. - return true; - } - // Need to update the image to be at the target base. - const ImageSection& objects_section = image_header.GetImageSection(ImageHeader::kSectionObjects); - uintptr_t objects_begin = reinterpret_cast<uintptr_t>(target_base + objects_section.Offset()); - uintptr_t objects_end = reinterpret_cast<uintptr_t>(target_base + objects_section.End()); - // Two pass approach, fix up all classes first, then fix up non class-objects. - FixupObjectVisitor fixup_object_visitor(boot_image, boot_oat, app_image, app_oat); - if (fixup_image) { - TimingLogger::ScopedTiming timing("Fixup classes", &logger); - // Fixup class only touches app image classes, don't need the mutator lock since the space is - // not yet visible to the GC. - FixupClassVisitor fixup_class_visitor(boot_image, boot_oat, app_image, app_oat); - bitmap->VisitMarkedRange(objects_begin, objects_end, fixup_class_visitor); - // Fixup objects may read fields in the boot image, use the mutator lock here for sanity. Though - // its probably not required. - 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.ContainsSource(reinterpret_cast<uintptr_t>(image_header.GetImageRoots()))); - image_header.RelocateImageObjects(app_image.Delta()); - CHECK_EQ(image_header.GetImageBegin(), target_base); - // Fix up dex cache DexFile pointers. - auto* dex_caches = image_header.GetImageRoot(ImageHeader::kDexCaches)-> - AsObjectArray<mirror::DexCache>(); - for (int32_t i = 0, count = dex_caches->GetLength(); i < count; ++i) { - mirror::DexCache* dex_cache = dex_caches->Get(i); - // Fix up dex cache pointers. - GcRoot<mirror::String>* strings = dex_cache->GetStrings(); - if (strings != nullptr) { - GcRoot<mirror::String>* new_strings = fixup_adapter.ForwardObject(strings); - if (strings != new_strings) { - dex_cache->SetFieldPtr64<false>(mirror::DexCache::StringsOffset(), new_strings); - } - dex_cache->FixupStrings(new_strings, fixup_adapter); - } - GcRoot<mirror::Class>* types = dex_cache->GetResolvedTypes(); - if (types != nullptr) { - GcRoot<mirror::Class>* new_types = fixup_adapter.ForwardObject(types); - if (types != new_types) { - dex_cache->SetFieldPtr64<false>(mirror::DexCache::ResolvedTypesOffset(), new_types); - } - dex_cache->FixupResolvedTypes(new_types, fixup_adapter); - } - ArtMethod** methods = dex_cache->GetResolvedMethods(); - if (methods != nullptr) { - ArtMethod** new_methods = fixup_adapter.ForwardObject(methods); - if (methods != new_methods) { - dex_cache->SetFieldPtr64<false>(mirror::DexCache::ResolvedMethodsOffset(), new_methods); - } - for (size_t j = 0, num = dex_cache->NumResolvedMethods(); j != num; ++j) { - ArtMethod* orig = mirror::DexCache::GetElementPtrSize(new_methods, j, sizeof(void*)); - ArtMethod* copy = fixup_adapter.ForwardObject(orig); - if (orig != copy) { - mirror::DexCache::SetElementPtrSize(new_methods, j, copy, sizeof(void*)); - } - } - } - ArtField** fields = dex_cache->GetResolvedFields(); - if (fields != nullptr) { - ArtField** new_fields = fixup_adapter.ForwardObject(fields); - if (fields != new_fields) { - dex_cache->SetFieldPtr64<false>(mirror::DexCache::ResolvedFieldsOffset(), new_fields); - } - for (size_t j = 0, num = dex_cache->NumResolvedFields(); j != num; ++j) { - ArtField* orig = mirror::DexCache::GetElementPtrSize(new_fields, j, sizeof(void*)); - ArtField* copy = fixup_adapter.ForwardObject(orig); - if (orig != copy) { - mirror::DexCache::SetElementPtrSize(new_fields, j, copy, sizeof(void*)); - } - } - } - } - } - { - // Only touches objects in the app image, no need for mutator lock. - TimingLogger::ScopedTiming timing("Fixup methods", &logger); - FixupArtMethodVisitor method_visitor(fixup_image, boot_image, boot_oat, app_image, app_oat); - image_header.GetImageSection(ImageHeader::kSectionArtMethods).VisitPackedArtMethods( - &method_visitor, - target_base, - sizeof(void*)); - } - 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.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()); - const auto& class_table_section = image_header.GetImageSection(ImageHeader::kSectionClassTable); - if (class_table_section.Size() > 0u) { - // 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. - ScopedObjectAccess soa(Thread::Current()); - WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); - ClassTable temp_table; - temp_table.ReadFromMemory(target_base + class_table_section.Offset()); - FixupRootVisitor root_visitor(boot_image, boot_oat, app_image, app_oat); - temp_table.VisitRoots(root_visitor); - } - } - if (VLOG_IS_ON(image)) { - logger.Dump(LOG(INFO)); - } - return true; -} - -ImageSpace* ImageSpace::Init(const char* image_filename, - const char* image_location, - bool validate_oat_file, - const OatFile* oat_file, - std::string* error_msg) { +ImageSpace* ImageSpace::Init(const char* image_filename, const char* image_location, + bool validate_oat_file, std::string* error_msg) { CHECK(image_filename != nullptr); CHECK(image_location != nullptr); - TimingLogger logger(__FUNCTION__, true, false); - VLOG(image) << "ImageSpace::Init entering image_filename=" << image_filename; + uint64_t start_time = 0; + if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) { + start_time = NanoTime(); + LOG(INFO) << "ImageSpace::Init entering image_filename=" << image_filename; + } - std::unique_ptr<File> file; - { - TimingLogger::ScopedTiming timing("OpenImageFile", &logger); - file.reset(OS::OpenFileForReading(image_filename)); - if (file == nullptr) { - *error_msg = StringPrintf("Failed to open '%s'", image_filename); - return nullptr; - } + std::unique_ptr<File> file(OS::OpenFileForReading(image_filename)); + if (file.get() == nullptr) { + *error_msg = StringPrintf("Failed to open '%s'", image_filename); + return nullptr; } - ImageHeader temp_image_header; - ImageHeader* image_header = &temp_image_header; - { - TimingLogger::ScopedTiming timing("ReadImageHeader", &logger); - bool success = file->ReadFully(image_header, sizeof(*image_header)); - if (!success || !image_header->IsValid()) { - *error_msg = StringPrintf("Invalid image header in '%s'", image_filename); - return nullptr; - } + ImageHeader image_header; + bool success = file->ReadFully(&image_header, sizeof(image_header)); + if (!success || !image_header.IsValid()) { + *error_msg = StringPrintf("Invalid image header in '%s'", image_filename); + return nullptr; } // Check that the file is larger or equal to the header size + data size. const uint64_t image_file_size = static_cast<uint64_t>(file->GetLength()); - if (image_file_size < sizeof(ImageHeader) + image_header->GetDataSize()) { + if (image_file_size < sizeof(ImageHeader) + image_header.GetDataSize()) { *error_msg = StringPrintf("Image file truncated: %" PRIu64 " vs. %" PRIu64 ".", image_file_size, - sizeof(ImageHeader) + image_header->GetDataSize()); + image_header.GetDataSize()); return nullptr; } @@ -1169,17 +704,17 @@ ImageSpace* ImageSpace::Init(const char* image_filename, LOG(INFO) << "Dumping image sections"; for (size_t i = 0; i < ImageHeader::kSectionCount; ++i) { const auto section_idx = static_cast<ImageHeader::ImageSections>(i); - auto& section = image_header->GetImageSection(section_idx); + auto& section = image_header.GetImageSection(section_idx); LOG(INFO) << section_idx << " start=" - << reinterpret_cast<void*>(image_header->GetImageBegin() + section.Offset()) << " " - << section; + << reinterpret_cast<void*>(image_header.GetImageBegin() + section.Offset()) << " " + << section; } } - const auto& bitmap_section = image_header->GetImageSection(ImageHeader::kSectionImageBitmap); + const auto& bitmap_section = image_header.GetImageSection(ImageHeader::kSectionImageBitmap); // The location we want to map from is the first aligned page after the end of the stored // (possibly compressed) data. - const size_t image_bitmap_offset = RoundUp(sizeof(ImageHeader) + image_header->GetDataSize(), + const size_t image_bitmap_offset = RoundUp(sizeof(image_header) + image_header.GetDataSize(), kPageSize); const size_t end_of_bitmap = image_bitmap_offset + bitmap_section.Size(); if (end_of_bitmap != image_file_size) { @@ -1189,84 +724,67 @@ ImageSpace* ImageSpace::Init(const char* image_filename, return nullptr; } - // The preferred address to map the image, null specifies any address. If we manage to map the - // image at the image begin, the amount of fixup work required is minimized. - std::vector<uint8_t*> addresses(1, image_header->GetImageBegin()); - if (image_header->IsPic()) { - // Can also map at a random low_4gb address since we can relocate in-place. - addresses.push_back(nullptr); - } - // Note: The image header is part of the image due to mmap page alignment required of offset. std::unique_ptr<MemMap> map; - std::string temp_error_msg; - for (uint8_t* address : addresses) { - TimingLogger::ScopedTiming timing("MapImageFile", &logger); - // Only care about the error message for the last address in addresses. We want to avoid the - // overhead of printing the process maps if we can relocate. - std::string* out_error_msg = (address == addresses.back()) ? &temp_error_msg : nullptr; - if (image_header->GetStorageMode() == ImageHeader::kStorageModeUncompressed) { - map.reset(MemMap::MapFileAtAddress(address, - image_header->GetImageSize(), - PROT_READ | PROT_WRITE, - MAP_PRIVATE, - file->Fd(), - 0, - /*low_4gb*/true, - /*reuse*/false, - image_filename, - /*out*/out_error_msg)); - } else { - // Reserve output and decompress into it. - map.reset(MemMap::MapAnonymous(image_location, - address, - image_header->GetImageSize(), - PROT_READ | PROT_WRITE, - /*low_4gb*/true, - /*reuse*/false, - out_error_msg)); - if (map != nullptr) { - const size_t stored_size = image_header->GetDataSize(); - const size_t write_offset = sizeof(ImageHeader); // Skip the header. - std::unique_ptr<MemMap> temp_map(MemMap::MapFile(sizeof(ImageHeader) + stored_size, - PROT_READ, - MAP_PRIVATE, - file->Fd(), - /*offset*/0, - /*low_4gb*/false, - image_filename, - out_error_msg)); - if (temp_map == nullptr) { - DCHECK(!out_error_msg->empty()); - return nullptr; - } - memcpy(map->Begin(), image_header, sizeof(ImageHeader)); - const uint64_t start = NanoTime(); - const size_t decompressed_size = LZ4_decompress_safe( - reinterpret_cast<char*>(temp_map->Begin()) + sizeof(ImageHeader), - reinterpret_cast<char*>(map->Begin()) + write_offset, - stored_size, - map->Size()); - VLOG(image) << "Decompressing image took " << PrettyDuration(NanoTime() - start); - if (decompressed_size + sizeof(ImageHeader) != image_header->GetImageSize()) { - *error_msg = StringPrintf("Decompressed size does not match expected image size %zu vs %zu", - decompressed_size + sizeof(ImageHeader), - image_header->GetImageSize()); - return nullptr; - } - } - } + if (image_header.GetStorageMode() == ImageHeader::kStorageModeUncompressed) { + map.reset(MemMap::MapFileAtAddress(image_header.GetImageBegin(), + image_header.GetImageSize(), + PROT_READ | PROT_WRITE, + MAP_PRIVATE, + file->Fd(), + 0, + /*low_4gb*/false, + /*reuse*/false, + image_filename, + error_msg)); + } else { + // Reserve output and decompress into it. + map.reset(MemMap::MapAnonymous(image_location, + image_header.GetImageBegin(), + image_header.GetImageSize(), + PROT_READ | PROT_WRITE, + /*low_4gb*/false, + /*reuse*/false, + error_msg)); if (map != nullptr) { - break; + const size_t stored_size = image_header.GetDataSize(); + const size_t write_offset = sizeof(image_header); // Skip the header. + std::unique_ptr<MemMap> temp_map(MemMap::MapFile(sizeof(ImageHeader) + stored_size, + PROT_READ, + MAP_PRIVATE, + file->Fd(), + /*offset*/0, + /*low_4gb*/false, + image_filename, + error_msg)); + if (temp_map == nullptr) { + DCHECK(!error_msg->empty()); + return nullptr; + } + memcpy(map->Begin(), &image_header, sizeof(image_header)); + const uint64_t start = NanoTime(); + const size_t decompressed_size = LZ4_decompress_safe( + reinterpret_cast<char*>(temp_map->Begin()) + sizeof(ImageHeader), + reinterpret_cast<char*>(map->Begin()) + write_offset, + stored_size, + map->Size()); + // TODO: VLOG(image) + VLOG(class_linker) << "Decompressing image took " << PrettyDuration(NanoTime() - start); + if (decompressed_size + sizeof(ImageHeader) != image_header.GetImageSize()) { + *error_msg = StringPrintf("Decompressed size does not match expected image size %zu vs %zu", + decompressed_size + sizeof(ImageHeader), + image_header.GetImageSize()); + return nullptr; + } } } if (map == nullptr) { - DCHECK(!temp_error_msg.empty()); - *error_msg = temp_error_msg; + DCHECK(!error_msg->empty()); return nullptr; } - DCHECK_EQ(0, memcmp(image_header, map->Begin(), sizeof(ImageHeader))); + CHECK_EQ(image_header.GetImageBegin(), map->Begin()); + DCHECK_EQ(0, memcmp(&image_header, map->Begin(), sizeof(ImageHeader))); std::unique_ptr<MemMap> image_bitmap_map(MemMap::MapFileAtAddress(nullptr, bitmap_section.Size(), @@ -1281,42 +799,25 @@ ImageSpace* ImageSpace::Init(const char* image_filename, *error_msg = StringPrintf("Failed to map image bitmap: %s", error_msg->c_str()); return nullptr; } - // Loaded the map, use the image header from the file now in case we patch it with - // RelocateInPlace. - image_header = reinterpret_cast<ImageHeader*>(map->Begin()); - const uint32_t bitmap_index = bitmap_index_.FetchAndAddSequentiallyConsistent(1); - std::string bitmap_name(StringPrintf("imagespace %s live-bitmap %u", - image_filename, + uint32_t bitmap_index = bitmap_index_.FetchAndAddSequentiallyConsistent(1); + std::string bitmap_name(StringPrintf("imagespace %s live-bitmap %u", image_filename, bitmap_index)); // Bitmap only needs to cover until the end of the mirror objects section. - const ImageSection& image_objects = image_header->GetImageSection(ImageHeader::kSectionObjects); - // We only want the mirror object, not the ArtFields and ArtMethods. - uint8_t* const image_end = map->Begin() + image_objects.End(); - std::unique_ptr<accounting::ContinuousSpaceBitmap> bitmap; - { - TimingLogger::ScopedTiming timing("CreateImageBitmap", &logger); - bitmap.reset( + const ImageSection& image_objects = image_header.GetImageSection(ImageHeader::kSectionObjects); + std::unique_ptr<accounting::ContinuousSpaceBitmap> bitmap( accounting::ContinuousSpaceBitmap::CreateFromMemMap( bitmap_name, image_bitmap_map.release(), reinterpret_cast<uint8_t*>(map->Begin()), image_objects.End())); - if (bitmap == nullptr) { - *error_msg = StringPrintf("Could not create bitmap '%s'", bitmap_name.c_str()); - return nullptr; - } - } - { - TimingLogger::ScopedTiming timing("RelocateImage", &logger); - if (!RelocateInPlace(*image_header, - map->Begin(), - bitmap.get(), - oat_file, - error_msg)) { - return nullptr; - } + if (bitmap == nullptr) { + *error_msg = StringPrintf("Could not create bitmap '%s'", bitmap_name.c_str()); + return nullptr; } + // We only want the mirror object, not the ArtFields and ArtMethods. + uint8_t* const image_end = + map->Begin() + image_header.GetImageSection(ImageHeader::kSectionObjects).End(); std::unique_ptr<ImageSpace> space(new ImageSpace(image_filename, image_location, map.release(), @@ -1328,61 +829,38 @@ ImageSpace* ImageSpace::Init(const char* image_filename, // and ArtField::java_lang_reflect_ArtField_, which are used from // Object::SizeOf() which VerifyImageAllocations() calls, are not // set yet at this point. - if (oat_file == nullptr) { - TimingLogger::ScopedTiming timing("OpenOatFile", &logger); - space->oat_file_.reset(space->OpenOatFile(image_filename, error_msg)); - if (space->oat_file_ == nullptr) { - DCHECK(!error_msg->empty()); - return nullptr; - } - space->oat_file_non_owned_ = space->oat_file_.get(); - } else { - space->oat_file_non_owned_ = oat_file; + + space->oat_file_.reset(space->OpenOatFile(image_filename, error_msg)); + if (space->oat_file_.get() == nullptr) { + DCHECK(!error_msg->empty()); + return nullptr; } + space->oat_file_non_owned_ = space->oat_file_.get(); - if (validate_oat_file) { - TimingLogger::ScopedTiming timing("ValidateOatFile", &logger); - if (!space->ValidateOatFile(error_msg)) { - DCHECK(!error_msg->empty()); - return nullptr; - } + if (validate_oat_file && !space->ValidateOatFile(error_msg)) { + DCHECK(!error_msg->empty()); + return nullptr; } Runtime* runtime = Runtime::Current(); + runtime->SetInstructionSet(space->oat_file_->GetOatHeader().GetInstructionSet()); - // If oat_file is null, then it is the boot image space. Use oat_file_non_owned_ from the space - // to set the runtime methods. - CHECK_EQ(oat_file != nullptr, image_header->IsAppImage()); - if (image_header->IsAppImage()) { - CHECK_EQ(runtime->GetResolutionMethod(), - image_header->GetImageMethod(ImageHeader::kResolutionMethod)); - CHECK_EQ(runtime->GetImtConflictMethod(), - image_header->GetImageMethod(ImageHeader::kImtConflictMethod)); - CHECK_EQ(runtime->GetImtUnimplementedMethod(), - image_header->GetImageMethod(ImageHeader::kImtUnimplementedMethod)); - CHECK_EQ(runtime->GetCalleeSaveMethod(Runtime::kSaveAll), - image_header->GetImageMethod(ImageHeader::kCalleeSaveMethod)); - CHECK_EQ(runtime->GetCalleeSaveMethod(Runtime::kRefsOnly), - image_header->GetImageMethod(ImageHeader::kRefsOnlySaveMethod)); - CHECK_EQ(runtime->GetCalleeSaveMethod(Runtime::kRefsAndArgs), - image_header->GetImageMethod(ImageHeader::kRefsAndArgsSaveMethod)); - } else if (!runtime->HasResolutionMethod()) { - runtime->SetInstructionSet(space->oat_file_non_owned_->GetOatHeader().GetInstructionSet()); - runtime->SetResolutionMethod(image_header->GetImageMethod(ImageHeader::kResolutionMethod)); - runtime->SetImtConflictMethod(image_header->GetImageMethod(ImageHeader::kImtConflictMethod)); + if (!runtime->HasResolutionMethod()) { + runtime->SetResolutionMethod(image_header.GetImageMethod(ImageHeader::kResolutionMethod)); + runtime->SetImtConflictMethod(image_header.GetImageMethod(ImageHeader::kImtConflictMethod)); runtime->SetImtUnimplementedMethod( - image_header->GetImageMethod(ImageHeader::kImtUnimplementedMethod)); + image_header.GetImageMethod(ImageHeader::kImtUnimplementedMethod)); runtime->SetCalleeSaveMethod( - image_header->GetImageMethod(ImageHeader::kCalleeSaveMethod), Runtime::kSaveAll); + image_header.GetImageMethod(ImageHeader::kCalleeSaveMethod), Runtime::kSaveAll); runtime->SetCalleeSaveMethod( - image_header->GetImageMethod(ImageHeader::kRefsOnlySaveMethod), Runtime::kRefsOnly); + image_header.GetImageMethod(ImageHeader::kRefsOnlySaveMethod), Runtime::kRefsOnly); runtime->SetCalleeSaveMethod( - image_header->GetImageMethod(ImageHeader::kRefsAndArgsSaveMethod), Runtime::kRefsAndArgs); + image_header.GetImageMethod(ImageHeader::kRefsAndArgsSaveMethod), Runtime::kRefsAndArgs); } - VLOG(image) << "ImageSpace::Init exiting " << *space.get(); - if (VLOG_IS_ON(image)) { - logger.Dump(LOG(INFO)); + if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) { + LOG(INFO) << "ImageSpace::Init exiting (" << PrettyDuration(NanoTime() - start_time) + << ") " << *space.get(); } return space.release(); } @@ -1524,16 +1002,6 @@ void ImageSpace::CreateMultiImageLocations(const std::string& input_image_file_n } } -ImageSpace* ImageSpace::CreateFromAppImage(const char* image, - const OatFile* oat_file, - std::string* error_msg) { - return gc::space::ImageSpace::Init(image, - image, - /*validate_oat_file*/false, - oat_file, - /*out*/error_msg); -} - } // namespace space } // namespace gc } // namespace art diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h index f2f416377e..9c8e8b2014 100644 --- a/runtime/gc/space/image_space.h +++ b/runtime/gc/space/image_space.h @@ -35,7 +35,7 @@ class ImageSpace : public MemMapSpace { return kSpaceTypeImageSpace; } - // Create a boot image space from an image file for a specified instruction + // Create a Space from an image file for a specified instruction // set. Cannot be used for future allocation or collected. // // Create also opens the OatFile associated with the image file so @@ -43,16 +43,10 @@ class ImageSpace : public MemMapSpace { // creation of the alloc space. The ReleaseOatFile will later be // used to transfer ownership of the OatFile to the ClassLinker when // it is initialized. - static ImageSpace* CreateBootImage(const char* image, - InstructionSet image_isa, - bool secondary_image, - std::string* error_msg) - SHARED_REQUIRES(Locks::mutator_lock_); - - // Try to open an existing app image space. - static ImageSpace* CreateFromAppImage(const char* image, - const OatFile* oat_file, - std::string* error_msg) + static ImageSpace* Create(const char* image, + InstructionSet image_isa, + bool secondary_image, + std::string* error_msg) SHARED_REQUIRES(Locks::mutator_lock_); // Reads the image header from the specified image location for the @@ -150,17 +144,15 @@ class ImageSpace : public MemMapSpace { } protected: - // Tries to initialize an ImageSpace from the given image path, returning null on error. + // Tries to initialize an ImageSpace from the given image path, + // returning null on error. // - // If validate_oat_file is false (for /system), do not verify that image's OatFile is up-to-date - // relative to its DexFile inputs. Otherwise (for /data), validate the inputs and generate the - // OatFile in /data/dalvik-cache if necessary. If the oat_file is null, it uses the oat file from - // the image. - static ImageSpace* Init(const char* image_filename, - const char* image_location, - bool validate_oat_file, - const OatFile* oat_file, - std::string* error_msg) + // If validate_oat_file is false (for /system), do not verify that + // image's OatFile is up-to-date relative to its DexFile + // inputs. Otherwise (for /data), validate the inputs and generate + // the OatFile in /data/dalvik-cache if necessary. + static ImageSpace* Init(const char* image_filename, const char* image_location, + bool validate_oat_file, std::string* error_msg) SHARED_REQUIRES(Locks::mutator_lock_); OatFile* OpenOatFile(const char* image, std::string* error_msg) const diff --git a/runtime/image.cc b/runtime/image.cc index cafd53acff..3cb66428fa 100644 --- a/runtime/image.cc +++ b/runtime/image.cc @@ -35,13 +35,8 @@ ImageHeader::ImageHeader(uint32_t image_begin, uint32_t oat_data_begin, uint32_t oat_data_end, uint32_t oat_file_end, - uint32_t boot_image_begin, - uint32_t boot_image_size, - uint32_t boot_oat_begin, - uint32_t boot_oat_size, uint32_t pointer_size, bool compile_pic, - bool is_pic, StorageMode storage_mode, size_t data_size) : image_begin_(image_begin), @@ -51,15 +46,10 @@ ImageHeader::ImageHeader(uint32_t image_begin, oat_data_begin_(oat_data_begin), oat_data_end_(oat_data_end), oat_file_end_(oat_file_end), - boot_image_begin_(boot_image_begin), - boot_image_size_(boot_image_size), - boot_oat_begin_(boot_oat_begin), - boot_oat_size_(boot_oat_size), patch_delta_(0), image_roots_(image_roots), pointer_size_(pointer_size), compile_pic_(compile_pic), - is_pic_(is_pic), storage_mode_(storage_mode), data_size_(data_size) { CHECK_EQ(image_begin, RoundUp(image_begin, kPageSize)); @@ -77,21 +67,13 @@ ImageHeader::ImageHeader(uint32_t image_begin, void ImageHeader::RelocateImage(off_t delta) { CHECK_ALIGNED(delta, kPageSize) << " patch delta must be page aligned"; + image_begin_ += delta; oat_file_begin_ += delta; oat_data_begin_ += delta; oat_data_end_ += delta; oat_file_end_ += delta; - patch_delta_ += delta; - RelocateImageObjects(delta); - RelocateImageMethods(delta); -} - -void ImageHeader::RelocateImageObjects(off_t delta) { - image_begin_ += delta; image_roots_ += delta; -} - -void ImageHeader::RelocateImageMethods(off_t delta) { + patch_delta_ += delta; for (size_t i = 0; i < kImageMethodsCount; ++i) { image_methods_[i] += delta; } diff --git a/runtime/image.h b/runtime/image.h index b3f177bc8f..7418f660aa 100644 --- a/runtime/image.h +++ b/runtime/image.h @@ -93,15 +93,10 @@ class PACKED(4) ImageHeader { oat_data_begin_(0U), oat_data_end_(0U), oat_file_end_(0U), - boot_image_begin_(0U), - boot_image_size_(0U), - boot_oat_begin_(0U), - boot_oat_size_(0U), patch_delta_(0), image_roots_(0U), pointer_size_(0U), compile_pic_(0), - is_pic_(0), storage_mode_(kDefaultStorageMode), data_size_(0) {} @@ -114,13 +109,8 @@ class PACKED(4) ImageHeader { uint32_t oat_data_begin, uint32_t oat_data_end, uint32_t oat_file_end, - uint32_t boot_image_begin, - uint32_t boot_image_size, - uint32_t boot_oat_begin, - uint32_t boot_oat_size, uint32_t pointer_size, bool compile_pic, - bool is_pic, StorageMode storage_mode, size_t data_size); @@ -218,33 +208,11 @@ class PACKED(4) ImageHeader { SHARED_REQUIRES(Locks::mutator_lock_); void RelocateImage(off_t delta); - void RelocateImageMethods(off_t delta); - void RelocateImageObjects(off_t delta); bool CompilePic() const { return compile_pic_ != 0; } - bool IsPic() const { - return is_pic_ != 0; - } - - uint32_t GetBootImageBegin() const { - return boot_image_begin_; - } - - uint32_t GetBootImageSize() const { - return boot_image_size_; - } - - uint32_t GetBootOatBegin() const { - return boot_oat_begin_; - } - - uint32_t GetBootOatSize() const { - return boot_oat_size_; - } - StorageMode GetStorageMode() const { return storage_mode_; } @@ -253,12 +221,6 @@ class PACKED(4) ImageHeader { return data_size_; } - bool IsAppImage() const { - // App images currently require a boot image, if the size is non zero then it is an app image - // header. - return boot_image_size_ != 0u; - } - private: static const uint8_t kImageMagic[4]; static const uint8_t kImageVersion[4]; @@ -288,16 +250,6 @@ class PACKED(4) ImageHeader { // .so files. Used for positioning a following alloc spaces. uint32_t oat_file_end_; - // Boot image begin and end (app image headers only). - uint32_t boot_image_begin_; - uint32_t boot_image_size_; - - // Boot oat begin and end (app image headers only). - uint32_t boot_oat_begin_; - uint32_t boot_oat_size_; - - // TODO: We should probably insert a boot image checksum for app images. - // The total delta that this image has been patched. int32_t patch_delta_; @@ -310,15 +262,10 @@ class PACKED(4) ImageHeader { // Boolean (0 or 1) to denote if the image was compiled with --compile-pic option const uint32_t compile_pic_; - // Boolean (0 or 1) to denote if the image can be mapped at a random address, this only refers to - // the .art file. Currently, app oat files do not depend on their app image. There are no pointers - // from the app oat code to the app image. - const uint32_t is_pic_; - // Image section sizes/offsets correspond to the uncompressed form. ImageSection sections_[kSectionCount]; - // Image methods, may be inside of the boot image for app images. + // Image methods. uint64_t image_methods_[kImageMethodsCount]; // Storage method for the image, the image may be compressed. diff --git a/runtime/intern_table.cc b/runtime/intern_table.cc index 96854dad0e..015bf98e38 100644 --- a/runtime/intern_table.cc +++ b/runtime/intern_table.cc @@ -86,24 +86,14 @@ void InternTable::VisitRoots(RootVisitor* visitor, VisitRootFlags flags) { // Note: we deliberately don't visit the weak_interns_ table and the immutable image roots. } -mirror::String* InternTable::LookupWeak(Thread* self, mirror::String* s) { - MutexLock mu(self, *Locks::intern_table_lock_); - return LookupWeakLocked(s); -} - -mirror::String* InternTable::LookupStrong(Thread* self, mirror::String* s) { - MutexLock mu(self, *Locks::intern_table_lock_); - return LookupStrongLocked(s); +mirror::String* InternTable::LookupStrong(mirror::String* s) { + return strong_interns_.Find(s); } -mirror::String* InternTable::LookupWeakLocked(mirror::String* s) { +mirror::String* InternTable::LookupWeak(mirror::String* s) { return weak_interns_.Find(s); } -mirror::String* InternTable::LookupStrongLocked(mirror::String* s) { - return strong_interns_.Find(s); -} - void InternTable::AddNewTable() { MutexLock mu(Thread::Current(), *Locks::intern_table_lock_); weak_interns_.AddNewTable(); @@ -179,7 +169,7 @@ void InternTable::AddImagesStringsToTable(const std::vector<gc::space::ImageSpac for (size_t j = 0; j < num_strings; ++j) { mirror::String* image_string = dex_cache->GetResolvedString(j); if (image_string != nullptr) { - mirror::String* found = LookupStrongLocked(image_string); + mirror::String* found = LookupStrong(image_string); if (found == nullptr) { InsertStrong(image_string); } else { @@ -260,7 +250,7 @@ mirror::String* InternTable::Insert(mirror::String* s, bool is_strong, bool hold } } // Check the strong table for a match. - mirror::String* strong = LookupStrongLocked(s); + mirror::String* strong = LookupStrong(s); if (strong != nullptr) { return strong; } @@ -282,7 +272,7 @@ mirror::String* InternTable::Insert(mirror::String* s, bool is_strong, bool hold CHECK(self->GetWeakRefAccessEnabled()); } // There is no match in the strong table, check the weak table. - mirror::String* weak = LookupWeakLocked(s); + mirror::String* weak = LookupWeak(s); if (weak != nullptr) { if (is_strong) { // A match was found in the weak table. Promote to the strong table. @@ -327,7 +317,8 @@ mirror::String* InternTable::InternWeak(mirror::String* s) { } bool InternTable::ContainsWeak(mirror::String* s) { - return LookupWeak(Thread::Current(), s) == s; + MutexLock mu(Thread::Current(), *Locks::intern_table_lock_); + return LookupWeak(s) == s; } void InternTable::SweepInternTableWeaks(IsMarkedVisitor* visitor) { diff --git a/runtime/intern_table.h b/runtime/intern_table.h index 274f5ade5e..2b2176efe1 100644 --- a/runtime/intern_table.h +++ b/runtime/intern_table.h @@ -84,22 +84,10 @@ class InternTable { bool ContainsWeak(mirror::String* s) SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Locks::intern_table_lock_); - // Lookup a strong intern, returns null if not found. - mirror::String* LookupStrong(Thread* self, mirror::String* s) - REQUIRES(!Locks::intern_table_lock_) - SHARED_REQUIRES(Locks::mutator_lock_); - - // Lookup a weak intern, returns null if not found. - mirror::String* LookupWeak(Thread* self, mirror::String* s) - REQUIRES(!Locks::intern_table_lock_) - SHARED_REQUIRES(Locks::mutator_lock_); - // Total number of interned strings. size_t Size() const REQUIRES(!Locks::intern_table_lock_); - // Total number of weakly live interned strings. size_t StrongSize() const REQUIRES(!Locks::intern_table_lock_); - // Total number of strongly live interned strings. size_t WeakSize() const REQUIRES(!Locks::intern_table_lock_); @@ -198,9 +186,9 @@ class InternTable { mirror::String* Insert(mirror::String* s, bool is_strong, bool holding_locks) REQUIRES(!Locks::intern_table_lock_) SHARED_REQUIRES(Locks::mutator_lock_); - mirror::String* LookupStrongLocked(mirror::String* s) + mirror::String* LookupStrong(mirror::String* s) SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(Locks::intern_table_lock_); - mirror::String* LookupWeakLocked(mirror::String* s) + mirror::String* LookupWeak(mirror::String* s) SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(Locks::intern_table_lock_); mirror::String* InsertStrong(mirror::String* s) SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(Locks::intern_table_lock_); diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h index 75a3f1aa05..53118e07e1 100644 --- a/runtime/mirror/class-inl.h +++ b/runtime/mirror/class-inl.h @@ -47,15 +47,11 @@ inline uint32_t Class::GetObjectSize() { return GetField32(ObjectSizeOffset()); } -template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> inline Class* Class::GetSuperClass() { // Can only get super class for loaded classes (hack for when runtime is // initializing) - DCHECK(IsLoaded<kVerifyFlags>() || - IsErroneous<kVerifyFlags>() || - !Runtime::Current()->IsStarted()) << IsLoaded(); - return GetFieldObject<Class, kVerifyFlags, kReadBarrierOption>( - OFFSET_OF_OBJECT_MEMBER(Class, super_class_)); + DCHECK(IsLoaded() || IsErroneous() || !Runtime::Current()->IsStarted()) << IsLoaded(); + return GetFieldObject<Class>(OFFSET_OF_OBJECT_MEMBER(Class, super_class_)); } inline ClassLoader* Class::GetClassLoader() { @@ -230,12 +226,9 @@ inline ArtMethod* Class::GetVirtualMethodUnchecked(size_t i, size_t pointer_size return &GetVirtualMethodsSliceUnchecked(pointer_size).At(i); } -template<VerifyObjectFlags kVerifyFlags, - ReadBarrierOption kReadBarrierOption> inline PointerArray* Class::GetVTable() { - DCHECK(IsResolved<kVerifyFlags>() || IsErroneous<kVerifyFlags>()); - return GetFieldObject<PointerArray, kVerifyFlags, kReadBarrierOption>( - OFFSET_OF_OBJECT_MEMBER(Class, vtable_)); + DCHECK(IsResolved() || IsErroneous()); + return GetFieldObject<PointerArray>(OFFSET_OF_OBJECT_MEMBER(Class, vtable_)); } inline PointerArray* Class::GetVTableDuringLinking() { @@ -506,11 +499,8 @@ inline ArtMethod* Class::FindVirtualMethodForVirtualOrInterface(ArtMethod* metho return FindVirtualMethodForVirtual(method, pointer_size); } -template<VerifyObjectFlags kVerifyFlags, - ReadBarrierOption kReadBarrierOption> inline IfTable* Class::GetIfTable() { - return GetFieldObject<IfTable, kVerifyFlags, kReadBarrierOption>( - OFFSET_OF_OBJECT_MEMBER(Class, iftable_)); + return GetFieldObject<IfTable>(OFFSET_OF_OBJECT_MEMBER(Class, iftable_)); } inline int32_t Class::GetIfTableCount() { @@ -526,7 +516,7 @@ inline void Class::SetIfTable(IfTable* new_iftable) { } inline LengthPrefixedArray<ArtField>* Class::GetIFieldsPtr() { - DCHECK(IsLoaded() || IsErroneous()) << GetStatus(); + DCHECK(IsLoaded() || IsErroneous()); return GetFieldPtr<LengthPrefixedArray<ArtField>*>(OFFSET_OF_OBJECT_MEMBER(Class, ifields_)); } @@ -757,12 +747,9 @@ inline uint32_t Class::ComputeClassSize(bool has_embedded_tables, return size; } -template <bool kVisitNativeRoots, - VerifyObjectFlags kVerifyFlags, - ReadBarrierOption kReadBarrierOption, - typename Visitor> +template <typename Visitor> inline void Class::VisitReferences(mirror::Class* klass, const Visitor& visitor) { - VisitInstanceFieldsReferences<kVerifyFlags, kReadBarrierOption>(klass, visitor); + VisitInstanceFieldsReferences(klass, visitor); // Right after a class is allocated, but not yet loaded // (kStatusNotReady, see ClassLinker::LoadClass()), GC may find it // and scan it. IsTemp() may call Class::GetAccessFlags() but may @@ -770,16 +757,14 @@ inline void Class::VisitReferences(mirror::Class* klass, const Visitor& visitor) // status is kStatusNotReady. To avoid it, rely on IsResolved() // only. This is fine because a temp class never goes into the // kStatusResolved state. - if (IsResolved<kVerifyFlags>()) { + if (IsResolved()) { // Temp classes don't ever populate imt/vtable or static fields and they are not even // allocated with the right size for those. Also, unresolved classes don't have fields // linked yet. - VisitStaticFieldsReferences<kVerifyFlags, kReadBarrierOption>(this, visitor); - } - if (kVisitNativeRoots) { - // Since this class is reachable, we must also visit the associated roots when we scan it. - VisitNativeRoots(visitor, Runtime::Current()->GetClassLinker()->GetImagePointerSize()); + VisitStaticFieldsReferences(this, visitor); } + // Since this class is reachable, we must also visit the associated roots when we scan it. + VisitNativeRoots(visitor, Runtime::Current()->GetClassLinker()->GetImagePointerSize()); } template<ReadBarrierOption kReadBarrierOption> diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 3017820ea1..6b5ed910ba 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -494,11 +494,10 @@ class MANAGED Class FINAL : public Object { (IsAbstract() && IsArrayClass()); } - template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, - ReadBarrierOption kReadBarrierOption = kWithReadBarrier> + template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> bool IsObjectArrayClass() SHARED_REQUIRES(Locks::mutator_lock_) { - mirror::Class* const component_type = GetComponentType<kVerifyFlags, kReadBarrierOption>(); - return component_type != nullptr && !component_type->IsPrimitive(); + return GetComponentType<kVerifyFlags>() != nullptr && + !GetComponentType<kVerifyFlags>()->IsPrimitive(); } template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> @@ -657,8 +656,6 @@ class MANAGED Class FINAL : public Object { // to themselves. Classes for primitive types may not assign to each other. ALWAYS_INLINE bool IsAssignableFrom(Class* src) SHARED_REQUIRES(Locks::mutator_lock_); - template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, - ReadBarrierOption kReadBarrierOption = kWithReadBarrier> ALWAYS_INLINE Class* GetSuperClass() SHARED_REQUIRES(Locks::mutator_lock_); // Get first common super class. It will never return null. @@ -794,8 +791,6 @@ class MANAGED Class FINAL : public Object { ArtMethod* GetVirtualMethodDuringLinking(size_t i, size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_); - template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, - ReadBarrierOption kReadBarrierOption = kWithReadBarrier> ALWAYS_INLINE PointerArray* GetVTable() SHARED_REQUIRES(Locks::mutator_lock_); ALWAYS_INLINE PointerArray* GetVTableDuringLinking() SHARED_REQUIRES(Locks::mutator_lock_); @@ -946,8 +941,6 @@ class MANAGED Class FINAL : public Object { ALWAYS_INLINE int32_t GetIfTableCount() SHARED_REQUIRES(Locks::mutator_lock_); - template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, - ReadBarrierOption kReadBarrierOption = kWithReadBarrier> ALWAYS_INLINE IfTable* GetIfTable() SHARED_REQUIRES(Locks::mutator_lock_); ALWAYS_INLINE void SetIfTable(IfTable* new_iftable) SHARED_REQUIRES(Locks::mutator_lock_); @@ -1233,8 +1226,7 @@ class MANAGED Class FINAL : public Object { // Fix up all of the native pointers in the class by running them through the visitor. Only sets // the corresponding entry in dest if visitor(obj) != obj to prevent dirty memory. Dest should be - // initialized to a copy of *this to prevent issues. Does not visit the ArtMethod and ArtField - // roots. + // initialized to a copy of *this to prevent issues. template <typename Visitor> void FixupNativePointers(mirror::Class* dest, size_t pointer_size, const Visitor& visitor) SHARED_REQUIRES(Locks::mutator_lock_); @@ -1285,10 +1277,7 @@ class MANAGED Class FINAL : public Object { static MemberOffset EmbeddedImTableOffset(size_t pointer_size); static MemberOffset EmbeddedVTableOffset(size_t pointer_size); - template <bool kVisitNativeRoots, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, - ReadBarrierOption kReadBarrierOption = kWithReadBarrier, - typename Visitor> + template <typename Visitor> void VisitReferences(mirror::Class* klass, const Visitor& visitor) SHARED_REQUIRES(Locks::mutator_lock_); diff --git a/runtime/mirror/class_loader-inl.h b/runtime/mirror/class_loader-inl.h index 84fa80f023..e22ddd7e90 100644 --- a/runtime/mirror/class_loader-inl.h +++ b/runtime/mirror/class_loader-inl.h @@ -25,20 +25,15 @@ namespace art { namespace mirror { -template <bool kVisitClasses, - VerifyObjectFlags kVerifyFlags, - ReadBarrierOption kReadBarrierOption, - typename Visitor> +template <VerifyObjectFlags kVerifyFlags, typename Visitor> inline void ClassLoader::VisitReferences(mirror::Class* klass, const Visitor& visitor) { // Visit instance fields first. - VisitInstanceFieldsReferences<kVerifyFlags, kReadBarrierOption>(klass, visitor); - if (kVisitClasses) { - // Visit classes loaded after. - ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); - ClassTable* const class_table = GetClassTable(); - if (class_table != nullptr) { - class_table->VisitRoots(visitor); - } + VisitInstanceFieldsReferences(klass, visitor); + // Visit classes loaded after. + ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); + ClassTable* const class_table = GetClassTable(); + if (class_table != nullptr) { + class_table->VisitRoots(visitor); } } diff --git a/runtime/mirror/class_loader.h b/runtime/mirror/class_loader.h index 1957e13e36..c2a65d62e2 100644 --- a/runtime/mirror/class_loader.h +++ b/runtime/mirror/class_loader.h @@ -63,10 +63,7 @@ class MANAGED ClassLoader : public Object { private: // Visit instance fields of the class loader as well as its associated classes. // Null class loader is handled by ClassLinker::VisitClassRoots. - template <bool kVisitClasses, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, - ReadBarrierOption kReadBarrierOption = kWithReadBarrier, - typename Visitor> + template <VerifyObjectFlags kVerifyFlags, typename Visitor> void VisitReferences(mirror::Class* klass, const Visitor& visitor) SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Locks::classlinker_classes_lock_); diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h index 2ecc9fb1a8..975af61ca8 100644 --- a/runtime/mirror/dex_cache-inl.h +++ b/runtime/mirror/dex_cache-inl.h @@ -122,23 +122,18 @@ inline void DexCache::SetElementPtrSize(PtrType* ptr_array, } } -template <bool kVisitNativeRoots, - VerifyObjectFlags kVerifyFlags, - ReadBarrierOption kReadBarrierOption, - typename Visitor> +template <VerifyObjectFlags kVerifyFlags, typename Visitor> inline void DexCache::VisitReferences(mirror::Class* klass, const Visitor& visitor) { // Visit instance fields first. - VisitInstanceFieldsReferences<kVerifyFlags, kReadBarrierOption>(klass, visitor); + VisitInstanceFieldsReferences(klass, visitor); // Visit arrays after. - if (kVisitNativeRoots) { - GcRoot<mirror::String>* strings = GetStrings(); - for (size_t i = 0, num_strings = NumStrings(); i != num_strings; ++i) { - visitor.VisitRootIfNonNull(strings[i].AddressWithoutBarrier()); - } - GcRoot<mirror::Class>* resolved_types = GetResolvedTypes(); - for (size_t i = 0, num_types = NumResolvedTypes(); i != num_types; ++i) { - visitor.VisitRootIfNonNull(resolved_types[i].AddressWithoutBarrier()); - } + GcRoot<mirror::String>* strings = GetStrings(); + for (size_t i = 0, num_strings = NumStrings(); i != num_strings; ++i) { + visitor.VisitRootIfNonNull(strings[i].AddressWithoutBarrier()); + } + GcRoot<mirror::Class>* resolved_types = GetResolvedTypes(); + for (size_t i = 0, num_types = NumResolvedTypes(); i != num_types; ++i) { + visitor.VisitRootIfNonNull(resolved_types[i].AddressWithoutBarrier()); } } diff --git a/runtime/mirror/dex_cache.cc b/runtime/mirror/dex_cache.cc index 7b058d0c92..349a319992 100644 --- a/runtime/mirror/dex_cache.cc +++ b/runtime/mirror/dex_cache.cc @@ -51,10 +51,10 @@ void DexCache::Init(const DexFile* dex_file, SetDexFile(dex_file); SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, location_), location); - SetStrings(strings); - SetResolvedTypes(resolved_types); - SetResolvedMethods(resolved_methods); - SetResolvedFields(resolved_fields); + SetField64<false>(StringsOffset(), reinterpret_cast<uintptr_t>(strings)); + SetField64<false>(ResolvedTypesOffset(), reinterpret_cast<uintptr_t>(resolved_types)); + SetField64<false>(ResolvedMethodsOffset(), reinterpret_cast<uintptr_t>(resolved_methods)); + SetField64<false>(ResolvedFieldsOffset(), reinterpret_cast<uintptr_t>(resolved_fields)); SetField32<false>(NumStringsOffset(), num_strings); SetField32<false>(NumResolvedTypesOffset(), num_resolved_types); SetField32<false>(NumResolvedMethodsOffset(), num_resolved_methods); diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h index 5ed061f6a4..32eb59540d 100644 --- a/runtime/mirror/dex_cache.h +++ b/runtime/mirror/dex_cache.h @@ -137,40 +137,18 @@ class MANAGED DexCache FINAL : public Object { return GetFieldPtr<GcRoot<String>*>(StringsOffset()); } - void SetStrings(GcRoot<String>* strings) ALWAYS_INLINE SHARED_REQUIRES(Locks::mutator_lock_) { - SetFieldPtr<false>(StringsOffset(), strings); - } - GcRoot<Class>* GetResolvedTypes() ALWAYS_INLINE SHARED_REQUIRES(Locks::mutator_lock_) { return GetFieldPtr<GcRoot<Class>*>(ResolvedTypesOffset()); } - void SetResolvedTypes(GcRoot<Class>* resolved_types) - ALWAYS_INLINE - SHARED_REQUIRES(Locks::mutator_lock_) { - SetFieldPtr<false>(ResolvedTypesOffset(), resolved_types); - } - ArtMethod** GetResolvedMethods() ALWAYS_INLINE SHARED_REQUIRES(Locks::mutator_lock_) { return GetFieldPtr<ArtMethod**>(ResolvedMethodsOffset()); } - void SetResolvedMethods(ArtMethod** resolved_methods) - ALWAYS_INLINE - SHARED_REQUIRES(Locks::mutator_lock_) { - SetFieldPtr<false>(ResolvedMethodsOffset(), resolved_methods); - } - ArtField** GetResolvedFields() ALWAYS_INLINE SHARED_REQUIRES(Locks::mutator_lock_) { return GetFieldPtr<ArtField**>(ResolvedFieldsOffset()); } - void SetResolvedFields(ArtField** resolved_fields) - ALWAYS_INLINE - SHARED_REQUIRES(Locks::mutator_lock_) { - SetFieldPtr<false>(ResolvedFieldsOffset(), resolved_fields); - } - size_t NumStrings() SHARED_REQUIRES(Locks::mutator_lock_) { return GetField32(NumStringsOffset()); } @@ -208,10 +186,7 @@ class MANAGED DexCache FINAL : public Object { private: // Visit instance fields of the dex cache as well as its associated arrays. - template <bool kVisitNativeRoots, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, - ReadBarrierOption kReadBarrierOption = kWithReadBarrier, - typename Visitor> + template <VerifyObjectFlags kVerifyFlags, typename Visitor> void VisitReferences(mirror::Class* klass, const Visitor& visitor) SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(Locks::heap_bitmap_lock_); diff --git a/runtime/mirror/iftable.h b/runtime/mirror/iftable.h index 605deac608..b21ecdf6e8 100644 --- a/runtime/mirror/iftable.h +++ b/runtime/mirror/iftable.h @@ -34,11 +34,8 @@ class MANAGED IfTable FINAL : public ObjectArray<Object> { ALWAYS_INLINE void SetInterface(int32_t i, Class* interface) SHARED_REQUIRES(Locks::mutator_lock_); - template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, - ReadBarrierOption kReadBarrierOption = kWithReadBarrier> PointerArray* GetMethodArray(int32_t i) SHARED_REQUIRES(Locks::mutator_lock_) { - auto* method_array = down_cast<PointerArray*>(Get<kVerifyFlags, kReadBarrierOption>( - (i * kMax) + kMethodArray)); + auto* method_array = down_cast<PointerArray*>(Get((i * kMax) + kMethodArray)); DCHECK(method_array != nullptr); return method_array; } diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h index 760de9ab40..460342807a 100644 --- a/runtime/mirror/object-inl.h +++ b/runtime/mirror/object-inl.h @@ -1031,10 +1031,7 @@ inline bool Object::CasFieldStrongRelaxedObjectWithoutWriteBarrier( return success; } -template<bool kIsStatic, - VerifyObjectFlags kVerifyFlags, - ReadBarrierOption kReadBarrierOption, - typename Visitor> +template<bool kIsStatic, typename Visitor> inline void Object::VisitFieldsReferences(uint32_t ref_offsets, const Visitor& visitor) { if (!kIsStatic && (ref_offsets != mirror::Class::kClassWalkSuper)) { // Instance fields and not the slow-path. @@ -1050,12 +1047,9 @@ inline void Object::VisitFieldsReferences(uint32_t ref_offsets, const Visitor& v // There is no reference offset bitmap. In the non-static case, walk up the class // inheritance hierarchy and find reference offsets the hard way. In the static case, just // consider this class. - for (mirror::Class* klass = kIsStatic - ? AsClass<kVerifyFlags, kReadBarrierOption>() - : GetClass<kVerifyFlags, kReadBarrierOption>(); - klass != nullptr; - klass = kIsStatic ? nullptr : klass->GetSuperClass<kVerifyFlags, kReadBarrierOption>()) { - const size_t num_reference_fields = + for (mirror::Class* klass = kIsStatic ? AsClass() : GetClass(); klass != nullptr; + klass = kIsStatic ? nullptr : klass->GetSuperClass()) { + size_t num_reference_fields = kIsStatic ? klass->NumReferenceStaticFields() : klass->NumReferenceInstanceFields(); if (num_reference_fields == 0u) { continue; @@ -1078,54 +1072,49 @@ inline void Object::VisitFieldsReferences(uint32_t ref_offsets, const Visitor& v } } -template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption, typename Visitor> +template<typename Visitor> inline void Object::VisitInstanceFieldsReferences(mirror::Class* klass, const Visitor& visitor) { - VisitFieldsReferences<false, kVerifyFlags, kReadBarrierOption>( - klass->GetReferenceInstanceOffsets<kVerifyFlags>(), visitor); + VisitFieldsReferences<false>(klass->GetReferenceInstanceOffsets<kVerifyNone>(), visitor); } -template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption, typename Visitor> +template<typename Visitor> inline void Object::VisitStaticFieldsReferences(mirror::Class* klass, const Visitor& visitor) { DCHECK(!klass->IsTemp()); - klass->VisitFieldsReferences<true, kVerifyFlags, kReadBarrierOption>(0, visitor); + klass->VisitFieldsReferences<true>(0, visitor); } -template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> +template<VerifyObjectFlags kVerifyFlags> inline bool Object::IsClassLoader() { - return GetClass<kVerifyFlags, kReadBarrierOption>()->IsClassLoaderClass(); + return GetClass<kVerifyFlags>()->IsClassLoaderClass(); } -template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> +template<VerifyObjectFlags kVerifyFlags> inline mirror::ClassLoader* Object::AsClassLoader() { - DCHECK((IsClassLoader<kVerifyFlags, kReadBarrierOption>())); + DCHECK(IsClassLoader<kVerifyFlags>()); return down_cast<mirror::ClassLoader*>(this); } -template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> +template<VerifyObjectFlags kVerifyFlags> inline bool Object::IsDexCache() { - return GetClass<kVerifyFlags, kReadBarrierOption>()->IsDexCacheClass(); + return GetClass<kVerifyFlags>()->IsDexCacheClass(); } -template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> +template<VerifyObjectFlags kVerifyFlags> inline mirror::DexCache* Object::AsDexCache() { - DCHECK((IsDexCache<kVerifyFlags, kReadBarrierOption>())); + DCHECK(IsDexCache<kVerifyFlags>()); return down_cast<mirror::DexCache*>(this); } -template <bool kVisitNativeRoots, - VerifyObjectFlags kVerifyFlags, - ReadBarrierOption kReadBarrierOption, - typename Visitor, - typename JavaLangRefVisitor> +template <VerifyObjectFlags kVerifyFlags, typename Visitor, typename JavaLangRefVisitor> inline void Object::VisitReferences(const Visitor& visitor, const JavaLangRefVisitor& ref_visitor) { - mirror::Class* klass = GetClass<kVerifyFlags, kReadBarrierOption>(); + mirror::Class* klass = GetClass<kVerifyFlags>(); visitor(this, ClassOffset(), false); const uint32_t class_flags = klass->GetClassFlags<kVerifyNone>(); if (LIKELY(class_flags == kClassFlagNormal)) { DCHECK(!klass->IsVariableSize()); VisitInstanceFieldsReferences(klass, visitor); - DCHECK((!klass->IsClassClass<kVerifyFlags, kReadBarrierOption>())); + DCHECK(!klass->IsClassClass()); DCHECK(!klass->IsStringClass()); DCHECK(!klass->IsClassLoaderClass()); DCHECK(!klass->IsArrayClass()); @@ -1134,29 +1123,23 @@ inline void Object::VisitReferences(const Visitor& visitor, DCHECK(!klass->IsStringClass()); if (class_flags == kClassFlagClass) { DCHECK(klass->IsClassClass()); - AsClass<kVerifyNone>()->VisitReferences<kVisitNativeRoots, - kVerifyFlags, - kReadBarrierOption>(klass, visitor); + AsClass<kVerifyNone>()->VisitReferences(klass, visitor); } else if (class_flags == kClassFlagObjectArray) { - DCHECK((klass->IsObjectArrayClass<kVerifyFlags, kReadBarrierOption>())); + DCHECK(klass->IsObjectArrayClass()); AsObjectArray<mirror::Object, kVerifyNone>()->VisitReferences(visitor); } else if ((class_flags & kClassFlagReference) != 0) { VisitInstanceFieldsReferences(klass, visitor); ref_visitor(klass, AsReference()); } else if (class_flags == kClassFlagDexCache) { - mirror::DexCache* const dex_cache = AsDexCache<kVerifyFlags, kReadBarrierOption>(); - dex_cache->VisitReferences<kVisitNativeRoots, - kVerifyFlags, - kReadBarrierOption>(klass, visitor); + mirror::DexCache* const dex_cache = AsDexCache<kVerifyFlags>(); + dex_cache->VisitReferences<kVerifyFlags>(klass, visitor); } else { - mirror::ClassLoader* const class_loader = AsClassLoader<kVerifyFlags, kReadBarrierOption>(); - class_loader->VisitReferences<kVisitNativeRoots, - kVerifyFlags, - kReadBarrierOption>(klass, visitor); + mirror::ClassLoader* const class_loader = AsClassLoader<kVerifyFlags>(); + class_loader->VisitReferences<kVerifyFlags>(klass, visitor); } } else if (kIsDebugBuild) { - CHECK((!klass->IsClassClass<kVerifyFlags, kReadBarrierOption>())); - CHECK((!klass->IsObjectArrayClass<kVerifyFlags, kReadBarrierOption>())); + CHECK(!klass->IsClassClass()); + CHECK(!klass->IsObjectArrayClass()); // String still has instance fields for reflection purposes but these don't exist in // actual string instances. if (!klass->IsStringClass()) { @@ -1164,7 +1147,7 @@ inline void Object::VisitReferences(const Visitor& visitor, mirror::Class* super_class = klass; do { total_reference_instance_fields += super_class->NumReferenceInstanceFields(); - super_class = super_class->GetSuperClass<kVerifyFlags, kReadBarrierOption>(); + super_class = super_class->GetSuperClass(); } while (super_class != nullptr); // The only reference field should be the object's class. This field is handled at the // beginning of the function. diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h index d635002d12..71e704e704 100644 --- a/runtime/mirror/object.h +++ b/runtime/mirror/object.h @@ -164,18 +164,14 @@ class MANAGED LOCKABLE Object { template<class T, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> ObjectArray<T>* AsObjectArray() SHARED_REQUIRES(Locks::mutator_lock_); - template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, - ReadBarrierOption kReadBarrierOption = kWithReadBarrier> + template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> bool IsClassLoader() SHARED_REQUIRES(Locks::mutator_lock_); - template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, - ReadBarrierOption kReadBarrierOption = kWithReadBarrier> + template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> ClassLoader* AsClassLoader() SHARED_REQUIRES(Locks::mutator_lock_); - template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, - ReadBarrierOption kReadBarrierOption = kWithReadBarrier> + template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> bool IsDexCache() SHARED_REQUIRES(Locks::mutator_lock_); - template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, - ReadBarrierOption kReadBarrierOption = kWithReadBarrier> + template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> DexCache* AsDexCache() SHARED_REQUIRES(Locks::mutator_lock_); template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, @@ -460,13 +456,6 @@ class MANAGED LOCKABLE Object { SetFieldPtrWithSize<kTransactionActive, kCheckTransaction, kVerifyFlags>( field_offset, new_value, sizeof(void*)); } - template<bool kTransactionActive, bool kCheckTransaction = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, typename T> - void SetFieldPtr64(MemberOffset field_offset, T new_value) - SHARED_REQUIRES(Locks::mutator_lock_) { - SetFieldPtrWithSize<kTransactionActive, kCheckTransaction, kVerifyFlags>( - field_offset, new_value, 8u); - } template<bool kTransactionActive, bool kCheckTransaction = true, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, typename T> @@ -486,9 +475,7 @@ class MANAGED LOCKABLE Object { } // TODO fix thread safety analysis broken by the use of template. This should be // SHARED_REQUIRES(Locks::mutator_lock_). - template <bool kVisitNativeRoots = true, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, - ReadBarrierOption kReadBarrierOption = kWithReadBarrier, + template <VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, typename Visitor, typename JavaLangRefVisitor = VoidFunctor> void VisitReferences(const Visitor& visitor, const JavaLangRefVisitor& ref_visitor) @@ -508,11 +495,6 @@ class MANAGED LOCKABLE Object { SHARED_REQUIRES(Locks::mutator_lock_) { return GetFieldPtrWithSize<T, kVerifyFlags, kIsVolatile>(field_offset, sizeof(void*)); } - template<class T, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false> - T GetFieldPtr64(MemberOffset field_offset) - SHARED_REQUIRES(Locks::mutator_lock_) { - return GetFieldPtrWithSize<T, kVerifyFlags, kIsVolatile>(field_offset, 8u); - } template<class T, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false> ALWAYS_INLINE T GetFieldPtrWithSize(MemberOffset field_offset, size_t pointer_size) @@ -529,20 +511,13 @@ class MANAGED LOCKABLE Object { } // TODO: Fixme when anotatalysis works with visitors. - template<bool kIsStatic, - VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, - ReadBarrierOption kReadBarrierOption = kWithReadBarrier, - typename Visitor> + template<bool kIsStatic, typename Visitor> void VisitFieldsReferences(uint32_t ref_offsets, const Visitor& visitor) HOT_ATTR NO_THREAD_SAFETY_ANALYSIS; - template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, - ReadBarrierOption kReadBarrierOption = kWithReadBarrier, - typename Visitor> + template<typename Visitor> void VisitInstanceFieldsReferences(mirror::Class* klass, const Visitor& visitor) HOT_ATTR SHARED_REQUIRES(Locks::mutator_lock_); - template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, - ReadBarrierOption kReadBarrierOption = kWithReadBarrier, - typename Visitor> + template<typename Visitor> void VisitStaticFieldsReferences(mirror::Class* klass, const Visitor& visitor) HOT_ATTR SHARED_REQUIRES(Locks::mutator_lock_); diff --git a/runtime/mirror/object_array-inl.h b/runtime/mirror/object_array-inl.h index 6f9d64297a..5337760fb8 100644 --- a/runtime/mirror/object_array-inl.h +++ b/runtime/mirror/object_array-inl.h @@ -55,13 +55,13 @@ inline ObjectArray<T>* ObjectArray<T>::Alloc(Thread* self, Class* object_array_c Runtime::Current()->GetHeap()->GetCurrentAllocator()); } -template<class T> template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> +template<class T> inline T* ObjectArray<T>::Get(int32_t i) { if (!CheckIsValidIndex(i)) { DCHECK(Thread::Current()->IsExceptionPending()); return nullptr; } - return GetFieldObject<T, kVerifyFlags, kReadBarrierOption>(OffsetOfElement(i)); + return GetFieldObject<T>(OffsetOfElement(i)); } template<class T> template<VerifyObjectFlags kVerifyFlags> diff --git a/runtime/mirror/object_array.h b/runtime/mirror/object_array.h index 1b1295cedb..b45cafd2a3 100644 --- a/runtime/mirror/object_array.h +++ b/runtime/mirror/object_array.h @@ -37,9 +37,7 @@ class MANAGED ObjectArray: public Array { static ObjectArray<T>* Alloc(Thread* self, Class* object_array_class, int32_t length) SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); - template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, - ReadBarrierOption kReadBarrierOption = kWithReadBarrier> - ALWAYS_INLINE T* Get(int32_t i) SHARED_REQUIRES(Locks::mutator_lock_); + T* Get(int32_t i) ALWAYS_INLINE SHARED_REQUIRES(Locks::mutator_lock_); // Returns true if the object can be stored into the array. If not, throws // an ArrayStoreException and returns false. diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc index 6643ac2231..da6cf1f198 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -154,8 +154,10 @@ static jobject DexFile_openDexFileNative(JNIEnv* env, jstring javaSourceName, jstring javaOutputName, jint flags ATTRIBUTE_UNUSED, - jobject class_loader, - jobjectArray dex_elements) { + // class_loader will be used for app images. + jobject class_loader ATTRIBUTE_UNUSED, + // dex_elements will be used for app images. + jobject dex_elements ATTRIBUTE_UNUSED) { ScopedUtfChars sourceName(env, javaSourceName); if (sourceName.c_str() == nullptr) { return 0; @@ -172,8 +174,6 @@ static jobject DexFile_openDexFileNative(JNIEnv* env, dex_files = runtime->GetOatFileManager().OpenDexFilesFromOat(sourceName.c_str(), outputName.c_str(), - class_loader, - dex_elements, /*out*/ &oat_file, /*out*/ &error_msgs); diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc index 2bd5c76c00..d6b08684b9 100644 --- a/runtime/oat_file_assistant.cc +++ b/runtime/oat_file_assistant.cc @@ -38,7 +38,6 @@ #include "os.h" #include "profiler.h" #include "runtime.h" -#include "scoped_thread_state_change.h" #include "ScopedFd.h" #include "utils.h" @@ -327,17 +326,6 @@ bool OatFileAssistant::OdexFileIsUpToDate() { return cached_odex_file_is_up_to_date_; } -std::string OatFileAssistant::ArtFileName(const OatFile* oat_file) const { - const std::string oat_file_location = oat_file->GetLocation(); - // Replace extension with .art - const size_t last_ext = oat_file_location.find_last_of('.'); - if (last_ext == std::string::npos) { - LOG(ERROR) << "No extension in oat file " << oat_file_location; - return std::string(); - } - return oat_file_location.substr(0, last_ext) + ".art"; -} - const std::string* OatFileAssistant::OatFileName() { if (!cached_oat_file_name_attempted_) { cached_oat_file_name_attempted_ = true; @@ -1015,22 +1003,5 @@ ProfileFile* OatFileAssistant::GetOldProfile() { return old_profile_load_succeeded_ ? &cached_old_profile_ : nullptr; } -gc::space::ImageSpace* OatFileAssistant::OpenImageSpace(const OatFile* oat_file) { - DCHECK(oat_file != nullptr); - std::string art_file = ArtFileName(oat_file); - if (art_file.empty()) { - return nullptr; - } - std::string error_msg; - ScopedObjectAccess soa(Thread::Current()); - gc::space::ImageSpace* ret = gc::space::ImageSpace::CreateFromAppImage(art_file.c_str(), - oat_file, - &error_msg); - if (ret == nullptr) { - LOG(INFO) << "Failed to open app image " << art_file.c_str() << " " << error_msg; - } - return ret; -} - } // namespace art diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h index 7b45bca946..f781532b14 100644 --- a/runtime/oat_file_assistant.h +++ b/runtime/oat_file_assistant.h @@ -30,12 +30,6 @@ namespace art { -namespace gc { -namespace space { -class ImageSpace; -} // namespace space -} // namespace gc - // Class for assisting with oat file management. // // This class collects common utilities for determining the status of an oat @@ -169,9 +163,6 @@ class OatFileAssistant { // the OatFileAssistant object. std::unique_ptr<OatFile> GetBestOatFile(); - // Open and returns an image space associated with the oat file. - gc::space::ImageSpace* OpenImageSpace(const OatFile* oat_file); - // Loads the dex files in the given oat file for the given dex location. // The oat file should be up to date for the given dex location. // This loads multiple dex files in the case of multidex. @@ -223,9 +214,6 @@ class OatFileAssistant { bool OatFileNeedsRelocation(); bool OatFileIsUpToDate(); - // Return image file name. Does not cache since it relies on the oat file. - std::string ArtFileName(const OatFile* oat_file) const; - // These methods return the status for a given opened oat file with respect // to the dex location. OatStatus GivenOatFileStatus(const OatFile& file); diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc index 25dcbe4c63..f994f0c99d 100644 --- a/runtime/oat_file_assistant_test.cc +++ b/runtime/oat_file_assistant_test.cc @@ -996,8 +996,6 @@ class RaceGenerateTask : public Task { dex_files = Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat( dex_location_.c_str(), oat_location_.c_str(), - /*class_loader*/nullptr, - /*dex_elements*/nullptr, &oat_file, &error_msgs); CHECK(!dex_files.empty()) << Join(error_msgs, '\n'); diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc index b34b5505eb..7f216f9418 100644 --- a/runtime/oat_file_manager.cc +++ b/runtime/oat_file_manager.cc @@ -22,13 +22,9 @@ #include "base/logging.h" #include "base/stl_util.h" -#include "class_linker.h" #include "dex_file-inl.h" #include "gc/space/image_space.h" -#include "handle_scope-inl.h" -#include "mirror/class_loader.h" #include "oat_file_assistant.h" -#include "scoped_thread_state_change.h" #include "thread-inl.h" namespace art { @@ -38,9 +34,6 @@ namespace art { // normal builds. static constexpr bool kDuplicateClassesCheck = kIsDebugBuild; -// If true, then we attempt to load the application image if it exists. -static constexpr bool kEnableAppImage = true; - const OatFile* OatFileManager::RegisterOatFile(std::unique_ptr<const OatFile> oat_file) { WriterMutexLock mu(Thread::Current(), *Locks::oat_file_manager_lock_); DCHECK(oat_file != nullptr); @@ -291,8 +284,6 @@ bool OatFileManager::HasCollisions(const OatFile* oat_file, std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( const char* dex_location, const char* oat_location, - jobject class_loader, - jobjectArray dex_elements, const OatFile** out_oat_file, std::vector<std::string>* error_msgs) { CHECK(dex_location != nullptr); @@ -300,13 +291,12 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( // Verify we aren't holding the mutator lock, which could starve GC if we // have to generate or relocate an oat file. - Thread* const self = Thread::Current(); - Locks::mutator_lock_->AssertNotHeld(self); - Runtime* const runtime = Runtime::Current(); + Locks::mutator_lock_->AssertNotHeld(Thread::Current()); + OatFileAssistant oat_file_assistant(dex_location, oat_location, kRuntimeISA, - !runtime->IsAotCompiler()); + !Runtime::Current()->IsAotCompiler()); // Lock the target oat location to avoid races generating and loading the // oat file. @@ -327,7 +317,6 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( // Get the oat file on disk. std::unique_ptr<const OatFile> oat_file(oat_file_assistant.GetBestOatFile().release()); - if (oat_file != nullptr) { // Take the file only if it has no collisions, or we must take it because of preopting. bool accept_oat_file = !HasCollisions(oat_file.get(), /*out*/ &error_msg); @@ -362,42 +351,7 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( // Load the dex files from the oat file. if (source_oat_file != nullptr) { - bool added_image_space = false; - if (source_oat_file->IsExecutable()) { - std::unique_ptr<gc::space::ImageSpace> image_space( - kEnableAppImage ? oat_file_assistant.OpenImageSpace(source_oat_file) : nullptr); - if (image_space != nullptr) { - ScopedObjectAccess soa(self); - StackHandleScope<1> hs(self); - Handle<mirror::ClassLoader> h_loader( - hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader))); - // Can not load app image without class loader. - if (h_loader.Get() != nullptr) { - std::string temp_error_msg; - // Add image space has a race condition since other threads could be reading from the - // spaces array. - runtime->GetHeap()->AddSpace(image_space.get()); - added_image_space = true; - if (!runtime->GetClassLinker()->AddImageSpace(image_space.get(), - h_loader, - dex_elements, - dex_location, - /*out*/&dex_files, - /*out*/&temp_error_msg)) { - LOG(INFO) << "Failed to add image file " << temp_error_msg; - dex_files.clear(); - runtime->GetHeap()->RemoveSpace(image_space.get()); - added_image_space = false; - // Non-fatal, don't update error_msg. - } - image_space.release(); - } - } - } - if (!added_image_space) { - DCHECK(dex_files.empty()); - dex_files = oat_file_assistant.LoadDexFiles(*source_oat_file, dex_location); - } + dex_files = oat_file_assistant.LoadDexFiles(*source_oat_file, dex_location); if (dex_files.empty()) { error_msgs->push_back("Failed to open dex files from " + source_oat_file->GetLocation()); } diff --git a/runtime/oat_file_manager.h b/runtime/oat_file_manager.h index c508c4bf07..4690e4550b 100644 --- a/runtime/oat_file_manager.h +++ b/runtime/oat_file_manager.h @@ -25,7 +25,6 @@ #include "base/macros.h" #include "base/mutex.h" -#include "jni.h" namespace art { @@ -102,8 +101,6 @@ class OatFileManager { std::vector<std::unique_ptr<const DexFile>> OpenDexFilesFromOat( const char* dex_location, const char* oat_location, - jobject class_loader, - jobjectArray dex_elements, /*out*/ const OatFile** out_oat_file, /*out*/ std::vector<std::string>* error_msgs) REQUIRES(!Locks::oat_file_manager_lock_, !Locks::mutator_lock_); diff --git a/runtime/runtime.cc b/runtime/runtime.cc index f138c811d7..e30c26dd5e 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -1097,7 +1097,7 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { if (GetHeap()->HasBootImageSpace()) { ATRACE_BEGIN("InitFromImage"); std::string error_msg; - bool result = class_linker_->InitFromBootImage(&error_msg); + bool result = class_linker_->InitFromImage(&error_msg); ATRACE_END(); if (!result) { LOG(ERROR) << "Could not initialize from image: " << error_msg; diff --git a/runtime/runtime.h b/runtime/runtime.h index c8c2ee530d..20acffb697 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -366,7 +366,7 @@ class Runtime { SHARED_REQUIRES(Locks::mutator_lock_); // Returns a special method that calls into a trampoline for runtime method resolution - ArtMethod* GetResolutionMethod(); + ArtMethod* GetResolutionMethod() SHARED_REQUIRES(Locks::mutator_lock_); bool HasResolutionMethod() const { return resolution_method_ != nullptr; @@ -377,8 +377,8 @@ class Runtime { ArtMethod* CreateResolutionMethod() SHARED_REQUIRES(Locks::mutator_lock_); // Returns a special method that calls into a trampoline for runtime imt conflicts. - ArtMethod* GetImtConflictMethod(); - ArtMethod* GetImtUnimplementedMethod(); + ArtMethod* GetImtConflictMethod() SHARED_REQUIRES(Locks::mutator_lock_); + ArtMethod* GetImtUnimplementedMethod() SHARED_REQUIRES(Locks::mutator_lock_); bool HasImtConflictMethod() const { return imt_conflict_method_ != nullptr; diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc index c8714a60a8..727ffe5f33 100644 --- a/runtime/thread_list.cc +++ b/runtime/thread_list.cc @@ -1191,7 +1191,6 @@ void ThreadList::SuspendAllDaemonThreadsForShutdown() { } LOG(WARNING) << "timed out suspending all daemon threads"; } - void ThreadList::Register(Thread* self) { DCHECK_EQ(self, Thread::Current()); diff --git a/runtime/utils/dex_cache_arrays_layout-inl.h b/runtime/utils/dex_cache_arrays_layout-inl.h index f6ee6a2b1a..90e24b9632 100644 --- a/runtime/utils/dex_cache_arrays_layout-inl.h +++ b/runtime/utils/dex_cache_arrays_layout-inl.h @@ -60,9 +60,7 @@ inline size_t DexCacheArraysLayout::TypeOffset(uint32_t type_idx) const { } inline size_t DexCacheArraysLayout::TypesSize(size_t num_elements) const { - // App image patching relies on having enough room for a forwarding pointer in the types array. - // See FixupArtMethodArrayVisitor and ClassLinker::AddImageSpace. - return std::max(ArraySize(sizeof(GcRoot<mirror::Class>), num_elements), pointer_size_); + return ArraySize(sizeof(GcRoot<mirror::Class>), num_elements); } inline size_t DexCacheArraysLayout::TypesAlignment() const { @@ -74,8 +72,7 @@ inline size_t DexCacheArraysLayout::MethodOffset(uint32_t method_idx) const { } inline size_t DexCacheArraysLayout::MethodsSize(size_t num_elements) const { - // App image patching relies on having enough room for a forwarding pointer in the methods array. - return std::max(ArraySize(pointer_size_, num_elements), pointer_size_); + return ArraySize(pointer_size_, num_elements); } inline size_t DexCacheArraysLayout::MethodsAlignment() const { diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc index cfa8329a36..83009212e8 100644 --- a/runtime/well_known_classes.cc +++ b/runtime/well_known_classes.cc @@ -129,7 +129,6 @@ jmethodID WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer_broadcast; jmethodID WellKnownClasses::org_apache_harmony_dalvik_ddmc_DdmServer_dispatch; jfieldID WellKnownClasses::dalvik_system_DexFile_cookie; -jfieldID WellKnownClasses::dalvik_system_DexFile_fileName; jfieldID WellKnownClasses::dalvik_system_PathClassLoader_pathList; jfieldID WellKnownClasses::dalvik_system_DexPathList_dexElements; jfieldID WellKnownClasses::dalvik_system_DexPathList__Element_dexFile; @@ -334,7 +333,6 @@ void WellKnownClasses::Init(JNIEnv* env) { true, "newStringFromStringBuilder", "(Ljava/lang/StringBuilder;)Ljava/lang/String;"); dalvik_system_DexFile_cookie = CacheField(env, dalvik_system_DexFile, false, "mCookie", "Ljava/lang/Object;"); - dalvik_system_DexFile_fileName = CacheField(env, dalvik_system_DexFile, false, "mFileName", "Ljava/lang/String;"); dalvik_system_PathClassLoader_pathList = CacheField(env, dalvik_system_PathClassLoader, false, "pathList", "Ldalvik/system/DexPathList;"); dalvik_system_DexPathList_dexElements = CacheField(env, dalvik_system_DexPathList, false, "dexElements", "[Ldalvik/system/DexPathList$Element;"); dalvik_system_DexPathList__Element_dexFile = CacheField(env, dalvik_system_DexPathList__Element, false, "dexFile", "Ldalvik/system/DexFile;"); diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h index 482ff0a8f4..55158a77c6 100644 --- a/runtime/well_known_classes.h +++ b/runtime/well_known_classes.h @@ -140,7 +140,6 @@ struct WellKnownClasses { static jmethodID org_apache_harmony_dalvik_ddmc_DdmServer_dispatch; static jfieldID dalvik_system_DexFile_cookie; - static jfieldID dalvik_system_DexFile_fileName; static jfieldID dalvik_system_DexPathList_dexElements; static jfieldID dalvik_system_DexPathList__Element_dexFile; static jfieldID dalvik_system_PathClassLoader_pathList; diff --git a/test/496-checker-inlining-and-class-loader/src/Main.java b/test/496-checker-inlining-and-class-loader/src/Main.java index ea6df623a1..39c031a6bc 100644 --- a/test/496-checker-inlining-and-class-loader/src/Main.java +++ b/test/496-checker-inlining-and-class-loader/src/Main.java @@ -16,7 +16,6 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; -import java.util.ArrayList; import java.util.List; class MyClassLoader extends ClassLoader { @@ -31,31 +30,18 @@ class MyClassLoader extends ClassLoader { Object pathList = f.get(loader); // Some magic to get access to the dexField field of pathList. - // Need to make a copy of the dex elements since we don't want an app image with pre-resolved - // things. f = pathList.getClass().getDeclaredField("dexElements"); f.setAccessible(true); - Object[] dexElements = (Object[]) f.get(pathList); - f = dexElements[0].getClass().getDeclaredField("dexFile"); - f.setAccessible(true); - for (Object element : dexElements) { - Object dexFile = f.get(element); - // Make copy. - Field fileNameField = dexFile.getClass().getDeclaredField("mFileName"); - fileNameField.setAccessible(true); - dexFiles.add(dexFile.getClass().getDeclaredConstructor(String.class).newInstance( - fileNameField.get(dexFile))); - } + dexElements = (Object[]) f.get(pathList); + dexFileField = dexElements[0].getClass().getDeclaredField("dexFile"); + dexFileField.setAccessible(true); } - ArrayList<Object> dexFiles = new ArrayList<Object>(); + Object[] dexElements; Field dexFileField; protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException { - // Other classes may also get loaded, ignore those. - if (className.equals("LoadedByMyClassLoader") || className.equals("FirstSeenByMyClassLoader")) { - System.out.println("Request for " + className); - } + System.out.println("Request for " + className); // We're only going to handle LoadedByMyClassLoader. if (className != "LoadedByMyClassLoader") { @@ -64,12 +50,13 @@ class MyClassLoader extends ClassLoader { // Mimic what DexPathList.findClass is doing. try { - for (Object dexFile : dexFiles) { - Method method = dexFile.getClass().getDeclaredMethod( + for (Object element : dexElements) { + Object dex = dexFileField.get(element); + Method method = dex.getClass().getDeclaredMethod( "loadClassBinaryName", String.class, ClassLoader.class, List.class); - if (dexFile != null) { - Class clazz = (Class)method.invoke(dexFile, className, this, null); + if (dex != null) { + Class clazz = (Class)method.invoke(dex, className, this, null); if (clazz != null) { return clazz; } diff --git a/test/506-verify-aput/src/Main.java b/test/506-verify-aput/src/Main.java index 08368d4fa3..8359f2c452 100644 --- a/test/506-verify-aput/src/Main.java +++ b/test/506-verify-aput/src/Main.java @@ -23,12 +23,11 @@ public class Main { try { Class.forName("VerifyAPut1"); throw new Error("expected verification error"); - } catch (VerifyError e) { /* ignore */ - } catch (Error e) { System.out.println(e.getClass() + " " + e.getClass().getClassLoader()); } + } catch (VerifyError e) { /* ignore */ } + try { Class.forName("VerifyAPut2"); throw new Error("expected verification error"); - } catch (VerifyError e) { /* ignore */ - } catch (Error e) { System.out.println(e.getClass() + " " + e.getClass().getClassLoader()); } + } catch (VerifyError e) { /* ignore */ } } } |