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);
 }