Compile method one-by-one.
Change-Id: Ic56fb397f3bd6dee32372eb875261a3383eaf30c
diff --git a/src/compiler_llvm/compilation_unit.cc b/src/compiler_llvm/compilation_unit.cc
index 38faf61..fdbf575 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 @@
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 @@
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 @@
}
-bool CompilationUnit::Materialize(size_t thread_count) {
- MutexLock GUARD(cunit_lock_);
-
- // 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);
-
- return success;
+InstructionSet CompilationUnit::GetInstructionSet() const {
+ return compiler_llvm_->GetInstructionSet();
}
-void CompilationUnit::RegisterCompiledMethod(const llvm::Function* func,
- CompiledMethod* compiled_method) {
- MutexLock GUARD(cunit_lock_);
- compiled_methods_map_->Put(func, compiled_method);
-}
+bool CompilationUnit::Materialize() {
+ std::string elf_image;
-
-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();
- }
+ // 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;
+ }
+
+ DeleteResources();
+ return true;
}
-bool CompilationUnit::MaterializeToFile(llvm::raw_ostream& out_stream) {
+
+bool CompilationUnit::MaterializeToString(std::string& str_buffer) {
+ llvm::raw_string_ostream str_os(str_buffer);
+ return MaterializeToRawOStream(str_os);
+}
+
+
+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 @@
break;
default:
- LOG(FATAL) << "Unknown instruction set: " << insn_set_;
+ LOG(FATAL) << "Unknown instruction set: " << insn_set;
}
std::string errmsg;
@@ -375,11 +346,6 @@
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 @@
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 d391620..576b65f 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 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)
+ const std::vector<uint8_t>& GetCompiledCode() const {
+ DCHECK(IsMaterialized());
+ return compiled_code_;
}
- void AddMemUsageApproximation(size_t usage) {
- MutexLock GUARD(cunit_lock_);
- mem_usage_ += usage;
- }
-
- 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 @@
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_;
- size_t mem_usage_;
- uint16_t num_elf_funcs_;
+ SafeMap<const llvm::Function*, CompiledMethod*> compiled_methods_map_;
- bool MaterializeToFile(llvm::raw_ostream& out_stream);
+ void CheckCodeAlign(uint32_t offset) const;
+
+ void DeleteResources() {
+ module_ = NULL; // Managed by context_
+ context_.reset(NULL);
+ irb_.reset(NULL);
+ runtime_support_.reset(NULL);
+ }
+
+ bool MaterializeToString(std::string& str_buffer);
+ bool MaterializeToRawOStream(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 6c8188e..b793fbd 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 @@
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() {
- 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 7cc4a0e..24a766e 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 compiler_llvm {
class CompilationUnit;
-class ElfLoader;
class IRBuilder;
class CompilerLLVM {
@@ -63,10 +62,6 @@
~CompilerLLVM();
- void MaterializeIfThresholdReached();
-
- void MaterializeRemainder();
-
Compiler* GetCompiler() const {
return compiler_;
}
@@ -75,31 +70,10 @@
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 @@
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 8432a07..0000000
--- 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 9e8611c..0000000
--- 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 37ca82f..f4f5be5 100644
--- a/src/compiler_llvm/jni_compiler.cc
+++ b/src/compiler_llvm/jni_compiler.cc
@@ -51,8 +51,7 @@
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 @@
// 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 eef71db..da8f91a 100644
--- a/src/compiler_llvm/method_compiler.cc
+++ b/src/compiler_llvm/method_compiler.cc
@@ -72,8 +72,7 @@
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 @@
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 @@
// 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 0d64f0d..af05e52 100644
--- a/src/compiler_llvm/stub_compiler.cc
+++ b/src/compiler_llvm/stub_compiler.cc
@@ -48,13 +48,11 @@
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 @@
// 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 @@
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 @@
// 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 dd35f0a..eb5fd53 100644
--- a/src/compiler_llvm/utils_llvm.h
+++ b/src/compiler_llvm/utils_llvm.h
@@ -32,8 +32,8 @@
#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 {