diff options
Diffstat (limited to 'compiler/image_test.cc')
| -rw-r--r-- | compiler/image_test.cc | 157 |
1 files changed, 133 insertions, 24 deletions
diff --git a/compiler/image_test.cc b/compiler/image_test.cc index a68ab7cc9d..7e53d8d2ab 100644 --- a/compiler/image_test.cc +++ b/compiler/image_test.cc @@ -20,20 +20,27 @@ #include <string> #include <vector> +#include "android-base/stringprintf.h" + +#include "art_method-inl.h" #include "base/unix_file/fd_file.h" #include "class_linker-inl.h" +#include "compiler_callbacks.h" #include "common_compiler_test.h" #include "debug/method_debug_info.h" +#include "dex/quick_compiler_callbacks.h" #include "driver/compiler_options.h" #include "elf_writer.h" #include "elf_writer_quick.h" #include "gc/space/image_space.h" #include "image_writer.h" +#include "linker/buffered_output_stream.h" +#include "linker/file_output_stream.h" #include "linker/multi_oat_relative_patcher.h" #include "lock_word.h" #include "mirror/object-inl.h" #include "oat_writer.h" -#include "scoped_thread_state_change.h" +#include "scoped_thread_state_change-inl.h" #include "signal_catcher.h" #include "utils.h" @@ -47,6 +54,7 @@ struct CompilationHelper { std::vector<std::unique_ptr<const DexFile>> extra_dex_files; std::vector<ScratchFile> image_files; std::vector<ScratchFile> oat_files; + std::vector<ScratchFile> vdex_files; std::string image_dir; void Compile(CompilerDriver* driver, @@ -69,12 +77,32 @@ class ImageTest : public CommonCompilerTest { void Compile(ImageHeader::StorageMode storage_mode, CompilationHelper& out_helper, const std::string& extra_dex = "", - const std::string& image_class = ""); + const std::initializer_list<std::string>& image_classes = {}); + + void SetUpRuntimeOptions(RuntimeOptions* options) OVERRIDE { + CommonCompilerTest::SetUpRuntimeOptions(options); + callbacks_.reset(new QuickCompilerCallbacks( + verification_results_.get(), + CompilerCallbacks::CallbackMode::kCompileBootImage)); + options->push_back(std::make_pair("compilercallbacks", callbacks_.get())); + } std::unordered_set<std::string>* GetImageClasses() OVERRIDE { return new std::unordered_set<std::string>(image_classes_); } + ArtMethod* FindCopiedMethod(ArtMethod* origin, mirror::Class* klass) + REQUIRES_SHARED(Locks::mutator_lock_) { + PointerSize pointer_size = class_linker_->GetImagePointerSize(); + for (ArtMethod& m : klass->GetCopiedMethods(pointer_size)) { + if (strcmp(origin->GetName(), m.GetName()) == 0 && + origin->GetSignature() == m.GetSignature()) { + return &m; + } + } + return nullptr; + } + private: std::unordered_set<std::string> image_classes_; }; @@ -86,6 +114,9 @@ CompilationHelper::~CompilationHelper() { for (ScratchFile& oat_file : oat_files) { oat_file.Unlink(); } + for (ScratchFile& vdex_file : vdex_files) { + vdex_file.Unlink(); + } const int rmdir_result = rmdir(image_dir.c_str()); CHECK_EQ(0, rmdir_result); } @@ -124,12 +155,12 @@ void CompilationHelper::Compile(CompilerDriver* driver, dex_file->EnableWrite(); } } - { // Create a generic tmp file, to be the base of the .art and .oat temporary files. ScratchFile location; for (int i = 0; i < static_cast<int>(class_path.size()); ++i) { - std::string cur_location(StringPrintf("%s-%d.art", location.GetFilename().c_str(), i)); + std::string cur_location = + android::base::StringPrintf("%s-%d.art", location.GetFilename().c_str(), i); image_locations.push_back(ScratchFile(cur_location)); } } @@ -148,10 +179,14 @@ void CompilationHelper::Compile(CompilerDriver* driver, } std::vector<std::string> oat_filenames; + std::vector<std::string> vdex_filenames; for (const std::string& image_filename : image_filenames) { - std::string oat_filename(image_filename.substr(0, image_filename.size() - strlen("art")) + "oat"); + std::string oat_filename = ReplaceFileExtension(image_filename, "oat"); oat_files.push_back(ScratchFile(OS::CreateEmptyFile(oat_filename.c_str()))); oat_filenames.push_back(oat_filename); + std::string vdex_filename = ReplaceFileExtension(image_filename, "vdex"); + vdex_files.push_back(ScratchFile(OS::CreateEmptyFile(vdex_filename.c_str()))); + vdex_filenames.push_back(vdex_filename); } std::unordered_map<const DexFile*, size_t> dex_file_to_oat_index_map; @@ -182,7 +217,7 @@ void CompilationHelper::Compile(CompilerDriver* driver, TimingLogger timings("ImageTest::WriteRead", false, false); TimingLogger::ScopedTiming t("CompileAll", &timings); driver->SetDexFilesForOatFile(class_path); - driver->CompileAll(class_loader, class_path, &timings); + driver->CompileAll(class_loader, class_path, /* verifier_deps */ nullptr, &timings); t.NewTiming("WriteElf"); SafeMap<std::string, std::string> key_value_store; @@ -204,7 +239,9 @@ void CompilationHelper::Compile(CompilerDriver* driver, &driver->GetCompilerOptions(), oat_file.GetFile())); elf_writers.back()->Start(); - oat_writers.emplace_back(new OatWriter(/*compiling_boot_image*/true, &timings)); + oat_writers.emplace_back(new OatWriter(/*compiling_boot_image*/true, + &timings, + /*profile_compilation_info*/nullptr)); } std::vector<OutputStream*> rodata; @@ -224,12 +261,13 @@ void CompilationHelper::Compile(CompilerDriver* driver, std::unique_ptr<MemMap> cur_opened_dex_files_map; std::vector<std::unique_ptr<const DexFile>> cur_opened_dex_files; bool dex_files_ok = oat_writers[i]->WriteAndOpenDexFiles( + kIsVdexEnabled ? vdex_files[i].GetFile() : oat_files[i].GetFile(), rodata.back(), - oat_files[i].GetFile(), driver->GetInstructionSet(), driver->GetInstructionSetFeatures(), &key_value_store, /* verify */ false, // Dex files may be dex-to-dex-ed, don't verify. + /* update_input_vdex */ false, &cur_opened_dex_files_map, &cur_opened_dex_files); ASSERT_TRUE(dex_files_ok); @@ -244,25 +282,38 @@ void CompilationHelper::Compile(CompilerDriver* driver, ASSERT_TRUE(cur_opened_dex_files.empty()); } } - bool image_space_ok = writer->PrepareImageAddressSpace(); ASSERT_TRUE(image_space_ok); + if (kIsVdexEnabled) { + for (size_t i = 0, size = vdex_files.size(); i != size; ++i) { + std::unique_ptr<BufferedOutputStream> vdex_out( + MakeUnique<BufferedOutputStream>( + MakeUnique<FileOutputStream>(vdex_files[i].GetFile()))); + oat_writers[i]->WriteVerifierDeps(vdex_out.get(), nullptr); + oat_writers[i]->WriteChecksumsAndVdexHeader(vdex_out.get()); + } + } + for (size_t i = 0, size = oat_files.size(); i != size; ++i) { linker::MultiOatRelativePatcher patcher(driver->GetInstructionSet(), driver->GetInstructionSetFeatures()); OatWriter* const oat_writer = oat_writers[i].get(); ElfWriter* const elf_writer = elf_writers[i].get(); std::vector<const DexFile*> cur_dex_files(1u, class_path[i]); - oat_writer->PrepareLayout(driver, writer.get(), cur_dex_files, &patcher); + oat_writer->Initialize(driver, writer.get(), cur_dex_files); + oat_writer->PrepareLayout(&patcher); size_t rodata_size = oat_writer->GetOatHeader().GetExecutableOffset(); - size_t text_size = oat_writer->GetSize() - rodata_size; - elf_writer->SetLoadedSectionSizes(rodata_size, text_size, oat_writer->GetBssSize()); + size_t text_size = oat_writer->GetOatSize() - rodata_size; + elf_writer->PrepareDynamicSection(rodata_size, + text_size, + oat_writer->GetBssSize(), + oat_writer->GetBssRootsOffset()); writer->UpdateOatFileLayout(i, elf_writer->GetLoadedSize(), oat_writer->GetOatDataOffset(), - oat_writer->GetSize()); + oat_writer->GetOatSize()); bool rodata_ok = oat_writer->WriteRodata(rodata[i]); ASSERT_TRUE(rodata_ok); @@ -280,7 +331,6 @@ void CompilationHelper::Compile(CompilerDriver* driver, elf_writer->WriteDynamicSection(); elf_writer->WriteDebugInfo(oat_writer->GetMethodDebugInfo()); - elf_writer->WritePatchLocations(oat_writer->GetAbsolutePatchLocations()); bool success = elf_writer->End(); ASSERT_TRUE(success); @@ -308,26 +358,27 @@ void CompilationHelper::Compile(CompilerDriver* driver, void ImageTest::Compile(ImageHeader::StorageMode storage_mode, CompilationHelper& helper, const std::string& extra_dex, - const std::string& image_class) { - if (!image_class.empty()) { + const std::initializer_list<std::string>& image_classes) { + for (const std::string& image_class : image_classes) { image_classes_.insert(image_class); } CreateCompilerDriver(Compiler::kOptimizing, kRuntimeISA, kIsTargetBuild ? 2U : 16U); // Set inline filter values. - compiler_options_->SetInlineDepthLimit(CompilerOptions::kDefaultInlineDepthLimit); compiler_options_->SetInlineMaxCodeUnits(CompilerOptions::kDefaultInlineMaxCodeUnits); image_classes_.clear(); if (!extra_dex.empty()) { helper.extra_dex_files = OpenTestDexFiles(extra_dex.c_str()); } helper.Compile(compiler_driver_.get(), storage_mode); - if (!image_class.empty()) { + if (image_classes.begin() != image_classes.end()) { // Make sure the class got initialized. ScopedObjectAccess soa(Thread::Current()); ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); - mirror::Class* klass = class_linker->FindSystemClass(Thread::Current(), image_class.c_str()); - EXPECT_TRUE(klass != nullptr); - EXPECT_TRUE(klass->IsInitialized()); + for (const std::string& image_class : image_classes) { + mirror::Class* klass = class_linker->FindSystemClass(Thread::Current(), image_class.c_str()); + EXPECT_TRUE(klass != nullptr); + EXPECT_TRUE(klass->IsInitialized()); + } } } @@ -351,7 +402,6 @@ void ImageTest::TestWriteRead(ImageHeader::StorageMode storage_mode) { ASSERT_FALSE(space->IsImageSpace()); ASSERT_TRUE(space != nullptr); ASSERT_TRUE(space->IsMallocSpace()); - image_file_sizes.push_back(file->GetLength()); } @@ -456,7 +506,7 @@ TEST_F(ImageTest, TestImageLayout) { // Compile multi-image with ImageLayoutA being the last image. { CompilationHelper helper; - Compile(ImageHeader::kStorageModeUncompressed, helper, "ImageLayoutA", "LMyClass;"); + Compile(ImageHeader::kStorageModeUncompressed, helper, "ImageLayoutA", {"LMyClass;"}); image_sizes = helper.GetImageObjectSectionSizes(); } TearDown(); @@ -465,7 +515,7 @@ TEST_F(ImageTest, TestImageLayout) { // Compile multi-image with ImageLayoutB being the last image. { CompilationHelper helper; - Compile(ImageHeader::kStorageModeUncompressed, helper, "ImageLayoutB", "LMyClass;"); + Compile(ImageHeader::kStorageModeUncompressed, helper, "ImageLayoutB", {"LMyClass;"}); image_sizes_extra = helper.GetImageObjectSectionSizes(); } // Make sure that the new stuff in the clinit in ImageLayoutB is in the last image and not in the @@ -517,4 +567,63 @@ TEST_F(ImageTest, ImageHeaderIsValid) { ASSERT_FALSE(image_header.IsValid()); } +// Test that pointer to quick code is the same in +// a default method of an interface and in a copied method +// of a class which implements the interface. This should be true +// only if the copied method and the origin method are located in the +// same oat file. +TEST_F(ImageTest, TestDefaultMethods) { + CompilationHelper helper; + Compile(ImageHeader::kStorageModeUncompressed, + helper, + "DefaultMethods", + {"LIface;", "LImpl;", "LIterableBase;"}); + + PointerSize pointer_size = class_linker_->GetImagePointerSize(); + Thread* self = Thread::Current(); + ScopedObjectAccess soa(self); + + // Test the pointer to quick code is the same in origin method + // and in the copied method form the same oat file. + mirror::Class* iface_klass = class_linker_->LookupClass( + self, "LIface;", ObjPtr<mirror::ClassLoader>()); + ASSERT_NE(nullptr, iface_klass); + ArtMethod* origin = iface_klass->FindDeclaredVirtualMethod( + "defaultMethod", "()V", pointer_size); + ASSERT_NE(nullptr, origin); + const void* code = origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size); + // The origin method should have a pointer to quick code + ASSERT_NE(nullptr, code); + ASSERT_FALSE(class_linker_->IsQuickToInterpreterBridge(code)); + mirror::Class* impl_klass = class_linker_->LookupClass( + self, "LImpl;", ObjPtr<mirror::ClassLoader>()); + ASSERT_NE(nullptr, impl_klass); + ArtMethod* copied = FindCopiedMethod(origin, impl_klass); + ASSERT_NE(nullptr, copied); + // the copied method should have pointer to the same quick code as the origin method + ASSERT_EQ(code, copied->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size)); + + // Test the origin method has pointer to quick code + // but the copied method has pointer to interpreter + // because these methods are in different oat files. + mirror::Class* iterable_klass = class_linker_->LookupClass( + self, "Ljava/lang/Iterable;", ObjPtr<mirror::ClassLoader>()); + ASSERT_NE(nullptr, iterable_klass); + origin = iterable_klass->FindDeclaredVirtualMethod( + "forEach", "(Ljava/util/function/Consumer;)V", pointer_size); + ASSERT_NE(nullptr, origin); + code = origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size); + // the origin method should have a pointer to quick code + ASSERT_NE(nullptr, code); + ASSERT_FALSE(class_linker_->IsQuickToInterpreterBridge(code)); + mirror::Class* iterablebase_klass = class_linker_->LookupClass( + self, "LIterableBase;", ObjPtr<mirror::ClassLoader>()); + ASSERT_NE(nullptr, iterablebase_klass); + copied = FindCopiedMethod(origin, iterablebase_klass); + ASSERT_NE(nullptr, copied); + code = copied->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size); + // the copied method should have a pointer to interpreter + ASSERT_TRUE(class_linker_->IsQuickToInterpreterBridge(code)); +} + } // namespace art |