diff options
Diffstat (limited to 'src/compiler_llvm')
-rw-r--r-- | src/compiler_llvm/compilation_unit.cc | 247 | ||||
-rw-r--r-- | src/compiler_llvm/compilation_unit.h | 75 | ||||
-rw-r--r-- | src/compiler_llvm/compiler_llvm.cc | 216 | ||||
-rw-r--r-- | src/compiler_llvm/compiler_llvm.h | 47 | ||||
-rw-r--r-- | src/compiler_llvm/elf_loader.cc | 134 | ||||
-rw-r--r-- | src/compiler_llvm/elf_loader.h | 61 | ||||
-rw-r--r-- | src/compiler_llvm/jni_compiler.cc | 21 | ||||
-rw-r--r-- | src/compiler_llvm/method_compiler.cc | 21 | ||||
-rw-r--r-- | src/compiler_llvm/stub_compiler.cc | 22 | ||||
-rw-r--r-- | src/compiler_llvm/utils_llvm.h | 4 |
10 files changed, 242 insertions, 606 deletions
diff --git a/src/compiler_llvm/compilation_unit.cc b/src/compiler_llvm/compilation_unit.cc index 38faf618cf..fdbf575c0f 100644 --- a/src/compiler_llvm/compilation_unit.cc +++ b/src/compiler_llvm/compilation_unit.cc @@ -17,6 +17,7 @@ #include "compilation_unit.h" #include "compiled_method.h" +#include "compiler_llvm.h" #include "file.h" #include "instruction_set.h" #include "ir_builder.h" @@ -47,8 +48,10 @@ #include <llvm/DerivedTypes.h> #include <llvm/LLVMContext.h> #include <llvm/Module.h> +#include <llvm/Object/ObjectFile.h> #include <llvm/PassManager.h> #include <llvm/Support/Debug.h> +#include <llvm/Support/ELF.h> #include <llvm/Support/FormattedStream.h> #include <llvm/Support/ManagedStatic.h> #include <llvm/Support/MemoryBuffer.h> @@ -77,37 +80,6 @@ namespace { -class UpdateFrameSizePass : public llvm::MachineFunctionPass { - public: - static char ID; - - UpdateFrameSizePass() : llvm::MachineFunctionPass(ID), cunit_(NULL) { - LOG(FATAL) << "Unexpected instantiation of UpdateFrameSizePass"; - // NOTE: We have to declare this constructor for llvm::RegisterPass, but - // this constructor won't work because we have no information on - // CompilationUnit. Thus, we should place a LOG(FATAL) here. - } - - UpdateFrameSizePass(art::compiler_llvm::CompilationUnit* cunit) - : llvm::MachineFunctionPass(ID), cunit_(cunit) { - } - - virtual bool runOnMachineFunction(llvm::MachineFunction &MF) { - cunit_->UpdateFrameSizeInBytes(MF.getFunction(), - MF.getFrameInfo()->getStackSize()); - return false; - } - - private: - art::compiler_llvm::CompilationUnit* cunit_; -}; - -char UpdateFrameSizePass::ID = 0; - -llvm::RegisterPass<UpdateFrameSizePass> reg_update_frame_size_pass_( - "update-frame-size", "Update frame size pass", false, false); - - // TODO: We may need something to manage these passes. // TODO: We need high-level IR to analysis and do this at the IRBuilder level. class AddSuspendCheckToLoopLatchPass : public llvm::LoopPass { @@ -167,10 +139,10 @@ namespace compiler_llvm { llvm::Module* makeLLVMModuleContents(llvm::Module* module); -CompilationUnit::CompilationUnit(InstructionSet insn_set, size_t elf_idx) -: cunit_lock_("compilation_unit_lock"), insn_set_(insn_set), elf_idx_(elf_idx), - context_(new llvm::LLVMContext()), compiled_methods_map_(new CompiledMethodMap()), - mem_usage_(0), num_elf_funcs_(0) { +CompilationUnit::CompilationUnit(const CompilerLLVM* compiler_llvm, + size_t cunit_idx) +: compiler_llvm_(compiler_llvm), cunit_idx_(cunit_idx), + context_(new llvm::LLVMContext()) { // Create the module and include the runtime function declaration module_ = new llvm::Module("art", *context_); @@ -180,7 +152,7 @@ CompilationUnit::CompilationUnit(InstructionSet insn_set, size_t elf_idx) irb_.reset(new IRBuilder(*context_, *module_)); // We always need a switch case, so just use a normal function. - switch(insn_set_) { + switch(GetInstructionSet()) { default: runtime_support_.reset(new RuntimeSupportBuilder(*context_, *module_, *irb_)); break; @@ -205,57 +177,56 @@ CompilationUnit::~CompilationUnit() { } -bool CompilationUnit::Materialize(size_t thread_count) { - MutexLock GUARD(cunit_lock_); +InstructionSet CompilationUnit::GetInstructionSet() const { + return compiler_llvm_->GetInstructionSet(); +} - // Materialize the bitcode to elf_image_ - llvm::raw_string_ostream str_os(elf_image_); - bool success = MaterializeToFile(str_os); - LOG(INFO) << "Compilation Unit: " << elf_idx_ << (success ? " (done)" : " (failed)"); - // Free the resources - context_.reset(NULL); - irb_.reset(NULL); - module_ = NULL; - runtime_support_.reset(NULL); - compiled_methods_map_.reset(NULL); +bool CompilationUnit::Materialize() { + std::string elf_image; - return success; -} + // Compile and prelink llvm::Module + if (!MaterializeToString(elf_image)) { + LOG(ERROR) << "Failed to materialize compilation unit " << cunit_idx_; + DeleteResources(); + return false; + } +#if 0 + // Dump the ELF image for debugging + std::string filename(StringPrintf("%s/Art%zu.elf", + GetArtCacheOrDie(GetAndroidData()).c_str(), + cunit_idx_)); + UniquePtr<File> output(OS::OpenFile(filename.c_str(), true)); + output->WriteFully(elf_image.data(), elf_image.size()); +#endif + + // Extract the .text section and prelink the code + if (!ExtractCodeAndPrelink(elf_image)) { + LOG(ERROR) << "Failed to extract code from compilation unit " << cunit_idx_; + DeleteResources(); + return false; + } -void CompilationUnit::RegisterCompiledMethod(const llvm::Function* func, - CompiledMethod* compiled_method) { - MutexLock GUARD(cunit_lock_); - compiled_methods_map_->Put(func, compiled_method); + DeleteResources(); + return true; } -void CompilationUnit::UpdateFrameSizeInBytes(const llvm::Function* func, - size_t frame_size_in_bytes) { - MutexLock GUARD(cunit_lock_); - SafeMap<const llvm::Function*, CompiledMethod*>::iterator iter = - compiled_methods_map_->find(func); - - if (iter != compiled_methods_map_->end()) { - CompiledMethod* compiled_method = iter->second; - compiled_method->SetFrameSizeInBytes(frame_size_in_bytes); - - if (frame_size_in_bytes > 1728u) { - LOG(WARNING) << "Huge frame size: " << frame_size_in_bytes - << " elf_idx=" << compiled_method->GetElfIndex() - << " elf_func_idx=" << compiled_method->GetElfFuncIndex(); - } - } +bool CompilationUnit::MaterializeToString(std::string& str_buffer) { + llvm::raw_string_ostream str_os(str_buffer); + return MaterializeToRawOStream(str_os); } -bool CompilationUnit::MaterializeToFile(llvm::raw_ostream& out_stream) { + +bool CompilationUnit::MaterializeToRawOStream(llvm::raw_ostream& out_stream) { // Lookup the LLVM target char const* target_triple = NULL; char const* target_cpu = ""; char const* target_attr = NULL; - switch (insn_set_) { + InstructionSet insn_set = GetInstructionSet(); + switch (insn_set) { case kThumb2: target_triple = "thumb-none-linux-gnueabi"; target_cpu = "cortex-a9"; @@ -281,7 +252,7 @@ bool CompilationUnit::MaterializeToFile(llvm::raw_ostream& out_stream) { break; default: - LOG(FATAL) << "Unknown instruction set: " << insn_set_; + LOG(FATAL) << "Unknown instruction set: " << insn_set; } std::string errmsg; @@ -375,11 +346,6 @@ bool CompilationUnit::MaterializeToFile(llvm::raw_ostream& out_stream) { return false; } - // FIXME: Unable to run the UpdateFrameSizePass pass since it tries to - // update the value reside in the different address space. - // Add pass to update the frame_size_in_bytes_ - //pm.add(new ::UpdateFrameSizePass(this)); - // Run the per-function optimization fpm.doInitialization(); for (llvm::Module::iterator F = module_->begin(), E = module_->end(); @@ -395,5 +361,130 @@ bool CompilationUnit::MaterializeToFile(llvm::raw_ostream& out_stream) { return true; } + +bool CompilationUnit::ExtractCodeAndPrelink(const std::string& elf_image) { + llvm::OwningPtr<llvm::MemoryBuffer> elf_image_buff( + llvm::MemoryBuffer::getMemBuffer(llvm::StringRef(elf_image.data(), + elf_image.size()))); + + llvm::OwningPtr<llvm::object::ObjectFile> elf_file( + llvm::object::ObjectFile::createELFObjectFile(elf_image_buff.take())); + + llvm::error_code ec; + + const ProcedureLinkageTable& plt = compiler_llvm_->GetProcedureLinkageTable(); + + for (llvm::object::section_iterator + sec_iter = elf_file->begin_sections(), + sec_end = elf_file->end_sections(); + sec_iter != sec_end; sec_iter.increment(ec)) { + + CHECK(ec == 0) << "Failed to read section because " << ec.message(); + + // Read the section information + llvm::StringRef name; + uint64_t alignment = 0u; + uint64_t size = 0u; + + CHECK(sec_iter->getName(name) == 0); + CHECK(sec_iter->getSize(size) == 0); + CHECK(sec_iter->getAlignment(alignment) == 0); + + if (name == ".data" || name == ".bss" || name == ".rodata") { + if (size > 0) { + LOG(FATAL) << "Compilation unit " << cunit_idx_ << " has non-empty " + << name.str() << " section"; + } + + } else if (name == "" || name == ".rel.text" || + name == ".ARM.attributes" || name == ".symtab" || + name == ".strtab" || name == ".shstrtab") { + // We can ignore these sections. We don't have to copy them into + // the result Oat file. + + } else if (name == ".text") { + // Ensure the alignment requirement is less than or equal to + // kArchAlignment + CheckCodeAlign(alignment); + + // Copy the compiled code + llvm::StringRef contents; + CHECK(sec_iter->getContents(contents) == 0); + + copy(contents.data(), + contents.data() + contents.size(), + back_inserter(compiled_code_)); + + // Prelink the compiled code + for (llvm::object::relocation_iterator + rel_iter = sec_iter->begin_relocations(), + rel_end = sec_iter->end_relocations(); rel_iter != rel_end; + rel_iter.increment(ec)) { + + CHECK(ec == 0) << "Failed to read relocation because " << ec.message(); + + // Read the relocation information + llvm::object::SymbolRef sym_ref; + uint64_t rel_offset = 0; + uint64_t rel_type = 0; + int64_t rel_addend = 0; + + CHECK(rel_iter->getSymbol(sym_ref) == 0); + CHECK(rel_iter->getOffset(rel_offset) == 0); + CHECK(rel_iter->getType(rel_type) == 0); + CHECK(rel_iter->getAdditionalInfo(rel_addend) == 0); + + // Read the symbol related to this relocation fixup + llvm::StringRef sym_name; + CHECK(sym_ref.getName(sym_name) == 0); + + // Relocate the fixup. + // TODO: Support more relocation type. + CHECK(rel_type == llvm::ELF::R_ARM_ABS32); + CHECK_LE(rel_offset + 4, compiled_code_.size()); + + uintptr_t dest_addr = plt.GetEntryAddress(sym_name.str().c_str()); + uintptr_t final_addr = dest_addr + rel_addend; + compiled_code_[rel_offset] = final_addr & 0xff; + compiled_code_[rel_offset + 1] = (final_addr >> 8) & 0xff; + compiled_code_[rel_offset + 2] = (final_addr >> 16) & 0xff; + compiled_code_[rel_offset + 3] = (final_addr >> 24) & 0xff; + } + + } else { + LOG(WARNING) << "Unexpected section: " << name.str(); + } + } + + return true; +} + + +// Check whether the align is less than or equal to the code alignment of +// that architecture. Since the Oat writer only guarantee that the compiled +// method being aligned to kArchAlignment, we have no way to align the ELf +// section if the section alignment is greater than kArchAlignment. +void CompilationUnit::CheckCodeAlign(uint32_t align) const { + InstructionSet insn_set = GetInstructionSet(); + switch (insn_set) { + case kThumb2: + case kArm: + CHECK_LE(align, static_cast<uint32_t>(kArmAlignment)); + break; + + case kX86: + CHECK_LE(align, static_cast<uint32_t>(kX86Alignment)); + break; + + case kMips: + CHECK_LE(align, static_cast<uint32_t>(kMipsAlignment)); + break; + + default: + LOG(FATAL) << "Unknown instruction set: " << insn_set; + } +} + + } // namespace compiler_llvm } // namespace art diff --git a/src/compiler_llvm/compilation_unit.h b/src/compiler_llvm/compilation_unit.h index d391620798..576b65f8b3 100644 --- a/src/compiler_llvm/compilation_unit.h +++ b/src/compiler_llvm/compilation_unit.h @@ -18,7 +18,6 @@ #define ART_SRC_COMPILER_LLVM_COMPILATION_UNIT_H_ #include "../mutex.h" -#include "elf_image.h" #include "globals.h" #include "instruction_set.h" #include "logging.h" @@ -44,81 +43,52 @@ namespace llvm { namespace art { namespace compiler_llvm { +class CompilerLLVM; class IRBuilder; class CompilationUnit { public: - CompilationUnit(InstructionSet insn_set, size_t elf_idx); + CompilationUnit(const CompilerLLVM* compiler_llvm, + size_t cunit_idx); ~CompilationUnit(); - size_t GetElfIndex() const { - return elf_idx_; + size_t GetIndex() const { + return cunit_idx_; } - InstructionSet GetInstructionSet() const { - cunit_lock_.AssertHeld(); - return insn_set_; - } + InstructionSet GetInstructionSet() const; llvm::LLVMContext* GetLLVMContext() const { - cunit_lock_.AssertHeld(); return context_.get(); } llvm::Module* GetModule() const { - cunit_lock_.AssertHeld(); return module_; } IRBuilder* GetIRBuilder() const { - cunit_lock_.AssertHeld(); return irb_.get(); } - ElfImage GetElfImage() const { - MutexLock GUARD(cunit_lock_); - CHECK_GT(elf_image_.size(), 0u); - return ElfImage(elf_image_); - } - - uint16_t AcquireUniqueElfFuncIndex() { - cunit_lock_.AssertHeld(); - CHECK(num_elf_funcs_ < UINT16_MAX); - return num_elf_funcs_++; - } - void SetBitcodeFileName(const std::string& bitcode_filename) { - MutexLock GUARD(cunit_lock_); bitcode_filename_ = bitcode_filename; } - bool Materialize(size_t thread_count); + bool Materialize(); bool IsMaterialized() const { - MutexLock GUARD(cunit_lock_); return (context_.get() == NULL); } - bool IsMaterializeThresholdReached() const { - MutexLock GUARD(cunit_lock_); - return (mem_usage_ > 1000000u); // (threshold: 1 MB) - } - - void AddMemUsageApproximation(size_t usage) { - MutexLock GUARD(cunit_lock_); - mem_usage_ += usage; + const std::vector<uint8_t>& GetCompiledCode() const { + DCHECK(IsMaterialized()); + return compiled_code_; } - void RegisterCompiledMethod(const llvm::Function* func, CompiledMethod* cm); - - void UpdateFrameSizeInBytes(const llvm::Function* func, size_t frame_size_in_bytes); - - mutable Mutex cunit_lock_; - private: - InstructionSet insn_set_; - const size_t elf_idx_; + const CompilerLLVM* compiler_llvm_; + const size_t cunit_idx_; UniquePtr<llvm::LLVMContext> context_; UniquePtr<IRBuilder> irb_; @@ -126,15 +96,24 @@ class CompilationUnit { llvm::Module* module_; std::string bitcode_filename_; - std::string elf_image_; - typedef SafeMap<const llvm::Function*, CompiledMethod*> CompiledMethodMap; - UniquePtr<CompiledMethodMap> compiled_methods_map_; + std::vector<uint8_t> compiled_code_; + + SafeMap<const llvm::Function*, CompiledMethod*> compiled_methods_map_; + + void CheckCodeAlign(uint32_t offset) const; + + void DeleteResources() { + module_ = NULL; // Managed by context_ + context_.reset(NULL); + irb_.reset(NULL); + runtime_support_.reset(NULL); + } - size_t mem_usage_; - uint16_t num_elf_funcs_; + bool MaterializeToString(std::string& str_buffer); + bool MaterializeToRawOStream(llvm::raw_ostream& out_stream); - bool MaterializeToFile(llvm::raw_ostream& out_stream); + bool ExtractCodeAndPrelink(const std::string& elf_image); }; } // namespace compiler_llvm diff --git a/src/compiler_llvm/compiler_llvm.cc b/src/compiler_llvm/compiler_llvm.cc index 6c8188ef6f..b793fbda64 100644 --- a/src/compiler_llvm/compiler_llvm.cc +++ b/src/compiler_llvm/compiler_llvm.cc @@ -22,8 +22,6 @@ #include "compiled_method.h" #include "compiler.h" #include "dex_cache.h" -#include "elf_image.h" -#include "elf_loader.h" #include "ir_builder.h" #include "jni_compiler.h" #include "method_compiler.h" @@ -95,9 +93,9 @@ llvm::Module* makeLLVMModuleContents(llvm::Module* module); CompilerLLVM::CompilerLLVM(Compiler* compiler, InstructionSet insn_set) - : compiler_(compiler), compiler_lock_("llvm_compiler_lock"), - insn_set_(insn_set), curr_cunit_(NULL) { - + : compiler_(compiler), insn_set_(insn_set), + num_cunits_lock_("compilation unit counter lock"), num_cunits_(0), + plt_(insn_set) { // Initialize LLVM libraries pthread_once(&llvm_initialized, InitializeLLVM); @@ -105,152 +103,21 @@ CompilerLLVM::CompilerLLVM(Compiler* compiler, InstructionSet insn_set) CompilerLLVM::~CompilerLLVM() { - STLDeleteElements(&cunits_); -} - - -void CompilerLLVM::EnsureCompilationUnit() { - compiler_lock_.AssertHeld(); - - if (curr_cunit_ != NULL) { - return; - } - - // Allocate compilation unit - size_t cunit_idx = cunits_.size(); - curr_cunit_ = new CompilationUnit(insn_set_, cunit_idx); - - // Register compilation unit - cunits_.push_back(curr_cunit_); -} - - -void CompilerLLVM::MaterializeRemainder() { - compiler_lock_.Lock(); - // Localize - CompilationUnit* cunit = curr_cunit_; - // Reset the curr_cuit_ - curr_cunit_ = NULL; - compiler_lock_.Unlock(); - - if (cunit != NULL) { - Materialize(cunit); - } -} - - -void CompilerLLVM::MaterializeIfThresholdReached() { - compiler_lock_.Lock(); - // Localize - CompilationUnit* cunit = curr_cunit_; - - if (curr_cunit_ != NULL && curr_cunit_->IsMaterializeThresholdReached()) { - // Delete the compilation unit - curr_cunit_ = NULL; - } else { - // Reset cunit such that Materialize() won't be invoked - cunit = NULL; - } - - compiler_lock_.Unlock(); - - if (cunit != NULL) { - Materialize(cunit); - } } -void CompilerLLVM::Materialize(CompilationUnit* cunit) { - DCHECK(cunit != NULL); - DCHECK(!cunit->IsMaterialized()); - - // Write bitcode to file when filename is set - if (IsBitcodeFileNameAvailable()) { - const size_t cunit_idx = cunits_.size(); - cunit->SetBitcodeFileName( - StringPrintf("%s-%zu", bitcode_filename_.c_str(), cunit_idx)); - } - - // Materialize the llvm::Module into ELF object file - cunit->Materialize(compiler_->GetThreadCount()); - - // Load ELF image when automatic ELF loading is enabled - if (IsAutoElfLoadingEnabled()) { - LoadElfFromCompilationUnit(cunit); - } -} - - -void CompilerLLVM::EnableAutoElfLoading() { - MutexLock GUARD(compiler_lock_); - - if (IsAutoElfLoadingEnabled()) { - // If there is an existing ELF loader, then do nothing. - // Because the existing ELF loader may have returned some code address - // already. If we replace the existing ELF loader with - // elf_loader_.reset(...), then it is possible to have some dangling - // pointer. - return; - } - - // Create ELF loader and load the materialized CompilationUnit - elf_loader_.reset(new ElfLoader()); - - for (size_t i = 0; i < cunits_.size(); ++i) { - if (cunits_[i]->IsMaterialized()) { - LoadElfFromCompilationUnit(cunits_[i]); - } - } -} - - -void CompilerLLVM::LoadElfFromCompilationUnit(const CompilationUnit* cunit) { - MutexLock GUARD(compiler_lock_); - DCHECK(cunit->IsMaterialized()) << cunit->GetElfIndex(); - - if (!elf_loader_->LoadElfAt(cunit->GetElfIndex(), - cunit->GetElfImage(), - OatFile::kRelocAll)) { - LOG(ERROR) << "Failed to load ELF from compilation unit " - << cunit->GetElfIndex(); - } -} - - -const void* CompilerLLVM::GetMethodCodeAddr(const CompiledMethod* cm) const { - return elf_loader_->GetMethodCodeAddr(cm->GetElfIndex(), - cm->GetElfFuncIndex()); -} - - -const Method::InvokeStub* CompilerLLVM:: -GetMethodInvokeStubAddr(const CompiledInvokeStub* cm) const { - return elf_loader_->GetMethodInvokeStubAddr(cm->GetElfIndex(), - cm->GetElfFuncIndex()); -} - - -std::vector<ElfImage> CompilerLLVM::GetElfImages() const { - std::vector<ElfImage> result; - - for (size_t i = 0; i < cunits_.size(); ++i) { - result.push_back(cunits_[i]->GetElfImage()); - } - - return result; +CompilationUnit* CompilerLLVM::AllocateCompilationUnit() { + MutexLock GUARD(num_cunits_lock_); + return new CompilationUnit(this, num_cunits_++); } CompiledMethod* CompilerLLVM:: CompileDexMethod(OatCompilationUnit* oat_compilation_unit) { - MutexLock GUARD(compiler_lock_); - - EnsureCompilationUnit(); - - MutexLock GUARD_CUNIT(curr_cunit_->cunit_lock_); + UniquePtr<CompilationUnit> cunit(AllocateCompilationUnit()); UniquePtr<MethodCompiler> method_compiler( - new MethodCompiler(curr_cunit_, compiler_, oat_compilation_unit)); + new MethodCompiler(cunit.get(), compiler_, oat_compilation_unit)); return method_compiler->Compile(); } @@ -258,14 +125,10 @@ CompileDexMethod(OatCompilationUnit* oat_compilation_unit) { CompiledMethod* CompilerLLVM:: CompileNativeMethod(OatCompilationUnit* oat_compilation_unit) { - MutexLock GUARD(compiler_lock_); - - EnsureCompilationUnit(); - - MutexLock GUARD_CUNIT(curr_cunit_->cunit_lock_); + UniquePtr<CompilationUnit> cunit(AllocateCompilationUnit()); UniquePtr<JniCompiler> jni_compiler( - new JniCompiler(curr_cunit_, *compiler_, oat_compilation_unit)); + new JniCompiler(cunit.get(), *compiler_, oat_compilation_unit)); return jni_compiler->Compile(); } @@ -273,28 +136,20 @@ CompileNativeMethod(OatCompilationUnit* oat_compilation_unit) { CompiledInvokeStub* CompilerLLVM::CreateInvokeStub(bool is_static, char const *shorty) { - MutexLock GUARD(compiler_lock_); - - EnsureCompilationUnit(); - - MutexLock GUARD_CUNIT(curr_cunit_->cunit_lock_); + UniquePtr<CompilationUnit> cunit(AllocateCompilationUnit()); UniquePtr<StubCompiler> stub_compiler( - new StubCompiler(curr_cunit_, *compiler_)); + new StubCompiler(cunit.get(), *compiler_)); return stub_compiler->CreateInvokeStub(is_static, shorty); } CompiledInvokeStub* CompilerLLVM::CreateProxyStub(char const *shorty) { - MutexLock GUARD(compiler_lock_); - - EnsureCompilationUnit(); - - MutexLock GUARD_CUNIT(curr_cunit_->cunit_lock_); + UniquePtr<CompilationUnit> cunit(AllocateCompilationUnit()); UniquePtr<StubCompiler> stub_compiler( - new StubCompiler(curr_cunit_, *compiler_)); + new StubCompiler(cunit.get(), *compiler_)); return stub_compiler->CreateProxyStub(shorty); } @@ -324,6 +179,11 @@ extern "C" void ArtInitCompilerContext(art::Compiler& compiler) { compiler.SetCompilerContext(compiler_llvm); } +extern "C" void ArtUnInitCompilerContext(art::Compiler& compiler) { + delete ContextOf(compiler); + compiler.SetCompilerContext(NULL); +} + extern "C" art::CompiledMethod* ArtCompileMethod(art::Compiler& compiler, const art::DexFile::CodeItem* code_item, uint32_t access_flags, uint32_t method_idx, @@ -338,7 +198,6 @@ extern "C" art::CompiledMethod* ArtCompileMethod(art::Compiler& compiler, method_idx, access_flags); art::compiler_llvm::CompilerLLVM* compiler_llvm = ContextOf(compiler); art::CompiledMethod* result = compiler_llvm->CompileDexMethod(&oat_compilation_unit); - compiler_llvm->MaterializeIfThresholdReached(); return result; } @@ -354,7 +213,6 @@ extern "C" art::CompiledMethod* ArtJniCompileMethod(art::Compiler& compiler, art::compiler_llvm::CompilerLLVM* compiler_llvm = ContextOf(compiler); art::CompiledMethod* result = compiler_llvm->CompileNativeMethod(&oat_compilation_unit); - compiler_llvm->MaterializeIfThresholdReached(); return result; } @@ -364,7 +222,6 @@ extern "C" art::CompiledInvokeStub* ArtCreateInvokeStub(art::Compiler& compiler, uint32_t shorty_len) { art::compiler_llvm::CompilerLLVM* compiler_llvm = ContextOf(compiler); art::CompiledInvokeStub* result = compiler_llvm->CreateInvokeStub(is_static, shorty); - compiler_llvm->MaterializeIfThresholdReached(); return result; } @@ -373,7 +230,6 @@ extern "C" art::CompiledInvokeStub* ArtCreateProxyStub(art::Compiler& compiler, uint32_t shorty_len) { art::compiler_llvm::CompilerLLVM* compiler_llvm = ContextOf(compiler); art::CompiledInvokeStub* result = compiler_llvm->CreateProxyStub(shorty); - compiler_llvm->MaterializeIfThresholdReached(); return result; } @@ -381,37 +237,3 @@ extern "C" void compilerLLVMSetBitcodeFileName(art::Compiler& compiler, std::string const& filename) { ContextOf(compiler)->SetBitcodeFileName(filename); } - -extern "C" void compilerLLVMMaterializeRemainder(art::Compiler& compiler) { - ContextOf(compiler)->MaterializeRemainder(); -} - -extern "C" void compilerLLVMEnableAutoElfLoading(art::Compiler& compiler) { - art::compiler_llvm::CompilerLLVM* compiler_llvm = - reinterpret_cast<art::compiler_llvm::CompilerLLVM*>(compiler.GetCompilerContext()); - return compiler_llvm->EnableAutoElfLoading(); -} - -extern "C" const void* compilerLLVMGetMethodCodeAddr(const art::Compiler& compiler, - const art::CompiledMethod* cm, - const art::Method*) { - const art::compiler_llvm::CompilerLLVM* compiler_llvm = - reinterpret_cast<const art::compiler_llvm::CompilerLLVM*>(compiler.GetCompilerContext()); - return compiler_llvm->GetMethodCodeAddr(cm); -} - -extern "C" const art::Method::InvokeStub* compilerLLVMGetMethodInvokeStubAddr(const art::Compiler& compiler, - const art::CompiledInvokeStub* cm, - const art::Method*) { - const art::compiler_llvm::CompilerLLVM* compiler_llvm = - reinterpret_cast<const art::compiler_llvm::CompilerLLVM*>(compiler.GetCompilerContext()); - return compiler_llvm->GetMethodInvokeStubAddr(cm); -} - -extern "C" std::vector<art::ElfImage> compilerLLVMGetElfImages(const art::Compiler& compiler) { - return ContextOf(compiler)->GetElfImages(); -} - -extern "C" void compilerLLVMDispose(art::Compiler& compiler) { - delete ContextOf(compiler); -} diff --git a/src/compiler_llvm/compiler_llvm.h b/src/compiler_llvm/compiler_llvm.h index 7cc4a0e42d..24a766e2f4 100644 --- a/src/compiler_llvm/compiler_llvm.h +++ b/src/compiler_llvm/compiler_llvm.h @@ -19,10 +19,10 @@ #include "compiler.h" #include "dex_file.h" -#include "elf_image.h" #include "instruction_set.h" #include "macros.h" #include "object.h" +#include "procedure_linkage_table.h" #include <UniquePtr.h> @@ -54,7 +54,6 @@ namespace art { namespace compiler_llvm { class CompilationUnit; -class ElfLoader; class IRBuilder; class CompilerLLVM { @@ -63,10 +62,6 @@ class CompilerLLVM { ~CompilerLLVM(); - void MaterializeIfThresholdReached(); - - void MaterializeRemainder(); - Compiler* GetCompiler() const { return compiler_; } @@ -75,31 +70,10 @@ class CompilerLLVM { return insn_set_; } - size_t GetNumCompilationUnits() const { - return cunits_.size(); - } - - const CompilationUnit* GetCompilationUnit(size_t i) const { - return cunits_[i]; - } - void SetBitcodeFileName(std::string const& filename) { bitcode_filename_ = filename; } - void EnableAutoElfLoading(); - - bool IsAutoElfLoadingEnabled() const { - return (elf_loader_.get() != NULL); - } - - const void* GetMethodCodeAddr(const CompiledMethod* cm) const; - - const Method::InvokeStub* GetMethodInvokeStubAddr( - const CompiledInvokeStub* cm) const; - - std::vector<ElfImage> GetElfImages() const; - CompiledMethod* CompileDexMethod(OatCompilationUnit* oat_compilation_unit); CompiledMethod* CompileNativeMethod(OatCompilationUnit* oat_compilation_unit); @@ -108,32 +82,29 @@ class CompilerLLVM { CompiledInvokeStub* CreateProxyStub(const char *shorty); + const ProcedureLinkageTable& GetProcedureLinkageTable() const { + return plt_; + } + private: - void EnsureCompilationUnit(); + CompilationUnit* AllocateCompilationUnit(); void Materialize(CompilationUnit* cunit); - void LoadElfFromCompilationUnit(const CompilationUnit* cunit); - bool IsBitcodeFileNameAvailable() const { return !bitcode_filename_.empty(); } Compiler* compiler_; - public: - Mutex compiler_lock_; - - private: InstructionSet insn_set_; - CompilationUnit* curr_cunit_; - - std::vector<CompilationUnit*> cunits_; + Mutex num_cunits_lock_; + size_t num_cunits_; std::string bitcode_filename_; - UniquePtr<ElfLoader> elf_loader_; + ProcedureLinkageTable plt_; DISALLOW_COPY_AND_ASSIGN(CompilerLLVM); }; diff --git a/src/compiler_llvm/elf_loader.cc b/src/compiler_llvm/elf_loader.cc deleted file mode 100644 index 8432a07013..0000000000 --- a/src/compiler_llvm/elf_loader.cc +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "elf_loader.h" - -#include "compiled_method.h" -#include "elf_image.h" -#include "logging.h" -#include "oat_file.h" -#include "object.h" -#include "runtime_support_llvm.h" -#include "utils_llvm.h" - -#include <android/librsloader.h> - -namespace art { -namespace compiler_llvm { - - -ElfLoader::~ElfLoader() { - // Release every ELF object - for (size_t i = 0; i < executables_.size(); ++i) { - rsloaderDisposeExec(executables_[i]); - } -} - - -bool ElfLoader::LoadElfAt(size_t elf_idx, - const ElfImage& elf_image, - OatFile::RelocationBehavior reloc) { - if (elf_idx < executables_.size() && executables_[elf_idx] != NULL) { - return false; - } - - if (elf_idx >= executables_.size()) { - executables_.resize(elf_idx + 1); - elf_images_.resize(elf_idx + 1); - } - - RSExecRef executable = rsloaderLoadExecutable(elf_image.begin(), - elf_image.size(), - reloc == OatFile::kRelocNone ? 1 : 0); - - if (executable == NULL) { - LOG(WARNING) << "Failed to load ELF" - << " image: " << static_cast<const void*>(elf_image.begin()) - << " size: " << elf_image.size(); - return false; - } - - if (reloc == OatFile::kRelocAll) { - if (!rsloaderRelocateExecutable(executable, - art_find_runtime_support_func, NULL)) { - LOG(ERROR) << "Failed to relocate the ELF image"; - rsloaderDisposeExec(executable); - return false; - } - relocated = true; - } - - executables_[elf_idx] = executable; - elf_images_[elf_idx] = elf_image; - return true; -} - - -void ElfLoader::RelocateExecutable() { - if (relocated) { - return; - } - LOG(INFO) << "Reload ELF for relocate."; - for (size_t i = 0; i < executables_.size(); ++i) { - if (executables_[i] != NULL) { - // TODO: After implement in-place linking, we will no longer need to dispose and reload. - rsloaderDisposeExec(executables_[i]); - executables_[i] = rsloaderLoadExecutable(elf_images_[i].begin(), elf_images_[i].size(), 0); - if (executables_[i] == NULL) { - LOG(FATAL) << "Failed to reload ELF image " << i; - } - if (!rsloaderRelocateExecutable(executables_[i], - art_find_runtime_support_func, NULL)) { - LOG(FATAL) << "Failed to relocate ELF image " << i; - } - } - } - relocated = true; -} - - -const void* ElfLoader::GetMethodCodeAddr(uint16_t elf_idx, - uint16_t elf_func_idx) const { - CHECK_LT(elf_idx, executables_.size()); - return GetAddr(elf_idx, ElfFuncName(elf_func_idx).c_str()); -} - - -const Method::InvokeStub* ElfLoader:: -GetMethodInvokeStubAddr(uint16_t elf_idx, uint16_t elf_func_idx) const { - CHECK_LT(elf_idx, executables_.size()); - return reinterpret_cast<const Method::InvokeStub*>( - GetAddr(elf_idx, ElfFuncName(elf_func_idx).c_str())); -} - - -size_t ElfLoader::GetCodeSize(uint16_t elf_idx, uint16_t elf_func_idx) const { - CHECK_LT(elf_idx, executables_.size()); - CHECK(executables_[elf_idx] != NULL); - return rsloaderGetSymbolSize(executables_[elf_idx], - ElfFuncName(elf_func_idx).c_str()); -} - - -const void* ElfLoader::GetAddr(size_t elf_idx, const char* sym_name) const { - CHECK_LT(elf_idx, executables_.size()); - CHECK(executables_[elf_idx] != NULL); - return rsloaderGetSymbolAddress(executables_[elf_idx], sym_name); -} - - -} // namespace compiler_llvm -} // namespace art diff --git a/src/compiler_llvm/elf_loader.h b/src/compiler_llvm/elf_loader.h deleted file mode 100644 index 9e8611ca59..0000000000 --- a/src/compiler_llvm/elf_loader.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_SRC_COMPILER_LLVM_ELF_LOADER_H_ -#define ART_SRC_COMPILER_LLVM_ELF_LOADER_H_ - -#include "elf_image.h" -#include "globals.h" -#include "oat_file.h" -#include "object.h" - -#include <android/librsloader.h> -#include <vector> - -namespace art { -namespace compiler_llvm { - -class ElfLoader { - public: - ElfLoader() : relocated(false) {} - ~ElfLoader(); - - bool LoadElfAt(size_t elf_idx, const ElfImage& elf_image, - OatFile::RelocationBehavior reloc); - - void RelocateExecutable(); - - const void* GetMethodCodeAddr(uint16_t elf_idx, - uint16_t elf_func_idx) const; - - const Method::InvokeStub* GetMethodInvokeStubAddr(uint16_t elf_idx, - uint16_t elf_func_idx) const; - - size_t GetCodeSize(uint16_t elf_idx, uint16_t elf_func_idx) const; - - private: - const void* GetAddr(size_t elf_idx, const char* sym_name) const; - - bool relocated; - std::vector<ElfImage> elf_images_; - std::vector<RSExecRef> executables_; -}; - - -} // namespace compiler_llvm -} // namespace art - -#endif // ART_SRC_COMPILER_LLVM_ELF_LOADER_H_ diff --git a/src/compiler_llvm/jni_compiler.cc b/src/compiler_llvm/jni_compiler.cc index 37ca82f2ff..f4f5be56c3 100644 --- a/src/compiler_llvm/jni_compiler.cc +++ b/src/compiler_llvm/jni_compiler.cc @@ -51,8 +51,7 @@ JniCompiler::JniCompiler(CompilationUnit* cunit, class_loader_(oat_compilation_unit->class_loader_), dex_cache_(oat_compilation_unit->dex_cache_), dex_file_(oat_compilation_unit->dex_file_), - method_(dex_cache_->GetResolvedMethod(method_idx_)), - elf_func_idx_(cunit_->AcquireUniqueElfFuncIndex()) { + method_(dex_cache_->GetResolvedMethod(method_idx_)) { // Check: Ensure that the method is resolved CHECK_NE(method_, static_cast<art::Method*>(NULL)); @@ -262,26 +261,16 @@ CompiledMethod* JniCompiler::Compile() { // Verify the generated bitcode VERIFY_LLVM_FUNCTION(*func_); - // Add the memory usage approximation of the compilation unit - cunit_->AddMemUsageApproximation((sirt_size * 4 + 50) * 50); - // NOTE: We will emit 4 LLVM instructions per object argument, - // And about 50 instructions for other operations. (Some runtime support will be inlined.) - // Beside, we guess that we have to use 50 bytes to represent one LLVM instruction. + cunit_->Materialize(); - CompiledMethod* compiled_method = - new CompiledMethod(cunit_->GetInstructionSet(), - cunit_->GetElfIndex(), - elf_func_idx_); - - cunit_->RegisterCompiledMethod(func_, compiled_method); - - return compiled_method; + return new CompiledMethod(cunit_->GetInstructionSet(), + cunit_->GetCompiledCode()); } void JniCompiler::CreateFunction() { // LLVM function name - std::string func_name(ElfFuncName(elf_func_idx_)); + std::string func_name(ElfFuncName(cunit_->GetIndex())); // Get function type llvm::FunctionType* func_type = diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc index eef71db957..da8f91adf2 100644 --- a/src/compiler_llvm/method_compiler.cc +++ b/src/compiler_llvm/method_compiler.cc @@ -72,8 +72,7 @@ MethodCompiler::MethodCompiler(CompilationUnit* cunit, basic_block_landing_pads_(code_item_->tries_size_, NULL), basic_block_unwind_(NULL), basic_block_unreachable_(NULL), shadow_frame_(NULL), old_shadow_frame_(NULL), - already_pushed_shadow_frame_(NULL), shadow_frame_size_(0), - elf_func_idx_(cunit_->AcquireUniqueElfFuncIndex()) { + already_pushed_shadow_frame_(NULL), shadow_frame_size_(0) { } @@ -84,7 +83,7 @@ MethodCompiler::~MethodCompiler() { void MethodCompiler::CreateFunction() { // LLVM function name - std::string func_name(ElfFuncName(elf_func_idx_)); + std::string func_name(ElfFuncName(cunit_->GetIndex())); // Get function type llvm::FunctionType* func_type = @@ -3616,20 +3615,10 @@ CompiledMethod *MethodCompiler::Compile() { // Verify the generated bitcode VERIFY_LLVM_FUNCTION(*func_); - // Add the memory usage approximation of the compilation unit - cunit_->AddMemUsageApproximation(code_item_->insns_size_in_code_units_ * 900); - // NOTE: From statistics, the bitcode size is 4.5 times bigger than the - // Dex file. Besides, we have to convert the code unit into bytes. - // Thus, we got our magic number 9. + cunit_->Materialize(); - CompiledMethod* compiled_method = - new CompiledMethod(cunit_->GetInstructionSet(), - cunit_->GetElfIndex(), - elf_func_idx_); - - cunit_->RegisterCompiledMethod(func_, compiled_method); - - return compiled_method; + return new CompiledMethod(cunit_->GetInstructionSet(), + cunit_->GetCompiledCode()); } diff --git a/src/compiler_llvm/stub_compiler.cc b/src/compiler_llvm/stub_compiler.cc index 0d64f0defa..af05e5246f 100644 --- a/src/compiler_llvm/stub_compiler.cc +++ b/src/compiler_llvm/stub_compiler.cc @@ -48,13 +48,11 @@ StubCompiler::StubCompiler(CompilationUnit* cunit, Compiler& compiler) CompiledInvokeStub* StubCompiler::CreateInvokeStub(bool is_static, char const* shorty) { - uint16_t elf_func_idx = cunit_->AcquireUniqueElfFuncIndex(); - CHECK(shorty != NULL); size_t shorty_size = strlen(shorty); // Function name - std::string func_name(ElfFuncName(elf_func_idx)); + std::string func_name(ElfFuncName(cunit_->GetIndex())); // Get argument types llvm::Type* arg_types[] = { @@ -186,15 +184,10 @@ CompiledInvokeStub* StubCompiler::CreateInvokeStub(bool is_static, // Verify the generated function VERIFY_LLVM_FUNCTION(*func); - // Add the memory usage approximation of the compilation unit - cunit_->AddMemUsageApproximation((shorty_size * 3 + 8) * 50); - // NOTE: We will emit 3 LLVM instructions per shorty for the argument, - // plus 3 for pointer arithmetic, and 5 for code_addr, retval, ret_addr, - // store ret_addr, and ret_void. Beside, we guess that we have to use - // 50 bytes to represent one LLVM instruction. + cunit_->Materialize(); return new CompiledInvokeStub(cunit_->GetInstructionSet(), - cunit_->GetElfIndex(), elf_func_idx); + cunit_->GetCompiledCode()); } @@ -202,10 +195,8 @@ CompiledInvokeStub* StubCompiler::CreateProxyStub(char const* shorty) { CHECK(shorty != NULL); size_t shorty_size = strlen(shorty); - uint16_t elf_func_idx = cunit_->AcquireUniqueElfFuncIndex(); - // Function name - std::string func_name(ElfFuncName(elf_func_idx)); + std::string func_name(ElfFuncName(cunit_->GetIndex())); // Accurate function type llvm::Type* accurate_ret_type = irb_.getJType(shorty[0], kAccurate); @@ -266,11 +257,10 @@ CompiledInvokeStub* StubCompiler::CreateProxyStub(char const* shorty) { // Verify the generated function VERIFY_LLVM_FUNCTION(*func); - // Add the memory usage approximation of the compilation unit - cunit_->AddMemUsageApproximation((shorty_size + 2) * 50); + cunit_->Materialize(); return new CompiledInvokeStub(cunit_->GetInstructionSet(), - cunit_->GetElfIndex(), elf_func_idx); + cunit_->GetCompiledCode()); } diff --git a/src/compiler_llvm/utils_llvm.h b/src/compiler_llvm/utils_llvm.h index dd35f0a089..eb5fd53e0a 100644 --- a/src/compiler_llvm/utils_llvm.h +++ b/src/compiler_llvm/utils_llvm.h @@ -32,8 +32,8 @@ namespace art { #define VERIFY_LLVM_FUNCTION(func) #endif -inline static std::string ElfFuncName(uint16_t elf_func_idx) { - return StringPrintf("Art%u", static_cast<unsigned int>(elf_func_idx)); +inline static std::string ElfFuncName(uint16_t idx) { + return StringPrintf("Art%u", static_cast<unsigned int>(idx)); } class CStringLessThanComparator { |