From 6065402316da2b51eed5fc34cffbd991766bd408 Mon Sep 17 00:00:00 2001 From: Vladimir Marko Date: Tue, 16 Feb 2016 12:50:23 +0000 Subject: 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 --- compiler/driver/compiler_driver.cc | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'compiler/driver/compiler_driver.cc') 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* image_classes, + bool boot_image, + std::unordered_set* image_classes, std::unordered_set* compiled_classes, std::unordered_set* compiled_methods, - size_t thread_count, bool dump_stats, bool dump_passes, - CumulativeLogger* timer, int swap_fd, - const std::unordered_map* 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(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; -- cgit v1.2.3-59-g8ed1b From 45724f9a0cc38dbb3071beb3eeab96499868b49c Mon Sep 17 00:00:00 2001 From: Vladimir Marko Date: Wed, 17 Feb 2016 17:46:10 +0000 Subject: Revert "Allow method references across oat files for multi-image." Breaks Quick tests. This reverts commit 6065402316da2b51eed5fc34cffbd991766bd408. Change-Id: I8a5469ba7cea5f46b85cb489b3e0ef06ed548f03 --- compiler/common_compiler_test.cc | 11 +- compiler/dex/quick/quick_cfi_test.cc | 21 +- compiler/dex/quick/x86/quick_assemble_x86_test.cc | 23 +- compiler/driver/compiled_method_storage_test.cc | 26 +- compiler/driver/compiler_driver.cc | 18 +- compiler/driver/compiler_driver.h | 25 +- compiler/elf_builder.h | 298 ++++++---------------- compiler/elf_writer.h | 9 +- compiler/elf_writer_quick.cc | 52 ++-- compiler/image_test.cc | 5 +- compiler/image_writer.cc | 17 +- compiler/image_writer.h | 2 +- compiler/jit/jit_compiler.cc | 1 + compiler/linker/relative_patcher_test.h | 20 +- compiler/oat_test.cc | 24 +- dex2oat/dex2oat.cc | 36 ++- oatdump/oatdump.cc | 4 +- 17 files changed, 217 insertions(+), 375 deletions(-) (limited to 'compiler/driver/compiler_driver.cc') diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc index 239bc590e9..e4bfac9ee7 100644 --- a/compiler/common_compiler_test.cc +++ b/compiler/common_compiler_test.cc @@ -194,15 +194,16 @@ void CommonCompilerTest::CreateCompilerDriver(Compiler::Kind kind, InstructionSe kind, isa, instruction_set_features_.get(), - /* boot_image */ true, + true, GetImageClasses(), GetCompiledClasses(), GetCompiledMethods(), - /* thread_count */ 2, - /* dump_stats */ true, - /* dump_passes */ true, + 2, + true, + true, timer_.get(), - /* swap_fd */ -1, + -1, + /* dex_to_oat_map */ nullptr, 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 6c6c9cfb1e..0cd41bbf4c 100644 --- a/compiler/dex/quick/quick_cfi_test.cc +++ b/compiler/dex/quick/quick_cfi_test.cc @@ -84,16 +84,17 @@ class QuickCFITest : public CFITest { Compiler::kQuick, isa, isa_features.get(), - /* 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); + false, + nullptr, + nullptr, + nullptr, + 0, + false, + false, + 0, + -1, + nullptr, + 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 ff0ecea94c..efdc333261 100644 --- a/compiler/dex/quick/x86/quick_assemble_x86_test.cc +++ b/compiler/dex/quick/x86/quick_assemble_x86_test.cc @@ -64,17 +64,18 @@ class QuickAssembleX86TestBase : public testing::Test { method_inliner_map_.get(), Compiler::kQuick, isa_, - /* 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)); + nullptr, + false, + nullptr, + nullptr, + nullptr, + 0, + false, + false, + 0, + -1, + nullptr, + nullptr)); cu_.reset(new CompilationUnit(pool_.get(), isa_, compiler_driver_.get(), nullptr)); DexFile::CodeItem* code_item = static_cast( 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 0695cb56b3..2e2d1f99f3 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, - /* 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); + Compiler::kOptimizing, kNone, + nullptr, + false, + nullptr, + nullptr, + nullptr, + 1u, + false, + false, + nullptr, + -1, + nullptr, + 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 e80730fe11..670fe94988 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -342,15 +342,12 @@ CompilerDriver::CompilerDriver( Compiler::Kind compiler_kind, InstructionSet instruction_set, const InstructionSetFeatures* instruction_set_features, - bool boot_image, - std::unordered_set* image_classes, + bool boot_image, std::unordered_set* image_classes, std::unordered_set* compiled_classes, std::unordered_set* compiled_methods, - size_t thread_count, - bool dump_stats, - bool dump_passes, - CumulativeLogger* timer, - int swap_fd, + size_t thread_count, bool dump_stats, bool dump_passes, + CumulativeLogger* timer, int swap_fd, + const std::unordered_map* dex_to_oat_map, const ProfileCompilationInfo* profile_compilation_info) : compiler_options_(compiler_options), verification_results_(verification_results), @@ -377,6 +374,7 @@ 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); @@ -1680,6 +1678,12 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType use_dex_cache = true; } } + if (!use_dex_cache && IsBootImage()) { + if (!AreInSameOatFile(&(const_cast(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 ca340ee92c..5e35cbb309 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -94,11 +94,9 @@ class CompilerDriver { bool boot_image, std::unordered_set* image_classes, std::unordered_set* compiled_classes, std::unordered_set* compiled_methods, - size_t thread_count, - bool dump_stats, - bool dump_passes, - CumulativeLogger* timer, - int swap_fd, + size_t thread_count, bool dump_stats, bool dump_passes, + CumulativeLogger* timer, int swap_fd, + const std::unordered_map* dex_to_oat_map, const ProfileCompilationInfo* profile_compilation_info); ~CompilerDriver(); @@ -115,6 +113,20 @@ class CompilerDriver { : ArrayRef(); } + // 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& dex_files, TimingLogger* timings) @@ -688,6 +700,9 @@ class CompilerDriver { // List of dex files that will be stored in the oat file. const std::vector* dex_files_for_oat_file_; + // Map from dex files to the oat file (name) they will be compiled into. + const std::unordered_map* 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 f7da609e5d..b673eeb3b6 100644 --- a/compiler/elf_builder.h +++ b/compiler/elf_builder.h @@ -86,24 +86,12 @@ class ElfBuilder FINAL { // Base class of all sections. class Section : public OutputStream { public: - Section(ElfBuilder* 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* 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; @@ -240,84 +228,12 @@ class ElfBuilder FINAL { DISALLOW_COPY_AND_ASSIGN(Section); }; - class CachedSection : public Section { - public: - CachedSection(ElfBuilder* 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(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 cache_; - }; - - // Writer of .dynstr section. - class CachedStringSection FINAL : public CachedSection { - public: - CachedStringSection(ElfBuilder* 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. + // Writer of .dynstr .strtab and .shstrtab sections. class StringSection FINAL : public Section { public: - StringSection(ElfBuilder* owner, - const std::string& name, - Elf_Word flags, - Elf_Word align) - : Section(owner, - name, - SHT_STRTAB, - flags, - /* link */ nullptr, - /* info */ 0, - align, - /* entsize */ 0), + StringSection(ElfBuilder* owner, const std::string& name, + Elf_Word flags, Elf_Word align) + : Section(owner, name, SHT_STRTAB, flags, nullptr, 0, align, 0), current_offset_(0) { } @@ -336,60 +252,42 @@ class ElfBuilder FINAL { }; // Writer of .dynsym and .symtab sections. - class SymbolSection FINAL : public CachedSection { + class SymbolSection FINAL : public Section { public: - SymbolSection(ElfBuilder* 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)); + SymbolSection(ElfBuilder* 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)) { } // 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) { - 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(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) { + 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) { Elf_Sym sym = Elf_Sym(); sym.st_name = name; - sym.st_value = addr; + sym.st_value = addr + (is_relative ? section->GetAddress() : 0); sym.st_size = size; sym.st_other = other; - sym.st_shndx = section_index; + sym.st_shndx = (section != nullptr ? section->GetSectionIndex() + : static_cast(SHN_ABS)); sym.st_info = (binding << 4) + (type & 0xf); - CachedSection::Add(&sym, sizeof(sym)); + 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(); } + + private: + std::vector symbols_; }; ElfBuilder(InstructionSet isa, OutputStream* output) @@ -411,8 +309,6 @@ 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; @@ -484,14 +380,6 @@ 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(""); @@ -546,58 +434,45 @@ 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 PrepareDynamicSection(const std::string& elf_file_path, - Elf_Word rodata_size, - Elf_Word text_size, - Elf_Word bss_size) { + void WriteDynamicSection(const std::string& elf_file_path) { 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); } - // Calculate addresses of .text, .bss and .dynstr. - DCHECK_EQ(rodata_.header_.sh_addralign, static_cast(kPageSize)); - DCHECK_EQ(text_.header_.sh_addralign, static_cast(kPageSize)); - DCHECK_EQ(bss_.header_.sh_addralign, static_cast(kPageSize)); - DCHECK_EQ(dynstr_.header_.sh_addralign, static_cast(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) { + 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) { // rodata_ can be size 0 for dwarf_test. - 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); + dynsym_.Add(dynstr_.Write("oatlastword"), &rodata_, rodata_.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); + 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); } - Elf_Word soname_offset = dynstr_.Add(soname); + Elf_Word soname_offset = dynstr_.Write(soname); + dynstr_.End(); + + dynsym_.Start(); + dynsym_.Write(); + dynsym_.End(); // 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. - int count = dynsym_.GetCacheSize() / sizeof(Elf_Sym); // Includes NULL. + hash_.Start(); + int count = dynsym_.GetSize() / sizeof(Elf_Sym); // Includes NULL. std::vector hash; hash.push_back(1); // Number of buckets. hash.push_back(count); // Number of chains. @@ -609,44 +484,21 @@ 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_.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(kPageSize)); - Elf_Word dynamic_address = RoundUp(hash_address + dynsym_.GetCacheSize(), kPageSize); + hash_.WriteFully(hash.data(), hash.size() * sizeof(hash[0])); + hash_.End(); + dynamic_.Start(); Elf_Dyn dyns[] = { - { DT_HASH, { hash_address } }, - { DT_STRTAB, { dynstr_address } }, - { DT_SYMTAB, { dynsym_address } }, + { DT_HASH, { hash_.GetAddress() } }, + { DT_STRTAB, { dynstr_.GetAddress() } }, + { DT_SYMTAB, { dynsym_.GetAddress() } }, { DT_SYMENT, { sizeof(Elf_Sym) } }, - { DT_STRSZ, { dynstr_.GetCacheSize() } }, + { DT_STRSZ, { dynstr_.GetSize() } }, { DT_SONAME, { soname_offset } }, { DT_NULL, { 0 } }, }; - 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_; + dynamic_.WriteFully(&dyns, sizeof(dyns)); + dynamic_.End(); } // Returns true if all writes and seeks on the output stream succeeded. @@ -824,10 +676,10 @@ class ElfBuilder FINAL { Section rodata_; Section text_; Section bss_; - CachedStringSection dynstr_; + StringSection dynstr_; SymbolSection dynsym_; - CachedSection hash_; - CachedSection dynamic_; + Section hash_; + Section dynamic_; Section eh_frame_; Section eh_frame_hdr_; StringSection strtab_; @@ -842,14 +694,12 @@ class ElfBuilder FINAL { std::vector 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 c9ea0083d5..d50a08cb20 100644 --- a/compiler/elf_writer.h +++ b/compiler/elf_writer.h @@ -52,12 +52,14 @@ class ElfWriter { virtual ~ElfWriter() {} virtual void Start() = 0; - virtual void SetLoadedSectionSizes(size_t rodata_size, size_t text_size, size_t bss_size) = 0; - virtual void PrepareDebugInfo(const ArrayRef& method_infos) = 0; + virtual void PrepareDebugInfo(size_t rodata_section_size, + size_t text_section_size, + const ArrayRef& 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& method_infos) = 0; virtual void WritePatchLocations(const ArrayRef& patch_locations) = 0; @@ -68,9 +70,6 @@ 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 19346ecc2b..1d71e572d7 100644 --- a/compiler/elf_writer_quick.cc +++ b/compiler/elf_writer_quick.cc @@ -88,12 +88,14 @@ class ElfWriterQuick FINAL : public ElfWriter { ~ElfWriterQuick(); void Start() OVERRIDE; - void SetLoadedSectionSizes(size_t rodata_size, size_t text_size, size_t bss_size) OVERRIDE; - void PrepareDebugInfo(const ArrayRef& method_infos) OVERRIDE; + void PrepareDebugInfo(size_t rodata_section_size, + size_t text_section_size, + const ArrayRef& 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& method_infos) OVERRIDE; void WritePatchLocations(const ArrayRef& patch_locations) OVERRIDE; @@ -101,17 +103,12 @@ class ElfWriterQuick FINAL : public ElfWriter { virtual OutputStream* GetStream() OVERRIDE; - size_t GetLoadedSize() OVERRIDE; - static void EncodeOatPatches(const std::vector& locations, std::vector* 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 output_stream_; std::unique_ptr> builder_; std::unique_ptr debug_info_task_; @@ -137,9 +134,6 @@ ElfWriterQuick::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(MakeUnique(elf_file))), builder_(new ElfBuilder(instruction_set, output_stream_.get())) {} @@ -151,19 +145,6 @@ void ElfWriterQuick::Start() { builder_->Start(); } -template -void ElfWriterQuick::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 OutputStream* ElfWriterQuick::StartRoData() { auto* rodata = builder_->GetRoData(); @@ -191,21 +172,31 @@ void ElfWriterQuick::EndText(OutputStream* text) { } template -void ElfWriterQuick::WriteDynamicSection() { - if (bss_size_ != 0u) { - builder_->GetBss()->WriteNoBitsSection(bss_size_); +void ElfWriterQuick::SetBssSize(size_t bss_size) { + auto* bss = builder_->GetBss(); + if (bss_size != 0u) { + bss->WriteNoBitsSection(bss_size); } - builder_->WriteDynamicSection(); +} + +template +void ElfWriterQuick::WriteDynamicSection() { + builder_->WriteDynamicSection(elf_file_->GetPath()); } template void ElfWriterQuick::PrepareDebugInfo( + size_t rodata_section_size, + size_t text_section_size, const ArrayRef& 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( - new DebugInfoTask(builder_->GetIsa(), rodata_size_, text_size_, method_infos)); + new DebugInfoTask(builder_->GetIsa(), + rodata_section_size, + text_section_size, + method_infos)); debug_info_thread_pool_ = std::unique_ptr( new ThreadPool("Mini-debug-info writer", 1)); debug_info_thread_pool_->AddTask(self, debug_info_task_.get()); @@ -254,11 +245,6 @@ OutputStream* ElfWriterQuick::GetStream() { return builder_->GetStream(); } -template -size_t ElfWriterQuick::GetLoadedSize() { - return builder_->GetLoadedSize(); -} - // Explicit instantiations template class ElfWriterQuick; template class ElfWriterQuick; diff --git a/compiler/image_test.cc b/compiler/image_test.cc index 32f0a94c39..4920f9baa5 100644 --- a/compiler/image_test.cc +++ b/compiler/image_test.cc @@ -124,10 +124,6 @@ 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); @@ -143,6 +139,7 @@ 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 09046c7a3a..73574ba673 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -2274,18 +2274,25 @@ const ImageWriter::ImageInfo& ImageWriter::GetImageInfo(size_t index) const { return GetConstImageInfo(oat_filenames_[index]); } -void ImageWriter::UpdateOatFile(size_t index, size_t oat_loaded_size) { +void ImageWriter::UpdateOatFile(File* oat_file, const char* oat_filename) { + DCHECK(oat_file != nullptr); 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. - DCHECK_LT(index, oat_filenames_.size()); - if (index + 1u != oat_filenames_.size()) { + 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); // There is a following one. - ImageInfo& cur_image_info = GetImageInfo(oat_filenames_[index]); - ImageInfo& next_image_info = GetImageInfo(oat_filenames_[index + 1u]); + ImageInfo& next_image_info = GetImageInfo(*it); 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 a4a252e389..9371d9ffa9 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(size_t index, size_t oat_loaded_size); + void UpdateOatFile(File* oat_file, const char* oat_filename); private: bool AllocMemory(); diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc index c2b29eb01a..3fe786141e 100644 --- a/compiler/jit/jit_compiler.cc +++ b/compiler/jit/jit_compiler.cc @@ -172,6 +172,7 @@ 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 8bff41c976..bf8e786f64 100644 --- a/compiler/linker/relative_patcher_test.h +++ b/compiler/linker/relative_patcher_test.h @@ -44,22 +44,10 @@ class RelativePatcherTest : public testing::Test { : compiler_options_(), verification_results_(&compiler_options_), inliner_map_(), - 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), + driver_(&compiler_options_, &verification_results_, &inliner_map_, + Compiler::kQuick, instruction_set, nullptr, + false, nullptr, nullptr, nullptr, 1u, + false, false, nullptr, -1, nullptr, 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 d03b4f1055..894d29ee99 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -111,16 +111,17 @@ class OatTest : public CommonCompilerTest { compiler_kind, insn_set, insn_features_.get(), - /* boot_image */ false, - /* image_classes */ nullptr, - /* compiled_classes */ nullptr, - /* compiled_methods */ nullptr, - /* thread_count */ 2, - /* dump_stats */ true, - /* dump_passes */ true, + false, + nullptr, + nullptr, + nullptr, + 2, + true, + true, timer_.get(), - /* swap_fd */ -1, - /* profile_compilation_info */ nullptr)); + -1, + nullptr, + nullptr)); } bool WriteElf(File* file, @@ -200,10 +201,6 @@ 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; } @@ -219,6 +216,7 @@ 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()); diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 782926827a..541fb5a423 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -1557,12 +1557,13 @@ class Dex2Oat FINAL { IsBootImage(), image_classes_.release(), compiled_classes_.release(), - /* compiled_methods */ nullptr, + nullptr, thread_count_, dump_stats_, dump_passes_, compiler_phases_timings_.get(), swap_fd_, + &dex_file_oat_filename_map_, profile_compilation_info_.get())); driver_->SetDexFilesForOatFile(dex_files_); driver_->CompileAll(class_loader_, dex_files_, timings_); @@ -1679,33 +1680,18 @@ class Dex2Oat FINAL { { TimingLogger::ScopedTiming t2("dex2oat Write ELF", timings_); for (size_t i = 0, size = oat_files_.size(); i != size; ++i) { + std::unique_ptr& oat_file = oat_files_[i]; std::unique_ptr& elf_writer = elf_writers_[i]; std::unique_ptr& oat_writer = oat_writers_[i]; std::vector& dex_files = dex_files_per_oat_file_[i]; oat_writer->PrepareLayout(driver_.get(), image_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()); - - if (IsImage()) { - // Update oat estimates. - DCHECK(image_writer_ != nullptr); - DCHECK_LT(i, oat_filenames_.size()); - - image_writer_->UpdateOatFile(i, elf_writer->GetLoadedSize()); - } - } - - for (size_t i = 0, size = oat_files_.size(); i != size; ++i) { - std::unique_ptr& oat_file = oat_files_[i]; - std::unique_ptr& elf_writer = elf_writers_[i]; - std::unique_ptr& oat_writer = oat_writers_[i]; - // We need to mirror the layout of the ELF file in the compressed debug-info. // Therefore we need to propagate the sizes of at least those sections. - elf_writer->PrepareDebugInfo(oat_writer->GetMethodDebugInfo()); + size_t rodata_size = oat_writer->GetOatHeader().GetExecutableOffset(); + size_t text_size = oat_writer->GetSize() - rodata_size; + elf_writer->PrepareDebugInfo(rodata_size, text_size, oat_writer->GetMethodDebugInfo()); OutputStream*& rodata = rodata_[i]; DCHECK(rodata != nullptr); @@ -1731,6 +1717,7 @@ class Dex2Oat FINAL { return false; } + elf_writer->SetBssSize(oat_writer->GetBssSize()); elf_writer->WriteDynamicSection(); elf_writer->WriteDebugInfo(oat_writer->GetMethodDebugInfo()); elf_writer->WritePatchLocations(oat_writer->GetAbsolutePatchLocations()); @@ -1744,10 +1731,19 @@ class Dex2Oat FINAL { if (oat_files_[i] != nullptr) { if (oat_files_[i]->Flush() != 0) { PLOG(ERROR) << "Failed to flush oat file: " << oat_filenames_[i]; + oat_files_[i]->Erase(); return false; } } + if (IsImage()) { + // Update oat estimates. + DCHECK(image_writer_ != nullptr); + DCHECK_LT(i, oat_filenames_.size()); + + image_writer_->UpdateOatFile(oat_file.get(), oat_filenames_[i]); + } + VLOG(compiler) << "Oat file written successfully: " << oat_filenames_[i]; oat_writer.reset(); diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index e30b968a96..af08fc4e93 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -145,9 +145,7 @@ class OatSymbolizer FINAL { bss->WriteNoBitsSection(oat_file_->BssSize()); } - builder_->PrepareDynamicSection( - elf_file->GetPath(), rodata_size, text_size, oat_file_->BssSize()); - builder_->WriteDynamicSection(); + builder_->WriteDynamicSection(elf_file->GetPath()); Walk(&art::OatSymbolizer::RegisterForDedup); -- cgit v1.2.3-59-g8ed1b From 5b82d339955d1a0dc23eeb8d2d5659459ff987ba Mon Sep 17 00:00:00 2001 From: Nicolas Geoffray Date: Thu, 18 Feb 2016 14:22:32 +0000 Subject: The JIT does not need VerifedMethod nor CompilerCallbacks. bug:27173201 Change-Id: I971659f9ff6a8b780c94a7bed84de90fa9fc3456 --- compiler/driver/compiler_driver.cc | 1 - compiler/driver/compiler_driver.h | 1 + compiler/jit/jit_compiler.cc | 17 ++--------------- compiler/optimizing/inliner.cc | 25 +++++++++++++------------ compiler/optimizing/optimizing_compiler.cc | 2 +- runtime/jit/jit.cc | 13 ++----------- runtime/jit/jit.h | 7 +------ runtime/runtime.cc | 1 - 8 files changed, 20 insertions(+), 47 deletions(-) (limited to 'compiler/driver/compiler_driver.cc') diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 670fe94988..a51dd3209b 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -378,7 +378,6 @@ CompilerDriver::CompilerDriver( compiled_method_storage_(swap_fd), profile_compilation_info_(profile_compilation_info) { DCHECK(compiler_options_ != nullptr); - DCHECK(verification_results_ != nullptr); DCHECK(method_inliner_map_ != nullptr); compiler_->Init(); diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 5e35cbb309..d8f23f7a73 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -138,6 +138,7 @@ class CompilerDriver { REQUIRES(!compiled_methods_lock_, !compiled_classes_lock_); VerificationResults* GetVerificationResults() const { + DCHECK(Runtime::Current()->IsAotCompiler()); return verification_results_; } diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc index 3fe786141e..909d6822a8 100644 --- a/compiler/jit/jit_compiler.cc +++ b/compiler/jit/jit_compiler.cc @@ -23,10 +23,7 @@ #include "base/time_utils.h" #include "base/timing_logger.h" #include "base/unix_file/fd_file.h" -#include "compiler_callbacks.h" #include "debug/elf_debug_writer.h" -#include "dex/pass_manager.h" -#include "dex/quick_compiler_callbacks.h" #include "driver/compiler_driver.h" #include "driver/compiler_options.h" #include "jit/debugger_interface.h" @@ -36,7 +33,6 @@ #include "oat_quick_method_header.h" #include "object_lock.h" #include "thread_list.h" -#include "verifier/method_verifier-inl.h" namespace art { namespace jit { @@ -45,11 +41,10 @@ JitCompiler* JitCompiler::Create() { return new JitCompiler(); } -extern "C" void* jit_load(CompilerCallbacks** callbacks, bool* generate_debug_info) { +extern "C" void* jit_load(bool* generate_debug_info) { VLOG(jit) << "loading jit compiler"; auto* const jit_compiler = JitCompiler::Create(); CHECK(jit_compiler != nullptr); - *callbacks = jit_compiler->GetCompilerCallbacks(); *generate_debug_info = jit_compiler->GetCompilerOptions()->GetGenerateDebugInfo(); VLOG(jit) << "Done loading jit compiler"; return jit_compiler; @@ -151,14 +146,10 @@ JitCompiler::JitCompiler() : total_time_(0) { instruction_set_features_.reset(InstructionSetFeatures::FromCppDefines()); } cumulative_logger_.reset(new CumulativeLogger("jit times")); - verification_results_.reset(new VerificationResults(compiler_options_.get())); method_inliner_map_.reset(new DexFileToMethodInlinerMap); - callbacks_.reset(new QuickCompilerCallbacks(verification_results_.get(), - method_inliner_map_.get(), - CompilerCallbacks::CallbackMode::kCompileApp)); compiler_driver_.reset(new CompilerDriver( compiler_options_.get(), - verification_results_.get(), + /* verification_results */ nullptr, method_inliner_map_.get(), Compiler::kOptimizing, instruction_set, @@ -251,9 +242,5 @@ bool JitCompiler::CompileMethod(Thread* self, ArtMethod* method, bool osr) { return success; } -CompilerCallbacks* JitCompiler::GetCompilerCallbacks() const { - return callbacks_.get(); -} - } // namespace jit } // namespace art diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index a5acab81ab..d8e6903087 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -557,8 +557,9 @@ bool HInliner::TryBuildAndInline(HInvoke* invoke_instruction, if (!method->GetDeclaringClass()->IsVerified()) { uint16_t class_def_idx = method->GetDeclaringClass()->GetDexClassDefIndex(); - if (!compiler_driver_->IsMethodVerifiedWithoutFailures( - method->GetDexMethodIndex(), class_def_idx, *method->GetDexFile())) { + if (Runtime::Current()->UseJit() || + !compiler_driver_->IsMethodVerifiedWithoutFailures( + method->GetDexMethodIndex(), class_def_idx, *method->GetDexFile())) { VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file) << " couldn't be verified, so it cannot be inlined"; return false; @@ -781,16 +782,16 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker(); Handle dex_cache(handles_->NewHandle(resolved_method->GetDexCache())); DexCompilationUnit dex_compilation_unit( - nullptr, - caller_compilation_unit_.GetClassLoader(), - class_linker, - callee_dex_file, - code_item, - resolved_method->GetDeclaringClass()->GetDexClassDefIndex(), - method_index, - resolved_method->GetAccessFlags(), - compiler_driver_->GetVerifiedMethod(&callee_dex_file, method_index), - dex_cache); + nullptr, + caller_compilation_unit_.GetClassLoader(), + class_linker, + callee_dex_file, + code_item, + resolved_method->GetDeclaringClass()->GetDexClassDefIndex(), + method_index, + resolved_method->GetAccessFlags(), + /* verified_method */ nullptr, + dex_cache); bool requires_ctor_barrier = false; diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 12b748b7b6..b83957f213 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -651,7 +651,7 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* arena, DexCompilationUnit dex_compilation_unit( nullptr, class_loader, Runtime::Current()->GetClassLinker(), dex_file, code_item, class_def_idx, method_idx, access_flags, - compiler_driver->GetVerifiedMethod(&dex_file, method_idx), dex_cache); + nullptr, dex_cache); bool requires_barrier = dex_compilation_unit.IsConstructor() && compiler_driver->RequiresConstructorBarrier(Thread::Current(), diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc index 8d3da37762..bdc7ee2428 100644 --- a/runtime/jit/jit.cc +++ b/runtime/jit/jit.cc @@ -113,8 +113,7 @@ bool Jit::LoadCompiler(std::string* error_msg) { *error_msg = oss.str(); return false; } - jit_load_ = reinterpret_cast( - dlsym(jit_library_handle_, "jit_load")); + jit_load_ = reinterpret_cast(dlsym(jit_library_handle_, "jit_load")); if (jit_load_ == nullptr) { dlclose(jit_library_handle_); *error_msg = "JIT couldn't find jit_load entry point"; @@ -141,23 +140,15 @@ bool Jit::LoadCompiler(std::string* error_msg) { *error_msg = "JIT couldn't find jit_types_loaded entry point"; return false; } - CompilerCallbacks* callbacks = nullptr; bool will_generate_debug_symbols = false; VLOG(jit) << "Calling JitLoad interpreter_only=" << Runtime::Current()->GetInstrumentation()->InterpretOnly(); - jit_compiler_handle_ = (jit_load_)(&callbacks, &will_generate_debug_symbols); + jit_compiler_handle_ = (jit_load_)(&will_generate_debug_symbols); if (jit_compiler_handle_ == nullptr) { dlclose(jit_library_handle_); *error_msg = "JIT couldn't load compiler"; return false; } - if (callbacks == nullptr) { - dlclose(jit_library_handle_); - *error_msg = "JIT compiler callbacks were not set"; - jit_compiler_handle_ = nullptr; - return false; - } - compiler_callbacks_ = callbacks; generate_debug_info_ = will_generate_debug_symbols; return true; } diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h index 042da92b3b..109ca3dbd1 100644 --- a/runtime/jit/jit.h +++ b/runtime/jit/jit.h @@ -32,7 +32,6 @@ namespace art { class ArtMethod; -class CompilerCallbacks; struct RuntimeArgumentMap; namespace jit { @@ -55,9 +54,6 @@ class Jit { size_t warmup_threshold, size_t osr_threshold); void CreateThreadPool(); - CompilerCallbacks* GetCompilerCallbacks() { - return compiler_callbacks_; - } const JitCodeCache* GetCodeCache() const { return code_cache_.get(); } @@ -108,7 +104,7 @@ class Jit { // JIT compiler void* jit_library_handle_; void* jit_compiler_handle_; - void* (*jit_load_)(CompilerCallbacks**, bool*); + void* (*jit_load_)(bool*); void (*jit_unload_)(void*); bool (*jit_compile_method_)(void*, ArtMethod*, Thread*, bool); void (*jit_types_loaded_)(void*, mirror::Class**, size_t count); @@ -119,7 +115,6 @@ class Jit { std::unique_ptr instrumentation_cache_; std::unique_ptr code_cache_; - CompilerCallbacks* compiler_callbacks_; // Owned by the jit compiler. bool save_profiling_info_; bool generate_debug_info_; diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 2aeb7921ce..861bd85283 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -1887,7 +1887,6 @@ void Runtime::CreateJit() { std::string error_msg; jit_.reset(jit::Jit::Create(jit_options_.get(), &error_msg)); if (jit_.get() != nullptr) { - compiler_callbacks_ = jit_->GetCompilerCallbacks(); jit_->CreateInstrumentationCache(jit_options_->GetCompileThreshold(), jit_options_->GetWarmupThreshold(), jit_options_->GetOsrThreshold()); -- cgit v1.2.3-59-g8ed1b From ca76a1a0c1737b3e04961ba382c113102fdc00bf Mon Sep 17 00:00:00 2001 From: Jean-Philippe Halimi Date: Tue, 2 Feb 2016 19:48:52 +0100 Subject: Dex-wide ArenaPool scoping for AOT compilation The Arena Pool is a structure that holds memory allocated by the Arena Allocator, preventing system allocations and deallocations to occur too often during AOT compilation. Currently, the Arena Pool holds memory it allocates during the whole AOT compilation process. Unfortunately, such a behavior generates memory usage overhead, which is exacerbated by bigger applications such as Facebook. In this particular app, method size imbalance provokes unnecessary memory pressure, as one method might require a lot of arena allocations that won't be used in the remaining compilation. Because the compiler memory footprint keeps increasing during AOT compilation, the memory pressure becomes very high. The proposed patch is an attempt to find a tradeoff between allocations / deallocations time overhead, and the aforementioned memory pressure overhead resulting of the allocations being held by the Arena Pool. The patch adds a feature freeing up all memory allocated in the Arena Pool after each dex file is done compiling. We have measured no significant AOT compile-time overhead with the patch (<0.3%), because the selected dex-file granularity is coarse enough. In the meantime, it provides significant memory footprint improvements. The impact is especially big with Facebook, because this app has a few methods generating huge memory footprint peaks (peak native heap footprint goes down 34%). Change-Id: I27e867e6a20b8a6c28a82cb83140941a8c2b5847 Signed-off-by: Jean-Philippe Halimi --- compiler/driver/compiler_driver.cc | 1 + runtime/base/arena_allocator.cc | 9 +++++++++ runtime/base/arena_allocator.h | 2 ++ runtime/runtime.cc | 4 ++++ runtime/runtime.h | 3 +++ 5 files changed, 19 insertions(+) (limited to 'compiler/driver/compiler_driver.cc') diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 670fe94988..f5d7019260 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -2493,6 +2493,7 @@ void CompilerDriver::Compile(jobject class_loader, parallel_thread_pool_.get(), parallel_thread_count_, timings); + Runtime::Current()->ReclaimArenaPoolMemory(); } VLOG(compiler) << "Compile: " << GetMemoryUsageString(false); } diff --git a/runtime/base/arena_allocator.cc b/runtime/base/arena_allocator.cc index 771b2d0509..a4b38ea963 100644 --- a/runtime/base/arena_allocator.cc +++ b/runtime/base/arena_allocator.cc @@ -222,6 +222,10 @@ ArenaPool::ArenaPool(bool use_malloc, bool low_4gb) } ArenaPool::~ArenaPool() { + ReclaimMemory(); +} + +void ArenaPool::ReclaimMemory() { while (free_arenas_ != nullptr) { auto* arena = free_arenas_; free_arenas_ = free_arenas_->next_; @@ -229,6 +233,11 @@ ArenaPool::~ArenaPool() { } } +void ArenaPool::LockReclaimMemory() { + MutexLock lock(Thread::Current(), lock_); + ReclaimMemory(); +} + Arena* ArenaPool::AllocArena(size_t size) { Thread* self = Thread::Current(); Arena* ret = nullptr; diff --git a/runtime/base/arena_allocator.h b/runtime/base/arena_allocator.h index 36334c4129..8a96571e99 100644 --- a/runtime/base/arena_allocator.h +++ b/runtime/base/arena_allocator.h @@ -276,6 +276,8 @@ class ArenaPool { Arena* AllocArena(size_t size) REQUIRES(!lock_); void FreeArenaChain(Arena* first) REQUIRES(!lock_); size_t GetBytesAllocated() const REQUIRES(!lock_); + void ReclaimMemory() NO_THREAD_SAFETY_ANALYSIS; + void LockReclaimMemory() REQUIRES(!lock_); // Trim the maps in arenas by madvising, used by JIT to reduce memory usage. This only works // use_malloc is false. void TrimMaps() REQUIRES(!lock_); diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 2aeb7921ce..6c30eaa60e 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -1300,6 +1300,10 @@ void Runtime::InitNativeMethods() { VLOG(startup) << "Runtime::InitNativeMethods exiting"; } +void Runtime::ReclaimArenaPoolMemory() { + arena_pool_->LockReclaimMemory(); +} + void Runtime::InitThreadGroups(Thread* self) { JNIEnvExt* env = self->GetJniEnv(); ScopedJniEnvLocalRefState env_state(env); diff --git a/runtime/runtime.h b/runtime/runtime.h index cbb3e89444..8aac4ce9b4 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -564,6 +564,9 @@ class Runtime { const ArenaPool* GetArenaPool() const { return arena_pool_.get(); } + + void ReclaimArenaPoolMemory(); + LinearAlloc* GetLinearAlloc() { return linear_alloc_.get(); } -- cgit v1.2.3-59-g8ed1b