diff options
author | 2016-02-16 12:50:23 +0000 | |
---|---|---|
committer | 2016-02-17 16:38:46 +0000 | |
commit | 6065402316da2b51eed5fc34cffbd991766bd408 (patch) | |
tree | cb93e32b978ea03a70baf980c470a03263c084c0 /compiler | |
parent | 442643920a6c539e98aad76594e99b932b5631ba (diff) |
Allow method references across oat files for multi-image.
These were disabled because we didn't have sufficient
information about the multi-image layout when processing
link-time patches in OatWriter. This CL refactors the
ELF file creation so that the information is available.
Change-Id: I6f2e8dc8572d143c72cc2693bb0ba4fd76f889ab
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/common_compiler_test.cc | 11 | ||||
-rw-r--r-- | compiler/dex/quick/quick_cfi_test.cc | 21 | ||||
-rw-r--r-- | compiler/dex/quick/x86/quick_assemble_x86_test.cc | 23 | ||||
-rw-r--r-- | compiler/driver/compiled_method_storage_test.cc | 26 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.cc | 18 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.h | 25 | ||||
-rw-r--r-- | compiler/elf_builder.h | 298 | ||||
-rw-r--r-- | compiler/elf_writer.h | 9 | ||||
-rw-r--r-- | compiler/elf_writer_quick.cc | 52 | ||||
-rw-r--r-- | compiler/image_test.cc | 5 | ||||
-rw-r--r-- | compiler/image_writer.cc | 17 | ||||
-rw-r--r-- | compiler/image_writer.h | 2 | ||||
-rw-r--r-- | compiler/jit/jit_compiler.cc | 1 | ||||
-rw-r--r-- | compiler/linker/relative_patcher_test.h | 20 | ||||
-rw-r--r-- | compiler/oat_test.cc | 24 |
15 files changed, 352 insertions, 200 deletions
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc index e4bfac9ee7..239bc590e9 100644 --- a/compiler/common_compiler_test.cc +++ b/compiler/common_compiler_test.cc @@ -194,16 +194,15 @@ void CommonCompilerTest::CreateCompilerDriver(Compiler::Kind kind, InstructionSe kind, isa, instruction_set_features_.get(), - true, + /* boot_image */ true, GetImageClasses(), GetCompiledClasses(), GetCompiledMethods(), - 2, - true, - true, + /* thread_count */ 2, + /* dump_stats */ true, + /* dump_passes */ true, timer_.get(), - -1, - /* dex_to_oat_map */ nullptr, + /* swap_fd */ -1, GetProfileCompilationInfo())); // We typically don't generate an image in unit tests, disable this optimization by default. compiler_driver_->SetSupportBootImageFixup(false); diff --git a/compiler/dex/quick/quick_cfi_test.cc b/compiler/dex/quick/quick_cfi_test.cc index 0cd41bbf4c..6c6c9cfb1e 100644 --- a/compiler/dex/quick/quick_cfi_test.cc +++ b/compiler/dex/quick/quick_cfi_test.cc @@ -84,17 +84,16 @@ class QuickCFITest : public CFITest { Compiler::kQuick, isa, isa_features.get(), - false, - nullptr, - nullptr, - nullptr, - 0, - false, - false, - 0, - -1, - nullptr, - nullptr); + /* boot_image */ false, + /* image_classes */ nullptr, + /* compiled_classes */ nullptr, + /* compiled_methods */ nullptr, + /* thread_count */ 0, + /* dump_stats */ false, + /* dump_passes */ false, + /* timer */ nullptr, + /* swap_fd */ -1, + /* profile_compilation_info */ nullptr); ClassLinker* linker = nullptr; CompilationUnit cu(&pool, isa, &driver, linker); DexFile::CodeItem code_item { 0, 0, 0, 0, 0, 0, { 0 } }; // NOLINT diff --git a/compiler/dex/quick/x86/quick_assemble_x86_test.cc b/compiler/dex/quick/x86/quick_assemble_x86_test.cc index efdc333261..ff0ecea94c 100644 --- a/compiler/dex/quick/x86/quick_assemble_x86_test.cc +++ b/compiler/dex/quick/x86/quick_assemble_x86_test.cc @@ -64,18 +64,17 @@ class QuickAssembleX86TestBase : public testing::Test { method_inliner_map_.get(), Compiler::kQuick, isa_, - nullptr, - false, - nullptr, - nullptr, - nullptr, - 0, - false, - false, - 0, - -1, - nullptr, - nullptr)); + /* instruction_set_features*/ nullptr, + /* boot_image */ false, + /* image_classes */ nullptr, + /* compiled_classes */ nullptr, + /* compiled_methods */ nullptr, + /* thread_count */ 0, + /* dump_stats */ false, + /* dump_passes */ false, + /* timer */ nullptr, + /* swap_fd */ -1, + /* profile_compilation_info */ nullptr)); cu_.reset(new CompilationUnit(pool_.get(), isa_, compiler_driver_.get(), nullptr)); DexFile::CodeItem* code_item = static_cast<DexFile::CodeItem*>( cu_->arena.Alloc(sizeof(DexFile::CodeItem), kArenaAllocMisc)); diff --git a/compiler/driver/compiled_method_storage_test.cc b/compiler/driver/compiled_method_storage_test.cc index 2e2d1f99f3..0695cb56b3 100644 --- a/compiler/driver/compiled_method_storage_test.cc +++ b/compiler/driver/compiled_method_storage_test.cc @@ -32,19 +32,19 @@ TEST(CompiledMethodStorage, Deduplicate) { CompilerDriver driver(&compiler_options, &verification_results, &method_inliner_map, - Compiler::kOptimizing, kNone, - nullptr, - false, - nullptr, - nullptr, - nullptr, - 1u, - false, - false, - nullptr, - -1, - nullptr, - nullptr); + Compiler::kOptimizing, + /* instruction_set_ */ kNone, + /* instruction_set_features */ nullptr, + /* boot_image */ false, + /* image_classes */ nullptr, + /* compiled_classes */ nullptr, + /* compiled_methods */ nullptr, + /* thread_count */ 1u, + /* dump_stats */ false, + /* dump_passes */ false, + /* timer */ nullptr, + /* swap_fd */ -1, + /* profile_compilation_info */ nullptr); CompiledMethodStorage* storage = driver.GetCompiledMethodStorage(); ASSERT_TRUE(storage->DedupeEnabled()); // The default. diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 670fe94988..e80730fe11 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -342,12 +342,15 @@ CompilerDriver::CompilerDriver( Compiler::Kind compiler_kind, InstructionSet instruction_set, const InstructionSetFeatures* instruction_set_features, - bool boot_image, std::unordered_set<std::string>* image_classes, + bool boot_image, + std::unordered_set<std::string>* image_classes, std::unordered_set<std::string>* compiled_classes, std::unordered_set<std::string>* compiled_methods, - size_t thread_count, bool dump_stats, bool dump_passes, - CumulativeLogger* timer, int swap_fd, - const std::unordered_map<const DexFile*, const char*>* dex_to_oat_map, + size_t thread_count, + bool dump_stats, + bool dump_passes, + CumulativeLogger* timer, + int swap_fd, const ProfileCompilationInfo* profile_compilation_info) : compiler_options_(compiler_options), verification_results_(verification_results), @@ -374,7 +377,6 @@ CompilerDriver::CompilerDriver( compiler_context_(nullptr), support_boot_image_fixup_(instruction_set != kMips && instruction_set != kMips64), dex_files_for_oat_file_(nullptr), - dex_file_oat_filename_map_(dex_to_oat_map), compiled_method_storage_(swap_fd), profile_compilation_info_(profile_compilation_info) { DCHECK(compiler_options_ != nullptr); @@ -1678,12 +1680,6 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType use_dex_cache = true; } } - if (!use_dex_cache && IsBootImage()) { - if (!AreInSameOatFile(&(const_cast<mirror::Class*>(referrer_class)->GetDexFile()), - &declaring_class->GetDexFile())) { - use_dex_cache = true; - } - } // The method is defined not within this dex file. We need a dex cache slot within the current // dex file or direct pointers. bool must_use_direct_pointers = false; diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 5e35cbb309..ca340ee92c 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -94,9 +94,11 @@ class CompilerDriver { bool boot_image, std::unordered_set<std::string>* image_classes, std::unordered_set<std::string>* compiled_classes, std::unordered_set<std::string>* compiled_methods, - size_t thread_count, bool dump_stats, bool dump_passes, - CumulativeLogger* timer, int swap_fd, - const std::unordered_map<const DexFile*, const char*>* dex_to_oat_map, + size_t thread_count, + bool dump_stats, + bool dump_passes, + CumulativeLogger* timer, + int swap_fd, const ProfileCompilationInfo* profile_compilation_info); ~CompilerDriver(); @@ -113,20 +115,6 @@ class CompilerDriver { : ArrayRef<const DexFile* const>(); } - // Are the given dex files compiled into the same oat file? Should only be called after - // GetDexFilesForOatFile, as the conservative answer (when we don't have a map) is true. - bool AreInSameOatFile(const DexFile* d1, const DexFile* d2) { - if (dex_file_oat_filename_map_ == nullptr) { - // TODO: Check for this wrt/ apps and boot image calls. - return true; - } - auto it1 = dex_file_oat_filename_map_->find(d1); - DCHECK(it1 != dex_file_oat_filename_map_->end()); - auto it2 = dex_file_oat_filename_map_->find(d2); - DCHECK(it2 != dex_file_oat_filename_map_->end()); - return it1->second == it2->second; - } - void CompileAll(jobject class_loader, const std::vector<const DexFile*>& dex_files, TimingLogger* timings) @@ -700,9 +688,6 @@ class CompilerDriver { // List of dex files that will be stored in the oat file. const std::vector<const DexFile*>* dex_files_for_oat_file_; - // Map from dex files to the oat file (name) they will be compiled into. - const std::unordered_map<const DexFile*, const char*>* dex_file_oat_filename_map_; - CompiledMethodStorage compiled_method_storage_; // Info for profile guided compilation. diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h index b673eeb3b6..f7da609e5d 100644 --- a/compiler/elf_builder.h +++ b/compiler/elf_builder.h @@ -86,12 +86,24 @@ class ElfBuilder FINAL { // Base class of all sections. class Section : public OutputStream { public: - Section(ElfBuilder<ElfTypes>* owner, const std::string& name, - Elf_Word type, Elf_Word flags, const Section* link, - Elf_Word info, Elf_Word align, Elf_Word entsize) - : OutputStream(name), owner_(owner), header_(), - section_index_(0), name_(name), link_(link), - started_(false), finished_(false), phdr_flags_(PF_R), phdr_type_(0) { + Section(ElfBuilder<ElfTypes>* owner, + const std::string& name, + Elf_Word type, + Elf_Word flags, + const Section* link, + Elf_Word info, + Elf_Word align, + Elf_Word entsize) + : OutputStream(name), + owner_(owner), + header_(), + section_index_(0), + name_(name), + link_(link), + started_(false), + finished_(false), + phdr_flags_(PF_R), + phdr_type_(0) { DCHECK_GE(align, 1u); header_.sh_type = type; header_.sh_flags = flags; @@ -228,12 +240,84 @@ class ElfBuilder FINAL { DISALLOW_COPY_AND_ASSIGN(Section); }; - // Writer of .dynstr .strtab and .shstrtab sections. + class CachedSection : public Section { + public: + CachedSection(ElfBuilder<ElfTypes>* owner, + const std::string& name, + Elf_Word type, + Elf_Word flags, + const Section* link, + Elf_Word info, + Elf_Word align, + Elf_Word entsize) + : Section(owner, name, type, flags, link, info, align, entsize), cache_() { } + + Elf_Word Add(const void* data, size_t length) { + Elf_Word offset = cache_.size(); + const uint8_t* d = reinterpret_cast<const uint8_t*>(data); + cache_.insert(cache_.end(), d, d + length); + return offset; + } + + Elf_Word GetCacheSize() { + return cache_.size(); + } + + void Write() { + this->WriteFully(cache_.data(), cache_.size()); + cache_.clear(); + cache_.shrink_to_fit(); + } + + void WriteCachedSection() { + this->Start(); + Write(); + this->End(); + } + + private: + std::vector<uint8_t> cache_; + }; + + // Writer of .dynstr section. + class CachedStringSection FINAL : public CachedSection { + public: + CachedStringSection(ElfBuilder<ElfTypes>* owner, + const std::string& name, + Elf_Word flags, + Elf_Word align) + : CachedSection(owner, + name, + SHT_STRTAB, + flags, + /* link */ nullptr, + /* info */ 0, + align, + /* entsize */ 0) { } + + Elf_Word Add(const std::string& name) { + if (CachedSection::GetCacheSize() == 0u) { + DCHECK(name.empty()); + } + return CachedSection::Add(name.c_str(), name.length() + 1); + } + }; + + // Writer of .strtab and .shstrtab sections. class StringSection FINAL : public Section { public: - StringSection(ElfBuilder<ElfTypes>* owner, const std::string& name, - Elf_Word flags, Elf_Word align) - : Section(owner, name, SHT_STRTAB, flags, nullptr, 0, align, 0), + StringSection(ElfBuilder<ElfTypes>* owner, + const std::string& name, + Elf_Word flags, + Elf_Word align) + : Section(owner, + name, + SHT_STRTAB, + flags, + /* link */ nullptr, + /* info */ 0, + align, + /* entsize */ 0), current_offset_(0) { } @@ -252,42 +336,60 @@ class ElfBuilder FINAL { }; // Writer of .dynsym and .symtab sections. - class SymbolSection FINAL : public Section { + class SymbolSection FINAL : public CachedSection { public: - SymbolSection(ElfBuilder<ElfTypes>* owner, const std::string& name, - Elf_Word type, Elf_Word flags, StringSection* strtab) - : Section(owner, name, type, flags, strtab, 0, - sizeof(Elf_Off), sizeof(Elf_Sym)) { + SymbolSection(ElfBuilder<ElfTypes>* owner, + const std::string& name, + Elf_Word type, + Elf_Word flags, + Section* strtab) + : CachedSection(owner, + name, + type, + flags, + strtab, + /* info */ 0, + sizeof(Elf_Off), + sizeof(Elf_Sym)) { + // The symbol table always has to start with NULL symbol. + Elf_Sym null_symbol = Elf_Sym(); + CachedSection::Add(&null_symbol, sizeof(null_symbol)); } // Buffer symbol for this section. It will be written later. // If the symbol's section is null, it will be considered absolute (SHN_ABS). // (we use this in JIT to reference code which is stored outside the debug ELF file) - void Add(Elf_Word name, const Section* section, - Elf_Addr addr, bool is_relative, Elf_Word size, - uint8_t binding, uint8_t type, uint8_t other = 0) { + void Add(Elf_Word name, + const Section* section, + Elf_Addr addr, + bool is_relative, + Elf_Word size, + uint8_t binding, + uint8_t type, + uint8_t other = 0) { + DCHECK(section != nullptr || !is_relative); + Elf_Addr abs_addr = addr + (is_relative ? section->GetAddress() : 0); + Elf_Word section_index = + (section != nullptr) ? section->GetSectionIndex() : static_cast<Elf_Word>(SHN_ABS); + Add(name, section_index, abs_addr, size, binding, type, other); + } + + void Add(Elf_Word name, + Elf_Word section_index, + Elf_Addr addr, + Elf_Word size, + uint8_t binding, + uint8_t type, + uint8_t other = 0) { Elf_Sym sym = Elf_Sym(); sym.st_name = name; - sym.st_value = addr + (is_relative ? section->GetAddress() : 0); + sym.st_value = addr; sym.st_size = size; sym.st_other = other; - sym.st_shndx = (section != nullptr ? section->GetSectionIndex() - : static_cast<Elf_Word>(SHN_ABS)); + sym.st_shndx = section_index; sym.st_info = (binding << 4) + (type & 0xf); - symbols_.push_back(sym); - } - - void Write() { - // The symbol table always has to start with NULL symbol. - Elf_Sym null_symbol = Elf_Sym(); - this->WriteFully(&null_symbol, sizeof(null_symbol)); - this->WriteFully(symbols_.data(), symbols_.size() * sizeof(symbols_[0])); - symbols_.clear(); - symbols_.shrink_to_fit(); + CachedSection::Add(&sym, sizeof(sym)); } - - private: - std::vector<Elf_Sym> symbols_; }; ElfBuilder(InstructionSet isa, OutputStream* output) @@ -309,6 +411,8 @@ class ElfBuilder FINAL { debug_line_(this, ".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0), shstrtab_(this, ".shstrtab", 0, 1), started_(false), + write_program_headers_(false), + loaded_size_(0u), virtual_address_(0) { text_.phdr_flags_ = PF_R | PF_X; bss_.phdr_flags_ = PF_R | PF_W; @@ -380,6 +484,14 @@ class ElfBuilder FINAL { void End() { DCHECK(started_); + // Note: loaded_size_ == 0 for tests that don't write .rodata, .text, .bss, + // .dynstr, dynsym, .hash and .dynamic. These tests should not read loaded_size_. + // TODO: Either refactor the .eh_frame creation so that it counts towards loaded_size_, + // or remove all support for .eh_frame. (The currently unused .eh_frame counts towards + // the virtual_address_ but we don't consider it for loaded_size_.) + CHECK(loaded_size_ == 0 || loaded_size_ == RoundUp(virtual_address_, kPageSize)) + << loaded_size_ << " " << virtual_address_; + // Write section names and finish the section headers. shstrtab_.Start(); shstrtab_.Write(""); @@ -434,45 +546,58 @@ class ElfBuilder FINAL { // information like the address and size of .rodata and .text. // It also contains other metadata like the SONAME. // The .dynamic section is found using the PT_DYNAMIC program header. - void WriteDynamicSection(const std::string& elf_file_path) { + void PrepareDynamicSection(const std::string& elf_file_path, + Elf_Word rodata_size, + Elf_Word text_size, + Elf_Word bss_size) { std::string soname(elf_file_path); size_t directory_separator_pos = soname.rfind('/'); if (directory_separator_pos != std::string::npos) { soname = soname.substr(directory_separator_pos + 1); } - dynstr_.Start(); - dynstr_.Write(""); // dynstr should start with empty string. - dynsym_.Add(dynstr_.Write("oatdata"), &rodata_, 0, true, - rodata_.GetSize(), STB_GLOBAL, STT_OBJECT); - if (text_.GetSize() != 0u) { - dynsym_.Add(dynstr_.Write("oatexec"), &text_, 0, true, - text_.GetSize(), STB_GLOBAL, STT_OBJECT); - dynsym_.Add(dynstr_.Write("oatlastword"), &text_, text_.GetSize() - 4, - true, 4, STB_GLOBAL, STT_OBJECT); - } else if (rodata_.GetSize() != 0) { + // Calculate addresses of .text, .bss and .dynstr. + DCHECK_EQ(rodata_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize)); + DCHECK_EQ(text_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize)); + DCHECK_EQ(bss_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize)); + DCHECK_EQ(dynstr_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize)); + Elf_Word rodata_address = rodata_.GetAddress(); + Elf_Word text_address = RoundUp(rodata_address + rodata_size, kPageSize); + Elf_Word bss_address = RoundUp(text_address + text_size, kPageSize); + Elf_Word dynstr_address = RoundUp(bss_address + bss_size, kPageSize); + + // Cache .dynstr, .dynsym and .hash data. + dynstr_.Add(""); // dynstr should start with empty string. + Elf_Word rodata_index = rodata_.GetSectionIndex(); + Elf_Word oatdata = dynstr_.Add("oatdata"); + dynsym_.Add(oatdata, rodata_index, rodata_address, rodata_size, STB_GLOBAL, STT_OBJECT); + if (text_size != 0u) { + Elf_Word text_index = rodata_index + 1u; + Elf_Word oatexec = dynstr_.Add("oatexec"); + dynsym_.Add(oatexec, text_index, text_address, text_size, STB_GLOBAL, STT_OBJECT); + Elf_Word oatlastword = dynstr_.Add("oatlastword"); + Elf_Word oatlastword_address = text_address + text_size - 4; + dynsym_.Add(oatlastword, text_index, oatlastword_address, 4, STB_GLOBAL, STT_OBJECT); + } else if (rodata_size != 0) { // rodata_ can be size 0 for dwarf_test. - dynsym_.Add(dynstr_.Write("oatlastword"), &rodata_, rodata_.GetSize() - 4, - true, 4, STB_GLOBAL, STT_OBJECT); + Elf_Word oatlastword = dynstr_.Add("oatlastword"); + Elf_Word oatlastword_address = rodata_address + rodata_size - 4; + dynsym_.Add(oatlastword, rodata_index, oatlastword_address, 4, STB_GLOBAL, STT_OBJECT); } - if (bss_.finished_) { - dynsym_.Add(dynstr_.Write("oatbss"), &bss_, - 0, true, bss_.GetSize(), STB_GLOBAL, STT_OBJECT); - dynsym_.Add(dynstr_.Write("oatbsslastword"), &bss_, - bss_.GetSize() - 4, true, 4, STB_GLOBAL, STT_OBJECT); + if (bss_size != 0u) { + Elf_Word bss_index = rodata_index + 1u + (text_size != 0 ? 1u : 0u); + Elf_Word oatbss = dynstr_.Add("oatbss"); + dynsym_.Add(oatbss, bss_index, bss_address, bss_size, STB_GLOBAL, STT_OBJECT); + Elf_Word oatbsslastword = dynstr_.Add("oatbsslastword"); + Elf_Word bsslastword_address = bss_address + bss_size - 4; + dynsym_.Add(oatbsslastword, bss_index, bsslastword_address, 4, STB_GLOBAL, STT_OBJECT); } - Elf_Word soname_offset = dynstr_.Write(soname); - dynstr_.End(); - - dynsym_.Start(); - dynsym_.Write(); - dynsym_.End(); + Elf_Word soname_offset = dynstr_.Add(soname); // We do not really need a hash-table since there is so few entries. // However, the hash-table is the only way the linker can actually // determine the number of symbols in .dynsym so it is required. - hash_.Start(); - int count = dynsym_.GetSize() / sizeof(Elf_Sym); // Includes NULL. + int count = dynsym_.GetCacheSize() / sizeof(Elf_Sym); // Includes NULL. std::vector<Elf_Word> hash; hash.push_back(1); // Number of buckets. hash.push_back(count); // Number of chains. @@ -484,21 +609,44 @@ class ElfBuilder FINAL { hash.push_back(i + 1); // Each symbol points to the next one. } hash.push_back(0); // Last symbol terminates the chain. - hash_.WriteFully(hash.data(), hash.size() * sizeof(hash[0])); - hash_.End(); + hash_.Add(hash.data(), hash.size() * sizeof(hash[0])); + + // Calculate addresses of .dynsym, .hash and .dynamic. + DCHECK_EQ(dynstr_.header_.sh_flags, dynsym_.header_.sh_flags); + DCHECK_EQ(dynsym_.header_.sh_flags, hash_.header_.sh_flags); + Elf_Word dynsym_address = + RoundUp(dynstr_address + dynstr_.GetCacheSize(), dynsym_.header_.sh_addralign); + Elf_Word hash_address = + RoundUp(dynsym_address + dynsym_.GetCacheSize(), hash_.header_.sh_addralign); + DCHECK_EQ(dynamic_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize)); + Elf_Word dynamic_address = RoundUp(hash_address + dynsym_.GetCacheSize(), kPageSize); - dynamic_.Start(); Elf_Dyn dyns[] = { - { DT_HASH, { hash_.GetAddress() } }, - { DT_STRTAB, { dynstr_.GetAddress() } }, - { DT_SYMTAB, { dynsym_.GetAddress() } }, + { DT_HASH, { hash_address } }, + { DT_STRTAB, { dynstr_address } }, + { DT_SYMTAB, { dynsym_address } }, { DT_SYMENT, { sizeof(Elf_Sym) } }, - { DT_STRSZ, { dynstr_.GetSize() } }, + { DT_STRSZ, { dynstr_.GetCacheSize() } }, { DT_SONAME, { soname_offset } }, { DT_NULL, { 0 } }, }; - dynamic_.WriteFully(&dyns, sizeof(dyns)); - dynamic_.End(); + dynamic_.Add(&dyns, sizeof(dyns)); + + loaded_size_ = RoundUp(dynamic_address + dynamic_.GetCacheSize(), kPageSize); + } + + void WriteDynamicSection() { + dynstr_.WriteCachedSection(); + dynsym_.WriteCachedSection(); + hash_.WriteCachedSection(); + dynamic_.WriteCachedSection(); + + CHECK_EQ(loaded_size_, RoundUp(dynamic_.GetAddress() + dynamic_.GetSize(), kPageSize)); + } + + Elf_Word GetLoadedSize() { + CHECK_NE(loaded_size_, 0u); + return loaded_size_; } // Returns true if all writes and seeks on the output stream succeeded. @@ -676,10 +824,10 @@ class ElfBuilder FINAL { Section rodata_; Section text_; Section bss_; - StringSection dynstr_; + CachedStringSection dynstr_; SymbolSection dynsym_; - Section hash_; - Section dynamic_; + CachedSection hash_; + CachedSection dynamic_; Section eh_frame_; Section eh_frame_hdr_; StringSection strtab_; @@ -694,12 +842,14 @@ class ElfBuilder FINAL { std::vector<Section*> sections_; bool started_; + bool write_program_headers_; + + // The size of the memory taken by the ELF file when loaded. + size_t loaded_size_; // Used for allocation of virtual address space. Elf_Addr virtual_address_; - size_t write_program_headers_; - DISALLOW_COPY_AND_ASSIGN(ElfBuilder); }; diff --git a/compiler/elf_writer.h b/compiler/elf_writer.h index d50a08cb20..c9ea0083d5 100644 --- a/compiler/elf_writer.h +++ b/compiler/elf_writer.h @@ -52,14 +52,12 @@ class ElfWriter { virtual ~ElfWriter() {} virtual void Start() = 0; - virtual void PrepareDebugInfo(size_t rodata_section_size, - size_t text_section_size, - const ArrayRef<const debug::MethodDebugInfo>& method_infos) = 0; + virtual void SetLoadedSectionSizes(size_t rodata_size, size_t text_size, size_t bss_size) = 0; + virtual void PrepareDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) = 0; virtual OutputStream* StartRoData() = 0; virtual void EndRoData(OutputStream* rodata) = 0; virtual OutputStream* StartText() = 0; virtual void EndText(OutputStream* text) = 0; - virtual void SetBssSize(size_t bss_size) = 0; virtual void WriteDynamicSection() = 0; virtual void WriteDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) = 0; virtual void WritePatchLocations(const ArrayRef<const uintptr_t>& patch_locations) = 0; @@ -70,6 +68,9 @@ class ElfWriter { // should Seek() back to the position where the stream was before this operation. virtual OutputStream* GetStream() = 0; + // Get the size that the loaded ELF file will occupy in memory. + virtual size_t GetLoadedSize() = 0; + protected: ElfWriter() = default; }; diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc index 1d71e572d7..19346ecc2b 100644 --- a/compiler/elf_writer_quick.cc +++ b/compiler/elf_writer_quick.cc @@ -88,14 +88,12 @@ class ElfWriterQuick FINAL : public ElfWriter { ~ElfWriterQuick(); void Start() OVERRIDE; - void PrepareDebugInfo(size_t rodata_section_size, - size_t text_section_size, - const ArrayRef<const debug::MethodDebugInfo>& method_infos) OVERRIDE; + void SetLoadedSectionSizes(size_t rodata_size, size_t text_size, size_t bss_size) OVERRIDE; + void PrepareDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) OVERRIDE; OutputStream* StartRoData() OVERRIDE; void EndRoData(OutputStream* rodata) OVERRIDE; OutputStream* StartText() OVERRIDE; void EndText(OutputStream* text) OVERRIDE; - void SetBssSize(size_t bss_size) OVERRIDE; void WriteDynamicSection() OVERRIDE; void WriteDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) OVERRIDE; void WritePatchLocations(const ArrayRef<const uintptr_t>& patch_locations) OVERRIDE; @@ -103,12 +101,17 @@ class ElfWriterQuick FINAL : public ElfWriter { virtual OutputStream* GetStream() OVERRIDE; + size_t GetLoadedSize() OVERRIDE; + static void EncodeOatPatches(const std::vector<uintptr_t>& locations, std::vector<uint8_t>* buffer); private: const CompilerOptions* const compiler_options_; File* const elf_file_; + size_t rodata_size_; + size_t text_size_; + size_t bss_size_; std::unique_ptr<BufferedOutputStream> output_stream_; std::unique_ptr<ElfBuilder<ElfTypes>> builder_; std::unique_ptr<DebugInfoTask> debug_info_task_; @@ -134,6 +137,9 @@ ElfWriterQuick<ElfTypes>::ElfWriterQuick(InstructionSet instruction_set, : ElfWriter(), compiler_options_(compiler_options), elf_file_(elf_file), + rodata_size_(0u), + text_size_(0u), + bss_size_(0u), output_stream_(MakeUnique<BufferedOutputStream>(MakeUnique<FileOutputStream>(elf_file))), builder_(new ElfBuilder<ElfTypes>(instruction_set, output_stream_.get())) {} @@ -146,6 +152,19 @@ void ElfWriterQuick<ElfTypes>::Start() { } template <typename ElfTypes> +void ElfWriterQuick<ElfTypes>::SetLoadedSectionSizes(size_t rodata_size, + size_t text_size, + size_t bss_size) { + DCHECK_EQ(rodata_size_, 0u); + rodata_size_ = rodata_size; + DCHECK_EQ(text_size_, 0u); + text_size_ = text_size; + DCHECK_EQ(bss_size_, 0u); + bss_size_ = bss_size; + builder_->PrepareDynamicSection(elf_file_->GetPath(), rodata_size_, text_size_, bss_size_); +} + +template <typename ElfTypes> OutputStream* ElfWriterQuick<ElfTypes>::StartRoData() { auto* rodata = builder_->GetRoData(); rodata->Start(); @@ -172,31 +191,21 @@ void ElfWriterQuick<ElfTypes>::EndText(OutputStream* text) { } template <typename ElfTypes> -void ElfWriterQuick<ElfTypes>::SetBssSize(size_t bss_size) { - auto* bss = builder_->GetBss(); - if (bss_size != 0u) { - bss->WriteNoBitsSection(bss_size); - } -} - -template <typename ElfTypes> void ElfWriterQuick<ElfTypes>::WriteDynamicSection() { - builder_->WriteDynamicSection(elf_file_->GetPath()); + if (bss_size_ != 0u) { + builder_->GetBss()->WriteNoBitsSection(bss_size_); + } + builder_->WriteDynamicSection(); } template <typename ElfTypes> void ElfWriterQuick<ElfTypes>::PrepareDebugInfo( - size_t rodata_section_size, - size_t text_section_size, const ArrayRef<const debug::MethodDebugInfo>& method_infos) { if (!method_infos.empty() && compiler_options_->GetGenerateMiniDebugInfo()) { // Prepare the mini-debug-info in background while we do other I/O. Thread* self = Thread::Current(); debug_info_task_ = std::unique_ptr<DebugInfoTask>( - new DebugInfoTask(builder_->GetIsa(), - rodata_section_size, - text_section_size, - method_infos)); + new DebugInfoTask(builder_->GetIsa(), rodata_size_, text_size_, method_infos)); debug_info_thread_pool_ = std::unique_ptr<ThreadPool>( new ThreadPool("Mini-debug-info writer", 1)); debug_info_thread_pool_->AddTask(self, debug_info_task_.get()); @@ -245,6 +254,11 @@ OutputStream* ElfWriterQuick<ElfTypes>::GetStream() { return builder_->GetStream(); } +template <typename ElfTypes> +size_t ElfWriterQuick<ElfTypes>::GetLoadedSize() { + return builder_->GetLoadedSize(); +} + // Explicit instantiations template class ElfWriterQuick<ElfTypes32>; template class ElfWriterQuick<ElfTypes64>; diff --git a/compiler/image_test.cc b/compiler/image_test.cc index 4920f9baa5..32f0a94c39 100644 --- a/compiler/image_test.cc +++ b/compiler/image_test.cc @@ -124,6 +124,10 @@ void ImageTest::TestWriteRead(ImageHeader::StorageMode storage_mode) { &opened_dex_files); ASSERT_TRUE(dex_files_ok); oat_writer.PrepareLayout(compiler_driver_.get(), writer.get(), dex_files); + 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()); + bool image_space_ok = writer->PrepareImageAddressSpace(); ASSERT_TRUE(image_space_ok); @@ -139,7 +143,6 @@ void ImageTest::TestWriteRead(ImageHeader::StorageMode storage_mode) { bool header_ok = oat_writer.WriteHeader(elf_writer->GetStream(), 0u, 0u, 0u); ASSERT_TRUE(header_ok); - elf_writer->SetBssSize(oat_writer.GetBssSize()); elf_writer->WriteDynamicSection(); elf_writer->WriteDebugInfo(oat_writer.GetMethodDebugInfo()); elf_writer->WritePatchLocations(oat_writer.GetAbsolutePatchLocations()); diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index 73574ba673..09046c7a3a 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -2274,25 +2274,18 @@ const ImageWriter::ImageInfo& ImageWriter::GetImageInfo(size_t index) const { return GetConstImageInfo(oat_filenames_[index]); } -void ImageWriter::UpdateOatFile(File* oat_file, const char* oat_filename) { - DCHECK(oat_file != nullptr); +void ImageWriter::UpdateOatFile(size_t index, size_t oat_loaded_size) { if (compile_app_image_) { CHECK_EQ(oat_filenames_.size(), 1u) << "App image should have no next image."; return; } - ImageInfo& cur_image_info = GetImageInfo(oat_filename); // Update the oat_offset of the next image info. - auto it = std::find(oat_filenames_.begin(), oat_filenames_.end(), oat_filename); - DCHECK(it != oat_filenames_.end()); - - it++; - if (it != oat_filenames_.end()) { - size_t oat_loaded_size = 0; - size_t oat_data_offset = 0; - ElfWriter::GetOatElfInformation(oat_file, &oat_loaded_size, &oat_data_offset); + DCHECK_LT(index, oat_filenames_.size()); + if (index + 1u != oat_filenames_.size()) { // There is a following one. - ImageInfo& next_image_info = GetImageInfo(*it); + ImageInfo& cur_image_info = GetImageInfo(oat_filenames_[index]); + ImageInfo& next_image_info = GetImageInfo(oat_filenames_[index + 1u]); next_image_info.oat_offset_ = cur_image_info.oat_offset_ + oat_loaded_size; } } diff --git a/compiler/image_writer.h b/compiler/image_writer.h index 9371d9ffa9..a4a252e389 100644 --- a/compiler/image_writer.h +++ b/compiler/image_writer.h @@ -123,7 +123,7 @@ class ImageWriter FINAL { // Update the oat size for the given oat file. This will make the oat_offset for the next oat // file valid. - void UpdateOatFile(File* oat_file, const char* oat_filename); + void UpdateOatFile(size_t index, size_t oat_loaded_size); private: bool AllocMemory(); diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc index 3fe786141e..c2b29eb01a 100644 --- a/compiler/jit/jit_compiler.cc +++ b/compiler/jit/jit_compiler.cc @@ -172,7 +172,6 @@ JitCompiler::JitCompiler() : total_time_(0) { /* dump_passes */ false, cumulative_logger_.get(), /* swap_fd */ -1, - /* dex to oat map */ nullptr, /* profile_compilation_info */ nullptr)); // Disable dedupe so we can remove compiled methods. compiler_driver_->SetDedupeEnabled(false); diff --git a/compiler/linker/relative_patcher_test.h b/compiler/linker/relative_patcher_test.h index bf8e786f64..8bff41c976 100644 --- a/compiler/linker/relative_patcher_test.h +++ b/compiler/linker/relative_patcher_test.h @@ -44,10 +44,22 @@ class RelativePatcherTest : public testing::Test { : compiler_options_(), verification_results_(&compiler_options_), inliner_map_(), - driver_(&compiler_options_, &verification_results_, &inliner_map_, - Compiler::kQuick, instruction_set, nullptr, - false, nullptr, nullptr, nullptr, 1u, - false, false, nullptr, -1, nullptr, nullptr), + driver_(&compiler_options_, + &verification_results_, + &inliner_map_, + Compiler::kQuick, + instruction_set, + /* instruction_set_features*/ nullptr, + /* boot_image */ false, + /* image_classes */ nullptr, + /* compiled_classes */ nullptr, + /* compiled_methods */ nullptr, + /* thread_count */ 1u, + /* dump_stats */ false, + /* dump_passes */ false, + /* timer */ nullptr, + /* swap_fd */ -1, + /* profile_compilation_info */ nullptr), error_msg_(), instruction_set_(instruction_set), features_(InstructionSetFeatures::FromVariant(instruction_set, variant, &error_msg_)), diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc index 894d29ee99..d03b4f1055 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -111,17 +111,16 @@ class OatTest : public CommonCompilerTest { compiler_kind, insn_set, insn_features_.get(), - false, - nullptr, - nullptr, - nullptr, - 2, - true, - true, + /* boot_image */ false, + /* image_classes */ nullptr, + /* compiled_classes */ nullptr, + /* compiled_methods */ nullptr, + /* thread_count */ 2, + /* dump_stats */ true, + /* dump_passes */ true, timer_.get(), - -1, - nullptr, - nullptr)); + /* swap_fd */ -1, + /* profile_compilation_info */ nullptr)); } bool WriteElf(File* file, @@ -201,6 +200,10 @@ class OatTest : public CommonCompilerTest { class_linker->RegisterDexFile(*dex_file, runtime->GetLinearAlloc()); } oat_writer.PrepareLayout(compiler_driver_.get(), nullptr, dex_files); + 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()); + if (!oat_writer.WriteRodata(rodata)) { return false; } @@ -216,7 +219,6 @@ class OatTest : public CommonCompilerTest { return false; } - elf_writer->SetBssSize(oat_writer.GetBssSize()); elf_writer->WriteDynamicSection(); elf_writer->WriteDebugInfo(oat_writer.GetMethodDebugInfo()); elf_writer->WritePatchLocations(oat_writer.GetAbsolutePatchLocations()); |