Merge "Support for a set of verifier failures." into ics-mr1-plus-art
diff --git a/Android.mk b/Android.mk
index fa13d8b..6de5eff 100644
--- a/Android.mk
+++ b/Android.mk
@@ -23,6 +23,9 @@
ART_BUILD_HOST_NDEBUG ?= true
ART_BUILD_HOST_DEBUG ?= true
+ART_HOST_SHLIB_EXTENSION := $(HOST_SHLIB_SUFFIX)
+ART_HOST_SHLIB_EXTENSION ?= .so
+
build_path := $(LOCAL_PATH)/build
include $(build_path)/Android.common.mk
@@ -38,11 +41,7 @@
# ART_HOST_DEPENDENCIES depends on Android.executable.mk above for ART_HOST_EXECUTABLES
ART_HOST_DEPENDENCIES := $(ART_HOST_EXECUTABLES) $(HOST_OUT_JAVA_LIBRARIES)/core-hostdex.jar
-ifeq ($(HOST_OS),linux)
- ART_HOST_DEPENDENCIES += $(HOST_OUT_SHARED_LIBRARIES)/libjavacore.so
-else
- ART_HOST_DEPENDENCIES += $(HOST_OUT_SHARED_LIBRARIES)/libjavacore.dylib
-endif
+ART_HOST_DEPENDENCIES += $(HOST_OUT_SHARED_LIBRARIES)/libjavacore$(ART_HOST_SHLIB_EXTENSION)
ART_TARGET_DEPENDENCIES := $(ART_TARGET_EXECUTABLES) $(TARGET_OUT_JAVA_LIBRARIES)/core.jar $(TARGET_OUT_SHARED_LIBRARIES)/libjavacore.so
########################################################################
@@ -89,7 +88,7 @@
@echo test-art-host PASSED
.PHONY: test-art-host-dependencies
-test-art-host-dependencies: $(ART_HOST_TEST_DEPENDENCIES) $(HOST_OUT_SHARED_LIBRARIES)/libarttest.so
+test-art-host-dependencies: $(ART_HOST_TEST_DEPENDENCIES) $(HOST_OUT_SHARED_LIBRARIES)/libarttest$(ART_HOST_SHLIB_EXTENSION)
.PHONY: test-art-host-gtest
test-art-host-gtest: $(ART_HOST_TEST_TARGETS)
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 6c2041c..e62602c 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -14,7 +14,7 @@
# limitations under the License.
#
-# TODO: move the LLVM compiler out into a separate .so too...
+# TODO: move the LLVM compiler out into a separate shared library too...
# Use llvm as the backend
ifneq ($(wildcard art/USE_LLVM_COMPILER),)
ART_USE_LLVM_COMPILER := true
diff --git a/src/compiler_llvm/compilation_unit.cc b/src/compiler_llvm/compilation_unit.cc
index b976fd2..9c1f8d0 100644
--- a/src/compiler_llvm/compilation_unit.cc
+++ b/src/compiler_llvm/compilation_unit.cc
@@ -17,9 +17,11 @@
#include "compilation_unit.h"
#include "compiled_method.h"
+#include "file.h"
#include "instruction_set.h"
#include "ir_builder.h"
#include "logging.h"
+#include "os.h"
#include "runtime_support_builder_arm.h"
#include "runtime_support_builder_x86.h"
@@ -45,6 +47,7 @@
#include <llvm/Support/Debug.h>
#include <llvm/Support/FormattedStream.h>
#include <llvm/Support/ManagedStatic.h>
+#include <llvm/Support/MemoryBuffer.h>
#include <llvm/Support/PassNameParser.h>
#include <llvm/Support/PluginLoader.h>
#include <llvm/Support/PrettyStackTrace.h>
@@ -54,11 +57,17 @@
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/ToolOutputFile.h>
#include <llvm/Support/raw_ostream.h>
+#include <llvm/Support/system_error.h>
#include <llvm/Target/TargetData.h>
#include <llvm/Target/TargetLibraryInfo.h>
#include <llvm/Target/TargetMachine.h>
+#include <llvm/Transforms/IPO.h>
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
#include <string>
namespace {
@@ -136,11 +145,11 @@
}
-bool CompilationUnit::WriteBitcodeToFile() {
+bool CompilationUnit::WriteBitcodeToFile(const std::string& bitcode_filename) {
std::string errmsg;
llvm::OwningPtr<llvm::tool_output_file> out_file(
- new llvm::tool_output_file(bitcode_filename_.c_str(), errmsg,
+ new llvm::tool_output_file(bitcode_filename.c_str(), errmsg,
llvm::raw_fd_ostream::F_Binary));
@@ -155,115 +164,113 @@
return true;
}
-
-bool CompilationUnit::Materialize() {
- // Lookup the LLVM target
- char const* target_triple = NULL;
- char const* target_attr = NULL;
-
- switch (insn_set_) {
- case kThumb2:
- target_triple = "thumb-none-linux-gnueabi";
- target_attr = "+thumb2,+neon,+neonfp,+vfp3";
- break;
-
- case kArm:
- target_triple = "armv7-none-linux-gnueabi";
- target_attr = "+v7,+neon,+neonfp,+vfp3";
- break;
-
- case kX86:
- target_triple = "i386-pc-linux-gnu";
- target_attr = "";
- break;
-
- case kMips:
- target_triple = "mipsel-unknown-linux";
- target_attr = "mips32r2";
- break;
-
- default:
- LOG(FATAL) << "Unknown instruction set: " << insn_set_;
+// TODO: Move to scoped_temp_file.h
+class ScopedTempFile {
+ public:
+ ScopedTempFile(const std::string& filename_template)
+ : filename_(filename_template), file_(NULL) {
+ int fd = mkstemp(&filename_[0]);
+ CHECK_NE(-1, fd);
+ file_ = OS::FileFromFd(filename_.c_str(), fd);
}
- std::string errmsg;
- llvm::Target const* target =
- llvm::TargetRegistry::lookupTarget(target_triple, errmsg);
+ ~ScopedTempFile() {
+ delete file_;
+ TEMP_FAILURE_RETRY(unlink(filename_.c_str()));
+ }
- CHECK(target != NULL) << errmsg;
+ int GetFd() {
+ return file_->Fd();
+ }
- // Target options
- llvm::TargetOptions target_options;
- target_options.FloatABIType = llvm::FloatABI::Soft;
- target_options.NoFramePointerElim = true;
- target_options.NoFramePointerElimNonLeaf = true;
- target_options.UseSoftFloat = false;
- target_options.EnableFastISel = true;
+ const std::string &GetName() const {
+ return filename_;
+ }
- // Create the llvm::TargetMachine
- llvm::TargetMachine* target_machine =
- target->createTargetMachine(target_triple, "", target_attr, target_options,
- llvm::Reloc::Static, llvm::CodeModel::Small,
- llvm::CodeGenOpt::Less);
+ bool ReadToString(std::string &buffer) {
+ off_t file_size = file_->Length();
+ if (file_size <= 0) {
+ buffer.clear();
+ return true;
+ }
- CHECK(target_machine != NULL) << "Failed to create target machine";
+ buffer.reserve(file_size);
+ buffer.resize(file_size);
+ return file_->ReadFully(&buffer[0], file_size);
+ }
+ private:
+ std::string filename_;
+ File *file_;
+};
- // Add target data
- llvm::TargetData const* target_data = target_machine->getTargetData();
+bool CompilationUnit::Materialize() {
+ const std::string tmp_file = "/tmp/art-llvm-XXXXXX";
- // PassManager for code generation passes
- llvm::PassManager pm;
- pm.add(new llvm::TargetData(*target_data));
+ // Prepare the input
+ ScopedTempFile input(tmp_file);
+ if (input.GetFd() < 0) {
+ PLOG(ERROR) << "Failed to save the module to the file " << tmp_file;
+ return false;
+ }
- // FunctionPassManager for optimization pass
- llvm::FunctionPassManager fpm(module_);
- fpm.add(new llvm::TargetData(*target_data));
+ // Write the bitcode to the file
+ if (!WriteBitcodeToFile(input.GetName())) {
+ return false;
+ }
- // Add optimization pass
- llvm::PassManagerBuilder pm_builder;
- pm_builder.Inliner = NULL; // TODO: add some inline in the future
- pm_builder.OptLevel = 1;
- pm_builder.DisableSimplifyLibCalls = 1;
- pm_builder.populateModulePassManager(pm);
- pm_builder.populateFunctionPassManager(fpm);
+ // Prepare the output
+ ScopedTempFile output(tmp_file);
+ if (output.GetFd() < 0) {
+ PLOG(ERROR) << "Failed to prepare the output file " << tmp_file;
+ return false;
+ }
- // Add passes to emit ELF image
- {
- llvm::formatted_raw_ostream formatted_os(
- *(new llvm::raw_string_ostream(elf_image_)), true);
+ // Fork a process to do the compilation
+ pid_t pid = fork();
+ if (pid == 0) {
+ // change process groups, so we don't get ripped by ProcessManager
+ setpgid(0, 0);
- // Ask the target to add backend passes as necessary.
- if (target_machine->addPassesToEmitFile(pm,
- formatted_os,
- llvm::TargetMachine::CGFT_ObjectFile,
- true)) {
- LOG(FATAL) << "Unable to generate ELF for this target";
+ // TODO: Should use exec* family instead of invoking a function.
+ // Forward our compilation request to bcc.
+ exit(static_cast<int>(!MaterializeFile(input.GetFd(), output.GetFd(),
+ insn_set_)));
+ } else {
+ if (pid < 0) {
+ LOG(FATAL) << "Failed to fork a process to do the compilation: "
+ << strerror(errno);
+ }
+
+ // Free the resources
+ context_.reset(NULL);
+ irb_.reset(NULL);
+ module_ = NULL;
+
+ int status;
+
+ // Wait for child to finish
+ pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
+ if (got_pid != pid) {
+ PLOG(ERROR) << "waitpid failed: wanted " << pid << ", got " << got_pid;
return false;
}
- // 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();
- F != E; ++F) {
- fpm.run(*F);
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ LOG(ERROR) << "Failed to compile the bitcode: " << WEXITSTATUS(status);
+ return false;
}
- fpm.doFinalization();
+ }
- // Run the code generation passes
- pm.run(*module_);
+ // Read the result out from the output file
+ TEMP_FAILURE_RETRY(lseek(output.GetFd(), 0, SEEK_SET));
+ if (!output.ReadToString(elf_image_)) {
+ LOG(ERROR) << "Failed to read the result file";
+ return false;
}
LOG(INFO) << "Compilation Unit: " << elf_idx_ << " (done)";
- // Free the resources
- context_.reset(NULL);
- irb_.reset(NULL);
- module_ = NULL;
-
return true;
}
@@ -291,6 +298,141 @@
}
}
+bool CompilationUnit::MaterializeFile(int input_fd, int output_fd,
+ InstructionSet insn_set) {
+ // Initialize the LLVM first
+ llvm::InitializeAllTargets();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllAsmPrinters();
+ llvm::InitializeAllAsmParsers();
+
+ // Read the LLVM module from input_fd
+ llvm::OwningPtr<llvm::MemoryBuffer> memory_buffer;
+ llvm::error_code load_input_err =
+ llvm::MemoryBuffer::getOpenFile(input_fd, "<art-llvm-module>",
+ memory_buffer);
+
+ if (load_input_err) {
+ LOG(ERROR) << "Failed to load input for compiler into memory: "
+ << load_input_err.message();
+ return false;
+ }
+
+ // It's safe to use the global context now
+ std::string load_module_errmsg;
+ llvm::Module *module = ParseBitcodeFile(memory_buffer.get(),
+ llvm::getGlobalContext(),
+ &load_module_errmsg);
+ if (module == NULL) {
+ LOG(ERROR) << "Failed to load LLVM module to compiler: "
+ << load_module_errmsg;
+ return false;
+ }
+
+ // Lookup the LLVM target
+ char const* target_triple = NULL;
+ char const* target_attr = NULL;
+
+ switch (insn_set) {
+ case kThumb2:
+ target_triple = "thumb-none-linux-gnueabi";
+ target_attr = "+thumb2,+neon,+neonfp,+vfp3";
+ break;
+
+ case kArm:
+ target_triple = "armv7-none-linux-gnueabi";
+ // TODO: Fix for Xoom.
+ target_attr = "+v7,+neon,+neonfp,+vfp3";
+ break;
+
+ case kX86:
+ target_triple = "i386-pc-linux-gnu";
+ target_attr = "";
+ break;
+
+ case kMips:
+ target_triple = "mipsel-unknown-linux";
+ target_attr = "mips32r2";
+ break;
+
+ default:
+ LOG(FATAL) << "Unknown instruction set: " << insn_set;
+ }
+
+ std::string errmsg;
+ llvm::Target const* target =
+ llvm::TargetRegistry::lookupTarget(target_triple, errmsg);
+
+ CHECK(target != NULL) << errmsg;
+
+ // Target options
+ llvm::TargetOptions target_options;
+ target_options.FloatABIType = llvm::FloatABI::Soft;
+ target_options.NoFramePointerElim = true;
+ target_options.NoFramePointerElimNonLeaf = true;
+ target_options.UseSoftFloat = false;
+ target_options.EnableFastISel = true;
+
+ // Create the llvm::TargetMachine
+ llvm::TargetMachine* target_machine =
+ target->createTargetMachine(target_triple, "", target_attr, target_options,
+ llvm::Reloc::Static, llvm::CodeModel::Small,
+ llvm::CodeGenOpt::Less);
+
+ CHECK(target_machine != NULL) << "Failed to create target machine";
+
+ // Add target data
+ llvm::TargetData const* target_data = target_machine->getTargetData();
+
+ // PassManager for code generation passes
+ llvm::PassManager pm;
+ pm.add(new llvm::TargetData(*target_data));
+
+ // FunctionPassManager for optimization pass
+ llvm::FunctionPassManager fpm(module);
+ fpm.add(new llvm::TargetData(*target_data));
+
+ // Add optimization pass
+ llvm::PassManagerBuilder pm_builder;
+ pm_builder.Inliner = llvm::createAlwaysInlinerPass();
+ pm_builder.OptLevel = 1;
+ pm_builder.DisableSimplifyLibCalls = 1;
+ pm_builder.populateModulePassManager(pm);
+ pm_builder.populateFunctionPassManager(fpm);
+
+ // Add passes to emit ELF image
+ {
+ llvm::formatted_raw_ostream formatted_os(
+ *(new llvm::raw_fd_ostream(output_fd, /* shouldClose */false)), true);
+
+ // Ask the target to add backend passes as necessary.
+ if (target_machine->addPassesToEmitFile(pm,
+ formatted_os,
+ llvm::TargetMachine::CGFT_ObjectFile,
+ true)) {
+ LOG(FATAL) << "Unable to generate ELF for this target";
+ 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();
+ F != E; ++F) {
+ fpm.run(*F);
+ }
+ fpm.doFinalization();
+
+ // Run the code generation passes
+ pm.run(*module);
+ }
+
+ return true;
+}
} // namespace compiler_llvm
} // namespace art
diff --git a/src/compiler_llvm/compilation_unit.h b/src/compiler_llvm/compilation_unit.h
index 953f4f4..9d87704 100644
--- a/src/compiler_llvm/compilation_unit.h
+++ b/src/compiler_llvm/compilation_unit.h
@@ -69,14 +69,6 @@
return irb_.get();
}
- std::string const& GetBitcodeFileName() const {
- return bitcode_filename_;
- }
-
- void SetBitcodeFileName(std::string const& filename) {
- bitcode_filename_ = filename;
- }
-
ElfImage GetElfImage() const {
return ElfImage(elf_image_);
}
@@ -86,7 +78,7 @@
return num_elf_funcs_++;
}
- bool WriteBitcodeToFile();
+ bool WriteBitcodeToFile(const std::string& bitcode_filename);
bool Materialize();
@@ -116,12 +108,13 @@
llvm::Module* module_;
std::string elf_image_;
- std::string bitcode_filename_;
SafeMap<const llvm::Function*, CompiledMethod*> compiled_methods_map_;
size_t mem_usage_;
uint16_t num_elf_funcs_;
+
+ static bool MaterializeFile(int input_fd, int output_fd, InstructionSet insn_set);
};
} // namespace compiler_llvm
diff --git a/src/compiler_llvm/compiler_llvm.cc b/src/compiler_llvm/compiler_llvm.cc
index 8945210..2ebf5f6 100644
--- a/src/compiler_llvm/compiler_llvm.cc
+++ b/src/compiler_llvm/compiler_llvm.cc
@@ -129,57 +129,66 @@
// Allocate compilation unit
size_t cunit_idx = cunits_.size();
-
curr_cunit_ = new CompilationUnit(insn_set_, cunit_idx);
- // Setup bitcode output filename
- if (IsBitcodeFileNameAvailable()) {
- curr_cunit_->SetBitcodeFileName(
- StringPrintf("%s-%zu", bitcode_filename_.c_str(), cunit_idx));
- }
-
// Register compilation unit
cunits_.push_back(curr_cunit_);
}
void CompilerLLVM::MaterializeRemainder() {
- MutexLock GUARD(compiler_lock_);
- if (curr_cunit_ != NULL) {
- Materialize();
+ 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() {
- MutexLock GUARD(compiler_lock_);
+ compiler_lock_.Lock();
+ // Localize
+ CompilationUnit* cunit = curr_cunit_;
+
if (curr_cunit_ != NULL && curr_cunit_->IsMaterializeThresholdReached()) {
- Materialize();
+ // 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() {
- compiler_lock_.AssertHeld();
-
- DCHECK(curr_cunit_ != NULL);
- DCHECK(!curr_cunit_->IsMaterialized());
+void CompilerLLVM::Materialize(CompilationUnit* cunit) {
+ DCHECK(cunit != NULL);
+ DCHECK(!cunit->IsMaterialized());
// Write bitcode to file when filename is set
if (IsBitcodeFileNameAvailable()) {
- curr_cunit_->WriteBitcodeToFile();
+ const size_t cunit_idx = cunits_.size();
+ cunit->WriteBitcodeToFile(
+ StringPrintf("%s-%zu", bitcode_filename_.c_str(), cunit_idx));
}
// Materialize the llvm::Module into ELF object file
- curr_cunit_->Materialize();
+ cunit->Materialize();
// Load ELF image when automatic ELF loading is enabled
if (IsAutoElfLoadingEnabled()) {
- LoadElfFromCompilationUnit(curr_cunit_);
+ LoadElfFromCompilationUnit(cunit);
}
-
- // Delete the compilation unit
- curr_cunit_ = NULL;
}
diff --git a/src/compiler_llvm/compiler_llvm.h b/src/compiler_llvm/compiler_llvm.h
index 8bb053e..a6cf966 100644
--- a/src/compiler_llvm/compiler_llvm.h
+++ b/src/compiler_llvm/compiler_llvm.h
@@ -109,7 +109,7 @@
private:
void EnsureCompilationUnit();
- void Materialize();
+ void Materialize(CompilationUnit* cunit);
void LoadElfFromCompilationUnit(const CompilationUnit* cunit);