Refactor SourceInfo into Source.
A Script object is associated with a Source object (HAS-A relation.)
A Source object describes the source code (more specifically, the LLVM
module) that is going to be compiled.
BCCContext contains the context used in a Source object.
BCCContext is now managed by the user not the libbcc itself. That is,
user should supply the context object when they create a Source object.
Change-Id: Icb8980d6f15cf30aa0415e69e3ae585d990dc156
diff --git a/lib/ExecutionEngine/Android.mk b/lib/ExecutionEngine/Android.mk
index 78850dd..855d055 100644
--- a/lib/ExecutionEngine/Android.mk
+++ b/lib/ExecutionEngine/Android.mk
@@ -24,6 +24,7 @@
libbcc_executionengine_SRC_FILES := \
BCCContext.cpp \
+ BCCContextImpl.cpp \
Compiler.cpp \
FileHandle.cpp \
GDBJIT.cpp \
@@ -36,7 +37,7 @@
ScriptCached.cpp \
ScriptCompiled.cpp \
Sha1Helper.cpp \
- SourceInfo.cpp
+ Source.cpp
#=====================================================================
diff --git a/lib/ExecutionEngine/BCCContext.cpp b/lib/ExecutionEngine/BCCContext.cpp
index 6d0c5b9..892fd5a 100644
--- a/lib/ExecutionEngine/BCCContext.cpp
+++ b/lib/ExecutionEngine/BCCContext.cpp
@@ -19,7 +19,9 @@
#include <new>
#include "BCCContextImpl.h"
+#include "Compiler.h"
#include "DebugHelper.h"
+#include "Source.h"
using namespace bcc;
@@ -40,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;
@@ -49,9 +54,14 @@
// Reset the GlobalContext.
GlobalContext = NULL;
}
- return;
}
+void BCCContext::addSource(Source &pSource)
+{ mImpl->mOwnSources.insert(&pSource); }
+
+void BCCContext::removeSource(Source &pSource)
+{ mImpl->mOwnSources.erase(&pSource); }
+
llvm::LLVMContext &BCCContext::getLLVMContext()
{ return mImpl->mLLVMContext; }
diff --git a/lib/ExecutionEngine/BCCContext.h b/lib/ExecutionEngine/BCCContext.h
index 3e58acc..56962fe 100644
--- a/lib/ExecutionEngine/BCCContext.h
+++ b/lib/ExecutionEngine/BCCContext.h
@@ -24,6 +24,7 @@
namespace bcc {
class BCCContextImpl;
+class Source;
/*
* class BCCContext manages the global data across the libbcc infrastructure.
@@ -38,6 +39,9 @@
llvm::LLVMContext &getLLVMContext();
const llvm::LLVMContext &getLLVMContext() const;
+ void addSource(Source &pSource);
+ void removeSource(Source &pSource);
+
// Global BCCContext
static BCCContext *GetOrCreateGlobalContext();
static void DestroyGlobalContext();
diff --git a/lib/ExecutionEngine/BCCContextImpl.cpp b/lib/ExecutionEngine/BCCContextImpl.cpp
new file mode 100644
index 0000000..ec865fa
--- /dev/null
+++ b/lib/ExecutionEngine/BCCContextImpl.cpp
@@ -0,0 +1,33 @@
+/*
+ * 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 "BCCContextImpl.h"
+
+#include <vector>
+
+#include <llvm/ADT/STLExtras.h>
+
+#include "Source.h"
+
+using namespace bcc;
+
+BCCContextImpl::~BCCContextImpl() {
+ // Another temporary container is needed to store the Source objects that we
+ // are going to detroy. Since the destruction of Source object will call
+ // removeSource() and change the content of OwnSources.
+ std::vector<Source *> Sources(mOwnSources.begin(), mOwnSources.end());
+ llvm::DeleteContainerPointers(Sources);
+}
diff --git a/lib/ExecutionEngine/BCCContextImpl.h b/lib/ExecutionEngine/BCCContextImpl.h
index b23d798..446eb36 100644
--- a/lib/ExecutionEngine/BCCContextImpl.h
+++ b/lib/ExecutionEngine/BCCContextImpl.h
@@ -17,11 +17,13 @@
#ifndef BCC_EXECUTION_ENGINE_CONTEXT_IMPL_H
#define BCC_EXECUTION_ENGINE_CONTEXT_IMPL_H
+#include <llvm/ADT/SmallPtrSet.h>
#include <llvm/LLVMContext.h>
namespace bcc {
class BCCContext;
+class Source;
/*
* class BCCContextImpl contains the implementation of BCCCotext.
@@ -30,8 +32,12 @@
public:
llvm::LLVMContext mLLVMContext;
+ // The set of sources that initialized in this context. They will be destroyed
+ // automatically when this context is gone.
+ llvm::SmallPtrSet<Source *, 2> mOwnSources;
+
BCCContextImpl(BCCContext &pContext) { }
- ~BCCContextImpl() { }
+ ~BCCContextImpl();
};
} // namespace bcc
diff --git a/lib/ExecutionEngine/Compiler.cpp b/lib/ExecutionEngine/Compiler.cpp
index 58a49c5..100f54b 100644
--- a/lib/ExecutionEngine/Compiler.cpp
+++ b/lib/ExecutionEngine/Compiler.cpp
@@ -226,27 +226,27 @@
mRSExecutable(NULL),
mpSymbolLookupFn(NULL),
mpSymbolLookupContext(NULL),
- mModule(NULL),
- mHasLinked(false) /* Turn off linker */ {
+ mModule(NULL) {
llvm::remove_fatal_error_handler();
llvm::install_fatal_error_handler(LLVMErrorHandler, &mError);
return;
}
-
-int Compiler::linkModule(llvm::Module *moduleWith) {
- if (llvm::Linker::LinkModules(mModule, moduleWith,
- llvm::Linker::PreserveSource,
- &mError) != 0) {
- return hasError();
+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;
+ }
}
-
- // Everything for linking should be settled down here with no error occurs
- mHasLinked = true;
return hasError();
}
-
int Compiler::compile(const CompilerOption &option) {
llvm::Target const *Target = NULL;
llvm::TargetData *TD = NULL;
@@ -390,7 +390,7 @@
runInternalPasses(ForEachNameList, ForEachSigList);
// Perform link-time optimization if we have multiple modules
- if (mHasLinked) {
+ if (option.RunLTO) {
runLTO(new llvm::TargetData(*TD), ExportSymbols, CodeGenOptLevel);
}
diff --git a/lib/ExecutionEngine/Compiler.h b/lib/ExecutionEngine/Compiler.h
index 863cda6..8fee17c 100644
--- a/lib/ExecutionEngine/Compiler.h
+++ b/lib/ExecutionEngine/Compiler.h
@@ -93,8 +93,6 @@
llvm::Module *mModule;
- bool mHasLinked;
-
public:
Compiler(ScriptCompiled *result);
@@ -119,12 +117,7 @@
return mEmittedELFExecutable;
}
- int readModule(llvm::Module *module) {
- mModule = module;
- return hasError();
- }
-
- int linkModule(llvm::Module *module);
+ int readModule(llvm::Module &pModule);
int compile(const CompilerOption &option);
diff --git a/lib/ExecutionEngine/CompilerOption.h b/lib/ExecutionEngine/CompilerOption.h
index 75278c7..f7c1e50 100644
--- a/lib/ExecutionEngine/CompilerOption.h
+++ b/lib/ExecutionEngine/CompilerOption.h
@@ -82,6 +82,9 @@
CodeModelOpt = llvm::CodeModel::Small;
#endif
+ //-- Run LTO passes --//
+ RunLTO = true;
+
//-- Load the result object after successful compilation --//
LoadAfterCompile = true;
}
@@ -89,6 +92,7 @@
llvm::TargetOptions TargetOpt;
llvm::CodeModel::Model CodeModelOpt;
llvm::Reloc::Model RelocModelOpt;
+ bool RunLTO;
bool LoadAfterCompile;
};
diff --git a/lib/ExecutionEngine/Script.cpp b/lib/ExecutionEngine/Script.cpp
index 2dbdf40..7c79254 100644
--- a/lib/ExecutionEngine/Script.cpp
+++ b/lib/ExecutionEngine/Script.cpp
@@ -16,8 +16,19 @@
#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 <cutils/properties.h>
+
#include "Config.h"
-#include "bcinfo/BitcodeWrapper.h"
#include "MCCacheReader.h"
#include "MCCacheWriter.h"
@@ -30,16 +41,7 @@
#include "ScriptCompiled.h"
#include "ScriptCached.h"
#include "Sha1Helper.h"
-#include "SourceInfo.h"
-
-#include <errno.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <new>
-#include <string.h>
-#include <cutils/properties.h>
+#include "Source.h"
namespace {
@@ -53,6 +55,14 @@
namespace bcc {
+Script::Script(Source &pSource)
+ : mSource(&pSource),
+ mpExtSymbolLookupFn(NULL),
+ mpExtSymbolLookupFnContext(NULL) {
+ resetState();
+ return;
+}
+
Script::~Script() {
switch (mStatus) {
case ScriptStatus::Compiled:
@@ -66,111 +76,62 @@
default:
break;
}
+ llvm::DeleteContainerPointers(mDependencyInfos);
+}
- for (size_t i = 0; i < 2; ++i) {
- delete mSourceList[i];
- }
+void Script::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(mDependencyInfos);
+ return;
}
-int Script::addSourceBC(size_t idx,
- char const *resName,
- const char *bitcode,
- size_t bitcodeSize,
- unsigned long flags) {
-
- if (!resName) {
- mErrorCode = BCC_INVALID_VALUE;
- ALOGE("Invalid argument: resName = NULL\n");
- return 1;
- }
-
- if (mStatus != ScriptStatus::Unknown) {
- mErrorCode = BCC_INVALID_OPERATION;
- ALOGE("Bad operation: Adding source after bccPrepareExecutable\n");
- return 1;
- }
-
- if (!bitcode) {
- mErrorCode = BCC_INVALID_VALUE;
- ALOGE("Invalid argument: bitcode = NULL\n");
- return 1;
- }
-
- bcinfo::BitcodeWrapper wrapper(bitcode, bitcodeSize);
-
- mSourceList[idx] = SourceInfo::createFromBuffer(resName,
- bitcode, bitcodeSize,
- flags);
-
- if (!mSourceList[idx]) {
- mErrorCode = BCC_OUT_OF_MEMORY;
- ALOGE("Out of memory while adding source bitcode\n");
- return 1;
- }
-
- return 0;
+Script::DependencyInfo::DependencyInfo(MCO_ResourceType pSourceType,
+ const std::string &pSourceName,
+ const uint8_t *pSHA1)
+ : mSourceType(pSourceType), mSourceName(pSourceName) {
+ ::memcpy(mSHA1, pSHA1, sizeof(mSHA1));
+ return;
}
-
-int Script::addSourceModule(size_t idx,
- llvm::Module *module,
- unsigned long flags) {
- if (mStatus != ScriptStatus::Unknown) {
- mErrorCode = BCC_INVALID_OPERATION;
- ALOGE("Bad operation: Adding source after bccPrepareExecutable\n");
- return 1;
+bool Script::reset(Source &pSource, bool pPreserveCurrent) {
+ if (mSource == &pSource) {
+ return false;
}
- if (!module) {
- mErrorCode = BCC_INVALID_VALUE;
- ALOGE("Invalid argument: module = NULL\n");
- return 1;
+ if (!pPreserveCurrent) {
+ delete mSource;
}
-
- mSourceList[idx] = SourceInfo::createFromModule(module, flags);
-
- if (!mSourceList[idx]) {
- mErrorCode = BCC_OUT_OF_MEMORY;
- ALOGE("Out of memory when add source module\n");
- return 1;
- }
-
- return 0;
+ mSource = &pSource;
+ resetState();
+ return true;
}
+bool Script::mergeSource(Source &pSource, bool pPreserveSource) {
+ return mSource->merge(pSource, pPreserveSource);
+}
-int Script::addSourceFile(size_t idx,
- char const *path,
- unsigned long flags) {
- if (mStatus != ScriptStatus::Unknown) {
- mErrorCode = BCC_INVALID_OPERATION;
- ALOGE("Bad operation: Adding source after bccPrepareExecutable\n");
- return 1;
+bool Script::addSourceDependencyInfo(MCO_ResourceType pSourceType,
+ const std::string &pSourceName,
+ const uint8_t *pSHA1) {
+ DependencyInfo *dep_info = new (std::nothrow) DependencyInfo(pSourceType,
+ pSourceName,
+ pSHA1);
+ if (dep_info == NULL) {
+ ALOGE("Out of memory when record dependency information of `%s'!",
+ pSourceName.c_str());
+ return false;
}
- if (!path) {
- mErrorCode = BCC_INVALID_VALUE;
- ALOGE("Invalid argument: path = NULL\n");
- return 1;
- }
-
- struct stat sb;
- if (stat(path, &sb) != 0) {
- mErrorCode = BCC_INVALID_VALUE;
- ALOGE("File not found: %s\n", path);
- return 1;
- }
-
- mSourceList[idx] = SourceInfo::createFromFile(path, flags);
-
- if (!mSourceList[idx]) {
- mErrorCode = BCC_OUT_OF_MEMORY;
- ALOGE("Out of memory while adding source file\n");
- return 1;
- }
-
- return 0;
+ mDependencyInfos.push_back(dep_info);
+ return true;
}
int Script::prepareRelocatable(char const *objPath,
@@ -178,6 +139,7 @@
unsigned long flags) {
CompilerOption option;
option.RelocModelOpt = RelocModel;
+ option.RunLTO = false;
option.LoadAfterCompile = false;
int status = internalCompile(option);
@@ -295,10 +257,11 @@
reader.addDependency(BCC_FILE_RESOURCE, pathLibBCC_SHA1, sha1LibBCC_SHA1);
reader.addDependency(BCC_FILE_RESOURCE, pathLibRS, sha1LibRS);
- for (size_t i = 0; i < 2; ++i) {
- if (mSourceList[i]) {
- mSourceList[i]->introDependency(reader);
- }
+ for (unsigned i = 0; i < mDependencyInfos.size(); i++) {
+ const DependencyInfo *dep_info = mDependencyInfos[i];
+ reader.addDependency(dep_info->getSourceType(),
+ dep_info->getSourceName(),
+ dep_info->getSHA1Checksum());
}
if (checkOnly)
@@ -342,39 +305,12 @@
mpExtSymbolLookupFnContext);
}
- if (!mSourceList[0]) {
- ALOGE("Source bitcode is not set.\n");
- return 1;
- }
-
- // Parse Source bitcode file (if necessary)
- if (mSourceList[0]->prepareModule(mContext.mImpl->mLLVMContext) != 0) {
- ALOGE("Unable to setup source module\n");
- return 1;
- }
-
- // Parse Library bitcode file (if necessary)
- if (mSourceList[1]) {
- if (mSourceList[1]->prepareModule(mContext.mImpl->mLLVMContext) != 0) {
- ALOGE("Unable to setup library module\n");
- return 1;
- }
- }
-
// Set the main source module
- if (mCompiled->readModule(mSourceList[0]->getModule()) != 0) {
+ if (mCompiled->readModule(mSource->getModule()) != 0) {
ALOGE("Unable to read source module\n");
return 1;
}
- // Link the source module with the library module
- if (mSourceList[1]) {
- if (mCompiled->linkModule(mSourceList[1]->getModule()) != 0) {
- ALOGE("Unable to link library module\n");
- return 1;
- }
- }
-
// Compile and JIT the code
if (mCompiled->compile(option) != 0) {
ALOGE("Unable to compile.\n");
@@ -422,12 +358,14 @@
writer.addDependency(BCC_FILE_RESOURCE, pathLibRS, sha1LibRS);
#endif
- for (size_t i = 0; i < 2; ++i) {
- if (mSourceList[i]) {
- mSourceList[i]->introDependency(writer);
- }
+ for (unsigned i = 0; i < mDependencyInfos.size(); i++) {
+ const DependencyInfo *dep_info = mDependencyInfos[i];
+ writer.addDependency(dep_info->getSourceType(),
+ dep_info->getSourceName(),
+ dep_info->getSHA1Checksum());
}
+
// libRS is threadable dirty hack
// TODO: This should be removed in the future
uint32_t libRS_threadable = 0;
diff --git a/lib/ExecutionEngine/Script.h b/lib/ExecutionEngine/Script.h
index 4534951..b654797 100644
--- a/lib/ExecutionEngine/Script.h
+++ b/lib/ExecutionEngine/Script.h
@@ -17,19 +17,20 @@
#ifndef BCC_SCRIPT_H
#define BCC_SCRIPT_H
-#include <bcc/bcc.h>
-#include "bcc_internal.h"
-
-#include "BCCContext.h"
-#include "Compiler.h"
-
-#include <llvm/Support/CodeGen.h>
-
#include <vector>
#include <string>
+#include <stdint.h>
#include <stddef.h>
+#include <llvm/ADT/SmallVector.h>
+
+#include <bcc/bcc.h>
+#include <bcc/bcc_mccache.h>
+#include "bcc_internal.h"
+
+#include "Compiler.h"
+
namespace llvm {
class Module;
class GDBJITRegistrar;
@@ -38,7 +39,7 @@
namespace bcc {
class ScriptCompiled;
class ScriptCached;
- class SourceInfo;
+ class Source;
struct CompilerOption;
namespace ScriptStatus {
@@ -60,8 +61,6 @@
class Script {
private:
- BCCContext mContext;
-
int mErrorCode;
ScriptStatus::StatusType mStatus;
@@ -88,11 +87,31 @@
bool mIsContextSlotNotAvail;
- // Source List
- SourceInfo *mSourceList[2];
- // Note: mSourceList[0] (main source)
- // Note: mSourceList[1] (library source)
- // TODO(logan): Generalize this, use vector or SmallVector instead!
+ // This is the source associated with this object and is going to be
+ // compiled.
+ Source *mSource;
+
+ class DependencyInfo {
+ private:
+ MCO_ResourceType mSourceType;
+ std::string mSourceName;
+ uint8_t mSHA1[20];
+
+ public:
+ DependencyInfo(MCO_ResourceType pSourceType,
+ const std::string &pSourceName,
+ const uint8_t *pSHA1);
+
+ inline MCO_ResourceType getSourceType() const
+ { return mSourceType; }
+
+ inline const std::string getSourceName() const
+ { return mSourceName; }
+
+ inline const uint8_t *getSHA1Checksum() const
+ { return mSHA1; }
+ };
+ llvm::SmallVector<DependencyInfo *, 2> mDependencyInfos;
// External Function List
std::vector<char const *> mUserDefinedExternalSymbols;
@@ -101,32 +120,31 @@
BCCSymbolLookupFn mpExtSymbolLookupFn;
void *mpExtSymbolLookupFnContext;
- public:
- Script() : mErrorCode(BCC_NO_ERROR), mStatus(ScriptStatus::Unknown),
- mObjectType(ScriptObject::Unknown),
- mIsContextSlotNotAvail(false),
- mpExtSymbolLookupFn(NULL), mpExtSymbolLookupFnContext(NULL) {
- Compiler::GlobalInitialization();
+ // Reset the state of this script object
+ void resetState();
- mSourceList[0] = NULL;
- mSourceList[1] = NULL;
- }
+ public:
+ Script(Source &pSource);
~Script();
- int addSourceBC(size_t idx,
- char const *resName,
- const char *bitcode,
- size_t bitcodeSize,
- unsigned long flags);
+ // Reset this object with the new source supplied. Return false if this
+ // object remains unchanged after the call (e.g., the supplied source is
+ // the same with the one contain in this object.) If pPreserveCurrent is
+ // false, the current containing source will be destroyed after successfully
+ // reset.
+ bool reset(Source &pSource, bool pPreserveCurrent = false);
- int addSourceModule(size_t idx,
- llvm::Module *module,
- unsigned long flags);
+ // Merge (or link) another source into the current source associated with
+ // this Script object. Return false on error.
+ bool mergeSource(Source &pSource, bool pPreserveSource = false);
- int addSourceFile(size_t idx,
- char const *path,
- unsigned long flags);
+ // 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 addSourceDependencyInfo(MCO_ResourceType pSourceType,
+ const std::string &pSourceName,
+ const uint8_t *pSHA1);
void markExternalSymbol(char const *name) {
mUserDefinedExternalSymbols.push_back(name);
@@ -142,7 +160,7 @@
int writeCache();
/*
- * Link the given bitcodes in mSourceList to shared object (.so).
+ * 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.
@@ -153,7 +171,7 @@
* 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 the bitcodes in mSourceList[0].
+ * TODO: Currently, we only support to link a bitcode (i.e., mSource.)
*
*/
int prepareSharedObject(char const *objPath,
diff --git a/lib/ExecutionEngine/ScriptCompiled.h b/lib/ExecutionEngine/ScriptCompiled.h
index 7b7b62a..8752aa3 100644
--- a/lib/ExecutionEngine/ScriptCompiled.h
+++ b/lib/ExecutionEngine/ScriptCompiled.h
@@ -17,17 +17,17 @@
#ifndef BCC_SCRIPTCOMPILED_H
#define BCC_SCRIPTCOMPILED_H
-#include "Compiler.h"
-#include "Script.h"
-
-#include <bcc/bcc.h>
-
#include <list>
#include <map>
#include <string>
#include <utility>
#include <vector>
+#include <bcc/bcc.h>
+
+#include "Compiler.h"
+#include "Script.h"
+
namespace llvm {
class Module;
}
@@ -73,12 +73,8 @@
~ScriptCompiled();
- int readModule(llvm::Module *module) {
- return mCompiler.readModule(module);
- }
-
- int linkModule(llvm::Module *module) {
- return mCompiler.linkModule(module);
+ int readModule(llvm::Module &pModule) {
+ return mCompiler.readModule(pModule);
}
int compile(const CompilerOption &option) {
diff --git a/lib/ExecutionEngine/Source.cpp b/lib/ExecutionEngine/Source.cpp
new file mode 100644
index 0000000..754f3e5
--- /dev/null
+++ b/lib/ExecutionEngine/Source.cpp
@@ -0,0 +1,177 @@
+/*
+ * 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 "Source.h"
+
+#include <new>
+
+#include <llvm/Bitcode/ReaderWriter.h>
+#include <llvm/LLVMContext.h>
+#include <llvm/Linker.h>
+#include <llvm/Module.h>
+#include <llvm/Support/MemoryBuffer.h>
+#include <llvm/Support/system_error.h>
+
+#include "BCCContext.h"
+#include "BCCContextImpl.h"
+#include "DebugHelper.h"
+
+namespace {
+
+// Helper function to load the bitcode. This uses "bitcode lazy load" feature to
+// reduce the startup time. On success, return the LLVM module object created
+// and take the ownership of input memory buffer (i.e., pInput). On error,
+// return NULL and will NOT take the ownership of pInput.
+static inline llvm::Module *helper_load_bitcode(llvm::LLVMContext &pContext,
+ llvm::MemoryBuffer *pInput) {
+ std::string error;
+ llvm::Module *module = llvm::getLazyBitcodeModule(pInput, pContext, &error);
+
+ if (module == NULL) {
+ ALOGE("Unable to parse the given bitcode file `%s'! (%s)",
+ pInput->getBufferIdentifier(), error.c_str());
+ }
+
+ return module;
+}
+
+} // end anonymous namespace
+
+namespace bcc {
+
+Source *Source::CreateFromBuffer(BCCContext &pContext,
+ const char *pName,
+ const char *pBitcode,
+ size_t pBitcodeSize) {
+ llvm::StringRef input_data(pBitcode, pBitcodeSize);
+ llvm::MemoryBuffer *input_memory =
+ llvm::MemoryBuffer::getMemBuffer(input_data, pName);
+
+ if (input_memory == NULL) {
+ ALOGE("Unable to load bitcode `%s' from buffer!", pName);
+ return NULL;
+ }
+
+ llvm::Module *module = helper_load_bitcode(pContext.mImpl->mLLVMContext,
+ input_memory);
+ if (module == NULL) {
+ delete input_memory;
+ return NULL;
+ }
+
+ Source *result = CreateFromModule(pContext, *module, /* pNoDelete */false);
+ if (result == NULL) {
+ delete module;
+ }
+
+ return result;
+}
+
+
+Source *Source::CreateFromFile(BCCContext &pContext, const std::string &pPath) {
+ llvm::OwningPtr<llvm::MemoryBuffer> input_data;
+
+ llvm::error_code ec = llvm::MemoryBuffer::getFile(pPath, input_data);
+ if (ec != llvm::error_code::success()) {
+ ALOGE("Failed to load bitcode from path %s! (%s)", pPath.c_str(),
+ ec.message().c_str());
+ return NULL;
+ }
+
+ llvm::MemoryBuffer *input_memory = input_data.take();
+ llvm::Module *module = helper_load_bitcode(pContext.mImpl->mLLVMContext,
+ input_memory);
+ if (module == NULL) {
+ delete input_memory;
+ return NULL;
+ }
+
+ Source *result = CreateFromModule(pContext, *module, /* pNoDelete */false);
+ if (result == NULL) {
+ delete module;
+ }
+
+ return result;
+}
+
+
+Source *Source::CreateFromModule(BCCContext &pContext, llvm::Module &pModule,
+ bool pNoDelete) {
+ Source *result = new (std::nothrow) Source(pContext, pModule, pNoDelete);
+ if (result == NULL) {
+ ALOGE("Out of memory during Source object allocation for `%s'!",
+ pModule.getModuleIdentifier().c_str());
+ }
+ return result;
+}
+
+Source::Source(BCCContext &pContext, llvm::Module &pModule, bool pNoDelete)
+ : mContext(pContext), mModule(&pModule), mNoDelete(pNoDelete) {
+ pContext.addSource(*this);
+}
+
+Source::~Source() {
+ mContext.removeSource(*this);
+ if (!mNoDelete)
+ delete mModule;
+}
+
+bool Source::merge(Source &pSource, bool pPreserveSource) {
+ std::string error;
+ llvm::Linker::LinkerMode mode =
+ ((pPreserveSource) ? llvm::Linker::PreserveSource :
+ llvm::Linker::DestroySource);
+
+ if (llvm::Linker::LinkModules(mModule, &pSource.getModule(),
+ mode, &error) != 0) {
+ ALOGE("Failed to link source `%s' with `%s' (%s)!",
+ getIdentifier().c_str(),
+ pSource.getIdentifier().c_str(),
+ error.c_str());
+ return false;
+ }
+
+ if (!pPreserveSource) {
+ pSource.mNoDelete = true;
+ delete &pSource;
+ }
+
+ return true;
+}
+
+Source *Source::CreateEmpty(BCCContext &pContext, const std::string &pName) {
+ // Create an empty module
+ llvm::Module *module =
+ new (std::nothrow) llvm::Module(pName, pContext.mImpl->mLLVMContext);
+
+ if (module == NULL) {
+ ALOGE("Out of memory when creating empty LLVM module `%s'!", pName.c_str());
+ return NULL;
+ }
+
+ Source *result = CreateFromModule(pContext, *module, /* pNoDelete */false);
+ if (result == NULL) {
+ delete module;
+ }
+
+ return result;
+}
+
+const std::string &Source::getIdentifier() const {
+ return mModule->getModuleIdentifier();
+}
+
+} // namespace bcc
diff --git a/lib/ExecutionEngine/Source.h b/lib/ExecutionEngine/Source.h
new file mode 100644
index 0000000..b9a98e8
--- /dev/null
+++ b/lib/ExecutionEngine/Source.h
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ * 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_SOURCE_H
+#define BCC_EXECUTION_ENGINE_SOURCE_H
+
+#include <string>
+
+namespace llvm {
+ class Module;
+}
+
+namespace bcc {
+
+class BCCContext;
+
+class Source {
+private:
+ BCCContext &mContext;
+ llvm::Module *mModule;
+
+ // If true, destructor won't destroy the mModule.
+ bool mNoDelete;
+
+private:
+ Source(BCCContext &pContext, llvm::Module &pModule, bool pNoDelete = false);
+
+public:
+ static Source *CreateFromBuffer(BCCContext &pContext,
+ const char *pName,
+ const char *pBitcode,
+ size_t pBitcodeSize);
+
+ static Source *CreateFromFile(BCCContext &pContext,
+ const std::string &pPath);
+
+ // Create a Source object from an existing module. If pNoDelete
+ // is true, destructor won't call delete on the given module.
+ static Source *CreateFromModule(BCCContext &pContext,
+ llvm::Module &pModule,
+ bool pNoDelete = false);
+
+ static Source *CreateEmpty(BCCContext &pContext, const std::string &pName);
+
+ // Merge the current source with pSource. If pPreserveSource is false, pSource
+ // will be destroyed after successfully merged. Return false on error.
+ bool merge(Source &pSource, bool pPreserveSource = false);
+
+ inline BCCContext &getContext()
+ { return mContext; }
+ inline const BCCContext &getContext() const
+ { return mContext; }
+
+ inline llvm::Module &getModule()
+ { return *mModule; }
+ inline const llvm::Module &getModule() const
+ { return *mModule; }
+
+ // Get the "identifier" of the bitcode. This will return the value of pName
+ // when it's created using CreateFromBuffer and pPath if CreateFromFile().
+ const std::string &getIdentifier() const;
+
+ ~Source();
+};
+
+} // namespace bcc
+
+#endif // BCC_EXECUTION_ENGINE_SOURCE_H
diff --git a/lib/ExecutionEngine/SourceInfo.cpp b/lib/ExecutionEngine/SourceInfo.cpp
deleted file mode 100644
index 5477514..0000000
--- a/lib/ExecutionEngine/SourceInfo.cpp
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * 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.
- * 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 "SourceInfo.h"
-
-#include "MCCacheWriter.h"
-#include "MCCacheReader.h"
-
-#include "DebugHelper.h"
-#include "ScriptCompiled.h"
-#include "Sha1Helper.h"
-
-#include <bcc/bcc.h>
-
-#include <llvm/Bitcode/ReaderWriter.h>
-#include <llvm/Module.h>
-#include <llvm/ADT/OwningPtr.h>
-#include <llvm/ADT/StringRef.h>
-#include <llvm/Support/MemoryBuffer.h>
-#include <llvm/Support/system_error.h>
-
-#include <stddef.h>
-#include <string.h>
-
-namespace bcc {
-
-
-SourceInfo *SourceInfo::createFromBuffer(char const *resName,
- char const *bitcode,
- size_t bitcodeSize,
- unsigned long flags) {
- SourceInfo *result = new SourceInfo();
-
- if (!result) {
- return NULL;
- }
-
- result->type = SourceKind::Buffer;
- result->buffer.resName = resName;
- result->buffer.bitcode = bitcode;
- result->buffer.bitcodeSize = bitcodeSize;
- result->flags = flags;
-
- if (!resName && !(flags & BCC_SKIP_DEP_SHA1)) {
- result->flags |= BCC_SKIP_DEP_SHA1;
-
- ALOGW("It is required to give resName for sha1 dependency check.\n");
- ALOGW("Sha1sum dependency check will be skipped.\n");
- ALOGW("Set BCC_SKIP_DEP_SHA1 for flags to surpress this warning.\n");
- }
-
- if (result->flags & BCC_SKIP_DEP_SHA1) {
- memset(result->sha1, '\0', 20);
- } else {
- calcSHA1(result->sha1, bitcode, bitcodeSize);
- }
-
- return result;
-}
-
-
-SourceInfo *SourceInfo::createFromFile(char const *path,
- unsigned long flags) {
- SourceInfo *result = new SourceInfo();
-
- if (!result) {
- return NULL;
- }
-
- result->type = SourceKind::File;
- result->file.path = path;
- result->flags = flags;
-
- memset(result->sha1, '\0', 20);
-
- if (!(result->flags & BCC_SKIP_DEP_SHA1)) {
- calcFileSHA1(result->sha1, path);
- }
-
- return result;
-}
-
-
-SourceInfo *SourceInfo::createFromModule(llvm::Module *module,
- unsigned long flags) {
- SourceInfo *result = new SourceInfo();
-
- if (!result) {
- return NULL;
- }
-
- result->type = SourceKind::Module;
- result->module = module;
- result->flags = flags;
-
- if (! (flags & BCC_SKIP_DEP_SHA1)) {
- result->flags |= BCC_SKIP_DEP_SHA1;
-
- ALOGW("Unable to calculate sha1sum for llvm::Module.\n");
- ALOGW("Sha1sum dependency check will be skipped.\n");
- ALOGW("Set BCC_SKIP_DEP_SHA1 for flags to surpress this warning.\n");
- }
-
- memset(result->sha1, '\0', 20);
-
- return result;
-}
-
-
-int SourceInfo::prepareModule(llvm::LLVMContext &context) {
- if (module)
- return 0;
-
- llvm::OwningPtr<llvm::MemoryBuffer> mem;
- std::string errmsg;
-
- switch (type) {
- case SourceKind::Buffer:
- {
- mem.reset(llvm::MemoryBuffer::getMemBuffer(
- llvm::StringRef(buffer.bitcode, buffer.bitcodeSize)));
-
- if (!mem.get()) {
- ALOGE("Unable to MemoryBuffer::getMemBuffer(addr=%p, size=%lu)\n",
- buffer.bitcode, (unsigned long)buffer.bitcodeSize);
- return 1;
- }
- }
- break;
-
- case SourceKind::File:
- {
- if (llvm::error_code ec = llvm::MemoryBuffer::getFile(file.path, mem)) {
- ALOGE("Unable to MemoryBuffer::getFile(path=%s, %s)\n",
- file.path, ec.message().c_str());
- return 1;
- }
- }
- break;
-
- default:
- return 0;
- break;
- }
-
- module = llvm::ParseBitcodeFile(mem.get(), context, &errmsg);
- if (module == NULL) {
- ALOGE("Unable to ParseBitcodeFile: %s\n", errmsg.c_str());
- }
-
- return (module == NULL);
-}
-
-SourceInfo::~SourceInfo() {
- delete module;
-}
-
-template <typename T> void SourceInfo::introDependency(T &checker) {
- if (flags & BCC_SKIP_DEP_SHA1) {
- return;
- }
-
- switch (type) {
- case SourceKind::Buffer:
- checker.addDependency(BCC_APK_RESOURCE, buffer.resName, sha1);
- break;
-
- case SourceKind::File:
- checker.addDependency(BCC_FILE_RESOURCE, file.path, sha1);
- break;
-
- default:
- break;
- }
-}
-
-template void SourceInfo::introDependency<MCCacheWriter>(MCCacheWriter &);
-template void SourceInfo::introDependency<MCCacheReader>(MCCacheReader &);
-
-
-} // namespace bcc
diff --git a/lib/ExecutionEngine/SourceInfo.h b/lib/ExecutionEngine/SourceInfo.h
deleted file mode 100644
index f838f71..0000000
--- a/lib/ExecutionEngine/SourceInfo.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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.
- * 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_SOURCEINFO_H
-#define BCC_SOURCEINFO_H
-
-#include "Config.h"
-
-#include <llvm/Module.h>
-
-#include <stddef.h>
-
-namespace bcc {
- namespace SourceKind {
- enum SourceType {
- File,
- Buffer,
- Module,
- };
- }
-
- class SourceInfo {
- private:
- SourceKind::SourceType type;
-
- // Note: module should not be a part of union. Since, we are going to
- // use module to store the pointer to parsed bitcode.
- llvm::Module *module;
-
- union {
- struct {
- char const *resName;
- char const *bitcode;
- size_t bitcodeSize;
- } buffer;
-
- struct {
- char const *path;
- } file;
- };
-
- unsigned long flags;
-
- unsigned char sha1[20];
-
- private:
- SourceInfo() : module(NULL) { }
-
- public:
- static SourceInfo *createFromBuffer(char const *resName,
- char const *bitcode,
- size_t bitcodeSize,
- unsigned long flags);
-
- static SourceInfo *createFromFile(char const *path,
- unsigned long flags);
-
- static SourceInfo *createFromModule(llvm::Module *module,
- unsigned long flags);
-
- inline llvm::Module *getModule() const {
- return module;
- }
-
- // Share with the given context if it's provided.
- int prepareModule(llvm::LLVMContext &context);
-
- template <typename T> void introDependency(T &checker);
-
- ~SourceInfo();
- };
-
-
-} // namespace bcc
-
-#endif // BCC_SOURCEINFO_H
diff --git a/lib/ExecutionEngine/bcc.cpp b/lib/ExecutionEngine/bcc.cpp
index 01ef32f..ee6efaa 100644
--- a/lib/ExecutionEngine/bcc.cpp
+++ b/lib/ExecutionEngine/bcc.cpp
@@ -18,19 +18,22 @@
// This is an eager-compilation JIT running on Android.
#include <bcc/bcc.h>
-#include "bcc_internal.h"
-
-#include "Config.h"
-
-#include "Compiler.h"
-#include "DebugHelper.h"
-#include "Script.h"
#include <string>
#include <utils/StopWatch.h>
-#include <llvm/Support/CodeGen.h>
+#include "Config.h"
+
+#include <bcc/bcc_mccache.h>
+#include "bcc_internal.h"
+
+#include "BCCContext.h"
+#include "Compiler.h"
+#include "DebugHelper.h"
+#include "Script.h"
+#include "Sha1Helper.h"
+#include "Source.h"
using namespace bcc;
@@ -51,7 +54,15 @@
extern "C" BCCScriptRef bccCreateScript() {
BCC_FUNC_LOGGER();
bccPrintBuildStamp();
- return wrap(new bcc::Script());
+ // 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;
+ }
+
+ Source *source = Source::CreateEmpty(*context, "empty");
+ return wrap(new Script(*source));
}
@@ -74,13 +85,102 @@
return unwrap(script)->getError();
}
+static bool helper_add_source(Script *pScript,
+ char const *pName,
+ char const *pBitcode,
+ size_t pBitcodeSize,
+ unsigned long pFlags,
+ bool pIsLink) {
+ bool need_dependency_check = !(pFlags & BCC_SKIP_DEP_SHA1);
+ if (!pName && need_dependency_check) {
+ pFlags |= BCC_SKIP_DEP_SHA1;
+
+ ALOGW("It is required to give resName for sha1 dependency check.\n");
+ ALOGW("Sha1sum dependency check will be skipped.\n");
+ ALOGW("Set BCC_SKIP_DEP_SHA1 for flags to surpress this warning.\n");
+ }
+
+ BCCContext *context = BCCContext::GetOrCreateGlobalContext();
+ if (context == NULL) {
+ return false;
+ }
+
+ Source *source = Source::CreateFromBuffer(*context, pName,
+ pBitcode, pBitcodeSize);
+ if (source == NULL) {
+ return false;
+ }
+
+ if (need_dependency_check) {
+ uint8_t sha1[20];
+ calcSHA1(sha1, pBitcode, pBitcodeSize);
+ if (!pScript->addSourceDependencyInfo(BCC_APK_RESOURCE, pName, sha1)) {
+ return false;
+ }
+ }
+
+ return ((pIsLink) ? pScript->mergeSource(*source) : pScript->reset(*source));
+}
+
+static bool helper_add_source(Script *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(*context, *pModule, true);
+ if (source == NULL) {
+ return false;
+ }
+
+ return ((pIsLink) ? pScript->mergeSource(*source) : pScript->reset(*source));
+}
+
+static bool helper_add_source(Script *pScript,
+ char const *pPath,
+ unsigned long pFlags,
+ bool pIsLink) {
+ bool need_dependency_check = !(pFlags & BCC_SKIP_DEP_SHA1);
+ BCCContext *context = BCCContext::GetOrCreateGlobalContext();
+ if (context == NULL) {
+ 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 (!pScript->addSourceDependencyInfo(BCC_APK_RESOURCE, pPath, sha1)) {
+ return false;
+ }
+ }
+
+ return ((pIsLink) ? pScript->mergeSource(*source) : pScript->reset(*source));
+}
+
extern "C" int bccReadBC(BCCScriptRef script,
char const *resName,
char const *bitcode,
size_t bitcodeSize,
unsigned long flags) {
BCC_FUNC_LOGGER();
- return unwrap(script)->addSourceBC(0, resName, bitcode, bitcodeSize, flags);
+ return (helper_add_source(unwrap(script), resName,
+ bitcode, bitcodeSize,
+ flags, /* pIsLink */false) == false);
}
@@ -89,7 +189,8 @@
LLVMModuleRef module,
unsigned long flags) {
BCC_FUNC_LOGGER();
- return unwrap(script)->addSourceModule(0, unwrap(module), flags);
+ return (helper_add_source(unwrap(script), unwrap(module),
+ /* pIsLink */false) == false);
}
@@ -97,7 +198,8 @@
char const *path,
unsigned long flags) {
BCC_FUNC_LOGGER();
- return unwrap(script)->addSourceFile(0, path, flags);
+ return (helper_add_source(unwrap(script), path,
+ flags, /* pIsLink */false) == false);
}
@@ -107,7 +209,9 @@
size_t bitcodeSize,
unsigned long flags) {
BCC_FUNC_LOGGER();
- return unwrap(script)->addSourceBC(1, resName, bitcode, bitcodeSize, flags);
+ return (helper_add_source(unwrap(script), resName,
+ bitcode, bitcodeSize,
+ flags, /* pIsLink */true) == false);
}
@@ -115,7 +219,8 @@
char const *path,
unsigned long flags) {
BCC_FUNC_LOGGER();
- return unwrap(script)->addSourceFile(1, path, flags);
+ return (helper_add_source(unwrap(script), path,
+ flags, /* pIsLink */true) == false);
}