Revert "Switch to use RSCompilerDriver."
This reverts commit fef9a1b0b772034b4f0894d1e2b29d1115617be0.
Conflicts:
lib/ExecutionEngine/RSCompiler.cpp
Change-Id: Ic6f3a3643e286a20799e1c7f03dee5d6c3683fef
diff --git a/lib/ExecutionEngine/Android.mk b/lib/ExecutionEngine/Android.mk
index 8c78cd0..f9877d5 100644
--- a/lib/ExecutionEngine/Android.mk
+++ b/lib/ExecutionEngine/Android.mk
@@ -34,10 +34,10 @@
GDBJITRegistrar.cpp \
Initialization.cpp \
InputFile.cpp \
+ MCCacheWriter.cpp \
+ MCCacheReader.cpp \
ObjectLoader.cpp \
OutputFile.cpp \
- RSCompiler.cpp \
- RSCompilerDriver.cpp \
RSExecutable.cpp \
RSForEachExpand.cpp \
RSInfo.cpp \
@@ -47,6 +47,8 @@
RSScript.cpp \
BCCRuntimeStub.c \
Script.cpp \
+ ScriptCached.cpp \
+ ScriptCompiled.cpp \
Sha1Helper.cpp \
Source.cpp \
SymbolResolverProxy.cpp \
diff --git a/lib/ExecutionEngine/BCCContext.cpp b/lib/ExecutionEngine/BCCContext.cpp
index 62995ed..892fd5a 100644
--- a/lib/ExecutionEngine/BCCContext.cpp
+++ b/lib/ExecutionEngine/BCCContext.cpp
@@ -19,6 +19,7 @@
#include <new>
#include "BCCContextImpl.h"
+#include "Compiler.h"
#include "DebugHelper.h"
#include "Source.h"
@@ -41,7 +42,10 @@
GlobalContext = NULL;
}
-BCCContext::BCCContext() : mImpl(new BCCContextImpl(*this)) { }
+BCCContext::BCCContext() : mImpl(new BCCContextImpl(*this)) {
+ // Initialize the LLVM compiler infrastructure.
+ Compiler::GlobalInitialization();
+}
BCCContext::~BCCContext() {
delete mImpl;
diff --git a/lib/ExecutionEngine/Compiler.cpp b/lib/ExecutionEngine/Compiler.cpp
index 2348d56..458d835 100644
--- a/lib/ExecutionEngine/Compiler.cpp
+++ b/lib/ExecutionEngine/Compiler.cpp
@@ -16,367 +16,656 @@
#include "Compiler.h"
-#include <llvm/Analysis/Passes.h>
-#include <llvm/CodeGen/RegAllocRegistry.h>
-#include <llvm/Module.h>
-#include <llvm/PassManager.h>
-#include <llvm/Support/TargetRegistry.h>
-#include <llvm/Support/raw_ostream.h>
-#include <llvm/Target/TargetData.h>
-#include <llvm/Target/TargetMachine.h>
-#include <llvm/Transforms/IPO.h>
-#include <llvm/Transforms/Scalar.h>
+#include "Config.h"
+#include <bcinfo/MetadataExtractor.h>
-#include "CompilerConfig.h"
+#if USE_DISASSEMBLER
+#include "Disassembler/Disassembler.h"
+#endif
+
+#include "BCCRuntimeSymbolResolver.h"
#include "DebugHelper.h"
-#include "OutputFile.h"
-#include "Script.h"
-#include "Source.h"
+#include "ScriptCompiled.h"
+#include "Sha1Helper.h"
+#include "CompilerOption.h"
+#include "SymbolResolverProxy.h"
+#include "SymbolResolvers.h"
-using namespace bcc;
+#include "librsloader.h"
-const char *Compiler::GetErrorString(enum ErrorCode pErrCode) {
- static const char *ErrorString[] = {
- /* kSuccess */
- "Successfully compiled.",
- /* kInvalidConfigNoTarget */
- "Invalid compiler config supplied (getTarget() returns NULL.) "
- "(missing call to CompilerConfig::initialize()?)",
- /* kErrCreateTargetMachine */
- "Failed to create llvm::TargetMachine.",
- /* kErrSwitchTargetMachine */
- "Failed to switch llvm::TargetMachine.",
- /* kErrNoTargetMachine */
- "Failed to compile the script since there's no available TargetMachine."
- " (missing call to Compiler::config()?)",
- /* kErrTargetDataNoMemory */
- "Out of memory when create TargetData during compilation.",
- /* kErrMaterialization */
- "Failed to materialize the module.",
- /* kErrInvalidOutputFileState */
- "Supplied output file was invalid (in the error state.)",
- /* kErrPrepareOutput */
- "Failed to prepare file for output.",
- /* kPrepareCodeGenPass */
- "Failed to construct pass list for code-generation.",
+#include "RSTransforms.h"
- /* kErrHookBeforeAddLTOPasses */
- "Error occurred during beforeAddLTOPasses() in subclass.",
- /* kErrHookAfterAddLTOPasses */
- "Error occurred during afterAddLTOPasses() in subclass.",
- /* kErrHookBeforeExecuteLTOPasses */
- "Error occurred during beforeExecuteLTOPasses() in subclass.",
- /* kErrHookAfterExecuteLTOPasses */
- "Error occurred during afterExecuteLTOPasses() in subclass.",
+#include "llvm/ADT/StringRef.h"
- /* kErrHookBeforeAddCodeGenPasses */
- "Error occurred during beforeAddCodeGenPasses() in subclass.",
- /* kErrHookAfterAddCodeGenPasses */
- "Error occurred during afterAddCodeGenPasses() in subclass.",
- /* kErrHookBeforeExecuteCodeGenPasses */
- "Error occurred during beforeExecuteCodeGenPasses() in subclass.",
- /* kErrHookAfterExecuteCodeGenPasses */
- "Error occurred during afterExecuteCodeGenPasses() in subclass.",
+#include "llvm/Analysis/Passes.h"
- /* kMaxErrorCode */
- "(Unknown error code)"
- };
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/CodeGen/RegAllocRegistry.h"
+#include "llvm/CodeGen/SchedulerRegistry.h"
- if (pErrCode > kMaxErrorCode) {
- pErrCode = kMaxErrorCode;
- }
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/SubtargetFeature.h"
- return ErrorString[ static_cast<size_t>(pErrCode) ];
-}
+#include "llvm/Transforms/IPO.h"
+#include "llvm/Transforms/Scalar.h"
-//===----------------------------------------------------------------------===//
-// Instance Methods
-//===----------------------------------------------------------------------===//
-Compiler::Compiler() : mTarget(NULL), mEnableLTO(true) {
- return;
-}
+#include "llvm/Target/TargetData.h"
+#include "llvm/Target/TargetMachine.h"
-Compiler::Compiler(const CompilerConfig &pConfig) : mTarget(NULL),
- mEnableLTO(true) {
- const std::string &triple = pConfig.getTriple();
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/raw_ostream.h"
- enum ErrorCode err = config(pConfig);
- if (err != kSuccess) {
- ALOGE("%s (%s, features: %s)", GetErrorString(err),
- triple.c_str(), pConfig.getFeatureString().c_str());
+#include "llvm/Constants.h"
+#include "llvm/GlobalValue.h"
+#include "llvm/Linker.h"
+#include "llvm/LLVMContext.h"
+#include "llvm/Module.h"
+#include "llvm/PassManager.h"
+#include "llvm/Type.h"
+#include "llvm/Value.h"
+
+#include <errno.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string.h>
+
+#include <algorithm>
+#include <iterator>
+#include <string>
+#include <vector>
+
+extern char* gDebugDumpDirectory;
+
+namespace bcc {
+
+//////////////////////////////////////////////////////////////////////////////
+// BCC Compiler Static Variables
+//////////////////////////////////////////////////////////////////////////////
+
+bool Compiler::GlobalInitialized = false;
+
+
+#if !defined(__HOST__)
+ #define TARGET_TRIPLE_STRING DEFAULT_TARGET_TRIPLE_STRING
+#else
+// In host TARGET_TRIPLE_STRING is a variable to allow cross-compilation.
+ #if defined(__cplusplus)
+ extern "C" {
+ #endif
+ char *TARGET_TRIPLE_STRING = (char*)DEFAULT_TARGET_TRIPLE_STRING;
+ #if defined(__cplusplus)
+ };
+ #endif
+#endif
+
+// Code generation optimization level for the compiler
+llvm::CodeGenOpt::Level Compiler::CodeGenOptLevel;
+
+std::string Compiler::Triple;
+llvm::Triple::ArchType Compiler::ArchType;
+
+std::string Compiler::CPU;
+
+std::vector<std::string> Compiler::Features;
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Compiler
+//////////////////////////////////////////////////////////////////////////////
+
+void Compiler::GlobalInitialization() {
+ if (GlobalInitialized) {
return;
}
+#if defined(PROVIDE_ARM_CODEGEN)
+ LLVMInitializeARMAsmPrinter();
+ LLVMInitializeARMTargetMC();
+ LLVMInitializeARMTargetInfo();
+ LLVMInitializeARMTarget();
+#endif
+
+#if defined(PROVIDE_MIPS_CODEGEN)
+ LLVMInitializeMipsAsmPrinter();
+ LLVMInitializeMipsTargetMC();
+ LLVMInitializeMipsTargetInfo();
+ LLVMInitializeMipsTarget();
+#endif
+
+#if defined(PROVIDE_X86_CODEGEN)
+ LLVMInitializeX86AsmPrinter();
+ LLVMInitializeX86TargetMC();
+ LLVMInitializeX86TargetInfo();
+ LLVMInitializeX86Target();
+#endif
+
+#if USE_DISASSEMBLER
+ InitializeDisassembler();
+#endif
+
+ // if (!llvm::llvm_is_multithreaded())
+ // llvm::llvm_start_multithreaded();
+
+ // Set Triple, CPU and Features here
+ Triple = TARGET_TRIPLE_STRING;
+
+ // Determine ArchType
+#if defined(__HOST__)
+ {
+ std::string Err;
+ llvm::Target const *Target = llvm::TargetRegistry::lookupTarget(Triple, Err);
+ if (Target != NULL) {
+ ArchType = llvm::Triple::getArchTypeForLLVMName(Target->getName());
+ } else {
+ ArchType = llvm::Triple::UnknownArch;
+ ALOGE("%s", Err.c_str());
+ }
+ }
+#elif defined(DEFAULT_ARM_CODEGEN)
+ ArchType = llvm::Triple::arm;
+#elif defined(DEFAULT_MIPS_CODEGEN)
+ ArchType = llvm::Triple::mipsel;
+#elif defined(DEFAULT_X86_CODEGEN)
+ ArchType = llvm::Triple::x86;
+#elif defined(DEFAULT_X86_64_CODEGEN)
+ ArchType = llvm::Triple::x86_64;
+#else
+ ArchType = llvm::Triple::UnknownArch;
+#endif
+
+ if ((ArchType == llvm::Triple::arm) || (ArchType == llvm::Triple::thumb)) {
+# if defined(ARCH_ARM_HAVE_VFP)
+ Features.push_back("+vfp3");
+# if !defined(ARCH_ARM_HAVE_VFP_D32)
+ Features.push_back("+d16");
+# endif
+# endif
+
+# if defined(ARCH_ARM_HAVE_NEON)
+ Features.push_back("+neon");
+ Features.push_back("+neonfp");
+# else
+ Features.push_back("-neon");
+ Features.push_back("-neonfp");
+# endif
+
+// FIXME(all): Turn NEON back on after debugging the rebase.
+# if 1 || defined(DISABLE_ARCH_ARM_HAVE_NEON)
+ Features.push_back("-neon");
+ Features.push_back("-neonfp");
+# endif
+ }
+
+ // Register the scheduler
+ llvm::RegisterScheduler::setDefault(llvm::createDefaultScheduler);
+
+ // Read in SHA1 checksum of libbcc and libRS.
+ readSHA1(sha1LibBCC_SHA1, sizeof(sha1LibBCC_SHA1), pathLibBCC_SHA1);
+
+ calcFileSHA1(sha1LibRS, pathLibRS);
+
+ GlobalInitialized = true;
+}
+
+
+void Compiler::LLVMErrorHandler(void *UserData, const std::string &Message) {
+ std::string *Error = static_cast<std::string*>(UserData);
+ Error->assign(Message);
+ ALOGE("%s", Message.c_str());
+ exit(1);
+}
+
+
+Compiler::Compiler(ScriptCompiled *result)
+ : mpResult(result),
+ mRSExecutable(NULL),
+ mpSymbolLookupFn(NULL),
+ mpSymbolLookupContext(NULL),
+ mModule(NULL) {
+ llvm::remove_fatal_error_handler();
+ llvm::install_fatal_error_handler(LLVMErrorHandler, &mError);
return;
}
-enum Compiler::ErrorCode Compiler::config(const CompilerConfig &pConfig) {
- if (pConfig.getTarget() == NULL) {
- return kInvalidConfigNoTarget;
+int Compiler::readModule(llvm::Module &pModule) {
+ mModule = &pModule;
+ if (pModule.getMaterializer() != NULL) {
+ // A module with non-null materializer means that it is a lazy-load module.
+ // Materialize it now via invoking MaterializeAllPermanently(). This
+ // function returns false when the materialization is successful.
+ if (pModule.MaterializeAllPermanently(&mError)) {
+ setError("Failed to materialize the module `" +
+ pModule.getModuleIdentifier() + "'! (" + mError + ")");
+ mModule = NULL;
+ }
+ }
+ return hasError();
+}
+
+int Compiler::compile(const CompilerOption &option) {
+ llvm::Target const *Target = NULL;
+ llvm::TargetData *TD = NULL;
+ llvm::TargetMachine *TM = NULL;
+
+ std::string FeaturesStr;
+
+ if (mModule == NULL) // No module was loaded
+ return 0;
+
+ bcinfo::MetadataExtractor ME(mModule);
+ ME.extract();
+
+ size_t VarCount = ME.getExportVarCount();
+ size_t FuncCount = ME.getExportFuncCount();
+ size_t ForEachSigCount = ME.getExportForEachSignatureCount();
+ size_t ObjectSlotCount = ME.getObjectSlotCount();
+ size_t PragmaCount = ME.getPragmaCount();
+
+ std::vector<std::string> &VarNameList = mpResult->mExportVarsName;
+ std::vector<std::string> &FuncNameList = mpResult->mExportFuncsName;
+ std::vector<std::string> &ForEachExpandList = mpResult->mExportForEachName;
+ RSInfo::ExportForeachFuncListTy ForEachFuncList;
+ std::vector<const char*> ExportSymbols;
+
+ // Defaults to maximum optimization level from MetadataExtractor.
+ uint32_t OptimizationLevel = ME.getOptimizationLevel();
+
+ if (OptimizationLevel == 0) {
+ CodeGenOptLevel = llvm::CodeGenOpt::None;
+ } else if (OptimizationLevel == 1) {
+ CodeGenOptLevel = llvm::CodeGenOpt::Less;
+ } else if (OptimizationLevel == 2) {
+ CodeGenOptLevel = llvm::CodeGenOpt::Default;
+ } else if (OptimizationLevel == 3) {
+ CodeGenOptLevel = llvm::CodeGenOpt::Aggressive;
}
- llvm::TargetMachine *new_target =
- (pConfig.getTarget())->createTargetMachine(pConfig.getTriple(),
- pConfig.getCPU(),
- pConfig.getFeatureString(),
- pConfig.getTargetOptions(),
- pConfig.getRelocationModel(),
- pConfig.getCodeModel(),
- pConfig.getOptimizationLevel());
+ // not the best place for this, but we need to set the register allocation
+ // policy after we read the optimization_level metadata from the bitcode
- if (new_target == NULL) {
- return ((mTarget != NULL) ? kErrSwitchTargetMachine :
- kErrCreateTargetMachine);
- }
-
- // Replace the old TargetMachine.
- delete mTarget;
- mTarget = new_target;
-
- // Adjust register allocation policy according to the optimization level.
+ // Register allocation policy:
// createFastRegisterAllocator: fast but bad quality
// createLinearScanRegisterAllocator: not so fast but good quality
- if ((pConfig.getOptimizationLevel() == llvm::CodeGenOpt::None)) {
- llvm::RegisterRegAlloc::setDefault(llvm::createFastRegisterAllocator);
- } else {
- llvm::RegisterRegAlloc::setDefault(llvm::createGreedyRegisterAllocator);
+ llvm::RegisterRegAlloc::setDefault
+ ((CodeGenOptLevel == llvm::CodeGenOpt::None) ?
+ llvm::createFastRegisterAllocator :
+ llvm::createGreedyRegisterAllocator);
+
+ // Find LLVM Target
+ Target = llvm::TargetRegistry::lookupTarget(Triple, mError);
+ if (hasError())
+ goto on_bcc_compile_error;
+
+#if defined(ARCH_ARM_HAVE_NEON)
+ // Full-precision means we have to disable NEON
+ if (ME.getRSFloatPrecision() == bcinfo::RS_FP_Full) {
+ Features.push_back("-neon");
+ Features.push_back("-neonfp");
+ }
+#endif
+
+ if (!CPU.empty() || !Features.empty()) {
+ llvm::SubtargetFeatures F;
+
+ for (std::vector<std::string>::const_iterator
+ I = Features.begin(), E = Features.end(); I != E; I++) {
+ F.AddFeature(*I);
+ }
+
+ FeaturesStr = F.getString();
}
- // Relax all machine instructions.
- mTarget->setMCRelaxAll(true);
+ // Create LLVM Target Machine
+ TM = Target->createTargetMachine(Triple, CPU, FeaturesStr,
+ option.TargetOpt,
+ option.RelocModelOpt,
+ option.CodeModelOpt);
- return kSuccess;
+ if (TM == NULL) {
+ setError("Failed to create target machine implementation for the"
+ " specified triple '" + Triple + "'");
+ goto on_bcc_compile_error;
+ }
+
+ // Get target data from Module
+ TD = new llvm::TargetData(mModule);
+
+ // Read pragma information from MetadataExtractor
+ if (PragmaCount) {
+ ScriptCompiled::PragmaList &PragmaPairs = mpResult->mPragmas;
+ const char **PragmaKeys = ME.getPragmaKeyList();
+ const char **PragmaValues = ME.getPragmaValueList();
+ for (size_t i = 0; i < PragmaCount; i++) {
+ PragmaPairs.push_back(std::make_pair(PragmaKeys[i], PragmaValues[i]));
+ }
+ }
+
+ if (VarCount) {
+ const char **VarNames = ME.getExportVarNameList();
+ for (size_t i = 0; i < VarCount; i++) {
+ VarNameList.push_back(VarNames[i]);
+ ExportSymbols.push_back(VarNames[i]);
+ }
+ }
+
+ if (FuncCount) {
+ const char **FuncNames = ME.getExportFuncNameList();
+ for (size_t i = 0; i < FuncCount; i++) {
+ FuncNameList.push_back(FuncNames[i]);
+ ExportSymbols.push_back(FuncNames[i]);
+ }
+ }
+
+ if (ForEachSigCount) {
+ const char **ForEachNames = ME.getExportForEachNameList();
+ const uint32_t *ForEachSigs = ME.getExportForEachSignatureList();
+ for (size_t i = 0; i < ForEachSigCount; i++) {
+ ForEachFuncList.push_back(std::make_pair(ForEachNames[i],
+ ForEachSigs[i]));
+ ForEachExpandList.push_back(std::string(ForEachNames[i]) + ".expand");
+ }
+
+ // Need to wait until ForEachExpandList is fully populated to fill in
+ // exported symbols.
+ for (size_t i = 0; i < ForEachSigCount; i++) {
+ ExportSymbols.push_back(ForEachExpandList[i].c_str());
+ }
+ }
+
+ if (ObjectSlotCount) {
+ ScriptCompiled::ObjectSlotList &objectSlotList = mpResult->mObjectSlots;
+ const uint32_t *ObjectSlots = ME.getObjectSlotList();
+ for (size_t i = 0; i < ObjectSlotCount; i++) {
+ objectSlotList.push_back(ObjectSlots[i]);
+ }
+ }
+
+ runInternalPasses(ForEachFuncList);
+
+ // Perform link-time optimization if we have multiple modules
+ if (option.RunLTO) {
+ runLTO(new llvm::TargetData(*TD), ExportSymbols, CodeGenOptLevel);
+ }
+
+ // Perform code generation
+ if (runMCCodeGen(new llvm::TargetData(*TD), TM) != 0) {
+ goto on_bcc_compile_error;
+ }
+
+ if (!option.LoadAfterCompile)
+ return 0;
+
+ // Load the ELF Object
+ {
+ BCCRuntimeSymbolResolver BCCRuntimesResolver;
+ LookupFunctionSymbolResolver<void*> RSSymbolResolver(mpSymbolLookupFn,
+ mpSymbolLookupContext);
+
+ SymbolResolverProxy Resolver;
+ Resolver.chainResolver(BCCRuntimesResolver);
+ Resolver.chainResolver(RSSymbolResolver);
+
+ mRSExecutable =
+ rsloaderCreateExec((unsigned char *)&*mEmittedELFExecutable.begin(),
+ mEmittedELFExecutable.size(),
+ SymbolResolverProxy::LookupFunction, &Resolver);
+ }
+
+ if (!mRSExecutable) {
+ setError("Fail to load emitted ELF relocatable file");
+ goto on_bcc_compile_error;
+ }
+
+ rsloaderUpdateSectionHeaders(mRSExecutable,
+ (unsigned char*) mEmittedELFExecutable.begin());
+
+ // Once the ELF object has been loaded, populate the various slots for RS
+ // with the appropriate relocated addresses.
+ if (VarCount) {
+ ScriptCompiled::ExportVarList &VarList = mpResult->mExportVars;
+ for (size_t i = 0; i < VarCount; i++) {
+ VarList.push_back(rsloaderGetSymbolAddress(mRSExecutable,
+ VarNameList[i].c_str()));
+ }
+ }
+
+ if (FuncCount) {
+ ScriptCompiled::ExportFuncList &FuncList = mpResult->mExportFuncs;
+ for (size_t i = 0; i < FuncCount; i++) {
+ FuncList.push_back(rsloaderGetSymbolAddress(mRSExecutable,
+ FuncNameList[i].c_str()));
+ }
+ }
+
+ if (ForEachSigCount) {
+ ScriptCompiled::ExportForEachList &ForEachList = mpResult->mExportForEach;
+ for (size_t i = 0; i < ForEachSigCount; i++) {
+ ForEachList.push_back(rsloaderGetSymbolAddress(mRSExecutable,
+ ForEachExpandList[i].c_str()));
+ }
+ }
+
+#if DEBUG_MC_DISASSEMBLER
+ {
+ // Get MC codegen emitted function name list
+ size_t func_list_size = rsloaderGetFuncCount(mRSExecutable);
+ std::vector<char const *> func_list(func_list_size, NULL);
+ rsloaderGetFuncNameList(mRSExecutable, func_list_size, &*func_list.begin());
+
+ // Disassemble each function
+ for (size_t i = 0; i < func_list_size; ++i) {
+ void *func = rsloaderGetSymbolAddress(mRSExecutable, func_list[i]);
+ if (func) {
+ size_t size = rsloaderGetSymbolSize(mRSExecutable, func_list[i]);
+ Disassemble(DEBUG_MC_DISASSEMBLER_FILE,
+ Target, TM, func_list[i], (unsigned char const *)func, size);
+ }
+ }
+ }
+#endif
+
+on_bcc_compile_error:
+ // ALOGE("on_bcc_compiler_error");
+ if (TD) {
+ delete TD;
+ }
+
+ if (TM) {
+ delete TM;
+ }
+
+ if (mError.empty()) {
+ return 0;
+ }
+
+ // ALOGE(getErrorMessage());
+ return 1;
}
-Compiler::~Compiler() {
- delete mTarget;
+
+int Compiler::runMCCodeGen(llvm::TargetData *TD, llvm::TargetMachine *TM) {
+ // Decorate mEmittedELFExecutable with formatted ostream
+ llvm::raw_svector_ostream OutSVOS(mEmittedELFExecutable);
+
+ // Relax all machine instructions
+ TM->setMCRelaxAll(/* RelaxAll= */ true);
+
+ // Create MC code generation pass manager
+ llvm::PassManager MCCodeGenPasses;
+
+ // Add TargetData to MC code generation pass manager
+ MCCodeGenPasses.add(TD);
+
+ // Add MC code generation passes to pass manager
+ llvm::MCContext *Ctx = NULL;
+ if (TM->addPassesToEmitMC(MCCodeGenPasses, Ctx, OutSVOS, false)) {
+ setError("Fail to add passes to emit file");
+ return 1;
+ }
+
+ MCCodeGenPasses.run(*mModule);
+ OutSVOS.flush();
+ return 0;
}
-enum Compiler::ErrorCode Compiler::runLTO(Script &pScript) {
- llvm::TargetData *target_data = NULL;
+int Compiler::runInternalPasses(RSInfo::ExportForeachFuncListTy pForEachFuncs) {
+ llvm::PassManager BCCPasses;
- // Pass manager for link-time optimization
- llvm::PassManager lto_passes;
+ // Expand ForEach on CPU path to reduce launch overhead.
+ BCCPasses.add(createRSForEachExpandPass(pForEachFuncs));
- // Prepare TargetData target data from Module
- target_data = new (std::nothrow) llvm::TargetData(*mTarget->getTargetData());
- if (target_data == NULL) {
- return kErrTargetDataNoMemory;
- }
+ BCCPasses.run(*mModule);
- // Add TargetData to the pass manager.
- lto_passes.add(target_data);
+ return 0;
+}
- // Invokde "beforeAddLTOPasses" before adding the first pass.
- if (!beforeAddLTOPasses(pScript, lto_passes)) {
- return kErrHookBeforeAddLTOPasses;
- }
+int Compiler::runLTO(llvm::TargetData *TD,
+ std::vector<const char*>& ExportSymbols,
+ llvm::CodeGenOpt::Level OptimizationLevel) {
+ // Note: ExportSymbols is a workaround for getting all exported variable,
+ // function, and kernel names.
+ // We should refine it soon.
+
+ // TODO(logan): Remove this after we have finished the
+ // bccMarkExternalSymbol API.
+
+ // root(), init(), and .rs.dtor() are born to be exported
+ ExportSymbols.push_back("root");
+ ExportSymbols.push_back("init");
+ ExportSymbols.push_back(".rs.dtor");
+
+ // User-defined exporting symbols
+ std::vector<char const *> const &UserDefinedExternalSymbols =
+ mpResult->getUserDefinedExternalSymbols();
+
+ std::copy(UserDefinedExternalSymbols.begin(),
+ UserDefinedExternalSymbols.end(),
+ std::back_inserter(ExportSymbols));
+
+ llvm::PassManager LTOPasses;
+
+ // Add TargetData to LTO passes
+ LTOPasses.add(TD);
// We now create passes list performing LTO. These are copied from
- // (including comments) llvm::PassManagerBuilder::populateLTOPassManager().
- // Only a subset of these LTO passes are enabled in optimization level 0 as
- // they interfere with interactive debugging.
- //
- // FIXME: Figure out which passes (if any) makes sense for levels 1 and 2.
- //if ( != llvm::CodeGenOpt::None) {
- if (mTarget->getOptLevel() == llvm::CodeGenOpt::None) {
- lto_passes.add(llvm::createGlobalOptimizerPass());
- lto_passes.add(llvm::createConstantMergePass());
- } else {
+ // (including comments) llvm::createStandardLTOPasses().
+ // Only a subset of these LTO passes are enabled in optimization level 0
+ // as they interfere with interactive debugging.
+ // FIXME: figure out which passes (if any) makes sense for levels 1 and 2
+
+ if (OptimizationLevel != llvm::CodeGenOpt::None) {
+ // Internalize all other symbols not listed in ExportSymbols
+ LTOPasses.add(llvm::createInternalizePass(ExportSymbols));
+
// Propagate constants at call sites into the functions they call. This
// opens opportunities for globalopt (and inlining) by substituting
// function pointers passed as arguments to direct uses of functions.
- lto_passes.add(llvm::createIPSCCPPass());
+ LTOPasses.add(llvm::createIPSCCPPass());
// Now that we internalized some globals, see if we can hack on them!
- lto_passes.add(llvm::createGlobalOptimizerPass());
+ LTOPasses.add(llvm::createGlobalOptimizerPass());
// Linking modules together can lead to duplicated global constants, only
// keep one copy of each constant...
- lto_passes.add(llvm::createConstantMergePass());
+ LTOPasses.add(llvm::createConstantMergePass());
// Remove unused arguments from functions...
- lto_passes.add(llvm::createDeadArgEliminationPass());
+ LTOPasses.add(llvm::createDeadArgEliminationPass());
// Reduce the code after globalopt and ipsccp. Both can open up
// significant simplification opportunities, and both can propagate
// functions through function pointers. When this happens, we often have
// to resolve varargs calls, etc, so let instcombine do this.
- lto_passes.add(llvm::createInstructionCombiningPass());
+ LTOPasses.add(llvm::createInstructionCombiningPass());
// Inline small functions
- lto_passes.add(llvm::createFunctionInliningPass());
+ LTOPasses.add(llvm::createFunctionInliningPass());
// Remove dead EH info.
- lto_passes.add(llvm::createPruneEHPass());
+ LTOPasses.add(llvm::createPruneEHPass());
// Internalize the globals again after inlining
- lto_passes.add(llvm::createGlobalOptimizerPass());
+ LTOPasses.add(llvm::createGlobalOptimizerPass());
// Remove dead functions.
- lto_passes.add(llvm::createGlobalDCEPass());
+ LTOPasses.add(llvm::createGlobalDCEPass());
// If we didn't decide to inline a function, check to see if we can
// transform it to pass arguments by value instead of by reference.
- lto_passes.add(llvm::createArgumentPromotionPass());
+ LTOPasses.add(llvm::createArgumentPromotionPass());
// The IPO passes may leave cruft around. Clean up after them.
- lto_passes.add(llvm::createInstructionCombiningPass());
- lto_passes.add(llvm::createJumpThreadingPass());
+ LTOPasses.add(llvm::createInstructionCombiningPass());
+ LTOPasses.add(llvm::createJumpThreadingPass());
// Break up allocas
- lto_passes.add(llvm::createScalarReplAggregatesPass());
+ LTOPasses.add(llvm::createScalarReplAggregatesPass());
// Run a few AA driven optimizations here and now, to cleanup the code.
- lto_passes.add(llvm::createFunctionAttrsPass()); // Add nocapture.
- lto_passes.add(llvm::createGlobalsModRefPass()); // IP alias analysis.
+ LTOPasses.add(llvm::createFunctionAttrsPass()); // Add nocapture.
+ LTOPasses.add(llvm::createGlobalsModRefPass()); // IP alias analysis.
// Hoist loop invariants.
- lto_passes.add(llvm::createLICMPass());
+ LTOPasses.add(llvm::createLICMPass());
// Remove redundancies.
- lto_passes.add(llvm::createGVNPass());
+ LTOPasses.add(llvm::createGVNPass());
// Remove dead memcpys.
- lto_passes.add(llvm::createMemCpyOptPass());
+ LTOPasses.add(llvm::createMemCpyOptPass());
// Nuke dead stores.
- lto_passes.add(llvm::createDeadStoreEliminationPass());
+ LTOPasses.add(llvm::createDeadStoreEliminationPass());
// Cleanup and simplify the code after the scalar optimizations.
- lto_passes.add(llvm::createInstructionCombiningPass());
+ LTOPasses.add(llvm::createInstructionCombiningPass());
- lto_passes.add(llvm::createJumpThreadingPass());
+ LTOPasses.add(llvm::createJumpThreadingPass());
// Delete basic blocks, which optimization passes may have killed.
- lto_passes.add(llvm::createCFGSimplificationPass());
+ LTOPasses.add(llvm::createCFGSimplificationPass());
// Now that we have optimized the program, discard unreachable functions.
- lto_passes.add(llvm::createGlobalDCEPass());
+ LTOPasses.add(llvm::createGlobalDCEPass());
+
+ } else {
+ LTOPasses.add(llvm::createInternalizePass(ExportSymbols));
+ LTOPasses.add(llvm::createGlobalOptimizerPass());
+ LTOPasses.add(llvm::createConstantMergePass());
}
- // Invokde "afterAddLTOPasses" after pass manager finished its
- // construction.
- if (!afterAddLTOPasses(pScript, lto_passes)) {
- return kErrHookAfterAddLTOPasses;
+ LTOPasses.run(*mModule);
+
+#if ANDROID_ENGINEERING_BUILD
+ if (0 != gDebugDumpDirectory) {
+ std::string errs;
+ std::string Filename(gDebugDumpDirectory);
+ Filename += "/post-lto-module.ll";
+ llvm::raw_fd_ostream FS(Filename.c_str(), errs);
+ mModule->print(FS, 0);
+ FS.close();
}
+#endif
- // Invokde "beforeExecuteLTOPasses" before executing the passes.
- if (!beforeExecuteLTOPasses(pScript, lto_passes)) {
- return kErrHookBeforeExecuteLTOPasses;
- }
-
- lto_passes.run(pScript.getSource().getModule());
-
- // Invokde "afterExecuteLTOPasses" before returning.
- if (!afterExecuteLTOPasses(pScript)) {
- return kErrHookAfterExecuteLTOPasses;
- }
-
- return kSuccess;
+ return 0;
}
-enum Compiler::ErrorCode Compiler::runCodeGen(Script &pScript,
- llvm::raw_ostream &pResult) {
- llvm::TargetData *target_data;
- llvm::MCContext *mc_context = NULL;
- // Create pass manager for MC code generation.
- llvm::PassManager codegen_passes;
-
- // Prepare TargetData target data from Module
- target_data = new (std::nothrow) llvm::TargetData(*mTarget->getTargetData());
- if (target_data == NULL) {
- return kErrTargetDataNoMemory;
- }
-
- // Add TargetData to the pass manager.
- codegen_passes.add(target_data);
-
- // Invokde "beforeAddCodeGenPasses" before adding the first pass.
- if (!beforeAddCodeGenPasses(pScript, codegen_passes)) {
- return kErrHookBeforeAddCodeGenPasses;
- }
-
- // Add passes to the pass manager to emit machine code through MC layer.
- if (mTarget->addPassesToEmitMC(codegen_passes, mc_context, pResult,
- /* DisableVerify */false)) {
- return kPrepareCodeGenPass;
- }
-
- // Invokde "afterAddCodeGenPasses" after pass manager finished its
- // construction.
- if (!afterAddCodeGenPasses(pScript, codegen_passes)) {
- return kErrHookAfterAddCodeGenPasses;
- }
-
- // Invokde "beforeExecuteCodeGenPasses" before executing the passes.
- if (!beforeExecuteCodeGenPasses(pScript, codegen_passes)) {
- return kErrHookBeforeExecuteCodeGenPasses;
- }
-
- // Execute the pass.
- codegen_passes.run(pScript.getSource().getModule());
-
- // Invokde "afterExecuteCodeGenPasses" before returning.
- if (!afterExecuteCodeGenPasses(pScript)) {
- return kErrHookAfterExecuteCodeGenPasses;
- }
-
- return kSuccess;
+void *Compiler::getSymbolAddress(char const *name) {
+ return rsloaderGetSymbolAddress(mRSExecutable, name);
}
-enum Compiler::ErrorCode Compiler::compile(Script &pScript,
- llvm::raw_ostream &pResult) {
- llvm::Module &module = pScript.getSource().getModule();
- enum ErrorCode err;
+Compiler::~Compiler() {
+ rsloaderDisposeExec(mRSExecutable);
- if (mTarget == NULL) {
- return kErrNoTargetMachine;
- }
-
- // Materialize the bitcode module.
- if (module.getMaterializer() != NULL) {
- std::string error;
- // A module with non-null materializer means that it is a lazy-load module.
- // Materialize it now via invoking MaterializeAllPermanently(). This
- // function returns false when the materialization is successful.
- if (module.MaterializeAllPermanently(&error)) {
- ALOGE("Failed to materialize the module `%s'! (%s)",
- module.getModuleIdentifier().c_str(), error.c_str());
- return kErrMaterialization;
- }
- }
-
- if (mEnableLTO && ((err = runLTO(pScript)) != kSuccess)) {
- return err;
- }
-
- if ((err = runCodeGen(pScript, pResult)) != kSuccess) {
- return err;
- }
-
- return kSuccess;
+ // llvm::llvm_shutdown();
}
-enum Compiler::ErrorCode Compiler::compile(Script &pScript,
- OutputFile &pResult) {
- // Check the state of the specified output file.
- if (pResult.hasError()) {
- return kErrInvalidOutputFileState;
- }
- // Open the output file decorated in llvm::raw_ostream.
- llvm::raw_ostream *out = pResult.dup();
- if (out == NULL) {
- return kErrPrepareOutput;
- }
-
- // Delegate the request.
- enum Compiler::ErrorCode err = compile(pScript, *out);
-
- // Close the output before return.
- delete out;
-
- return err;
-}
+} // namespace bcc
diff --git a/lib/ExecutionEngine/Compiler.h b/lib/ExecutionEngine/Compiler.h
index 5e37925..f0e75d1 100644
--- a/lib/ExecutionEngine/Compiler.h
+++ b/lib/ExecutionEngine/Compiler.h
@@ -14,130 +14,153 @@
* limitations under the License.
*/
-#ifndef BCC_EXECUTION_ENGINE_COMPILER_H
-#define BCC_EXECUTION_ENGINE_COMPILER_H
+#ifndef BCC_COMPILER_H
+#define BCC_COMPILER_H
+
+#include <bcc/bcc.h>
+
+#include <Config.h>
+
+#include "librsloader.h"
+
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Target/TargetMachine.h"
+
+#include <stddef.h>
+
+#include <list>
+#include <string>
+#include <vector>
+#include <utility>
+
+#include "RSInfo.h"
+
namespace llvm {
+ class Module;
+ class NamedMDNode;
+ class TargetData;
+}
-class raw_ostream;
-class PassManager;
-class TargetData;
-class TargetMachine;
-
-} // end namespace llvm
namespace bcc {
+ class ScriptCompiled;
+ struct CompilerOption;
-class CompilerConfig;
-class OutputFile;
-class Script;
+ class Compiler {
+ private:
+ //////////////////////////////////////////////////////////////////////////
+ // The variable section below (e.g., Triple, CodeGenOptLevel)
+ // is initialized in GlobalInitialization()
+ //
+ static bool GlobalInitialized;
-//===----------------------------------------------------------------------===//
-// Design of Compiler
-//===----------------------------------------------------------------------===//
-// 1. A compiler instance can be constructed provided an "initial config."
-// 2. A compiler can later be re-configured using config().
-// 3. Once config() is invoked, it'll re-create TargetMachine instance (i.e.,
-// mTarget) according to the configuration supplied. TargetMachine instance
-// is *shared* across the different calls to compile() before the next call
-// to config().
-// 4. Once a compiler instance is created, you can use the compile() service
-// to compile the file over and over again. Each call uses TargetMachine
-// instance to construct the compilation passes.
-class Compiler {
-public:
- enum ErrorCode {
- kSuccess,
+ // If given, this will be the name of the target triple to compile for.
+ // If not given, the initial values defined in this file will be used.
+ static std::string Triple;
+ static llvm::Triple::ArchType ArchType;
- kInvalidConfigNoTarget,
- kErrCreateTargetMachine,
- kErrSwitchTargetMachine,
- kErrNoTargetMachine,
- kErrTargetDataNoMemory,
- kErrMaterialization,
- kErrInvalidOutputFileState,
- kErrPrepareOutput,
- kPrepareCodeGenPass,
+ static llvm::CodeGenOpt::Level CodeGenOptLevel;
- kErrHookBeforeAddLTOPasses,
- kErrHookAfterAddLTOPasses,
- kErrHookBeforeExecuteLTOPasses,
- kErrHookAfterExecuteLTOPasses,
+ // End of section of GlobalInitializing variables
+ /////////////////////////////////////////////////////////////////////////
+ // If given, the name of the target CPU to generate code for.
+ static std::string CPU;
- kErrHookBeforeAddCodeGenPasses,
- kErrHookAfterAddCodeGenPasses,
- kErrHookBeforeExecuteCodeGenPasses,
- kErrHookAfterExecuteCodeGenPasses,
+ // The list of target specific features to enable or disable -- this should
+ // be a list of strings starting with '+' (enable) or '-' (disable).
+ static std::vector<std::string> Features;
- kMaxErrorCode,
- };
+ static void LLVMErrorHandler(void *UserData, const std::string &Message);
- static const char *GetErrorString(enum ErrorCode pErrCode);
+ friend class CodeEmitter;
+ friend class CodeMemoryManager;
-private:
- llvm::TargetMachine *mTarget;
- // LTO is enabled by default.
- bool mEnableLTO;
+ private:
+ ScriptCompiled *mpResult;
- enum ErrorCode runLTO(Script &pScript);
- enum ErrorCode runCodeGen(Script &pScript, llvm::raw_ostream &pResult);
+ std::string mError;
-public:
- Compiler();
- Compiler(const CompilerConfig &pConfig);
+ // Compilation buffer for MC
+ llvm::SmallVector<char, 1024> mEmittedELFExecutable;
- enum ErrorCode config(const CompilerConfig &pConfig);
+ // Loaded and relocated executable
+ RSExecRef mRSExecutable;
- // Compile a script and output the result to a LLVM stream.
- enum ErrorCode compile(Script &pScript, llvm::raw_ostream &pResult);
+ BCCSymbolLookupFn mpSymbolLookupFn;
+ void *mpSymbolLookupContext;
- // Compile a script and output the result to a file.
- enum ErrorCode compile(Script &pScript, OutputFile &pResult);
+ llvm::Module *mModule;
- void enableLTO(bool pEnable = true)
- { mEnableLTO = pEnable; }
+ public:
+ Compiler(ScriptCompiled *result);
- virtual ~Compiler();
+ static void GlobalInitialization();
-protected:
- //===--------------------------------------------------------------------===//
- // Plugin callbacks for sub-class.
- //===--------------------------------------------------------------------===//
- // Called before adding first pass to code-generation passes.
- virtual bool beforeAddLTOPasses(Script &pScript, llvm::PassManager &pPM)
- { return true; }
+ static std::string const &getTargetTriple() {
+ return Triple;
+ }
- // Called after adding last pass to code-generation passes.
- virtual bool afterAddLTOPasses(Script &pScript, llvm::PassManager &pPM)
- { return true; }
+ static llvm::Triple::ArchType getTargetArchType() {
+ return ArchType;
+ }
- // Called before executing code-generation passes.
- virtual bool beforeExecuteLTOPasses(Script &pScript,
- llvm::PassManager &pPM)
- { return true; }
+ void registerSymbolCallback(BCCSymbolLookupFn pFn, void *pContext) {
+ mpSymbolLookupFn = pFn;
+ mpSymbolLookupContext = pContext;
+ }
- // Called after executing code-generation passes.
- virtual bool afterExecuteLTOPasses(Script &pScript)
- { return true; }
+ void *getSymbolAddress(char const *name);
- // Called before adding first pass to code-generation passes.
- virtual bool beforeAddCodeGenPasses(Script &pScript, llvm::PassManager &pPM)
- { return true; }
+ const llvm::SmallVector<char, 1024> &getELF() const {
+ return mEmittedELFExecutable;
+ }
- // Called after adding last pass to code-generation passes.
- virtual bool afterAddCodeGenPasses(Script &pScript, llvm::PassManager &pPM)
- { return true; }
+ int readModule(llvm::Module &pModule);
- // Called before executing code-generation passes.
- virtual bool beforeExecuteCodeGenPasses(Script &pScript,
- llvm::PassManager &pPM)
- { return true; }
+ int compile(const CompilerOption &option);
- // Called after executing code-generation passes.
- virtual bool afterExecuteCodeGenPasses(Script &pScript)
- { return true; }
-};
+ char const *getErrorMessage() {
+ return mError.c_str();
+ }
-} // end namespace bcc
+ const llvm::Module *getModule() const {
+ return mModule;
+ }
-#endif // BCC_EXECUTION_ENGINE_COMPILER_H
+ ~Compiler();
+
+ private:
+
+ int runCodeGen(llvm::TargetData *TD, llvm::TargetMachine *TM,
+ llvm::NamedMDNode const *ExportVarMetadata,
+ llvm::NamedMDNode const *ExportFuncMetadata);
+
+ int runMCCodeGen(llvm::TargetData *TD, llvm::TargetMachine *TM);
+
+ int runInternalPasses(RSInfo::ExportForeachFuncListTy pForEachFuncs);
+
+ int runLTO(llvm::TargetData *TD,
+ std::vector<const char*>& ExportSymbols,
+ llvm::CodeGenOpt::Level OptimizationLevel);
+
+ bool hasError() const {
+ return !mError.empty();
+ }
+
+ void setError(const char *Error) {
+ mError.assign(Error); // Copying
+ }
+
+ void setError(const std::string &Error) {
+ mError = Error;
+ }
+
+ }; // End of class Compiler
+
+} // namespace bcc
+
+#endif // BCC_COMPILER_H
diff --git a/lib/ExecutionEngine/CompilerOption.h b/lib/ExecutionEngine/CompilerOption.h
new file mode 100644
index 0000000..f7c1e50
--- /dev/null
+++ b/lib/ExecutionEngine/CompilerOption.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright 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 BCC_COMPILER_OPTION_H
+#define BCC_COMPILER_OPTION_H
+
+#include "Config.h"
+#include "Compiler.h"
+
+#include "llvm/Target/TargetOptions.h"
+#include "llvm/Support/CodeGen.h"
+
+namespace bcc {
+
+class CompilerOption {
+ public:
+ // Constructor setup "default configuration". The "default configuration"
+ // here means the configuration for running RenderScript (more specifically,
+ // one can declare a CompilerOption object (call default constructor) and then
+ // pass to the Compiler::compiler() without any modification for RenderScript,
+ // see Script::prepareExecutable(...)).
+ //
+ // Must be invoked after calling Compiler::GlobalInitialization() at least once.
+ //
+ CompilerOption() {
+ //-- Setup options to llvm::TargetMachine --//
+
+ //-- Setup Frame Pointer Elimination Optimization --//
+#if defined(__HOST__)
+ // Disable frame pointer elimination optimization for X86_64 and X86
+ if ((Compiler::getTargetArchType() == llvm::Triple::x86_64) ||
+ (Compiler::getTargetArchType() == llvm::Triple::x86)) {
+ TargetOpt.NoFramePointerElim = true;
+ } else {
+ TargetOpt.NoFramePointerElim = false;
+ }
+#elif defined(DEFAULT_X86_64_CODEGEN)
+ TargetOpt.NoFramePointerElim = true;
+#elif defined(DEFAULT_X86_CODEGEN)
+ TargetOpt.NoFramePointerElim = true;
+#else
+ TargetOpt.NoFramePointerElim = false;
+#endif
+
+ // Use hardfloat ABI
+ //
+ // TODO(all): Need to detect the CPU capability and decide whether to use
+ // softfp. To use softfp, change following 2 lines to
+ //
+ // options.FloatABIType = llvm::FloatABI::Soft;
+ // options.UseSoftFloat = true;
+ TargetOpt.FloatABIType = llvm::FloatABI::Soft;
+ TargetOpt.UseSoftFloat = false;
+
+ //-- Setup relocation model --//
+ RelocModelOpt = llvm::Reloc::Static;
+
+ //-- Setup code model --//
+#if defined(__HOST__)
+ // Data address in X86_64 architecture may reside in a far-away place
+ if (Compiler::getTargetArchType() == llvm::Triple::x86_64) {
+ CodeModelOpt = llvm::CodeModel::Medium;
+ } else {
+ CodeModelOpt = llvm::CodeModel::Small;
+ }
+#elif defined(DEFAULT_X86_64_CODEGEN)
+ CodeModelOpt = llvm::CodeModel::Medium;
+#else
+ CodeModelOpt = llvm::CodeModel::Small;
+#endif
+
+ //-- Run LTO passes --//
+ RunLTO = true;
+
+ //-- Load the result object after successful compilation --//
+ LoadAfterCompile = true;
+ }
+
+ llvm::TargetOptions TargetOpt;
+ llvm::CodeModel::Model CodeModelOpt;
+ llvm::Reloc::Model RelocModelOpt;
+ bool RunLTO;
+ bool LoadAfterCompile;
+
+};
+
+} // namespace bcc
+
+#endif // BCC_COMPILER_OPTION_H
diff --git a/lib/ExecutionEngine/MCCacheReader.cpp b/lib/ExecutionEngine/MCCacheReader.cpp
new file mode 100644
index 0000000..dc4ba92
--- /dev/null
+++ b/lib/ExecutionEngine/MCCacheReader.cpp
@@ -0,0 +1,478 @@
+/*
+ * Copyright 2010-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 "MCCacheReader.h"
+
+#include "BCCRuntimeSymbolResolver.h"
+#include "DebugHelper.h"
+#include "InputFile.h"
+#include "ScriptCached.h"
+#include "SymbolResolverProxy.h"
+#include "SymbolResolvers.h"
+
+#include <bcc/bcc_mccache.h>
+
+#include <llvm/ADT/OwningPtr.h>
+
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <utility>
+#include <vector>
+
+#include <new>
+
+#include <stdlib.h>
+#include <string.h>
+
+using namespace std;
+
+namespace bcc {
+
+MCCacheReader::~MCCacheReader() {
+ if (mpHeader) { free(mpHeader); }
+ if (mpCachedDependTable) { free(mpCachedDependTable); }
+ if (mpPragmaList) { free(mpPragmaList); }
+ if (mpVarNameList) { free(mpVarNameList); }
+ if (mpFuncNameList) { free(mpFuncNameList); }
+}
+
+ScriptCached *MCCacheReader::readCacheFile(InputFile &objFile,
+ InputFile &infoFile,
+ Script *S) {
+ bool result = checkCacheFile(objFile, infoFile, S)
+ && readPragmaList()
+ && readObjectSlotList()
+ && readObjFile()
+ && readVarNameList()
+ && readFuncNameList()
+ && readForEachNameList()
+ //&& relocate()
+ ;
+
+ return result ? mpResult.take() : NULL;
+}
+
+bool MCCacheReader::checkCacheFile(InputFile &objFile,
+ InputFile &infoFile,
+ Script *S) {
+ // Check file handle
+ if (objFile.hasError() || infoFile.hasError()) {
+ return false;
+ }
+
+ mObjFile = &objFile;
+ mInfoFile = &infoFile;
+
+ // Allocate ScriptCached object
+ mpResult.reset(new (nothrow) ScriptCached(S));
+
+ if (!mpResult) {
+ ALOGE("Unable to allocate ScriptCached object.\n");
+ return false;
+ }
+
+ bool result = checkFileSize()
+ && readHeader()
+ && checkHeader()
+ && checkMachineIntType()
+ && checkSectionOffsetAndSize()
+ && readStringPool()
+ && checkStringPool()
+ && readDependencyTable()
+ && checkDependency()
+ ;
+
+ return result;
+}
+
+
+bool MCCacheReader::checkFileSize() {
+ struct stat stfile;
+ if (::stat(mInfoFile->getName().c_str(), &stfile) < 0) {
+ ALOGE("Unable to stat cache file.\n");
+ return false;
+ }
+
+ mInfoFileSize = stfile.st_size;
+
+ if (mInfoFileSize < (off_t)sizeof(MCO_Header)) {
+ ALOGE("Cache file is too small to be correct.\n");
+ return false;
+ }
+
+ return true;
+}
+
+
+bool MCCacheReader::readHeader() {
+ if (mInfoFile->seek(0) != 0) {
+ ALOGE("Unable to seek to 0. (reason: %s)\n", strerror(errno));
+ return false;
+ }
+
+ mpHeader = (MCO_Header *)malloc(sizeof(MCO_Header));
+ if (!mpHeader) {
+ ALOGE("Unable to allocate for cache header.\n");
+ return false;
+ }
+
+ if (mInfoFile->read(reinterpret_cast<char *>(mpHeader), sizeof(MCO_Header)) !=
+ (ssize_t)sizeof(MCO_Header)) {
+ ALOGE("Unable to read cache header.\n");
+ return false;
+ }
+
+ // Dirty hack for libRS.
+ // TODO(all): This should be removed in the future.
+ if (mpHeader->libRS_threadable) {
+ mpResult->mLibRSThreadable = true;
+ }
+
+ return true;
+}
+
+
+bool MCCacheReader::checkHeader() {
+ if (memcmp(mpHeader->magic, MCO_MAGIC, 4) != 0) {
+ ALOGE("Bad magic word\n");
+ return false;
+ }
+
+ if (memcmp(mpHeader->version, MCO_VERSION, 4) != 0) {
+ mpHeader->version[4 - 1] = '\0'; // ensure c-style string terminated
+ ALOGI("Cache file format version mismatch: now %s cached %s\n",
+ MCO_VERSION, mpHeader->version);
+ return false;
+ }
+ return true;
+}
+
+
+bool MCCacheReader::checkMachineIntType() {
+ uint32_t number = 0x00000001;
+
+ bool isLittleEndian = (*reinterpret_cast<char *>(&number) == 1);
+ if ((isLittleEndian && mpHeader->endianness != 'e') ||
+ (!isLittleEndian && mpHeader->endianness != 'E')) {
+ ALOGE("Machine endianness mismatch.\n");
+ return false;
+ }
+
+ if ((unsigned int)mpHeader->sizeof_off_t != sizeof(off_t) ||
+ (unsigned int)mpHeader->sizeof_size_t != sizeof(size_t) ||
+ (unsigned int)mpHeader->sizeof_ptr_t != sizeof(void *)) {
+ ALOGE("Machine integer size mismatch.\n");
+ return false;
+ }
+
+ return true;
+}
+
+
+bool MCCacheReader::checkSectionOffsetAndSize() {
+#define CHECK_SECTION_OFFSET(NAME) \
+ do { \
+ off_t offset = mpHeader-> NAME##_offset; \
+ off_t size = (off_t)mpHeader-> NAME##_size; \
+ \
+ if (mInfoFileSize < offset || mInfoFileSize < offset + size) { \
+ ALOGE(#NAME " section overflow.\n"); \
+ return false; \
+ } \
+ \
+ if (offset % sizeof(int) != 0) { \
+ ALOGE(#NAME " offset must aligned to %d.\n", (int)sizeof(int)); \
+ return false; \
+ } \
+ \
+ if (size < static_cast<off_t>(sizeof(size_t))) { \
+ ALOGE(#NAME " size is too small to be correct.\n"); \
+ return false; \
+ } \
+ } while (0)
+
+ CHECK_SECTION_OFFSET(str_pool);
+ CHECK_SECTION_OFFSET(depend_tab);
+ //CHECK_SECTION_OFFSET(reloc_tab);
+ CHECK_SECTION_OFFSET(pragma_list);
+
+#undef CHECK_SECTION_OFFSET
+
+ return true;
+}
+
+
+#define CACHE_READER_READ_SECTION(TYPE, AUTO_MANAGED_HOLDER, NAME) \
+ TYPE *NAME##_raw = (TYPE *)malloc(mpHeader->NAME##_size); \
+ \
+ if (!NAME##_raw) { \
+ ALOGE("Unable to allocate for " #NAME "\n"); \
+ return false; \
+ } \
+ \
+ /* We have to ensure that some one will deallocate NAME##_raw */ \
+ AUTO_MANAGED_HOLDER = NAME##_raw; \
+ \
+ if (mInfoFile->seek(mpHeader->NAME##_offset) == -1) { \
+ ALOGE("Unable to seek to " #NAME " section\n"); \
+ return false; \
+ } \
+ \
+ if (mInfoFile->read(reinterpret_cast<char *>(NAME##_raw), \
+ mpHeader->NAME##_size) != (ssize_t)mpHeader->NAME##_size) \
+ { \
+ ALOGE("Unable to read " #NAME ".\n"); \
+ return false; \
+ }
+
+
+bool MCCacheReader::readStringPool() {
+ CACHE_READER_READ_SECTION(MCO_StringPool,
+ mpResult->mpStringPoolRaw, str_pool);
+
+ char *str_base = reinterpret_cast<char *>(str_pool_raw);
+
+ vector<char const *> &pool = mpResult->mStringPool;
+ for (size_t i = 0; i < str_pool_raw->count; ++i) {
+ char *str = str_base + str_pool_raw->list[i].offset;
+ pool.push_back(str);
+ }
+
+ return true;
+}
+
+
+bool MCCacheReader::checkStringPool() {
+ MCO_StringPool *poolR = mpResult->mpStringPoolRaw;
+ vector<char const *> &pool = mpResult->mStringPool;
+
+ // Ensure that every c-style string is ended with '\0'
+ for (size_t i = 0; i < poolR->count; ++i) {
+ if (pool[i][poolR->list[i].length] != '\0') {
+ ALOGE("The %lu-th string does not end with '\\0'.\n", (unsigned long)i);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+bool MCCacheReader::readDependencyTable() {
+ CACHE_READER_READ_SECTION(MCO_DependencyTable, mpCachedDependTable,
+ depend_tab);
+ return true;
+}
+
+
+bool MCCacheReader::checkDependency() {
+ if (mDependencies.size() != mpCachedDependTable->count) {
+ ALOGE("Dependencies count mismatch. (%lu vs %lu)\n",
+ (unsigned long)mDependencies.size(),
+ (unsigned long)mpCachedDependTable->count);
+ return false;
+ }
+
+ vector<char const *> &strPool = mpResult->mStringPool;
+ map<string, unsigned char const *>::iterator dep;
+
+ dep = mDependencies.begin();
+ for (size_t i = 0; i < mpCachedDependTable->count; ++i, ++dep) {
+ string const &depName = dep->first;
+ unsigned char const *depSHA1 = dep->second;
+
+ MCO_Dependency *depCached =&mpCachedDependTable->table[i];
+ char const *depCachedName = strPool[depCached->res_name_strp_index];
+ //uint32_t depCachedType = depCached->res_type;
+ unsigned char const *depCachedSHA1 = depCached->sha1;
+
+ if (depName != depCachedName) {
+ ALOGE("Cache dependency name mismatch:\n");
+ ALOGE(" given: %s\n", depName.c_str());
+ ALOGE(" cached: %s\n", depCachedName);
+
+ return false;
+ }
+
+ if (memcmp(depSHA1, depCachedSHA1, 20) != 0) {
+ ALOGE("Cache dependency %s sha1 mismatch:\n", depCachedName);
+
+#define PRINT_SHA1(PREFIX, X, POSTFIX) \
+ ALOGE(PREFIX "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" \
+ "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" POSTFIX, \
+ X[0], X[1], X[2], X[3], X[4], X[5], X[6], X[7], X[8], X[9], \
+ X[10],X[11],X[12],X[13],X[14],X[15],X[16],X[17],X[18],X[19]);
+
+ PRINT_SHA1(" given: ", depSHA1, "\n");
+ PRINT_SHA1(" cached: ", depCachedSHA1, "\n");
+
+#undef PRINT_SHA1
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool MCCacheReader::readVarNameList() {
+ CACHE_READER_READ_SECTION(MCO_String_Ptr, mpVarNameList, export_var_name_list);
+ vector<char const *> const &strPool = mpResult->mStringPool;
+
+ mpResult->mpExportVars = (MCO_ExportVarList*)
+ malloc(sizeof(size_t) +
+ sizeof(void*) * export_var_name_list_raw->count);
+ if (!mpResult->mpExportVars) {
+ ALOGE("Unable to allocate for mpExportVars\n");
+ return false;
+ }
+ mpResult->mpExportVars->count = export_var_name_list_raw->count;
+
+ for (size_t i = 0; i < export_var_name_list_raw->count; ++i) {
+ mpResult->mpExportVars->cached_addr_list[i] =
+ rsloaderGetSymbolAddress(mpResult->mRSExecutable, strPool[export_var_name_list_raw->strp_indexs[i]]);
+#if DEBUG_MC_REFLECT
+ ALOGD("Get symbol address: %s -> %p",
+ strPool[export_var_name_list_raw->strp_indexs[i]], mpResult->mpExportVars->cached_addr_list[i]);
+#endif
+ }
+ return true;
+}
+
+bool MCCacheReader::readFuncNameList() {
+ CACHE_READER_READ_SECTION(MCO_String_Ptr, mpFuncNameList, export_func_name_list);
+ vector<char const *> const &strPool = mpResult->mStringPool;
+
+ mpResult->mpExportFuncs = (MCO_ExportFuncList*)
+ malloc(sizeof(size_t) +
+ sizeof(void*) * export_func_name_list_raw->count);
+ if (!mpResult->mpExportFuncs) {
+ ALOGE("Unable to allocate for mpExportFuncs\n");
+ return false;
+ }
+ mpResult->mpExportFuncs->count = export_func_name_list_raw->count;
+
+ for (size_t i = 0; i < export_func_name_list_raw->count; ++i) {
+ mpResult->mpExportFuncs->cached_addr_list[i] =
+ rsloaderGetSymbolAddress(mpResult->mRSExecutable, strPool[export_func_name_list_raw->strp_indexs[i]]);
+#if DEBUG_MC_REFLECT
+ ALOGD("Get function address: %s -> %p",
+ strPool[export_func_name_list_raw->strp_indexs[i]], mpResult->mpExportFuncs->cached_addr_list[i]);
+#endif
+ }
+ return true;
+}
+
+bool MCCacheReader::readForEachNameList() {
+ CACHE_READER_READ_SECTION(MCO_String_Ptr, mpForEachNameList, export_foreach_name_list);
+ vector<char const *> const &strPool = mpResult->mStringPool;
+
+ mpResult->mpExportForEach = (MCO_ExportForEachList*)
+ malloc(sizeof(size_t) +
+ sizeof(void*) * export_foreach_name_list_raw->count);
+ if (!mpResult->mpExportForEach) {
+ ALOGE("Unable to allocate for mpExportForEach\n");
+ return false;
+ }
+ mpResult->mpExportForEach->count = export_foreach_name_list_raw->count;
+
+ for (size_t i = 0; i < export_foreach_name_list_raw->count; ++i) {
+ mpResult->mpExportForEach->cached_addr_list[i] =
+ rsloaderGetSymbolAddress(mpResult->mRSExecutable, strPool[export_foreach_name_list_raw->strp_indexs[i]]);
+#if DEBUG_MC_REFLECT
+ ALOGE("Get foreach function address: %s -> %p",
+ strPool[export_foreach_name_list_raw->strp_indexs[i]], mpResult->mpExportForEach->cached_addr_list[i]);
+#endif
+ }
+ return true;
+}
+
+bool MCCacheReader::readPragmaList() {
+ CACHE_READER_READ_SECTION(MCO_PragmaList, mpPragmaList, pragma_list);
+
+ vector<char const *> const &strPool = mpResult->mStringPool;
+ ScriptCached::PragmaList &pragmas = mpResult->mPragmas;
+
+ for (size_t i = 0; i < pragma_list_raw->count; ++i) {
+ MCO_Pragma *pragma = &pragma_list_raw->list[i];
+ pragmas.push_back(make_pair(strPool[pragma->key_strp_index],
+ strPool[pragma->value_strp_index]));
+ }
+
+ return true;
+}
+
+
+bool MCCacheReader::readObjectSlotList() {
+ CACHE_READER_READ_SECTION(MCO_ObjectSlotList,
+ mpResult->mpObjectSlotList, object_slot_list);
+ return true;
+}
+
+bool MCCacheReader::readObjFile() {
+ if (mpResult->mCachedELFExecutable.size() != 0) {
+ ALOGE("Attempted to read cached object into a non-empty script");
+ return false;
+ }
+ char readBuffer[1024];
+ int readSize;
+ while ((readSize = mObjFile->read(readBuffer, 1024)) > 0) {
+ mpResult->mCachedELFExecutable.append(readBuffer, readBuffer + readSize);
+ }
+ if (readSize != 0) {
+ ALOGE("Read file Error");
+ return false;
+ }
+ ALOGD("Read object file size %d", (int)mpResult->mCachedELFExecutable.size());
+
+ BCCRuntimeSymbolResolver bccRuntimesResolver;
+ LookupFunctionSymbolResolver<void *> rsSymbolResolver(mpSymbolLookupFn,
+ mpSymbolLookupContext);
+
+ SymbolResolverProxy resolver;
+ resolver.chainResolver(bccRuntimesResolver);
+ resolver.chainResolver(rsSymbolResolver);
+
+ mpResult->mRSExecutable =
+ rsloaderCreateExec((unsigned char *)&*(mpResult->mCachedELFExecutable.begin()),
+ mpResult->mCachedELFExecutable.size(),
+ SymbolResolverProxy::LookupFunction, &resolver);
+
+ // Point ELF section headers to location of executable code, otherwise
+ // execution through GDB stops unexpectedly as GDB translates breakpoints
+ // in JITted code incorrectly (and complains about being unable to insert
+ // breakpoint at an invalid address)
+ rsloaderUpdateSectionHeaders(mpResult->mRSExecutable,
+ (unsigned char*) mpResult->mCachedELFExecutable.begin());
+
+ return true;
+}
+
+#undef CACHE_READER_READ_SECTION
+
+bool MCCacheReader::readRelocationTable() {
+ // TODO(logan): Not finished.
+ return true;
+}
+
+
+bool MCCacheReader::relocate() {
+ return true;
+}
+
+} // namespace bcc
diff --git a/lib/ExecutionEngine/MCCacheReader.h b/lib/ExecutionEngine/MCCacheReader.h
new file mode 100644
index 0000000..e2d10c5
--- /dev/null
+++ b/lib/ExecutionEngine/MCCacheReader.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2010-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 BCC_MCCACHEREADER_H
+#define BCC_MCCACHEREADER_H
+
+#include "ScriptCached.h"
+
+#include <llvm/ADT/OwningPtr.h>
+
+#include <map>
+#include <string>
+#include <utility>
+
+#include <stddef.h>
+#include <stdint.h>
+
+struct MCO_Header;
+
+namespace bcc {
+ class Script;
+ class InputFile;
+
+ class MCCacheReader {
+ private:
+ InputFile *mObjFile, *mInfoFile;
+ off_t mInfoFileSize;
+
+ MCO_Header *mpHeader;
+ MCO_DependencyTable *mpCachedDependTable;
+ MCO_PragmaList *mpPragmaList;
+ MCO_FuncTable *mpFuncTable;
+
+ MCO_String_Ptr *mpVarNameList;
+ MCO_String_Ptr *mpFuncNameList;
+ MCO_String_Ptr *mpForEachNameList;
+
+ llvm::OwningPtr<ScriptCached> mpResult;
+
+ std::map<std::string, unsigned char const *> mDependencies;
+
+ bool mIsContextSlotNotAvail;
+
+ BCCSymbolLookupFn mpSymbolLookupFn;
+ void *mpSymbolLookupContext;
+
+ public:
+ MCCacheReader()
+ : mObjFile(NULL), mInfoFile(NULL), mInfoFileSize(0), mpHeader(NULL),
+ mpCachedDependTable(NULL), mpPragmaList(NULL),
+ mpVarNameList(NULL), mpFuncNameList(NULL), mpForEachNameList(NULL),
+ mIsContextSlotNotAvail(false) {
+ }
+
+ ~MCCacheReader();
+
+ void addDependency(std::string const &resName,
+ unsigned char const *sha1) {
+ mDependencies.insert(std::make_pair(resName, sha1));
+ }
+
+ ScriptCached *readCacheFile(InputFile &objFile, InputFile &infoFile, Script *s);
+ bool checkCacheFile(InputFile &objFile, InputFile &infoFile, Script *S);
+
+ bool isContextSlotNotAvail() const {
+ return mIsContextSlotNotAvail;
+ }
+
+ void registerSymbolCallback(BCCSymbolLookupFn pFn, void *pContext) {
+ mpSymbolLookupFn = pFn;
+ mpSymbolLookupContext = pContext;
+ }
+
+ private:
+ bool readHeader();
+ bool readStringPool();
+ bool readDependencyTable();
+ bool readPragmaList();
+ bool readObjectSlotList();
+ bool readObjFile();
+ bool readRelocationTable();
+
+ bool readVarNameList();
+ bool readFuncNameList();
+ bool readForEachNameList();
+
+ bool checkFileSize();
+ bool checkHeader();
+ bool checkMachineIntType();
+ bool checkSectionOffsetAndSize();
+ bool checkStringPool();
+ bool checkDependency();
+ bool checkContext();
+
+ bool relocate();
+ };
+
+} // namespace bcc
+
+#endif // BCC_MCCACHEREADER_H
diff --git a/lib/ExecutionEngine/MCCacheWriter.cpp b/lib/ExecutionEngine/MCCacheWriter.cpp
new file mode 100644
index 0000000..c667c19
--- /dev/null
+++ b/lib/ExecutionEngine/MCCacheWriter.cpp
@@ -0,0 +1,387 @@
+/*
+ * Copyright 2010-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 "MCCacheWriter.h"
+
+#include "DebugHelper.h"
+#include "OutputFile.h"
+#include "RSScript.h"
+
+#include <map>
+#include <string>
+#include <vector>
+#include <utility>
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+using namespace std;
+
+namespace bcc {
+
+MCCacheWriter::~MCCacheWriter() {
+#define CHECK_AND_FREE(VAR) if (VAR) { free(VAR); }
+
+ CHECK_AND_FREE(mpHeaderSection);
+ CHECK_AND_FREE(mpStringPoolSection);
+ CHECK_AND_FREE(mpDependencyTableSection);
+ CHECK_AND_FREE(mpPragmaListSection);
+ CHECK_AND_FREE(mpObjectSlotSection);
+ CHECK_AND_FREE(mpExportVarNameListSection);
+ CHECK_AND_FREE(mpExportFuncNameListSection);
+
+#undef CHECK_AND_FREE
+}
+
+bool MCCacheWriter::writeCacheFile(OutputFile &objFile, OutputFile &infoFile,
+ RSScript *S, uint32_t libRS_threadable) {
+ if (objFile.hasError() || infoFile.hasError()) {
+ return false;
+ }
+
+ mObjFile = &objFile;
+ mInfoFile = &infoFile;
+ mpOwner = S;
+
+ bool result = prepareHeader(libRS_threadable)
+ && prepareDependencyTable()
+ && preparePragmaList()
+ && prepareExportVarNameList()
+ && prepareExportFuncNameList()
+ && prepareExportForEachNameList()
+ && prepareStringPool()
+ && prepareObjectSlotList()
+ && calcSectionOffset()
+ && writeAll()
+ ;
+
+ return result;
+}
+
+
+bool MCCacheWriter::prepareHeader(uint32_t libRS_threadable) {
+ MCO_Header *header = (MCO_Header *)malloc(sizeof(MCO_Header));
+
+ if (!header) {
+ ALOGE("Unable to allocate for header.\n");
+ return false;
+ }
+
+ mpHeaderSection = header;
+
+ // Initialize
+ memset(header, '\0', sizeof(MCO_Header));
+
+ // Magic word and version
+ memcpy(header->magic, MCO_MAGIC, 4);
+ memcpy(header->version, MCO_VERSION, 4);
+
+ // Machine Integer Type
+ uint32_t number = 0x00000001;
+ header->endianness = (*reinterpret_cast<char *>(&number) == 1) ? 'e' : 'E';
+ header->sizeof_off_t = sizeof(off_t);
+ header->sizeof_size_t = sizeof(size_t);
+ header->sizeof_ptr_t = sizeof(void *);
+
+ // libRS is threadable dirty hack
+ // TODO: This should be removed in the future
+ header->libRS_threadable = libRS_threadable;
+
+ return true;
+}
+
+
+bool MCCacheWriter::prepareDependencyTable() {
+ size_t tableSize = sizeof(MCO_DependencyTable) +
+ sizeof(MCO_Dependency) * mDependencies.size();
+
+ MCO_DependencyTable *tab = (MCO_DependencyTable *)malloc(tableSize);
+
+ if (!tab) {
+ ALOGE("Unable to allocate for dependency table section.\n");
+ return false;
+ }
+
+ mpDependencyTableSection = tab;
+ mpHeaderSection->depend_tab_size = tableSize;
+
+ tab->count = mDependencies.size();
+
+ size_t i = 0;
+ for (map<string, unsigned char const *>::iterator
+ I = mDependencies.begin(), E = mDependencies.end(); I != E; ++I, ++i) {
+ MCO_Dependency *dep = &tab->table[i];
+
+ dep->res_name_strp_index = addString(I->first.c_str(), I->first.size());
+ memcpy(dep->sha1, I->second, 20);
+ }
+
+ return true;
+}
+
+bool MCCacheWriter::preparePragmaList() {
+ size_t pragmaCount = mpOwner->getPragmaCount();
+
+ size_t listSize = sizeof(MCO_PragmaList) +
+ sizeof(MCO_Pragma) * pragmaCount;
+
+ MCO_PragmaList *list = (MCO_PragmaList *)malloc(listSize);
+
+ if (!list) {
+ ALOGE("Unable to allocate for pragma list\n");
+ return false;
+ }
+
+ mpPragmaListSection = list;
+ mpHeaderSection->pragma_list_size = listSize;
+
+ list->count = pragmaCount;
+
+ vector<char const *> keyList(pragmaCount);
+ vector<char const *> valueList(pragmaCount);
+ mpOwner->getPragmaList(pragmaCount, &*keyList.begin(), &*valueList.begin());
+
+ for (size_t i = 0; i < pragmaCount; ++i) {
+ char const *key = keyList[i];
+ char const *value = valueList[i];
+
+ size_t keyLen = strlen(key);
+ size_t valueLen = strlen(value);
+
+ MCO_Pragma *pragma = &list->list[i];
+ pragma->key_strp_index = addString(key, keyLen);
+ pragma->value_strp_index = addString(value, valueLen);
+ }
+
+ return true;
+}
+
+bool MCCacheWriter::prepareStringPool() {
+ // Calculate string pool size
+ size_t size = sizeof(MCO_StringPool) +
+ sizeof(MCO_String) * mStringPool.size();
+
+ off_t strOffset = size;
+
+ for (size_t i = 0; i < mStringPool.size(); ++i) {
+ size += mStringPool[i].second + 1;
+ }
+
+ // Create string pool
+ MCO_StringPool *pool = (MCO_StringPool *)malloc(size);
+
+ if (!pool) {
+ ALOGE("Unable to allocate string pool.\n");
+ return false;
+ }
+
+ mpStringPoolSection = pool;
+ mpHeaderSection->str_pool_size = size;
+
+ pool->count = mStringPool.size();
+
+ char *strPtr = reinterpret_cast<char *>(pool) + strOffset;
+
+ for (size_t i = 0; i < mStringPool.size(); ++i) {
+ MCO_String *str = &pool->list[i];
+
+ str->length = mStringPool[i].second;
+ str->offset = strOffset;
+ memcpy(strPtr, mStringPool[i].first, str->length);
+
+ strPtr += str->length;
+ *strPtr++ = '\0';
+
+ strOffset += str->length + 1;
+ }
+
+ return true;
+}
+
+
+bool MCCacheWriter::prepareExportVarNameList() {
+ size_t varCount = mpOwner->getExportVarCount();
+ size_t listSize = sizeof(MCO_String_Ptr) + sizeof(size_t) * varCount;
+
+ MCO_String_Ptr *list = (MCO_String_Ptr*)malloc(listSize);
+
+ if (!list) {
+ ALOGE("Unable to allocate for export variable name list\n");
+ return false;
+ }
+
+ mpExportVarNameListSection = list;
+ mpHeaderSection->export_var_name_list_size = listSize;
+
+ list->count = static_cast<size_t>(varCount);
+
+ mpOwner->getExportVarNameList(varNameList);
+ for (size_t i = 0; i < varCount; ++i) {
+ list->strp_indexs[i] = addString(varNameList[i].c_str(), varNameList[i].length());
+ }
+ return true;
+}
+
+
+bool MCCacheWriter::prepareExportFuncNameList() {
+ size_t funcCount = mpOwner->getExportFuncCount();
+ size_t listSize = sizeof(MCO_String_Ptr) + sizeof(size_t) * funcCount;
+
+ MCO_String_Ptr *list = (MCO_String_Ptr*)malloc(listSize);
+
+ if (!list) {
+ ALOGE("Unable to allocate for export function name list\n");
+ return false;
+ }
+
+ mpExportFuncNameListSection = list;
+ mpHeaderSection->export_func_name_list_size = listSize;
+
+ list->count = static_cast<size_t>(funcCount);
+
+ mpOwner->getExportFuncNameList(funcNameList);
+ for (size_t i = 0; i < funcCount; ++i) {
+ list->strp_indexs[i] = addString(funcNameList[i].c_str(), funcNameList[i].length());
+ }
+ return true;
+}
+
+
+bool MCCacheWriter::prepareExportForEachNameList() {
+ size_t forEachCount = mpOwner->getExportForEachCount();
+ size_t listSize = sizeof(MCO_String_Ptr) + sizeof(size_t) * forEachCount;
+
+ MCO_String_Ptr *list = (MCO_String_Ptr*)malloc(listSize);
+
+ if (!list) {
+ ALOGE("Unable to allocate for export forEach name list\n");
+ return false;
+ }
+
+ mpExportForEachNameListSection = list;
+ mpHeaderSection->export_foreach_name_list_size = listSize;
+
+ list->count = static_cast<size_t>(forEachCount);
+
+ mpOwner->getExportForEachNameList(forEachNameList);
+ for (size_t i = 0; i < forEachCount; ++i) {
+ list->strp_indexs[i] = addString(forEachNameList[i].c_str(), forEachNameList[i].length());
+ }
+ return true;
+}
+
+
+bool MCCacheWriter::prepareObjectSlotList() {
+ size_t objectSlotCount = mpOwner->getObjectSlotCount();
+
+ size_t listSize = sizeof(MCO_ObjectSlotList) +
+ sizeof(uint32_t) * objectSlotCount;
+
+ MCO_ObjectSlotList *list = (MCO_ObjectSlotList *)malloc(listSize);
+
+ if (!list) {
+ ALOGE("Unable to allocate for object slot list\n");
+ return false;
+ }
+
+ mpObjectSlotSection = list;
+ mpHeaderSection->object_slot_list_size = listSize;
+
+ list->count = objectSlotCount;
+
+ mpOwner->getObjectSlotList(objectSlotCount, list->object_slot_list);
+ return true;
+}
+
+
+bool MCCacheWriter::calcSectionOffset() {
+ size_t offset = sizeof(MCO_Header);
+
+#define OFFSET_INCREASE(NAME) \
+ do { \
+ /* Align to a word */ \
+ size_t rem = offset % sizeof(int); \
+ if (rem > 0) { \
+ offset += sizeof(int) - rem; \
+ } \
+ \
+ /* Save the offset and increase it */ \
+ mpHeaderSection->NAME##_offset = offset; \
+ offset += mpHeaderSection->NAME##_size; \
+ } while (0)
+
+ OFFSET_INCREASE(str_pool);
+ OFFSET_INCREASE(depend_tab);
+ OFFSET_INCREASE(pragma_list);
+ OFFSET_INCREASE(func_table);
+ OFFSET_INCREASE(object_slot_list);
+ OFFSET_INCREASE(export_var_name_list);
+ OFFSET_INCREASE(export_func_name_list);
+ OFFSET_INCREASE(export_foreach_name_list);
+
+#undef OFFSET_INCREASE
+
+ return true;
+}
+
+
+bool MCCacheWriter::writeAll() {
+#define WRITE_SECTION(NAME, OFFSET, SIZE, SECTION) \
+ do { \
+ if (mInfoFile->seek(OFFSET) == -1) { \
+ ALOGE("Unable to seek to " #NAME " section for writing.\n"); \
+ return false; \
+ } \
+ \
+ if (mInfoFile->write(reinterpret_cast<char *>(SECTION), (SIZE)) != \
+ static_cast<ssize_t>(SIZE)) { \
+ ALOGE("Unable to write " #NAME " section to cache file.\n"); \
+ return false; \
+ } \
+ } while (0)
+
+#define WRITE_SECTION_SIMPLE(NAME, SECTION) \
+ WRITE_SECTION(NAME, \
+ mpHeaderSection->NAME##_offset, \
+ mpHeaderSection->NAME##_size, \
+ SECTION)
+
+ WRITE_SECTION(header, 0, sizeof(MCO_Header), mpHeaderSection);
+
+ WRITE_SECTION_SIMPLE(str_pool, mpStringPoolSection);
+ WRITE_SECTION_SIMPLE(depend_tab, mpDependencyTableSection);
+ WRITE_SECTION_SIMPLE(pragma_list, mpPragmaListSection);
+ WRITE_SECTION_SIMPLE(object_slot_list, mpObjectSlotSection);
+
+ WRITE_SECTION_SIMPLE(export_var_name_list, mpExportVarNameListSection);
+ WRITE_SECTION_SIMPLE(export_func_name_list, mpExportFuncNameListSection);
+ WRITE_SECTION_SIMPLE(export_foreach_name_list, mpExportForEachNameListSection);
+
+#undef WRITE_SECTION_SIMPLE
+#undef WRITE_SECTION
+
+ if (static_cast<size_t>(mObjFile->write(mpOwner->getELF(),
+ mpOwner->getELFSize()))
+ != mpOwner->getELFSize()) {
+ ALOGE("Unable to write ELF to cache file.\n");
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace bcc
diff --git a/lib/ExecutionEngine/MCCacheWriter.h b/lib/ExecutionEngine/MCCacheWriter.h
new file mode 100644
index 0000000..47f1e40
--- /dev/null
+++ b/lib/ExecutionEngine/MCCacheWriter.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2010-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 BCC_MCCACHEWRITER_H
+#define BCC_MCCACHEWRITER_H
+
+#include <bcc/bcc_mccache.h>
+
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace bcc {
+ class OutputFile;
+ class RSScript;
+
+ class MCCacheWriter {
+ private:
+ RSScript *mpOwner;
+
+ OutputFile *mObjFile, *mInfoFile;
+
+ std::vector<std::pair<char const *, size_t> > mStringPool;
+
+ std::map<std::string, unsigned char const *> mDependencies;
+
+ MCO_Header *mpHeaderSection;
+ MCO_StringPool *mpStringPoolSection;
+ MCO_DependencyTable *mpDependencyTableSection;
+ MCO_PragmaList *mpPragmaListSection;
+ MCO_ObjectSlotList *mpObjectSlotSection;
+
+ MCO_String_Ptr *mpExportVarNameListSection;
+ MCO_String_Ptr *mpExportFuncNameListSection;
+ MCO_String_Ptr *mpExportForEachNameListSection;
+
+ std::vector<std::string> varNameList;
+ std::vector<std::string> funcNameList;
+ std::vector<std::string> forEachNameList;
+
+ public:
+ MCCacheWriter()
+ : mpHeaderSection(NULL), mpStringPoolSection(NULL),
+ mpDependencyTableSection(NULL), mpPragmaListSection(NULL),
+ mpObjectSlotSection(NULL) {
+ }
+
+ ~MCCacheWriter();
+
+ bool writeCacheFile(OutputFile &objFile, OutputFile &infoFile,
+ RSScript *S, uint32_t libRS_threadable);
+
+ void addDependency(std::string const &resName,
+ unsigned char const *sha1) {
+ mDependencies.insert(std::make_pair(resName, sha1));
+ }
+
+ private:
+ bool prepareHeader(uint32_t libRS_threadable);
+ bool prepareStringPool();
+ bool prepareDependencyTable();
+ bool prepareRelocationTable();
+ bool preparePragmaList();
+ bool prepareObjectSlotList();
+
+ bool prepareExportVarNameList();
+ bool prepareExportFuncNameList();
+ bool prepareExportForEachNameList();
+
+ bool writeAll();
+
+ bool calcSectionOffset();
+
+ size_t addString(char const *str, size_t size) {
+ mStringPool.push_back(std::make_pair(str, size));
+ return mStringPool.size() - 1;
+ }
+
+ };
+
+} // namespace bcc
+
+#endif // BCC_MCCACHEWRITER_H
diff --git a/lib/ExecutionEngine/RSCompiler.cpp b/lib/ExecutionEngine/RSCompiler.cpp
deleted file mode 100644
index e431086..0000000
--- a/lib/ExecutionEngine/RSCompiler.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright 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 "RSCompiler.h"
-
-#include <llvm/Module.h>
-#include <llvm/PassManager.h>
-#include <llvm/Transforms/IPO.h>
-
-#include "DebugHelper.h"
-#include "RSExecutable.h"
-#include "RSInfo.h"
-#include "RSScript.h"
-#include "RSTransforms.h"
-#include "Source.h"
-
-using namespace bcc;
-
-bool RSCompiler::beforeAddLTOPasses(Script &pScript, llvm::PassManager &pPM) {
- // Add a pass to internalize the symbols that don't need to have global
- // visibility.
- RSScript &script = static_cast<RSScript &>(pScript);
- const RSInfo *info = script.getInfo();
-
- // The vector contains the symbols that should not be internalized.
- std::vector<const char *> export_symbols;
-
- // Special RS functions should always be global symbols.
- const char **special_functions = RSExecutable::SpecialFunctionNames;
- while (*special_functions != NULL) {
- export_symbols.push_back(*special_functions);
- special_functions++;
- }
-
- // Visibility of symbols appeared in rs_export_var and rs_export_func should
- // also be preserved.
- const RSInfo::ExportVarNameListTy &export_vars = info->getExportVarNames();
- const RSInfo::ExportFuncNameListTy &export_funcs = info->getExportFuncNames();
-
- for (RSInfo::ExportVarNameListTy::const_iterator
- export_var_iter = export_vars.begin(),
- export_var_end = export_vars.end();
- export_var_iter != export_var_end; export_var_iter++) {
- export_symbols.push_back(*export_var_iter);
- }
-
- for (RSInfo::ExportFuncNameListTy::const_iterator
- export_func_iter = export_funcs.begin(),
- export_func_end = export_funcs.end();
- export_func_iter != export_func_end; export_func_iter++) {
- export_symbols.push_back(*export_func_iter);
- }
-
- // Expanded foreach functions should not be internalized, too.
- const RSInfo::ExportForeachFuncListTy &export_foreach_func =
- info->getExportForeachFuncs();
- std::vector<std::string> expanded_foreach_funcs;
- for (RSInfo::ExportForeachFuncListTy::const_iterator
- foreach_func_iter = export_foreach_func.begin(),
- foreach_func_end = export_foreach_func.end();
- foreach_func_iter != foreach_func_end; foreach_func_iter++) {
- std::string name(foreach_func_iter->first);
- expanded_foreach_funcs.push_back(name.append(".expand"));
- }
-
- // Need to wait until ForEachExpandList is fully populated to fill in
- // exported symbols.
- for (size_t i = 0; i < expanded_foreach_funcs.size(); i++) {
- export_symbols.push_back(expanded_foreach_funcs[i].c_str());
- }
-
- pPM.add(llvm::createInternalizePass(export_symbols));
-
- return true;
-}
-
-bool RSCompiler::beforeExecuteLTOPasses(Script &pScript,
- llvm::PassManager &pPM) {
- // Execute a pass to expand foreach-able functions
- llvm::PassManager rs_passes;
-
- // Script passed to RSCompiler must be a RSScript.
- RSScript &script = static_cast<RSScript &>(pScript);
- const RSInfo *info = script.getInfo();
- llvm::Module &module = script.getSource().getModule();
-
- if (info == NULL) {
- ALOGE("Missing RSInfo in RSScript to run the pass for foreach expansion on "
- "%s!", module.getModuleIdentifier().c_str());
- return false;
- }
-
- // Expand ForEach on CPU path to reduce launch overhead.
- rs_passes.add(createRSForEachExpandPass(info->getExportForeachFuncs()));
-
- // Execute the pass.
- rs_passes.run(module);
-
- return true;
-}
diff --git a/lib/ExecutionEngine/RSCompiler.h b/lib/ExecutionEngine/RSCompiler.h
deleted file mode 100644
index 227727b..0000000
--- a/lib/ExecutionEngine/RSCompiler.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 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 BCC_EXECUTION_ENGINE_RS_COMPILER_H
-#define BCC_EXECUTION_ENGINE_RS_COMPILER_H
-
-#include "Compiler.h"
-
-namespace bcc {
-
-class RSCompiler : public Compiler {
-private:
- virtual bool beforeAddLTOPasses(Script &pScript, llvm::PassManager &pPM);
- virtual bool beforeExecuteLTOPasses(Script &pScript, llvm::PassManager &pPM);
-};
-
-} // end namespace bcc
-
-#endif // BCC_EXECUTION_ENGINE_RS_COMPILER_H
diff --git a/lib/ExecutionEngine/RSScript.cpp b/lib/ExecutionEngine/RSScript.cpp
index 7ec84d9..2ca97a5 100644
--- a/lib/ExecutionEngine/RSScript.cpp
+++ b/lib/ExecutionEngine/RSScript.cpp
@@ -14,15 +14,47 @@
* limitations under the License.
*/
-#include "RSScript.h"
+#include "Script.h"
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <new>
#include <cstring>
#include <llvm/ADT/STLExtras.h>
-#include "DebugHelper.h"
+#include <cutils/properties.h>
-using namespace bcc;
+#include "Config.h"
+
+#include "MCCacheReader.h"
+#include "MCCacheWriter.h"
+#include "CompilerOption.h"
+
+#include "DebugHelper.h"
+#include "FileMutex.h"
+#include "GDBJITRegistrar.h"
+#include "InputFile.h"
+#include "OutputFile.h"
+#include "ScriptCompiled.h"
+#include "ScriptCached.h"
+#include "Sha1Helper.h"
+#include "Source.h"
+
+namespace {
+
+bool getBooleanProp(const char *str) {
+ char buf[PROPERTY_VALUE_MAX];
+ property_get(str, buf, "0");
+ return strcmp(buf, "0") != 0;
+}
+
+} // namespace anonymous
+
+namespace bcc {
RSScript::SourceDependency::SourceDependency(const std::string &pSourceName,
const uint8_t *pSHA1)
@@ -32,18 +64,44 @@
}
RSScript::RSScript(Source &pSource)
- : Script(pSource), mInfo(NULL), mCompilerVersion(0),
- mOptimizationLevel(kOptLvl3) { }
+ : Script(pSource),
+ mpExtSymbolLookupFn(NULL),
+ mpExtSymbolLookupFnContext(NULL) {
+ resetState();
+ return;
+}
RSScript::~RSScript() {
+ switch (mStatus) {
+ case ScriptStatus::Compiled:
+ delete mCompiled;
+ break;
+
+ case ScriptStatus::Cached:
+ delete mCached;
+ break;
+
+ default:
+ break;
+ }
llvm::DeleteContainerPointers(mSourceDependencies);
}
-bool RSScript::doReset() {
- mInfo = NULL;
- mCompilerVersion = 0;
- mOptimizationLevel = kOptLvl3;
+void RSScript::resetState() {
+ mErrorCode = BCC_NO_ERROR;
+ mStatus = ScriptStatus::Unknown;
+ mObjectType = ScriptObject::Unknown;
+ mIsContextSlotNotAvail = false;
+ // FIXME: mpExtSymbolLookupFn and mpExtSymbolLookupFnContext should be assign
+ // to NULL during state resetting.
+ //mpExtSymbolLookupFn = NULL;
+ //mpExtSymbolLookupFnContext = NULL;
llvm::DeleteContainerPointers(mSourceDependencies);
+ return;
+}
+
+bool RSScript::doReset() {
+ resetState();
return true;
}
@@ -60,3 +118,653 @@
mSourceDependencies.push_back(source_dep);
return true;
}
+
+int RSScript::prepareRelocatable(char const *objPath,
+ llvm::Reloc::Model RelocModel,
+ unsigned long flags) {
+ CompilerOption option;
+ option.RelocModelOpt = RelocModel;
+ option.LoadAfterCompile = false;
+
+ int status = internalCompile(option);
+ if (status != 0) {
+ ALOGE("LLVM error message: %s\n", getCompilerErrorMessage());
+ return status;
+ }
+
+ OutputFile objFile(objPath);
+ if (objFile.hasError()) {
+ ALOGE("Failed to open %s for write. (%s)", objPath,
+ objFile.getErrorMessage().c_str());
+ return 1;
+ }
+
+ if (static_cast<size_t>(objFile.write(getELF(),
+ getELFSize())) != getELFSize()) {
+ objFile.close();
+ ::unlink(objPath);
+ ALOGE("Unable to write ELF to file %s.\n", objPath);
+ return false;
+ }
+
+ mObjectType = ScriptObject::Relocatable;
+
+ return 0;
+}
+
+
+int RSScript::prepareSharedObject(char const *objPath,
+ char const *dsoPath,
+ unsigned long flags) {
+ // TODO: Support cached shared object.
+ return 1;
+}
+
+
+int RSScript::prepareExecutable(char const *cacheDir,
+ char const *cacheName,
+ unsigned long flags) {
+ if (mStatus != ScriptStatus::Unknown) {
+ mErrorCode = BCC_INVALID_OPERATION;
+ ALOGE("Invalid operation: %s\n", __func__);
+ return 1;
+ }
+
+ int status = internalLoadCache(cacheDir, cacheName, /* checkOnly */ false);
+
+ if (status != 0) {
+ CompilerOption option;
+ status = internalCompile(option);
+
+ if (status != 0) {
+ ALOGE("LLVM error message: %s\n", getCompilerErrorMessage());
+ return status;
+ }
+
+ status = writeCache();
+ if (status != 0) {
+ ALOGE("Failed to write the cache for %s\n", cacheName);
+ return status;
+ }
+ }
+
+ // FIXME: Registration can be conditional on the presence of debug metadata
+ registerObjectWithGDB(getELF(), getELFSize()); // thread-safe registration
+
+ mObjectType = ScriptObject::Executable;
+
+ return status;
+}
+
+int RSScript::internalLoadCache(char const *cacheDir, char const *cacheName,
+ bool checkOnly) {
+ if ((cacheDir == NULL) || (cacheName == NULL)) {
+ return 1;
+ }
+
+ // Set cache file Name
+ mCacheName = cacheName;
+
+ // Santize mCacheDir. Ensure that mCacheDir ends with '/'.
+ mCacheDir = cacheDir;
+ if (!mCacheDir.empty() && *mCacheDir.rbegin() != '/') {
+ mCacheDir.push_back('/');
+ }
+
+ if (!isCacheable()) {
+ return 1;
+ }
+
+ std::string objPath = getCachedObjectPath();
+ std::string infoPath = getCacheInfoPath();
+
+ // Locks for reading object file and info file.
+ FileMutex<FileBase::kReadLock> objFileMutex(objPath);
+ FileMutex<FileBase::kReadLock> infoFileMutex(infoPath);
+
+ // Aquire read lock for object file.
+ if (objFileMutex.hasError() || !objFileMutex.lock()) {
+ ALOGE("Unable to acquire the lock for %s! (%s)", objPath.c_str(),
+ objFileMutex.getErrorMessage().c_str());
+ return 1;
+ }
+
+ // Aquire read lock for info file.
+ if (infoFileMutex.hasError() || !infoFileMutex.lock()) {
+ ALOGE("Unable to acquire the lock for %s! (%s)", infoPath.c_str(),
+ infoFileMutex.getErrorMessage().c_str());
+ return 1;
+ }
+
+ // Open the object file and info file
+ InputFile objFile(objPath);
+ InputFile infoFile(infoPath);
+
+ if (objFile.hasError()) {
+ ALOGE("Unable to open %s for reading! (%s)", objPath.c_str(),
+ objFile.getErrorMessage().c_str());
+ return 1;
+ }
+
+ if (infoFile.hasError()) {
+ ALOGE("Unable to open %s for reading! (%s)", infoPath.c_str(),
+ infoFile.getErrorMessage().c_str());
+ return 1;
+ }
+
+ MCCacheReader reader;
+
+ // Register symbol lookup function
+ if (mpExtSymbolLookupFn) {
+ reader.registerSymbolCallback(mpExtSymbolLookupFn,
+ mpExtSymbolLookupFnContext);
+ }
+
+ // Dependencies
+ reader.addDependency(pathLibBCC_SHA1, sha1LibBCC_SHA1);
+ reader.addDependency(pathLibRS, sha1LibRS);
+
+ for (unsigned i = 0; i < mSourceDependencies.size(); i++) {
+ const SourceDependency *source_dep = mSourceDependencies[i];
+ reader.addDependency(source_dep->getSourceName(),
+ source_dep->getSHA1Checksum());
+ }
+
+ if (checkOnly)
+ return !reader.checkCacheFile(objFile, infoFile, this);
+
+ // Read cache file
+ ScriptCached *cached = reader.readCacheFile(objFile, infoFile, this);
+
+ if (!cached) {
+ mIsContextSlotNotAvail = reader.isContextSlotNotAvail();
+ return 1;
+ }
+
+ mCached = cached;
+ mStatus = ScriptStatus::Cached;
+
+ // Dirty hack for libRS.
+ // TODO(all): This dirty hack should be removed in the future.
+ if (!cached->isLibRSThreadable() && mpExtSymbolLookupFn) {
+ mpExtSymbolLookupFn(mpExtSymbolLookupFnContext, "__clearThreadable");
+ }
+
+ return 0;
+}
+
+int RSScript::internalCompile(const CompilerOption &option) {
+ // Create the ScriptCompiled object
+ mCompiled = new (std::nothrow) ScriptCompiled(this);
+
+ if (!mCompiled) {
+ mErrorCode = BCC_OUT_OF_MEMORY;
+ ALOGE("Out of memory: %s %d\n", __FILE__, __LINE__);
+ return 1;
+ }
+
+ mStatus = ScriptStatus::Compiled;
+
+ // Register symbol lookup function
+ if (mpExtSymbolLookupFn) {
+ mCompiled->registerSymbolCallback(mpExtSymbolLookupFn,
+ mpExtSymbolLookupFnContext);
+ }
+
+ // Set the main source module
+ if (mCompiled->readModule(getSource().getModule()) != 0) {
+ ALOGE("Unable to read source module\n");
+ return 1;
+ }
+
+ // Compile and JIT the code
+ if (mCompiled->compile(option) != 0) {
+ ALOGE("Unable to compile.\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+int RSScript::writeCache() {
+ // Not compiled script or encountered error during the compilation.
+ if ((mStatus != ScriptStatus::Compiled) ||
+ (getCompilerErrorMessage() == NULL))
+ return 1;
+
+ // Note: If we re-compile the script because the cached context slot not
+ // available, then we don't have to write the cache.
+
+ // Note: If the address of the context is not in the context slot, then
+ // we don't have to cache it.
+
+ if (isCacheable()) {
+ std::string objPath = getCachedObjectPath();
+ std::string infoPath = getCacheInfoPath();
+
+ // Locks for writing object file and info file.
+ FileMutex<FileBase::kWriteLock> objFileMutex(objPath);
+ FileMutex<FileBase::kWriteLock> infoFileMutex(infoPath);
+
+ // Aquire write lock for object file.
+ if (objFileMutex.hasError() || !objFileMutex.lock()) {
+ ALOGE("Unable to acquire the lock for %s! (%s)", objPath.c_str(),
+ objFileMutex.getErrorMessage().c_str());
+ return 1;
+ }
+
+ // Aquire write lock for info file.
+ if (infoFileMutex.hasError() || !infoFileMutex.lock()) {
+ ALOGE("Unable to acquire the lock for %s! (%s)", infoPath.c_str(),
+ infoFileMutex.getErrorMessage().c_str());
+ return 1;
+ }
+
+ // Open the object file and info file
+ OutputFile objFile(objPath);
+ OutputFile infoFile(infoPath);
+
+ if (objFile.hasError()) {
+ ALOGE("Unable to open %s for writing! (%s)", objPath.c_str(),
+ objFile.getErrorMessage().c_str());
+ return 1;
+ }
+
+ if (infoFile.hasError()) {
+ ALOGE("Unable to open %s for writing! (%s)", infoPath.c_str(),
+ infoFile.getErrorMessage().c_str());
+ return 1;
+ }
+
+ MCCacheWriter writer;
+
+#ifdef TARGET_BUILD
+ // Dependencies
+ writer.addDependency(pathLibBCC_SHA1, sha1LibBCC_SHA1);
+ writer.addDependency(pathLibRS, sha1LibRS);
+#endif
+
+ for (unsigned i = 0; i < mSourceDependencies.size(); i++) {
+ const SourceDependency *source_dep = mSourceDependencies[i];
+ writer.addDependency(source_dep->getSourceName(),
+ source_dep->getSHA1Checksum());
+ }
+
+
+ // libRS is threadable dirty hack
+ // TODO: This should be removed in the future
+ uint32_t libRS_threadable = 0;
+ if (mpExtSymbolLookupFn) {
+ libRS_threadable =
+ (uint32_t)mpExtSymbolLookupFn(mpExtSymbolLookupFnContext,
+ "__isThreadable");
+ }
+
+ if (!writer.writeCacheFile(objFile, infoFile, this, libRS_threadable)) {
+ // Erase the file contents.
+ objFile.truncate();
+ infoFile.truncate();
+
+ // Close the file such that we can removed it from the filesystem.
+ objFile.close();
+ infoFile.close();
+
+ if (::unlink(objPath.c_str()) != 0) {
+ ALOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
+ objPath.c_str(), ::strerror(errno));
+ }
+
+ if (::unlink(infoPath.c_str()) != 0) {
+ ALOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
+ infoPath.c_str(), ::strerror(errno));
+ }
+ }
+ } // isCacheable()
+
+ return 0;
+}
+
+char const *RSScript::getCompilerErrorMessage() {
+ if (mStatus != ScriptStatus::Compiled) {
+ mErrorCode = BCC_INVALID_OPERATION;
+ return NULL;
+ }
+
+ return mCompiled->getCompilerErrorMessage();
+}
+
+
+void *RSScript::lookup(const char *name) {
+ switch (mStatus) {
+ case ScriptStatus::Compiled: {
+ return mCompiled->lookup(name);
+ }
+
+ case ScriptStatus::Cached: {
+ return mCached->lookup(name);
+ }
+
+ default: {
+ mErrorCode = BCC_INVALID_OPERATION;
+ return NULL;
+ }
+ }
+}
+
+
+size_t RSScript::getExportVarCount() const {
+ switch (mStatus) {
+ case ScriptStatus::Compiled: {
+ return mCompiled->getExportVarCount();
+ }
+
+ case ScriptStatus::Cached: {
+ return mCached->getExportVarCount();
+ }
+
+ default: {
+ return 0;
+ }
+ }
+}
+
+
+size_t RSScript::getExportFuncCount() const {
+ switch (mStatus) {
+ case ScriptStatus::Compiled: {
+ return mCompiled->getExportFuncCount();
+ }
+
+ case ScriptStatus::Cached: {
+ return mCached->getExportFuncCount();
+ }
+
+ default: {
+ return 0;
+ }
+ }
+}
+
+
+size_t RSScript::getExportForEachCount() const {
+ switch (mStatus) {
+ case ScriptStatus::Compiled: {
+ return mCompiled->getExportForEachCount();
+ }
+
+ case ScriptStatus::Cached: {
+ return mCached->getExportForEachCount();
+ }
+
+ default: {
+ return 0;
+ }
+ }
+}
+
+
+size_t RSScript::getPragmaCount() const {
+ switch (mStatus) {
+ case ScriptStatus::Compiled: {
+ return mCompiled->getPragmaCount();
+ }
+
+ case ScriptStatus::Cached: {
+ return mCached->getPragmaCount();
+ }
+
+ default: {
+ return 0;
+ }
+ }
+}
+
+
+size_t RSScript::getFuncCount() const {
+ switch (mStatus) {
+ case ScriptStatus::Compiled: {
+ return mCompiled->getFuncCount();
+ }
+
+ case ScriptStatus::Cached: {
+ return mCached->getFuncCount();
+ }
+
+ default: {
+ return 0;
+ }
+ }
+}
+
+
+size_t RSScript::getObjectSlotCount() const {
+ switch (mStatus) {
+ case ScriptStatus::Compiled: {
+ return mCompiled->getObjectSlotCount();
+ }
+
+ case ScriptStatus::Cached: {
+ return mCached->getObjectSlotCount();
+ }
+
+ default: {
+ return 0;
+ }
+ }
+}
+
+
+void RSScript::getExportVarList(size_t varListSize, void **varList) {
+ switch (mStatus) {
+#define DELEGATE(STATUS) \
+ case ScriptStatus::STATUS: \
+ m##STATUS->getExportVarList(varListSize, varList); \
+ break;
+
+ DELEGATE(Cached);
+
+ DELEGATE(Compiled);
+#undef DELEGATE
+
+ default: {
+ mErrorCode = BCC_INVALID_OPERATION;
+ }
+ }
+}
+
+void RSScript::getExportVarNameList(std::vector<std::string> &varList) {
+ switch (mStatus) {
+ case ScriptStatus::Compiled: {
+ return mCompiled->getExportVarNameList(varList);
+ }
+
+ default: {
+ mErrorCode = BCC_INVALID_OPERATION;
+ }
+ }
+}
+
+
+void RSScript::getExportFuncList(size_t funcListSize, void **funcList) {
+ switch (mStatus) {
+#define DELEGATE(STATUS) \
+ case ScriptStatus::STATUS: \
+ m##STATUS->getExportFuncList(funcListSize, funcList); \
+ break;
+
+ DELEGATE(Cached);
+
+ DELEGATE(Compiled);
+#undef DELEGATE
+
+ default: {
+ mErrorCode = BCC_INVALID_OPERATION;
+ }
+ }
+}
+
+void RSScript::getExportFuncNameList(std::vector<std::string> &funcList) {
+ switch (mStatus) {
+ case ScriptStatus::Compiled: {
+ return mCompiled->getExportFuncNameList(funcList);
+ }
+
+ default: {
+ mErrorCode = BCC_INVALID_OPERATION;
+ }
+ }
+}
+
+void RSScript::getExportForEachList(size_t funcListSize, void **funcList) {
+ switch (mStatus) {
+#define DELEGATE(STATUS) \
+ case ScriptStatus::STATUS: \
+ m##STATUS->getExportForEachList(funcListSize, funcList); \
+ break;
+
+ DELEGATE(Cached);
+
+ DELEGATE(Compiled);
+#undef DELEGATE
+
+ default: {
+ mErrorCode = BCC_INVALID_OPERATION;
+ }
+ }
+}
+
+void RSScript::getExportForEachNameList(std::vector<std::string> &forEachList) {
+ switch (mStatus) {
+ case ScriptStatus::Compiled: {
+ return mCompiled->getExportForEachNameList(forEachList);
+ }
+
+ default: {
+ mErrorCode = BCC_INVALID_OPERATION;
+ }
+ }
+}
+
+void RSScript::getPragmaList(size_t pragmaListSize,
+ char const **keyList,
+ char const **valueList) {
+ switch (mStatus) {
+#define DELEGATE(STATUS) \
+ case ScriptStatus::STATUS: \
+ m##STATUS->getPragmaList(pragmaListSize, keyList, valueList); \
+ break;
+
+ DELEGATE(Cached);
+
+ DELEGATE(Compiled);
+#undef DELEGATE
+
+ default: {
+ mErrorCode = BCC_INVALID_OPERATION;
+ }
+ }
+}
+
+
+void RSScript::getFuncInfoList(size_t funcInfoListSize,
+ FuncInfo *funcInfoList) {
+ switch (mStatus) {
+#define DELEGATE(STATUS) \
+ case ScriptStatus::STATUS: \
+ m##STATUS->getFuncInfoList(funcInfoListSize, funcInfoList); \
+ break;
+
+ DELEGATE(Cached);
+
+ DELEGATE(Compiled);
+#undef DELEGATE
+
+ default: {
+ mErrorCode = BCC_INVALID_OPERATION;
+ }
+ }
+}
+
+
+void RSScript::getObjectSlotList(size_t objectSlotListSize,
+ uint32_t *objectSlotList) {
+ switch (mStatus) {
+#define DELEGATE(STATUS) \
+ case ScriptStatus::STATUS: \
+ m##STATUS->getObjectSlotList(objectSlotListSize, objectSlotList); \
+ break;
+
+ DELEGATE(Cached);
+
+ DELEGATE(Compiled);
+#undef DELEGATE
+
+ default: {
+ mErrorCode = BCC_INVALID_OPERATION;
+ }
+ }
+}
+
+
+int RSScript::registerSymbolCallback(BCCSymbolLookupFn pFn, void *pContext) {
+ mpExtSymbolLookupFn = pFn;
+ mpExtSymbolLookupFnContext = pContext;
+
+ if (mStatus != ScriptStatus::Unknown) {
+ mErrorCode = BCC_INVALID_OPERATION;
+ ALOGE("Invalid operation: %s\n", __func__);
+ return 1;
+ }
+ return 0;
+}
+
+bool RSScript::isCacheable() const {
+ if (getBooleanProp("debug.bcc.nocache")) {
+ // Android system environment property: Disables the cache mechanism by
+ // setting "debug.bcc.nocache". So we will not load the cache file any
+ // way.
+ return false;
+ }
+
+ if (mCacheDir.empty() || mCacheName.empty()) {
+ // The application developer has not specified the cachePath, so
+ // we don't know where to open the cache file.
+ return false;
+ }
+
+ return true;
+}
+
+size_t RSScript::getELFSize() const {
+ switch (mStatus) {
+ case ScriptStatus::Compiled: {
+ return mCompiled->getELFSize();
+ }
+
+ case ScriptStatus::Cached: {
+ return mCached->getELFSize();
+ }
+
+ default: {
+ return 0;
+ }
+ }
+}
+
+const char *RSScript::getELF() const {
+ switch (mStatus) {
+ case ScriptStatus::Compiled: {
+ return mCompiled->getELF();
+ }
+
+ case ScriptStatus::Cached: {
+ return mCached->getELF();
+ }
+
+ default: {
+ return NULL;
+ }
+ }
+}
+
+} // namespace bcc
diff --git a/lib/ExecutionEngine/RSScript.h b/lib/ExecutionEngine/RSScript.h
index 1ae9c9d..4fc1f90 100644
--- a/lib/ExecutionEngine/RSScript.h
+++ b/lib/ExecutionEngine/RSScript.h
@@ -17,94 +17,237 @@
#ifndef BCC_EXECUTION_ENGINE_RS_SCRIPT_H
#define BCC_EXECUTION_ENGINE_RS_SCRIPT_H
+#include <vector>
#include <string>
+#include <stdint.h>
+#include <stddef.h>
+
#include <llvm/ADT/SmallVector.h>
#include <llvm/Support/CodeGen.h>
+#include <bcc/bcc.h>
+#include <bcc/bcc_mccache.h>
+#include "bcc_internal.h"
+
#include "Script.h"
+namespace llvm {
+ class Module;
+ class GDBJITRegistrar;
+}
+
namespace bcc {
+ class RSInfo;
+ class ScriptCompiled;
+ class ScriptCached;
+ class Source;
+ struct CompilerOption;
-class RSInfo;
-class Source;
+ namespace ScriptStatus {
+ enum StatusType {
+ Unknown,
+ Compiled,
+ Cached
+ };
+ }
-class RSScript : public Script {
-public:
- class SourceDependency {
+ namespace ScriptObject {
+ enum ObjectType {
+ Unknown,
+ Relocatable,
+ SharedObject,
+ Executable,
+ };
+ }
+
+ class RSScript : public Script {
+ public:
+ class SourceDependency {
+ private:
+ std::string mSourceName;
+ uint8_t mSHA1[20];
+
+ public:
+ SourceDependency(const std::string &pSourceName,
+ const uint8_t *pSHA1);
+
+ inline const std::string &getSourceName() const
+ { return mSourceName; }
+
+ inline const uint8_t *getSHA1Checksum() const
+ { return mSHA1; }
+ };
+ typedef llvm::SmallVectorImpl<SourceDependency *> SourceDependencyListTy;
+
private:
- std::string mSourceName;
- uint8_t mSHA1[20];
+ int mErrorCode;
+
+ ScriptStatus::StatusType mStatus;
+ // The type of the object behind this script after compilation. For
+ // example, after returning from a successful call to prepareRelocatable(),
+ // the value of mObjectType will be ScriptObject::Relocatable.
+ ScriptObject::ObjectType mObjectType;
+
+ union {
+ ScriptCompiled *mCompiled;
+ ScriptCached *mCached;
+ };
+
+ std::string mCacheDir;
+ std::string mCacheName;
+
+ inline std::string getCachedObjectPath() const {
+ return std::string(mCacheDir + mCacheName + ".o");
+ }
+
+ inline std::string getCacheInfoPath() const {
+ return getCachedObjectPath().append(".info");
+ }
+
+ bool mIsContextSlotNotAvail;
+
+ llvm::SmallVector<SourceDependency *, 4> mSourceDependencies;
+
+ const RSInfo *mInfo;
+
+ // External Function List
+ std::vector<char const *> mUserDefinedExternalSymbols;
+
+ // Register Symbol Lookup Function
+ BCCSymbolLookupFn mpExtSymbolLookupFn;
+ void *mpExtSymbolLookupFnContext;
+
+ // This will be invoked when the containing source has been reset.
+ virtual bool doReset();
+
+ // Reset the state of this script object
+ void resetState();
public:
- SourceDependency(const std::string &pSourceName,
- const uint8_t *pSHA1);
+ RSScript(Source &pSource);
- inline const std::string &getSourceName() const
- { return mSourceName; }
+ ~RSScript();
- inline const uint8_t *getSHA1Checksum() const
- { return mSHA1; }
- };
- typedef llvm::SmallVectorImpl<SourceDependency *> SourceDependencyListTy;
+ // Add dependency information for this script given the source named
+ // pSourceName. pSHA1 is the SHA-1 checksum of the given source. Return
+ // false on error.
+ bool addSourceDependency(const std::string &pSourceName,
+ const uint8_t *pSHA1);
- // This is one-one mapping with the llvm::CodeGenOpt::Level in
- // llvm/Support/CodeGen.h. Therefore, value of this type can safely cast
- // to llvm::CodeGenOpt::Level. This makes RSScript LLVM-free.
- enum OptimizationLevel {
- kOptLvl0, // -O0
- kOptLvl1, // -O1
- kOptLvl2, // -O2, -Os
- kOptLvl3 // -O3
+ const SourceDependencyListTy &getSourceDependencies() const
+ { return mSourceDependencies; }
+
+ // Set the associated RSInfo of the script.
+ void setInfo(const RSInfo *pInfo)
+ { mInfo = pInfo; }
+
+ const RSInfo *getInfo() const
+ { return mInfo; }
+
+ void markExternalSymbol(char const *name) {
+ mUserDefinedExternalSymbols.push_back(name);
+ }
+
+ std::vector<char const *> const &getUserDefinedExternalSymbols() const {
+ return mUserDefinedExternalSymbols;
+ }
+
+ int prepareExecutable(char const *cacheDir,
+ char const *cacheName,
+ unsigned long flags);
+ int writeCache();
+
+ /*
+ * Link the given bitcodes in mSource to shared object (.so).
+ *
+ * Currently, it requires one to provide the relocatable object files with
+ * given bitcodes to output a shared object.
+ *
+ * The usage of this function is flexible. You can have a relocatable object
+ * compiled before and pass it in objPath to generate shared object. If the
+ * objPath is NULL, we'll invoke prepareRelocatable() to get .o first (if
+ * you haven't done that yet) and then link the output relocatable object
+ * file to .so in dsoPath.
+ *
+ * TODO: Currently, we only support to link a bitcode (i.e., mSource.)
+ *
+ */
+ int prepareSharedObject(char const *objPath,
+ char const *dsoPath,
+ unsigned long flags);
+
+ int prepareRelocatable(char const *objPath,
+ llvm::Reloc::Model RelocModel,
+ unsigned long flags);
+
+ char const *getCompilerErrorMessage();
+
+ void *lookup(const char *name);
+
+ size_t getExportVarCount() const;
+
+ size_t getExportFuncCount() const;
+
+ size_t getExportForEachCount() const;
+
+ size_t getPragmaCount() const;
+
+ size_t getFuncCount() const;
+
+ size_t getObjectSlotCount() const;
+
+ void getExportVarList(size_t size, void **list);
+
+ void getExportFuncList(size_t size, void **list);
+
+ void getExportForEachList(size_t size, void **list);
+
+ void getExportVarNameList(std::vector<std::string> &list);
+
+ void getExportFuncNameList(std::vector<std::string> &list);
+
+ void getExportForEachNameList(std::vector<std::string> &list);
+
+ void getPragmaList(size_t size,
+ char const **keyList,
+ char const **valueList);
+
+ void getFuncInfoList(size_t size, FuncInfo *list);
+
+ void getObjectSlotList(size_t size, uint32_t *list);
+
+ size_t getELFSize() const;
+
+ const char *getELF() const;
+
+ int registerSymbolCallback(BCCSymbolLookupFn pFn, void *pContext);
+
+ bool isCacheable() const;
+
+ void setError(int error) {
+ if (mErrorCode == BCC_NO_ERROR && error != BCC_NO_ERROR) {
+ mErrorCode = error;
+ }
+ }
+
+ int getError() {
+ int result = mErrorCode;
+ mErrorCode = BCC_NO_ERROR;
+ return result;
+ }
+
+ private:
+ //
+ // It returns 0 if there's a cache hit.
+ //
+ // Side effect: it will set mCacheDir, mCacheName.
+ int internalLoadCache(char const *cacheDir, char const *cacheName,
+ bool checkOnly);
+
+ int internalCompile(const CompilerOption&);
};
-private:
- llvm::SmallVector<SourceDependency *, 4> mSourceDependencies;
-
- const RSInfo *mInfo;
-
- unsigned mCompilerVersion;
-
- OptimizationLevel mOptimizationLevel;
-
-private:
- // This will be invoked when the containing source has been reset.
- virtual bool doReset();
-
-public:
- RSScript(Source &pSource);
-
- // Add dependency information for this script given the source named
- // pSourceName. pSHA1 is the SHA-1 checksum of the given source. Return
- // false on error.
- bool addSourceDependency(const std::string &pSourceName,
- const uint8_t *pSHA1);
-
- const SourceDependencyListTy &getSourceDependencies() const
- { return mSourceDependencies; }
-
- // Set the associated RSInfo of the script.
- void setInfo(const RSInfo *pInfo)
- { mInfo = pInfo; }
-
- const RSInfo *getInfo() const
- { return mInfo; }
-
- void setCompilerVersion(unsigned pCompilerVersion)
- { mCompilerVersion = pCompilerVersion; }
-
- unsigned getCompilerVersion() const
- { return mCompilerVersion; }
-
- void setOptimizationLevel(OptimizationLevel pOptimizationLevel)
- { mOptimizationLevel = pOptimizationLevel; }
-
- OptimizationLevel getOptimizationLevel() const
- { return mOptimizationLevel; }
-
- ~RSScript();
-};
-
-} // end namespace bcc
+} // namespace bcc
#endif // BCC_EXECUTION_ENGINE_RS_SCRIPT_H
diff --git a/lib/ExecutionEngine/ScriptCached.cpp b/lib/ExecutionEngine/ScriptCached.cpp
new file mode 100644
index 0000000..bbfac2b
--- /dev/null
+++ b/lib/ExecutionEngine/ScriptCached.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2010-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 "Config.h"
+
+#include "ScriptCached.h"
+
+#include "DebugHelper.h"
+
+#include <stdlib.h>
+
+namespace bcc {
+
+ScriptCached::~ScriptCached() {
+ // Deallocate string pool, exported var list, exported func list
+ if (mpStringPoolRaw) { free(mpStringPoolRaw); }
+ if (mpExportVars) { free(mpExportVars); }
+ if (mpExportFuncs) { free(mpExportFuncs); }
+ if (mpExportForEach) { free(mpExportForEach); }
+ if (mpObjectSlotList) { free(mpObjectSlotList); }
+}
+
+void ScriptCached::getExportVarList(size_t varListSize, void **varList) {
+ if (varList) {
+ size_t varCount = getExportVarCount();
+
+ if (varCount > varListSize) {
+ varCount = varListSize;
+ }
+
+ memcpy(varList, mpExportVars->cached_addr_list, sizeof(void *) * varCount);
+ }
+}
+
+
+void ScriptCached::getExportFuncList(size_t funcListSize, void **funcList) {
+ if (funcList) {
+ size_t funcCount = getExportFuncCount();
+
+ if (funcCount > funcListSize) {
+ funcCount = funcListSize;
+ }
+
+ memcpy(funcList, mpExportFuncs->cached_addr_list,
+ sizeof(void *) * funcCount);
+ }
+}
+
+
+void ScriptCached::getExportForEachList(size_t forEachListSize,
+ void **forEachList) {
+ if (forEachList) {
+ size_t forEachCount = getExportForEachCount();
+
+ if (forEachCount > forEachListSize) {
+ forEachCount = forEachListSize;
+ }
+
+ memcpy(forEachList, mpExportForEach->cached_addr_list,
+ sizeof(void *) * forEachCount);
+ }
+}
+
+
+void ScriptCached::getPragmaList(size_t pragmaListSize,
+ char const **keyList,
+ char const **valueList) {
+ size_t pragmaCount = getPragmaCount();
+
+ if (pragmaCount > pragmaListSize) {
+ pragmaCount = pragmaListSize;
+ }
+
+ if (keyList) {
+ for (size_t i = 0; i < pragmaCount; ++i) {
+ *keyList++ = mPragmas[i].first;
+ }
+ }
+
+ if (valueList) {
+ for (size_t i = 0; i < pragmaCount; ++i) {
+ *valueList++ = mPragmas[i].second;
+ }
+ }
+}
+
+
+void ScriptCached::getObjectSlotList(size_t objectSlotListSize,
+ uint32_t *objectSlotList) {
+ if (objectSlotList) {
+ size_t objectSlotCount = getObjectSlotCount();
+
+ if (objectSlotCount > objectSlotListSize) {
+ objectSlotCount = objectSlotListSize;
+ }
+
+ memcpy(objectSlotList, mpObjectSlotList->object_slot_list,
+ sizeof(uint32_t) * objectSlotCount);
+ }
+}
+
+
+void *ScriptCached::lookup(const char *name) {
+ return rsloaderGetSymbolAddress(mRSExecutable, name);
+}
+
+void ScriptCached::getFuncInfoList(size_t funcInfoListSize,
+ FuncInfo *funcInfoList) {
+ if (funcInfoList) {
+ size_t funcCount = getFuncCount();
+
+ if (funcCount > funcInfoListSize) {
+ funcCount = funcInfoListSize;
+ }
+
+ FuncInfo *info = funcInfoList;
+ for (FuncTable::const_iterator
+ I = mFunctions.begin(), E = mFunctions.end();
+ I != E && funcCount > 0; ++I, ++info, --funcCount) {
+ info->name = I->first.c_str();
+ info->addr = I->second.first;
+ info->size = I->second.second;
+ }
+ }
+}
+
+
+} // namespace bcc
diff --git a/lib/ExecutionEngine/ScriptCached.h b/lib/ExecutionEngine/ScriptCached.h
new file mode 100644
index 0000000..e24a714
--- /dev/null
+++ b/lib/ExecutionEngine/ScriptCached.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2010-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 BCC_SCRIPTCACHED_H
+#define BCC_SCRIPTCACHED_H
+
+#include "Config.h"
+
+#include <bcc/bcc.h>
+#include <bcc/bcc_mccache.h>
+#include "bcc_internal.h"
+
+#include "librsloader.h"
+
+#include <llvm/ADT/SmallVector.h>
+
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <stddef.h>
+
+namespace llvm {
+ class Module;
+}
+
+namespace bcc {
+ class Script;
+
+ class ScriptCached {
+ friend class CacheReader;
+ friend class MCCacheReader;
+
+ private:
+ enum { SMALL_VECTOR_QUICKN = 16 };
+
+ typedef llvm::SmallVector<std::pair<char const *, char const *>,
+ SMALL_VECTOR_QUICKN> PragmaList;
+
+ typedef std::map<std::string, std::pair<void *, size_t> > FuncTable;
+
+ private:
+ Script *mpOwner;
+
+ MCO_ExportVarList *mpExportVars;
+ MCO_ExportFuncList *mpExportFuncs;
+ MCO_ExportForEachList *mpExportForEach;
+ PragmaList mPragmas;
+ MCO_ObjectSlotList *mpObjectSlotList;
+
+ FuncTable mFunctions;
+
+ RSExecRef mRSExecutable;
+ llvm::SmallVector<char, 1024> mCachedELFExecutable;
+
+ MCO_StringPool *mpStringPoolRaw;
+ std::vector<char const *> mStringPool;
+
+ bool mLibRSThreadable;
+
+ public:
+ ScriptCached(Script *owner)
+ : mpOwner(owner),
+ mpExportVars(NULL),
+ mpExportFuncs(NULL),
+ mpExportForEach(NULL),
+ mpObjectSlotList(NULL),
+ mpStringPoolRaw(NULL),
+ mLibRSThreadable(false) {
+ }
+
+ ~ScriptCached();
+
+ void *lookup(const char *name);
+
+
+ size_t getExportVarCount() const {
+ return mpExportVars->count;
+ }
+
+ size_t getExportFuncCount() const {
+ return mpExportFuncs->count;
+ }
+
+ size_t getExportForEachCount() const {
+ return mpExportForEach->count;
+ }
+
+ size_t getPragmaCount() const {
+ return mPragmas.size();
+ }
+
+ size_t getFuncCount() const {
+ return mFunctions.size();
+ }
+
+ size_t getObjectSlotCount() const {
+ return mpObjectSlotList->count;
+ }
+
+ void getExportVarList(size_t varListSize, void **varList);
+
+ void getExportFuncList(size_t funcListSize, void **funcList);
+
+ void getExportForEachList(size_t forEachListSize, void **forEachList);
+
+ void getPragmaList(size_t pragmaListSize,
+ char const **keyList,
+ char const **valueList);
+
+ void getFuncInfoList(size_t funcInfoListSize, FuncInfo *funcNameList);
+
+ void getObjectSlotList(size_t objectSlotListSize,
+ uint32_t *objectSlotList);
+
+ const char *getELF() const {
+ return &*mCachedELFExecutable.begin();
+ }
+
+ size_t getELFSize() const {
+ return mCachedELFExecutable.size();
+ }
+
+ // Dirty hack for libRS.
+ // TODO(all): This should be removed in the future.
+ bool isLibRSThreadable() const {
+ return mLibRSThreadable;
+ }
+
+#if 0
+ void registerSymbolCallback(BCCSymbolLookupFn pFn, BCCvoid *pContext) {
+ mCompiler.registerSymbolCallback(pFn, pContext);
+ }
+#endif
+ };
+
+} // namespace bcc
+
+#endif // BCC_SCRIPTCACHED_H
diff --git a/lib/ExecutionEngine/ScriptCompiled.cpp b/lib/ExecutionEngine/ScriptCompiled.cpp
new file mode 100644
index 0000000..4f2bb1b
--- /dev/null
+++ b/lib/ExecutionEngine/ScriptCompiled.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2010-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 "ScriptCompiled.h"
+
+#include "bcc_internal.h"
+#include "DebugHelper.h"
+
+namespace bcc {
+
+ScriptCompiled::~ScriptCompiled() {
+}
+
+void ScriptCompiled::getExportVarList(size_t varListSize, void **varList) {
+ if (varList) {
+ size_t varCount = getExportVarCount();
+
+ if (varCount > varListSize) {
+ varCount = varListSize;
+ }
+
+ for (ExportVarList::const_iterator
+ I = mExportVars.begin(), E = mExportVars.end();
+ I != E && varCount > 0; ++I, --varCount) {
+ *varList++ = *I;
+ }
+ }
+}
+
+void ScriptCompiled::getExportVarNameList(std::vector<std::string> &varList) {
+ varList = mExportVarsName;
+}
+
+
+void ScriptCompiled::getExportFuncNameList(std::vector<std::string> &funcList) {
+ funcList = mExportFuncsName;
+}
+
+
+void ScriptCompiled::getExportForEachNameList(std::vector<std::string> &forEachList) {
+ forEachList = mExportForEachName;
+}
+
+
+void ScriptCompiled::getExportFuncList(size_t funcListSize, void **funcList) {
+ if (funcList) {
+ size_t funcCount = getExportFuncCount();
+
+ if (funcCount > funcListSize) {
+ funcCount = funcListSize;
+ }
+
+ for (ExportFuncList::const_iterator
+ I = mExportFuncs.begin(), E = mExportFuncs.end();
+ I != E && funcCount > 0; ++I, --funcCount) {
+ *funcList++ = *I;
+ }
+ }
+}
+
+
+void ScriptCompiled::getExportForEachList(size_t forEachListSize,
+ void **forEachList) {
+ if (forEachList) {
+ size_t forEachCount = getExportForEachCount();
+
+ if (forEachCount > forEachListSize) {
+ forEachCount = forEachListSize;
+ }
+
+ for (ExportForEachList::const_iterator
+ I = mExportForEach.begin(), E = mExportForEach.end();
+ I != E && forEachCount > 0; ++I, --forEachCount) {
+ *forEachList++ = *I;
+ }
+ }
+}
+
+
+void ScriptCompiled::getPragmaList(size_t pragmaListSize,
+ char const **keyList,
+ char const **valueList) {
+ size_t pragmaCount = getPragmaCount();
+
+ if (pragmaCount > pragmaListSize) {
+ pragmaCount = pragmaListSize;
+ }
+
+ for (PragmaList::const_iterator
+ I = mPragmas.begin(), E = mPragmas.end();
+ I != E && pragmaCount > 0; ++I, --pragmaCount) {
+ if (keyList) { *keyList++ = I->first.c_str(); }
+ if (valueList) { *valueList++ = I->second.c_str(); }
+ }
+}
+
+
+void *ScriptCompiled::lookup(const char *name) {
+ return mCompiler.getSymbolAddress(name);
+}
+
+
+void ScriptCompiled::getFuncInfoList(size_t funcInfoListSize,
+ FuncInfo *funcInfoList) {
+ if (funcInfoList) {
+ size_t funcCount = getFuncCount();
+
+ if (funcCount > funcInfoListSize) {
+ funcCount = funcInfoListSize;
+ }
+
+ FuncInfo *info = funcInfoList;
+ for (FuncInfoMap::const_iterator
+ I = mEmittedFunctions.begin(), E = mEmittedFunctions.end();
+ I != E && funcCount > 0; ++I, ++info, --funcCount) {
+ info->name = I->first.c_str();
+ info->addr = I->second->addr;
+ info->size = I->second->size;
+ }
+ }
+}
+
+void ScriptCompiled::getObjectSlotList(size_t objectSlotListSize,
+ uint32_t *objectSlotList) {
+ if (objectSlotList) {
+ size_t objectSlotCount = getObjectSlotCount();
+
+ if (objectSlotCount > objectSlotListSize) {
+ objectSlotCount = objectSlotListSize;
+ }
+
+ for (ObjectSlotList::const_iterator
+ I = mObjectSlots.begin(), E = mObjectSlots.end();
+ I != E && objectSlotCount > 0; ++I, --objectSlotCount) {
+ *objectSlotList++ = *I;
+ }
+ }
+
+}
+
+} // namespace bcc
diff --git a/lib/ExecutionEngine/ScriptCompiled.h b/lib/ExecutionEngine/ScriptCompiled.h
new file mode 100644
index 0000000..e96dbe2
--- /dev/null
+++ b/lib/ExecutionEngine/ScriptCompiled.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2010-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 BCC_SCRIPTCOMPILED_H
+#define BCC_SCRIPTCOMPILED_H
+
+#include <list>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <bcc/bcc.h>
+
+#include "Compiler.h"
+#include "RSScript.h"
+
+namespace llvm {
+ class Module;
+}
+
+namespace bcc {
+ struct CompilerOption;
+
+ class ScriptCompiled {
+ friend class Compiler;
+ friend class CodeEmitter;
+
+ private:
+ typedef std::list<std::pair<std::string, std::string> > PragmaList;
+ typedef std::list<void*> ExportVarList;
+ typedef std::list<void*> ExportFuncList;
+ typedef std::list<void*> ExportForEachList;
+ typedef std::map<std::string, FuncInfo *> FuncInfoMap;
+ typedef std::list<uint32_t> ObjectSlotList;
+
+ private:
+ RSScript *mpOwner;
+
+ Compiler mCompiler;
+
+ ExportVarList mExportVars;
+
+ std::vector<std::string> mExportVarsName;
+ std::vector<std::string> mExportFuncsName;
+ std::vector<std::string> mExportForEachName;
+
+ ExportFuncList mExportFuncs;
+ ExportForEachList mExportForEach;
+ PragmaList mPragmas;
+ ObjectSlotList mObjectSlots;
+
+ FuncInfoMap mEmittedFunctions;
+
+ public:
+ ScriptCompiled(RSScript *owner)
+ : mpOwner(owner), mCompiler(this)
+ {
+ }
+
+ ~ScriptCompiled();
+
+ int readModule(llvm::Module &pModule) {
+ return mCompiler.readModule(pModule);
+ }
+
+ int compile(const CompilerOption &option) {
+ return mCompiler.compile(option);
+ }
+
+ char const *getCompilerErrorMessage() {
+ return mCompiler.getErrorMessage();
+ }
+
+ void *lookup(const char *name);
+
+ size_t getExportVarCount() const {
+ return mExportVars.size();
+ }
+
+ size_t getExportFuncCount() const {
+ return mExportFuncs.size();
+ }
+
+ size_t getExportForEachCount() const {
+ return mExportForEach.size();
+ }
+
+ size_t getPragmaCount() const {
+ return mPragmas.size();
+ }
+
+ size_t getFuncCount() const {
+ return mEmittedFunctions.size();
+ }
+
+ size_t getObjectSlotCount() const {
+ return mObjectSlots.size();
+ }
+
+ void getExportVarList(size_t varListSize, void **varList);
+
+ void getExportFuncList(size_t funcListSize, void **funcList);
+
+ void getExportForEachList(size_t forEachListSize, void **forEachList);
+
+ void getExportVarNameList(std::vector<std::string> &varList);
+
+ void getExportFuncNameList(std::vector<std::string> &funcList);
+
+ void getExportForEachNameList(std::vector<std::string> &forEachList);
+
+ void getPragmaList(size_t pragmaListSize,
+ char const **keyList,
+ char const **valueList);
+
+ void getFuncInfoList(size_t funcInfoListSize,
+ FuncInfo *funcInfoList);
+
+ void getObjectSlotList(size_t objectSlotListSize,
+ uint32_t *objectSlotList);
+
+ std::vector<char const *> const & getUserDefinedExternalSymbols() const {
+ return mpOwner->getUserDefinedExternalSymbols();
+ }
+
+ const char *getELF() const {
+ return &*mCompiler.getELF().begin();
+ }
+
+ size_t getELFSize() const {
+ return mCompiler.getELF().size();
+ }
+
+ void registerSymbolCallback(BCCSymbolLookupFn pFn, void *pContext) {
+ mCompiler.registerSymbolCallback(pFn, pContext);
+ }
+ };
+
+} // namespace bcc
+
+#endif // BCC_SCRIPTCOMPILED_H
diff --git a/lib/ExecutionEngine/bcc.cpp b/lib/ExecutionEngine/bcc.cpp
index b830ec2..6baa3e0 100644
--- a/lib/ExecutionEngine/bcc.cpp
+++ b/lib/ExecutionEngine/bcc.cpp
@@ -19,20 +19,22 @@
#include <bcc/bcc.h>
-#include <llvm/Support/CodeGen.h>
+#include <string>
#include <utils/StopWatch.h>
+#include "Config.h"
+
+#include <bcc/bcc_mccache.h>
+#include "bcc_internal.h"
+
+#include "BCCContext.h"
+#include "Compiler.h"
#include "DebugHelper.h"
-#include "Initialization.h"
-#include "RSExecutable.h"
#include "RSScript.h"
#include "Sha1Helper.h"
#include "Source.h"
-#include "bcc_internal.h"
-#include <bcinfo/BitcodeWrapper.h>
-
using namespace bcc;
namespace llvm {
@@ -52,24 +54,21 @@
extern "C" BCCScriptRef bccCreateScript() {
BCC_FUNC_LOGGER();
bccPrintBuildStamp();
- init::Initialize();
- RSScriptContext *rsctx = new (std::nothrow) RSScriptContext();
- if (rsctx != NULL) {
- rsctx->script = NULL;
- rsctx->result = NULL;
+ // FIXME: This is a workaround for this API: use global BCC context and
+ // create an empty source to create a Script object.
+ BCCContext *context = BCCContext::GetOrCreateGlobalContext();
+ if (context == NULL) {
+ return NULL;
}
- return wrap(rsctx);
+
+ Source *source = Source::CreateEmpty(*context, "empty");
+ return wrap(new RSScript(*source));
}
extern "C" void bccDisposeScript(BCCScriptRef script) {
BCC_FUNC_LOGGER();
- RSScriptContext *rsctx = unwrap(script);
- if (rsctx != NULL) {
- delete rsctx->script;
- delete rsctx->result;
- }
- delete rsctx;
+ delete unwrap(script);
}
@@ -77,18 +76,16 @@
BCCSymbolLookupFn pFn,
void *pContext) {
BCC_FUNC_LOGGER();
- unwrap(script)->driver.setRSRuntimeLookupFunction(pFn);
- unwrap(script)->driver.setRSRuntimeLookupContext(pContext);
- return BCC_NO_ERROR;
+ return unwrap(script)->registerSymbolCallback(pFn, pContext);
}
extern "C" int bccGetError(BCCScriptRef script) {
BCC_FUNC_LOGGER();
- return BCC_DEPRECATED_API;
+ return unwrap(script)->getError();
}
-static bool helper_add_source(RSScriptContext *pCtx,
+static bool helper_add_source(RSScript *pScript,
char const *pName,
char const *pBitcode,
size_t pBitcodeSize,
@@ -103,119 +100,76 @@
ALOGW("Set BCC_SKIP_DEP_SHA1 for flags to surpress this warning.\n");
}
- Source *source = Source::CreateFromBuffer(pCtx->context, pName,
+ BCCContext *context = BCCContext::GetOrCreateGlobalContext();
+ if (context == NULL) {
+ return false;
+ }
+
+ Source *source = Source::CreateFromBuffer(*context, pName,
pBitcode, pBitcodeSize);
if (source == NULL) {
return false;
}
- if (pCtx->script == NULL) {
- pCtx->script = new (std::nothrow) RSScript(*source);
- if (pCtx->script == NULL) {
- ALOGE("Out of memory during script creation.");
- return false;
- }
- } else {
- bool result;
- if (pIsLink) {
- result = pCtx->script->mergeSource(*source);
- } else {
- result = pCtx->script->reset(*source);
- }
- if (!result) {
- return false;
- } else {
- bcinfo::BitcodeWrapper wrapper(pBitcode, pBitcodeSize);
- pCtx->script->setCompilerVersion(wrapper.getCompilerVersion());
- pCtx->script->setOptimizationLevel(
- static_cast<RSScript::OptimizationLevel>(
- wrapper.getOptimizationLevel()));
- }
- }
-
if (need_dependency_check) {
uint8_t sha1[20];
calcSHA1(sha1, pBitcode, pBitcodeSize);
- if (!pCtx->script->addSourceDependency(pName, sha1)) {
+ if (!pScript->addSourceDependency(pName, sha1)) {
return false;
}
}
- return true;
+ return ((pIsLink) ? pScript->mergeSource(*source) : pScript->reset(*source));
}
-static bool helper_add_source(RSScriptContext *pCtx,
+static bool helper_add_source(RSScript *pScript,
llvm::Module *pModule,
bool pIsLink) {
+ if (pModule == NULL)
+ return false;
+
+ BCCContext *context = BCCContext::GetOrCreateGlobalContext();
+ if (context == NULL) {
+ return false;
+ }
+
if (pModule == NULL) {
ALOGE("Cannot add null module to script!");
return false;
}
- Source *source = Source::CreateFromModule(pCtx->context, *pModule, true);
+ Source *source = Source::CreateFromModule(*context, *pModule, true);
if (source == NULL) {
return false;
}
- if (pCtx->script == NULL) {
- pCtx->script = new (std::nothrow) RSScript(*source);
- if (pCtx->script == NULL) {
- ALOGE("Out of memory during script creation.");
- return false;
- }
- } else {
- bool result;
- if (pIsLink) {
- result = pCtx->script->mergeSource(*source);
- } else {
- result = pCtx->script->reset(*source);
- }
- if (!result) {
- return false;
- }
- }
-
- return true;
+ return ((pIsLink) ? pScript->mergeSource(*source) : pScript->reset(*source));
}
-static bool helper_add_source(RSScriptContext *pCtx,
+static bool helper_add_source(RSScript *pScript,
char const *pPath,
unsigned long pFlags,
bool pIsLink) {
bool need_dependency_check = !(pFlags & BCC_SKIP_DEP_SHA1);
-
- Source *source = Source::CreateFromFile(pCtx->context, pPath);
- if (source == NULL) {
+ BCCContext *context = BCCContext::GetOrCreateGlobalContext();
+ if (context == NULL) {
return false;
}
- if (pCtx->script == NULL) {
- pCtx->script = new (std::nothrow) RSScript(*source);
- if (pCtx->script == NULL) {
- ALOGE("Out of memory during script creation.");
- return false;
- }
- } else {
- bool result;
- if (pIsLink) {
- result = pCtx->script->mergeSource(*source);
- } else {
- result = pCtx->script->reset(*source);
- }
- if (!result) {
- return false;
- }
+ Source *source = Source::CreateFromFile(*context, pPath);
+ if (source == NULL) {
+ return false;
}
if (need_dependency_check) {
uint8_t sha1[20];
calcFileSHA1(sha1, pPath);
- if (!pCtx->script->addSourceDependency(pPath, sha1)) {
+ if (!pScript->addSourceDependency(pPath, sha1)) {
return false;
}
}
- return true;
+ return ((pIsLink) ? pScript->mergeSource(*source) : pScript->reset(*source));
}
extern "C" int bccReadBC(BCCScriptRef script,
@@ -272,7 +226,7 @@
extern "C" void bccMarkExternalSymbol(BCCScriptRef script, char const *name) {
BCC_FUNC_LOGGER();
- return /* BCC_DEPRECATED_API */;
+ unwrap(script)->markExternalSymbol(name);
}
@@ -281,7 +235,32 @@
bccRelocModelEnum RelocModel,
unsigned long flags) {
BCC_FUNC_LOGGER();
- return BCC_DEPRECATED_API;
+ llvm::Reloc::Model RM;
+
+ switch (RelocModel) {
+ case bccRelocDefault: {
+ RM = llvm::Reloc::Default;
+ break;
+ }
+ case bccRelocStatic: {
+ RM = llvm::Reloc::Static;
+ break;
+ }
+ case bccRelocPIC: {
+ RM = llvm::Reloc::PIC_;
+ break;
+ }
+ case bccRelocDynamicNoPIC: {
+ RM = llvm::Reloc::DynamicNoPIC;
+ break;
+ }
+ default: {
+ ALOGE("Unrecognized relocation model for bccPrepareObject!");
+ return BCC_INVALID_VALUE;
+ }
+ }
+
+ return unwrap(script)->prepareRelocatable(objPath, RM, flags);
}
@@ -290,7 +269,7 @@
char const *dsoPath,
unsigned long flags) {
BCC_FUNC_LOGGER();
- return BCC_DEPRECATED_API;
+ return unwrap(script)->prepareSharedObject(objPath, dsoPath, flags);
}
@@ -302,41 +281,14 @@
android::StopWatch compileTimer("bcc: PrepareExecutable time");
- RSScriptContext *rsctx = unwrap(script);
-
- if (rsctx->script == NULL) {
- return 1;
- }
-
- // Construct the output path.
- std::string output_path(cacheDir);
- if (!output_path.empty() && (*output_path.rbegin() != '/')) {
- output_path.append(1, '/');
- }
- output_path.append(cacheName);
- output_path.append(".o");
-
- // Make sure the result container is clean.
- if (rsctx->result != NULL) {
- delete rsctx->result;
- rsctx->result = NULL;
- }
-
- rsctx->result = rsctx->driver.build(*rsctx->script, output_path);
-
- return (rsctx->result == NULL);
+ return unwrap(script)->prepareExecutable(cacheDir, cacheName, flags);
}
extern "C" void *bccGetFuncAddr(BCCScriptRef script, char const *funcname) {
BCC_FUNC_LOGGER();
- RSScriptContext *rsctx = unwrap(script);
-
- void *addr = NULL;
- if (rsctx->result != NULL) {
- addr = rsctx->result->getSymbolAddress(funcname);
- }
+ void *addr = unwrap(script)->lookup(funcname);
#if DEBUG_BCC_REFLECT
ALOGD("Function Address: %s --> %p\n", funcname, addr);
@@ -351,27 +303,19 @@
void **varList) {
BCC_FUNC_LOGGER();
- const RSScriptContext *rsctx = unwrap(script);
- if (varList && rsctx->result) {
- const android::Vector<void *> &export_var_addrs =
- rsctx->result->getExportVarAddrs();
- size_t count = export_var_addrs.size();
+ if (varList) {
+ unwrap(script)->getExportVarList(varListSize, varList);
+
+#if DEBUG_BCC_REFLECT
+ size_t count = unwrap(script)->getExportVarCount();
+ ALOGD("ExportVarCount = %lu\n", (unsigned long)count);
if (count > varListSize) {
count = varListSize;
}
for (size_t i = 0; i < count; ++i) {
- varList[i] = export_var_addrs[i];
- }
-
-#if DEBUG_BCC_REFLECT
- ALOGD("ExportVarCount = %lu\n",
- static_cast<unsigned long>(export_var_addrs.size()));
-
- for (size_t i = 0; i < count; ++i) {
- ALOGD("ExportVarList[%lu] = %p\n", static_cast<unsigned long>(i),
- varList[i]);
+ ALOGD("ExportVarList[%lu] = %p\n", (unsigned long)i, varList[i]);
}
#endif
}
@@ -383,27 +327,19 @@
void **funcList) {
BCC_FUNC_LOGGER();
- const RSScriptContext *rsctx = unwrap(script);
- if (funcList && rsctx->result) {
- const android::Vector<void *> &export_func_addrs =
- rsctx->result->getExportFuncAddrs();
- size_t count = export_func_addrs.size();
+ if (funcList) {
+ unwrap(script)->getExportFuncList(funcListSize, funcList);
+
+#if DEBUG_BCC_REFLECT
+ size_t count = unwrap(script)->getExportFuncCount();
+ ALOGD("ExportFuncCount = %lu\n", (unsigned long)count);
if (count > funcListSize) {
count = funcListSize;
}
for (size_t i = 0; i < count; ++i) {
- funcList[i] = export_func_addrs[i];
- }
-
-#if DEBUG_BCC_REFLECT
- ALOGD("ExportFuncCount = %lu\n",
- static_cast<unsigned long>(export_var_addrs.size()));
-
- for (size_t i = 0; i < count; ++i) {
- ALOGD("ExportFuncList[%lu] = %p\n", static_cast<unsigned long>(i),
- varList[i]);
+ ALOGD("ExportFuncList[%lu] = %p\n", (unsigned long)i, funcList[i]);
}
#endif
}
@@ -415,27 +351,19 @@
void **forEachList) {
BCC_FUNC_LOGGER();
- const RSScriptContext *rsctx = unwrap(script);
- if (forEachList && rsctx->result) {
- const android::Vector<void *> &export_foreach_func_addrs =
- rsctx->result->getExportForeachFuncAddrs();
- size_t count = export_foreach_func_addrs.size();
+ if (forEachList) {
+ unwrap(script)->getExportForEachList(forEachListSize, forEachList);
+
+#if DEBUG_BCC_REFLECT
+ size_t count = unwrap(script)->getExportForEachCount();
+ ALOGD("ExportForEachCount = %lu\n", (unsigned long)count);
if (count > forEachListSize) {
count = forEachListSize;
}
for (size_t i = 0; i < count; ++i) {
- forEachList[i] = export_foreach_func_addrs[i];
- }
-
-#if DEBUG_BCC_REFLECT
- ALOGD("ExportForEachCount = %lu\n",
- static_cast<unsigned long>(export_foreach_func_addrs.size()));
-
- for (size_t i = 0; i < count; ++i) {
- ALOGD("ExportForEachList[%lu] = %p\n", static_cast<unsigned long>(i),
- forEachList[i]);
+ ALOGD("ExportForEachList[%lu] = %p\n", (unsigned long)i, forEachList[i]);
}
#endif
}
diff --git a/lib/ExecutionEngine/bcc_internal.h b/lib/ExecutionEngine/bcc_internal.h
index c003d6c..553034c 100644
--- a/lib/ExecutionEngine/bcc_internal.h
+++ b/lib/ExecutionEngine/bcc_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2010-2012, The Android Open Source Project
+ * Copyright 2010, 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.
@@ -19,9 +19,6 @@
#include <bcc/bcc.h>
-#include "BCCContext.h"
-#include "RSCompilerDriver.h"
-
#if defined(__cplusplus)
#define BCC_OPAQUE_TYPE_CONVERSION(TRANSPARENT_TYPE, OPAQUE_TYPE) \
@@ -38,23 +35,17 @@
}
namespace bcc {
+ class RSScript;
-class RSScript;
-class RSExecutable;
+ /* Function information struct */
+ struct FuncInfo {
+ char const *name;
+ void *addr;
+ size_t size;
+ };
-struct RSScriptContext {
- // The context required in libbcc.
- BCCContext context;
- // The compiler driver
- RSCompilerDriver driver;
- // The script hold the source which is about to compile.
- RSScript *script;
- // The compilation result.
- RSExecutable *result;
-};
-
-BCC_OPAQUE_TYPE_CONVERSION(bcc::RSScriptContext *, BCCScriptRef);
-BCC_OPAQUE_TYPE_CONVERSION(llvm::Module *, LLVMModuleRef);
+ BCC_OPAQUE_TYPE_CONVERSION(bcc::RSScript *, BCCScriptRef);
+ BCC_OPAQUE_TYPE_CONVERSION(llvm::Module *, LLVMModuleRef);
} // namespace bcc