josephwen Adds caching for MC JIT.

New MCCacheReader in addition to the classic JIT's CacheReader.[cpp|h].
New MCCacheWriter in addition to the classic JIT's CacheReader.[cpp|h].

Change-Id: Iffd490caf25136d52cefc1c6bc2a78fa991236cd
diff --git a/lib/ExecutionEngine/Compiler.h b/lib/ExecutionEngine/Compiler.h
index 8e9ce98..dd2a50c 100644
--- a/lib/ExecutionEngine/Compiler.h
+++ b/lib/ExecutionEngine/Compiler.h
@@ -139,6 +139,10 @@
     bool getObjPath(std::string &objPath);
 
     void *getSymbolAddress(char const *name);
+
+    const llvm::SmallVector<char, 1024> &getELF() const {
+      return mEmittedELFExecutable;
+    }
 #endif
 
     llvm::Module *parseBitcodeFile(llvm::MemoryBuffer *MEM);
diff --git a/lib/ExecutionEngine/MCCacheReader.cpp b/lib/ExecutionEngine/MCCacheReader.cpp
new file mode 100644
index 0000000..692cac3
--- /dev/null
+++ b/lib/ExecutionEngine/MCCacheReader.cpp
@@ -0,0 +1,449 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MCCacheReader.h"
+
+#include "ContextManager.h"
+#include "DebugHelper.h"
+#include "FileHandle.h"
+#include "ScriptCached.h"
+#include "Runtime.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;
+
+
+#if USE_MCJIT
+namespace bcc {
+
+MCCacheReader::~MCCacheReader() {
+  if (mpHeader) { free(mpHeader); }
+  if (mpCachedDependTable) { free(mpCachedDependTable); }
+  if (mpPragmaList) { free(mpPragmaList); }
+  if (mpFuncTable) { free(mpFuncTable); }
+}
+
+ScriptCached *MCCacheReader::readCacheFile(FileHandle *objFile, FileHandle *infoFile, Script *S) {
+  // Check file handle
+  if (!objFile || objFile->getFD() < 0 || !infoFile || infoFile->getFD() < 0) {
+    return false;
+  }
+
+  mObjFile = objFile;
+  mInfoFile = infoFile;
+
+  // Allocate ScriptCached object
+  mpResult.reset(new (nothrow) ScriptCached(S));
+
+  if (!mpResult) {
+    LOGE("Unable to allocate ScriptCached object.\n");
+    return NULL;
+  }
+
+  bool result = checkFileSize()
+             && readHeader()
+             && checkHeader()
+             && checkMachineIntType()
+             && checkSectionOffsetAndSize()
+             && readStringPool()
+             && checkStringPool()
+             && readDependencyTable()
+             && checkDependency()
+             && readExportVarList()
+             && readExportFuncList()
+             && readPragmaList()
+             && readFuncTable()
+             && readObjectSlotList()
+             && readObjFile()
+             && relocate()
+             ;
+
+  return result ? mpResult.take() : NULL;
+}
+
+
+bool MCCacheReader::checkFileSize() {
+  struct stat stfile;
+  if (fstat(mInfoFile->getFD(), &stfile) < 0) {
+    LOGE("Unable to stat cache file.\n");
+    return false;
+  }
+
+  mInfoFileSize = stfile.st_size;
+
+  if (mInfoFileSize < (off_t)sizeof(MCO_Header)) {
+    LOGE("Cache file is too small to be correct.\n");
+    return false;
+  }
+
+  return true;
+}
+
+
+bool MCCacheReader::readHeader() {
+  if (mInfoFile->seek(0, SEEK_SET) != 0) {
+    LOGE("Unable to seek to 0. (reason: %s)\n", strerror(errno));
+    return false;
+  }
+
+  mpHeader = (MCO_Header *)malloc(sizeof(MCO_Header));
+  if (!mpHeader) {
+    LOGE("Unable to allocate for cache header.\n");
+    return false;
+  }
+
+  if (mInfoFile->read(reinterpret_cast<char *>(mpHeader), sizeof(MCO_Header)) !=
+      (ssize_t)sizeof(MCO_Header)) {
+    LOGE("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, OBCC_MAGIC, 4) != 0) {
+    LOGE("Bad magic word\n");
+    return false;
+  }
+
+  if (memcmp(mpHeader->version, OBCC_VERSION, 4) != 0) {
+    mpHeader->version[4 - 1] = '\0'; // ensure c-style string terminated
+    LOGI("Cache file format version mismatch: now %s cached %s\n",
+         OBCC_VERSION, mpHeader->version);
+    return false;
+  }
+
+  if (memcmp(mpHeader->libbcc_build_time, libbcc_build_time, 24) != 0) {
+    mpHeader->libbcc_build_time[24 - 1] = '\0'; // ensure terminated
+    LOGW("Build time mismatch: lib %s cached %s\n", libbcc_build_time,
+         mpHeader->libbcc_build_time);
+    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')) {
+    LOGE("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 *)) {
+    LOGE("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) {          \
+      LOGE(#NAME " section overflow.\n");                                   \
+      return false;                                                         \
+    }                                                                       \
+                                                                            \
+    if (offset % sizeof(int) != 0) {                                        \
+      LOGE(#NAME " offset must aligned to %d.\n", (int)sizeof(int));        \
+      return false;                                                         \
+    }                                                                       \
+                                                                            \
+    if (size < static_cast<off_t>(sizeof(size_t))) {                        \
+      LOGE(#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(export_var_list);
+  CHECK_SECTION_OFFSET(export_func_list);
+  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) {                                                        \
+    LOGE("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, SEEK_SET) == -1) {           \
+    LOGE("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) \
+  {                                                                         \
+    LOGE("Unable to read " #NAME ".\n");                                    \
+    return false;                                                           \
+  }
+
+
+bool MCCacheReader::readStringPool() {
+  CACHE_READER_READ_SECTION(OBCC_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() {
+  OBCC_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') {
+      LOGE("The %lu-th string does not end with '\\0'.\n", (unsigned long)i);
+      return false;
+    }
+  }
+
+  return true;
+}
+
+
+bool MCCacheReader::readDependencyTable() {
+  CACHE_READER_READ_SECTION(OBCC_DependencyTable, mpCachedDependTable,
+                            depend_tab);
+  return true;
+}
+
+
+bool MCCacheReader::checkDependency() {
+  if (mDependencies.size() != mpCachedDependTable->count) {
+    LOGE("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, pair<uint32_t, unsigned char const *> >::iterator dep;
+
+  dep = mDependencies.begin();
+  for (size_t i = 0; i < mpCachedDependTable->count; ++i, ++dep) {
+    string const &depName = dep->first;
+    uint32_t depType = dep->second.first;
+    unsigned char const *depSHA1 = dep->second.second;
+
+    OBCC_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) {
+      LOGE("Cache dependency name mismatch:\n");
+      LOGE("  given:  %s\n", depName.c_str());
+      LOGE("  cached: %s\n", depCachedName);
+
+      return false;
+    }
+
+    if (memcmp(depSHA1, depCachedSHA1, 20) != 0) {
+      LOGE("Cache dependency %s sha1 mismatch:\n", depCachedName);
+
+#define PRINT_SHA1(PREFIX, X, POSTFIX) \
+      LOGE(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;
+    }
+
+    if (depType != depCachedType) {
+      LOGE("Cache dependency %s resource type mismatch.\n", depCachedName);
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool MCCacheReader::readExportVarList() {
+  CACHE_READER_READ_SECTION(OBCC_ExportVarList,
+                            mpResult->mpExportVars, export_var_list);
+  return true;
+}
+
+
+bool MCCacheReader::readExportFuncList() {
+  CACHE_READER_READ_SECTION(OBCC_ExportFuncList,
+                            mpResult->mpExportFuncs, export_func_list);
+  return true;
+}
+
+
+bool MCCacheReader::readPragmaList() {
+  CACHE_READER_READ_SECTION(OBCC_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) {
+    OBCC_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(OBCC_ObjectSlotList,
+                            mpResult->mpObjectSlotList, object_slot_list);
+  return true;
+}
+
+void *MCCacheReader::resolveSymbolAdapter(void *context, char const *name) {
+  MCCacheReader *self = reinterpret_cast<MCCacheReader *>(context);
+
+  if (void *Addr = FindRuntimeFunction(name)) {
+    return Addr;
+  }
+
+  if (self->mpSymbolLookupFn) {
+    if (void *Addr = self->mpSymbolLookupFn(self->mpSymbolLookupContext, name)) {
+      return Addr;
+    }
+  }
+
+  LOGE("Unable to resolve symbol: %s\n", name);
+  return NULL;
+}
+
+bool MCCacheReader::readObjFile() {
+  llvm::SmallVector<char, 1024> mEmittedELFExecutable;
+  char readBuffer[1024];
+  int readSize;
+  while ((readSize = mObjFile->read(readBuffer, 1024)) > 0) {
+    mEmittedELFExecutable.append(readBuffer, readBuffer + readSize);
+  }
+  if (readSize != 0) {
+    LOGE("Read file Error");
+    return false;
+  }
+  LOGD("Read object file size %d", mEmittedELFExecutable.size());
+  mpResult->mRSExecutable =
+  rsloaderCreateExec((unsigned char *)&*mEmittedELFExecutable.begin(),
+                     mEmittedELFExecutable.size(),
+                     &resolveSymbolAdapter, this);
+  return true;
+}
+
+bool MCCacheReader::readFuncTable() {
+  CACHE_READER_READ_SECTION(OBCC_FuncTable, mpFuncTable, func_table);
+
+  vector<char const *> &strPool = mpResult->mStringPool;
+  ScriptCached::FuncTable &table = mpResult->mFunctions;
+  for (size_t i = 0; i < func_table_raw->count; ++i) {
+    OBCC_FuncInfo *func = &func_table_raw->table[i];
+    table.insert(make_pair(strPool[func->name_strp_index],
+                           make_pair(func->cached_addr, func->size)));
+  }
+
+  return true;
+}
+
+#undef CACHE_READER_READ_SECTION
+
+bool MCCacheReader::readRelocationTable() {
+  // TODO(logan): Not finished.
+  return true;
+}
+
+
+bool MCCacheReader::relocate() {
+  void *rootPtr = rsloaderGetSymbolAddress(mpResult->mRSExecutable, "root");
+  int mRootOffset = reinterpret_cast<char *>(rootPtr) -
+                    reinterpret_cast<char *>(mpHeader->root_base_addr);
+  for (size_t i = 0; i < mpResult->getExportVarCount(); ++i) {
+    mpResult->mpExportVars->cached_addr_list[i] =
+    reinterpret_cast<void *>(reinterpret_cast<char *>(mpResult->mpExportVars->cached_addr_list[i]) + mRootOffset);
+  }
+  for (size_t i = 0; i < mpResult->getExportFuncCount(); ++i) {
+    mpResult->mpExportFuncs->cached_addr_list[i] =
+    reinterpret_cast<void *>(reinterpret_cast<char *>(mpResult->mpExportFuncs->cached_addr_list[i]) + mRootOffset);
+  }
+  return true;
+}
+
+
+} // namespace bcc
+#endif
diff --git a/lib/ExecutionEngine/MCCacheReader.h b/lib/ExecutionEngine/MCCacheReader.h
new file mode 100644
index 0000000..d1f230e
--- /dev/null
+++ b/lib/ExecutionEngine/MCCacheReader.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_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 FileHandle;
+  class Script;
+
+  class MCCacheReader {
+  private:
+    FileHandle *mObjFile, *mInfoFile;
+    off_t mInfoFileSize;
+
+    MCO_Header *mpHeader;
+    OBCC_DependencyTable *mpCachedDependTable;
+    OBCC_PragmaList *mpPragmaList;
+    OBCC_FuncTable *mpFuncTable;
+
+    llvm::OwningPtr<ScriptCached> mpResult;
+
+    std::map<std::string,
+             std::pair<uint32_t, unsigned char const *> > mDependencies;
+
+    bool mIsContextSlotNotAvail;
+
+    BCCSymbolLookupFn mpSymbolLookupFn;
+    void *mpSymbolLookupContext;
+
+  public:
+    MCCacheReader()
+      : mObjFile(NULL), mInfoFile(NULL), mInfoFileSize(0), mpHeader(NULL),
+        mpCachedDependTable(NULL), mpPragmaList(NULL), mpFuncTable(NULL),
+        mIsContextSlotNotAvail(false) {
+    }
+
+    ~MCCacheReader();
+
+    void addDependency(OBCC_ResourceType resType,
+                       std::string const &resName,
+                       unsigned char const *sha1) {
+      mDependencies.insert(std::make_pair(resName,
+                           std::make_pair((uint32_t)resType, sha1)));
+    }
+
+    ScriptCached *readCacheFile(FileHandle *objFile, FileHandle *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 readExportVarList();
+    bool readExportFuncList();
+    bool readPragmaList();
+    bool readFuncTable();
+    bool readObjectSlotList();
+    bool readObjFile();
+    bool readRelocationTable();
+
+    bool checkFileSize();
+    bool checkHeader();
+    bool checkMachineIntType();
+    bool checkSectionOffsetAndSize();
+    bool checkStringPool();
+    bool checkDependency();
+    bool checkContext();
+
+    bool relocate();
+
+    static void *resolveSymbolAdapter(void *context, char const *name);
+
+  };
+
+} // namespace bcc
+
+#endif // BCC_MCCACHEREADER_H
diff --git a/lib/ExecutionEngine/MCCacheWriter.cpp b/lib/ExecutionEngine/MCCacheWriter.cpp
new file mode 100644
index 0000000..7642572
--- /dev/null
+++ b/lib/ExecutionEngine/MCCacheWriter.cpp
@@ -0,0 +1,401 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MCCacheWriter.h"
+
+#include "ContextManager.h"
+#include "DebugHelper.h"
+#include "FileHandle.h"
+#include "Script.h"
+
+#include <map>
+#include <string>
+#include <vector>
+#include <utility>
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+using namespace std;
+
+#if USE_MCJIT
+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(mpExportVarListSection);
+  CHECK_AND_FREE(mpExportFuncListSection);
+  CHECK_AND_FREE(mpPragmaListSection);
+  CHECK_AND_FREE(mpFuncTableSection);
+  CHECK_AND_FREE(mpObjectSlotSection);
+
+#undef CHECK_AND_FREE
+}
+
+bool MCCacheWriter::writeCacheFile(FileHandle *objFile, FileHandle *infoFile,
+                                 Script *S, uint32_t libRS_threadable) {
+  if (!objFile || objFile->getFD() < 0 || !infoFile || infoFile->getFD() < 0) {
+    return false;
+  }
+
+  mObjFile = objFile;
+  mInfoFile = infoFile;
+  mpOwner = S;
+
+  bool result = prepareHeader(libRS_threadable)
+             && prepareDependencyTable()
+             && prepareFuncTable()
+             && preparePragmaList()
+             && prepareStringPool()
+             && prepareExportVarList()
+             && prepareExportFuncList()
+             && prepareObjectSlotList()
+             && calcSectionOffset()
+             && writeAll()
+             ;
+
+  return result;
+}
+
+
+bool MCCacheWriter::prepareHeader(uint32_t libRS_threadable) {
+  MCO_Header *header = (MCO_Header *)malloc(sizeof(MCO_Header));
+
+  if (!header) {
+    LOGE("Unable to allocate for header.\n");
+    return false;
+  }
+
+  mpHeaderSection = header;
+
+  // Initialize
+  memset(header, '\0', sizeof(MCO_Header));
+
+  // Magic word and version
+  memcpy(header->magic, OBCC_MAGIC, 4);
+  memcpy(header->version, OBCC_VERSION, 4);
+  memcpy(header->libbcc_build_time, libbcc_build_time, 24);
+
+  // 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 *);
+
+  header->root_base_addr = mpOwner->lookup("root");
+
+  LOGD("Lookup root() address [%p]", header->root_base_addr);
+
+  // 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(OBCC_DependencyTable) +
+                     sizeof(OBCC_Dependency) * mDependencies.size();
+
+  OBCC_DependencyTable *tab = (OBCC_DependencyTable *)malloc(tableSize);
+
+  if (!tab) {
+    LOGE("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, pair<uint32_t, unsigned char const *> >::iterator
+       I = mDependencies.begin(), E = mDependencies.end(); I != E; ++I, ++i) {
+    OBCC_Dependency *dep = &tab->table[i];
+
+    dep->res_name_strp_index = addString(I->first.c_str(), I->first.size());
+    dep->res_type = I->second.first;
+    memcpy(dep->sha1, I->second.second, 20);
+  }
+
+  return true;
+}
+
+
+bool MCCacheWriter::prepareFuncTable() {
+  size_t funcCount = mpOwner->getFuncCount();
+
+  size_t tableSize = sizeof(OBCC_FuncTable) +
+                     sizeof(OBCC_FuncInfo) * funcCount;
+
+  OBCC_FuncTable *tab = (OBCC_FuncTable *)malloc(tableSize);
+
+  if (!tab) {
+    LOGE("Unable to allocate for function table section.\n");
+    return false;
+  }
+
+  mpFuncTableSection = tab;
+  mpHeaderSection->func_table_size = tableSize;
+
+  tab->count = static_cast<size_t>(funcCount);
+
+  // Get the function informations
+  vector<FuncInfo> funcInfoList(funcCount);
+  mpOwner->getFuncInfoList(funcCount, &*funcInfoList.begin());
+
+  for (size_t i = 0; i < funcCount; ++i) {
+    FuncInfo *info = &funcInfoList[i];
+    OBCC_FuncInfo *outputInfo = &tab->table[i];
+
+    outputInfo->name_strp_index = addString(info->name, strlen(info->name));
+    outputInfo->cached_addr = info->addr;
+    outputInfo->size = info->size;
+  }
+
+  return true;
+}
+
+
+bool MCCacheWriter::preparePragmaList() {
+  size_t pragmaCount = mpOwner->getPragmaCount();
+
+  size_t listSize = sizeof(OBCC_PragmaList) +
+                    sizeof(OBCC_Pragma) * pragmaCount;
+
+  OBCC_PragmaList *list = (OBCC_PragmaList *)malloc(listSize);
+
+  if (!list) {
+    LOGE("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);
+
+    OBCC_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(OBCC_StringPool) +
+                sizeof(OBCC_String) * mStringPool.size();
+
+  off_t strOffset = size;
+
+  for (size_t i = 0; i < mStringPool.size(); ++i) {
+    size += mStringPool[i].second + 1;
+  }
+
+  // Create string pool
+  OBCC_StringPool *pool = (OBCC_StringPool *)malloc(size);
+
+  if (!pool) {
+    LOGE("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) {
+    OBCC_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::prepareExportVarList() {
+  size_t varCount = mpOwner->getExportVarCount();
+  size_t listSize = sizeof(OBCC_ExportVarList) + sizeof(void *) * varCount;
+
+  OBCC_ExportVarList *list = (OBCC_ExportVarList *)malloc(listSize);
+
+  if (!list) {
+    LOGE("Unable to allocate for export variable list\n");
+    return false;
+  }
+
+  mpExportVarListSection = list;
+  mpHeaderSection->export_var_list_size = listSize;
+
+  list->count = static_cast<size_t>(varCount);
+
+  mpOwner->getExportVarList(varCount, list->cached_addr_list);
+  return true;
+}
+
+
+bool MCCacheWriter::prepareExportFuncList() {
+  size_t funcCount = mpOwner->getExportFuncCount();
+  size_t listSize = sizeof(OBCC_ExportFuncList) + sizeof(void *) * funcCount;
+
+  OBCC_ExportFuncList *list = (OBCC_ExportFuncList *)malloc(listSize);
+
+  if (!list) {
+    LOGE("Unable to allocate for export function list\n");
+    return false;
+  }
+
+  mpExportFuncListSection = list;
+  mpHeaderSection->export_func_list_size = listSize;
+
+  list->count = static_cast<size_t>(funcCount);
+
+  mpOwner->getExportFuncList(funcCount, list->cached_addr_list);
+  return true;
+}
+
+
+bool MCCacheWriter::prepareObjectSlotList() {
+  size_t objectSlotCount = mpOwner->getObjectSlotCount();
+
+  size_t listSize = sizeof(OBCC_ObjectSlotList) +
+                    sizeof(uint32_t) * objectSlotCount;
+
+  OBCC_ObjectSlotList *list = (OBCC_ObjectSlotList *)malloc(listSize);
+
+  if (!list) {
+    LOGE("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(export_var_list);
+  OFFSET_INCREASE(export_func_list);
+  OFFSET_INCREASE(pragma_list);
+  OFFSET_INCREASE(func_table);
+  OFFSET_INCREASE(object_slot_list);
+
+#undef OFFSET_INCREASE
+
+  return true;
+}
+
+
+bool MCCacheWriter::writeAll() {
+#define WRITE_SECTION(NAME, OFFSET, SIZE, SECTION)                          \
+  do {                                                                      \
+    if (mInfoFile->seek(OFFSET, SEEK_SET) == -1) {                              \
+      LOGE("Unable to seek to " #NAME " section for writing.\n");           \
+      return false;                                                         \
+    }                                                                       \
+                                                                            \
+    if (mInfoFile->write(reinterpret_cast<char *>(SECTION), (SIZE)) !=          \
+        static_cast<ssize_t>(SIZE)) {                                       \
+      LOGE("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(export_var_list, mpExportVarListSection);
+  WRITE_SECTION_SIMPLE(export_func_list, mpExportFuncListSection);
+  WRITE_SECTION_SIMPLE(pragma_list, mpPragmaListSection);
+  WRITE_SECTION_SIMPLE(func_table, mpFuncTableSection);
+  WRITE_SECTION_SIMPLE(object_slot_list, mpObjectSlotSection);
+
+#undef WRITE_SECTION_SIMPLE
+#undef WRITE_SECTION
+  
+  if (static_cast<size_t>(mObjFile->write(mpOwner->getELF(), mpOwner->getELFSize()))
+      != mpOwner->getELFSize()) {
+      LOGE("Unable to write ELF to cache file.\n");
+      return false;
+  }
+
+  return true;
+}
+
+
+} // namespace bcc
+#endif
diff --git a/lib/ExecutionEngine/MCCacheWriter.h b/lib/ExecutionEngine/MCCacheWriter.h
new file mode 100644
index 0000000..9970dfb
--- /dev/null
+++ b/lib/ExecutionEngine/MCCacheWriter.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_MCCACHEWRITER_H
+#define BCC_MCCACHEWRITER_H
+
+#include <bcc/bcc_mccache.h>
+
+#include "FileHandle.h"
+
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace bcc {
+  class Script;
+
+  class MCCacheWriter {
+  private:
+    Script *mpOwner;
+
+    FileHandle *mObjFile, *mInfoFile;
+
+    std::vector<std::pair<char const *, size_t> > mStringPool;
+
+    std::map<std::string,
+             std::pair<uint32_t, unsigned char const *> > mDependencies;
+
+    MCO_Header *mpHeaderSection;
+    OBCC_StringPool *mpStringPoolSection;
+    OBCC_DependencyTable *mpDependencyTableSection;
+    OBCC_ExportVarList *mpExportVarListSection;
+    OBCC_ExportFuncList *mpExportFuncListSection;
+    OBCC_PragmaList *mpPragmaListSection;
+    OBCC_FuncTable *mpFuncTableSection;
+    OBCC_ObjectSlotList *mpObjectSlotSection;
+
+  public:
+    MCCacheWriter()
+      : mpHeaderSection(NULL), mpStringPoolSection(NULL),
+        mpDependencyTableSection(NULL), mpExportVarListSection(NULL),
+        mpExportFuncListSection(NULL), mpPragmaListSection(NULL),
+        mpFuncTableSection(NULL), mpObjectSlotSection(NULL) {
+    }
+
+    ~MCCacheWriter();
+
+    bool writeCacheFile(FileHandle *objFile, FileHandle *infoFile,
+                        Script *S, uint32_t libRS_threadable);
+
+    void addDependency(OBCC_ResourceType resType,
+                       std::string const &resName,
+                       unsigned char const *sha1) {
+      mDependencies.insert(std::make_pair(resName,
+                           std::make_pair((uint32_t)resType, sha1)));
+    }
+
+  private:
+    bool prepareHeader(uint32_t libRS_threadable);
+    bool prepareStringPool();
+    bool prepareDependencyTable();
+    bool prepareRelocationTable();
+    bool prepareExportVarList();
+    bool prepareExportFuncList();
+    bool preparePragmaList();
+    bool prepareFuncTable();
+    bool prepareObjectSlotList();
+
+    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/Script.cpp b/lib/ExecutionEngine/Script.cpp
index 0dbb8b6..4e81864 100644
--- a/lib/ExecutionEngine/Script.cpp
+++ b/lib/ExecutionEngine/Script.cpp
@@ -20,6 +20,8 @@
 
 #include "CacheReader.h"
 #include "CacheWriter.h"
+#include "MCCacheReader.h"
+#include "MCCacheWriter.h"
 #include "ContextManager.h"
 #include "DebugHelper.h"
 #include "FileHandle.h"
@@ -194,6 +196,34 @@
 
 
 #if USE_CACHE
+bool getObjPath(std::string &objPath) {
+  size_t found0 = objPath.find("@");
+  size_t found1 = objPath.rfind("@");
+
+  if (found0 == found1 ||
+      found0 == std::string::npos ||
+      found1 == std::string::npos) {
+    LOGE("Ill formatted resource name '%s'. The name should contain 2 @s",
+         objPath.c_str());
+    return false;
+  }
+
+  objPath.replace(found0, found1 - found0 + 1, "", 0);
+  objPath.resize(objPath.length() - 3);
+
+  LOGV("objPath = %s", objPath.c_str());
+  return true;
+}
+
+bool getInfoPath(std::string &infoPath) {
+  getObjPath(infoPath);
+  infoPath.erase(infoPath.size() - 1, 1);
+  infoPath.append("info");
+
+  LOGV("infoPath = %s", infoPath.c_str());
+  return true;
+}
+
 int Script::internalLoadCache() {
   if (getBooleanProp("debug.bcc.nocache")) {
     // Android system environment property disable the cache mechanism by
@@ -207,15 +237,38 @@
     // we don't know where to open the cache file.
     return 1;
   }
+  FileHandle objFile, infoFile;
 
-  FileHandle file;
+  std::string objPath(mCachePath);
+  std::string infoPath(mCachePath);
 
-  if (file.open(mCachePath, OpenMode::Read) < 0) {
+#if USE_MCJIT
+  getObjPath(objPath);
+  getInfoPath(infoPath);
+ #endif
+
+  if (objFile.open(objPath.c_str(), OpenMode::Read) < 0) {
     // Unable to open the cache file in read mode.
     return 1;
   }
 
+ #if USE_OLD_JIT
   CacheReader reader;
+ #endif
+#if USE_MCJIT
+  if (infoFile.open(infoPath.c_str(), OpenMode::Read) < 0) {
+    // Unable to open the cache file in read mode.
+    return 1;
+  }
+
+  MCCacheReader reader;
+
+  // Register symbol lookup function
+  if (mpExtSymbolLookupFn) {
+    reader.registerSymbolCallback(mpExtSymbolLookupFn,
+                                      mpExtSymbolLookupFnContext);
+  }
+ #endif
 
   // Dependencies
 #if USE_LIBBCC_SHA1SUM
@@ -231,7 +284,12 @@
   }
 
   // Read cache file
-  ScriptCached *cached = reader.readCacheFile(&file, this);
+#if USE_MCJIT
+  ScriptCached *cached = reader.readCacheFile(&objFile, &infoFile, this);
+#endif
+#if USE_OLD_JIT
+  ScriptCached *cached = reader.readCacheFile(&objFile, this);
+#endif
   if (!cached) {
     mIsContextSlotNotAvail = reader.isContextSlotNotAvail();
     return 1;
@@ -250,7 +308,6 @@
 }
 #endif
 
-
 int Script::internalCompile() {
   // Create the ScriptCompiled object
   mCompiled = new (std::nothrow) ScriptCompiled(this);
@@ -312,20 +369,42 @@
   // we don't have to cache it.
 
   if (mCachePath &&
+#if USE_OLD_JIT
       !mIsContextSlotNotAvail &&
       ContextManager::get().isManagingContext(getContext()) &&
+#endif
       !getBooleanProp("debug.bcc.nocache")) {
 
-    FileHandle file;
+    FileHandle infoFile, objFile;
+
+    std::string objPath(mCachePath);
+    std::string infoPath(mCachePath);
+
+#if USE_MCJIT
+    getObjPath(objPath);
+    getInfoPath(infoPath);
+#endif
 
     // Remove the file if it already exists before writing the new file.
     // The old file may still be mapped elsewhere in memory and we do not want
     // to modify its contents.  (The same script may be running concurrently in
     // the same process or a different process!)
-    ::unlink(mCachePath);
+    ::unlink(objPath.c_str());
+#if USE_MCJIT
+    ::unlink(infoPath.c_str());
+#endif
 
-    if (file.open(mCachePath, OpenMode::Write) >= 0) {
+    if (objFile.open(objPath.c_str(), OpenMode::Write) >= 0
+#if USE_MCJIT
+        && infoFile.open(infoPath.c_str(), OpenMode::Write) >= 0
+#endif
+	) {
+#if USE_MCJIT
+      MCCacheWriter writer;
+#endif
+#if USE_OLD_JIT
       CacheWriter writer;
+#endif
 
       // Dependencies
 #if USE_LIBBCC_SHA1SUM
@@ -347,15 +426,29 @@
           (uint32_t)mpExtSymbolLookupFn(mpExtSymbolLookupFnContext,
                                         "__isThreadable");
       }
+#if USE_OLD_JIT
+      if (!writer.writeCacheFile(&objFile, this, libRS_threadable)) {
+#endif
+#if USE_MCJIT
+      if (!writer.writeCacheFile(&objFile, &infoFile, this, libRS_threadable)) {
+#endif
+        objFile.truncate();
+        objFile.close();
 
-      if (!writer.writeCacheFile(&file, this, libRS_threadable)) {
-        file.truncate();
-        file.close();
-
-        if (unlink(mCachePath) != 0) {
+        if (unlink(objPath.c_str()) != 0) {
           LOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
-               mCachePath, strerror(errno));
+               objPath.c_str(), strerror(errno));
         }
+
+#if USE_MCJIT
+        infoFile.truncate();
+        infoFile.close();
+
+        if (unlink(infoPath.c_str()) != 0) {
+          LOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
+               infoPath.c_str(), strerror(errno));
+        }
+#endif
       }
     }
   }
@@ -573,5 +666,25 @@
   }
   return 0;
 }
+#if USE_MCJIT
+size_t Script::getELFSize() const {
+  switch (mStatus) {
+  case ScriptStatus::Compiled:  return mCompiled->getELFSize();
+
+  default:
+    return NULL;
+  }
+  return 0;
+}
+
+const char *Script::getELF() const {
+  switch (mStatus) {
+  case ScriptStatus::Compiled:  return mCompiled->getELF();
+
+  default:
+    return NULL;
+  }
+}
+#endif
 
 } // namespace bcc
diff --git a/lib/ExecutionEngine/Script.h b/lib/ExecutionEngine/Script.h
index dc115da..97747b9 100644
--- a/lib/ExecutionEngine/Script.h
+++ b/lib/ExecutionEngine/Script.h
@@ -125,6 +125,9 @@
 
     void getObjectSlotList(size_t size, uint32_t *list);
 
+    size_t getELFSize() const;
+
+    const char *getELF() const;
 
     int registerSymbolCallback(BCCSymbolLookupFn pFn, void *pContext);
 
diff --git a/lib/ExecutionEngine/ScriptCached.cpp b/lib/ExecutionEngine/ScriptCached.cpp
index b1dd9ce..da32ad0 100644
--- a/lib/ExecutionEngine/ScriptCached.cpp
+++ b/lib/ExecutionEngine/ScriptCached.cpp
@@ -104,11 +104,13 @@
 
 
 void *ScriptCached::lookup(const char *name) {
+#if USE_MCJIT
+  return rsloaderGetSymbolAddress(mRSExecutable, name);
+#endif
   FuncTable::const_iterator I = mFunctions.find(name);
   return (I == mFunctions.end()) ? NULL : I->second.first;
 }
 
-
 void ScriptCached::getFuncInfoList(size_t funcInfoListSize,
                                    FuncInfo *funcInfoList) {
   if (funcInfoList) {
diff --git a/lib/ExecutionEngine/ScriptCached.h b/lib/ExecutionEngine/ScriptCached.h
index 26db663..53cb967 100644
--- a/lib/ExecutionEngine/ScriptCached.h
+++ b/lib/ExecutionEngine/ScriptCached.h
@@ -19,8 +19,11 @@
 
 #include <bcc/bcc.h>
 #include <bcc/bcc_cache.h>
+#include <bcc/bcc_mccache.h>
 #include "bcc_internal.h"
 
+#include "librsloader.h"
+
 #include <llvm/ADT/SmallVector.h>
 
 #include <map>
@@ -39,6 +42,7 @@
 
   class ScriptCached {
     friend class CacheReader;
+    friend class MCCacheReader;
 
   private:
     enum { SMALL_VECTOR_QUICKN = 16 };
@@ -60,6 +64,8 @@
 
     char *mContext;
 
+    RSExecRef mRSExecutable;
+
     OBCC_StringPool *mpStringPoolRaw;
     std::vector<char const *> mStringPool;
 
diff --git a/lib/ExecutionEngine/ScriptCompiled.h b/lib/ExecutionEngine/ScriptCompiled.h
index 35c9b83..66efe3a 100644
--- a/lib/ExecutionEngine/ScriptCompiled.h
+++ b/lib/ExecutionEngine/ScriptCompiled.h
@@ -131,6 +131,15 @@
     char *getContext() {
       return mContext;
     }
+#if USE_MCJIT
+    const char *getELF() const {
+      return &*mCompiler.getELF().begin();
+    }
+
+    size_t getELFSize() const {
+      return mCompiler.getELF().size();
+    }
+#endif
 
     void registerSymbolCallback(BCCSymbolLookupFn pFn, void *pContext) {
       mCompiler.registerSymbolCallback(pFn, pContext);
diff --git a/lib/ExecutionEngine/SourceInfo.cpp b/lib/ExecutionEngine/SourceInfo.cpp
index c8126a8..40b2fd9 100644
--- a/lib/ExecutionEngine/SourceInfo.cpp
+++ b/lib/ExecutionEngine/SourceInfo.cpp
@@ -19,6 +19,8 @@
 #if USE_CACHE
 #include "CacheReader.h"
 #include "CacheWriter.h"
+#include "MCCacheWriter.h"
+#include "MCCacheReader.h"
 #endif
 
 #include "DebugHelper.h"
@@ -188,6 +190,8 @@
 
 template void SourceInfo::introDependency<CacheReader>(CacheReader &);
 template void SourceInfo::introDependency<CacheWriter>(CacheWriter &);
+template void SourceInfo::introDependency<MCCacheWriter>(MCCacheWriter &);
+template void SourceInfo::introDependency<MCCacheReader>(MCCacheReader &);
 #endif // USE_CACHE