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